diff options
author | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2015-04-21 06:12:35 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2015-04-21 06:12:35 -0300 |
commit | 676ee36be04985062522804c2de04f0764212be6 (patch) | |
tree | 781df135c5a91a04decad1b7d53b5a925dc11522 | |
parent | b18042a673e88c9457a6d1716219c2367ca447b0 (diff) | |
parent | e183201b9e917daf2530b637b2f34f1d5afb934d (diff) |
Merge branch 'patchwork' into v4l_for_linus
* patchwork: (404 commits)
[media] uvcvideo: add support for VIDIOC_QUERY_EXT_CTRL
[media] uvcvideo: fix cropcap v4l2-compliance failure
[media] media: omap3isp: remove unused clkdev
[media] coda: Add tracing support
[media] coda: drop dma_sync_single_for_device in coda_bitstream_queue
[media] coda: fix fill bitstream errors in nonstreaming case
[media] coda: call SEQ_END when the first queue is stopped
[media] coda: fail to start streaming if userspace set invalid formats
[media] coda: remove duplicate error messages for buffer allocations
[media] coda: move parameter buffer in together with context buffer allocation
[media] coda: allocate bitstream buffer from REQBUFS, size depends on the format
[media] coda: allocate per-context buffers from REQBUFS
[media] coda: use strlcpy instead of snprintf
[media] coda: bitstream payload is unsigned
[media] coda: fix double call to debugfs_remove
[media] coda: check kasprintf return value in coda_open
[media] coda: bitrate can only be set in kbps steps
[media] v4l2-mem2mem: no need to initialize b in v4l2_m2m_next_buf and v4l2_m2m_buf_remove
[media] s5p-mfc: set allow_zero_bytesused flag for vb2_queue_init
[media] coda: set allow_zero_bytesused flag for vb2_queue_init
...
464 files changed, 17050 insertions, 6367 deletions
diff --git a/Documentation/DocBook/media/v4l/biblio.xml b/Documentation/DocBook/media/v4l/biblio.xml index 7ff01a23c2fe..fdee6b3f3eca 100644 --- a/Documentation/DocBook/media/v4l/biblio.xml +++ b/Documentation/DocBook/media/v4l/biblio.xml @@ -1,14 +1,13 @@ <bibliography> <title>References</title> - <biblioentry id="eia608"> - <abbrev>EIA 608-B</abbrev> + <biblioentry id="cea608"> + <abbrev>CEA 608-E</abbrev> <authorgroup> - <corpauthor>Electronic Industries Alliance (<ulink -url="http://www.eia.org">http://www.eia.org</ulink>)</corpauthor> + <corpauthor>Consumer Electronics Association (<ulink +url="http://www.ce.org">http://www.ce.org</ulink>)</corpauthor> </authorgroup> - <title>EIA 608-B "Recommended Practice for Line 21 Data -Service"</title> + <title>CEA-608-E R-2014 "Line 21 Data Services"</title> </biblioentry> <biblioentry id="en300294"> diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml index 350dfb3d71ea..a0aef85d33c1 100644 --- a/Documentation/DocBook/media/v4l/compat.xml +++ b/Documentation/DocBook/media/v4l/compat.xml @@ -2491,7 +2491,7 @@ that used it. It was originally scheduled for removal in 2.6.35. </listitem> <listitem> <para>Added <constant>V4L2_EVENT_CTRL_CH_RANGE</constant> control event - changes flag. See <xref linkend="changes-flags"/>.</para> + changes flag. See <xref linkend="ctrl-changes-flags"/>.</para> </listitem> </orderedlist> </section> diff --git a/Documentation/DocBook/media/v4l/dev-sliced-vbi.xml b/Documentation/DocBook/media/v4l/dev-sliced-vbi.xml index 7a8bf3011ee9..0aec62ed2bf8 100644 --- a/Documentation/DocBook/media/v4l/dev-sliced-vbi.xml +++ b/Documentation/DocBook/media/v4l/dev-sliced-vbi.xml @@ -254,7 +254,7 @@ ETS 300 231, lsb first transmitted.</entry> <row> <entry><constant>V4L2_SLICED_CAPTION_525</constant></entry> <entry>0x1000</entry> - <entry><xref linkend="eia608" /></entry> + <entry><xref linkend="cea608" /></entry> <entry>NTSC line 21, 284 (second field 21)</entry> <entry>Two bytes in transmission order, including parity bit, lsb first transmitted.</entry> diff --git a/Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml b/Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml index 116c301656e0..5872f8bbf774 100644 --- a/Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml +++ b/Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml @@ -143,86 +143,28 @@ <row> <entry></entry> <entry>struct</entry> - <entry><structfield>v4l</structfield></entry> + <entry><structfield>dev</structfield></entry> <entry></entry> - <entry>Valid for V4L sub-devices and nodes only.</entry> + <entry>Valid for (sub-)devices that create a single device node.</entry> </row> <row> <entry></entry> <entry></entry> <entry>__u32</entry> <entry><structfield>major</structfield></entry> - <entry>V4L device node major number. For V4L sub-devices with no - device node, set by the driver to 0.</entry> + <entry>Device node major number.</entry> </row> <row> <entry></entry> <entry></entry> <entry>__u32</entry> <entry><structfield>minor</structfield></entry> - <entry>V4L device node minor number. For V4L sub-devices with no - device node, set by the driver to 0.</entry> - </row> - <row> - <entry></entry> - <entry>struct</entry> - <entry><structfield>fb</structfield></entry> - <entry></entry> - <entry>Valid for frame buffer nodes only.</entry> - </row> - <row> - <entry></entry> - <entry></entry> - <entry>__u32</entry> - <entry><structfield>major</structfield></entry> - <entry>Frame buffer device node major number.</entry> - </row> - <row> - <entry></entry> - <entry></entry> - <entry>__u32</entry> - <entry><structfield>minor</structfield></entry> - <entry>Frame buffer device node minor number.</entry> - </row> - <row> - <entry></entry> - <entry>struct</entry> - <entry><structfield>alsa</structfield></entry> - <entry></entry> - <entry>Valid for ALSA devices only.</entry> - </row> - <row> - <entry></entry> - <entry></entry> - <entry>__u32</entry> - <entry><structfield>card</structfield></entry> - <entry>ALSA card number</entry> - </row> - <row> - <entry></entry> - <entry></entry> - <entry>__u32</entry> - <entry><structfield>device</structfield></entry> - <entry>ALSA device number</entry> - </row> - <row> - <entry></entry> - <entry></entry> - <entry>__u32</entry> - <entry><structfield>subdevice</structfield></entry> - <entry>ALSA sub-device number</entry> - </row> - <row> - <entry></entry> - <entry>int</entry> - <entry><structfield>dvb</structfield></entry> - <entry></entry> - <entry>DVB card number</entry> + <entry>Device node minor number.</entry> </row> <row> <entry></entry> <entry>__u8</entry> - <entry><structfield>raw</structfield>[180]</entry> + <entry><structfield>raw</structfield>[184]</entry> <entry></entry> <entry></entry> </row> @@ -253,8 +195,24 @@ <entry>ALSA card</entry> </row> <row> - <entry><constant>MEDIA_ENT_T_DEVNODE_DVB</constant></entry> - <entry>DVB card</entry> + <entry><constant>MEDIA_ENT_T_DEVNODE_DVB_FE</constant></entry> + <entry>DVB frontend devnode</entry> + </row> + <row> + <entry><constant>MEDIA_ENT_T_DEVNODE_DVB_DEMUX</constant></entry> + <entry>DVB demux devnode</entry> + </row> + <row> + <entry><constant>MEDIA_ENT_T_DEVNODE_DVB_DVR</constant></entry> + <entry>DVB DVR devnode</entry> + </row> + <row> + <entry><constant>MEDIA_ENT_T_DEVNODE_DVB_CA</constant></entry> + <entry>DVB CAM devnode</entry> + </row> + <row> + <entry><constant>MEDIA_ENT_T_DEVNODE_DVB_NET</constant></entry> + <entry>DVB network devnode</entry> </row> <row> <entry><constant>MEDIA_ENT_T_V4L2_SUBDEV</constant></entry> @@ -282,6 +240,10 @@ it in some digital video standard, with appropriate embedded timing signals.</entry> </row> + <row> + <entry><constant>MEDIA_ENT_T_V4L2_SUBDEV_TUNER</constant></entry> + <entry>TV and/or radio tuner</entry> + </row> </tbody> </tgroup> </table> diff --git a/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml b/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml index 6ab4f0f3db64..b60fb935b91b 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml @@ -303,45 +303,6 @@ for a pixel lie next to each other in memory.</para> <entry>b<subscript>1</subscript></entry> <entry>b<subscript>0</subscript></entry> </row> - <row id="V4L2-PIX-FMT-BGR666"> - <entry><constant>V4L2_PIX_FMT_BGR666</constant></entry> - <entry>'BGRH'</entry> - <entry></entry> - <entry>b<subscript>5</subscript></entry> - <entry>b<subscript>4</subscript></entry> - <entry>b<subscript>3</subscript></entry> - <entry>b<subscript>2</subscript></entry> - <entry>b<subscript>1</subscript></entry> - <entry>b<subscript>0</subscript></entry> - <entry>g<subscript>5</subscript></entry> - <entry>g<subscript>4</subscript></entry> - <entry></entry> - <entry>g<subscript>3</subscript></entry> - <entry>g<subscript>2</subscript></entry> - <entry>g<subscript>1</subscript></entry> - <entry>g<subscript>0</subscript></entry> - <entry>r<subscript>5</subscript></entry> - <entry>r<subscript>4</subscript></entry> - <entry>r<subscript>3</subscript></entry> - <entry>r<subscript>2</subscript></entry> - <entry></entry> - <entry>r<subscript>1</subscript></entry> - <entry>r<subscript>0</subscript></entry> - <entry></entry> - <entry></entry> - <entry></entry> - <entry></entry> - <entry></entry> - <entry></entry> - <entry></entry> - <entry></entry> - <entry></entry> - <entry></entry> - <entry></entry> - <entry></entry> - <entry></entry> - <entry></entry> - </row> <row id="V4L2-PIX-FMT-BGR24"> <entry><constant>V4L2_PIX_FMT_BGR24</constant></entry> <entry>'BGR3'</entry> @@ -404,6 +365,46 @@ for a pixel lie next to each other in memory.</para> <entry>b<subscript>1</subscript></entry> <entry>b<subscript>0</subscript></entry> </row> + <row id="V4L2-PIX-FMT-BGR666"> + <entry><constant>V4L2_PIX_FMT_BGR666</constant></entry> + <entry>'BGRH'</entry> + <entry></entry> + <entry>b<subscript>5</subscript></entry> + <entry>b<subscript>4</subscript></entry> + <entry>b<subscript>3</subscript></entry> + <entry>b<subscript>2</subscript></entry> + <entry>b<subscript>1</subscript></entry> + <entry>b<subscript>0</subscript></entry> + <entry>g<subscript>5</subscript></entry> + <entry>g<subscript>4</subscript></entry> + <entry></entry> + <entry>g<subscript>3</subscript></entry> + <entry>g<subscript>2</subscript></entry> + <entry>g<subscript>1</subscript></entry> + <entry>g<subscript>0</subscript></entry> + <entry>r<subscript>5</subscript></entry> + <entry>r<subscript>4</subscript></entry> + <entry>r<subscript>3</subscript></entry> + <entry>r<subscript>2</subscript></entry> + <entry></entry> + <entry>r<subscript>1</subscript></entry> + <entry>r<subscript>0</subscript></entry> + <entry>-</entry> + <entry>-</entry> + <entry>-</entry> + <entry>-</entry> + <entry>-</entry> + <entry>-</entry> + <entry></entry> + <entry>-</entry> + <entry>-</entry> + <entry>-</entry> + <entry>-</entry> + <entry>-</entry> + <entry>-</entry> + <entry>-</entry> + <entry>-</entry> + </row> <row id="V4L2-PIX-FMT-ABGR32"> <entry><constant>V4L2_PIX_FMT_ABGR32</constant></entry> <entry>'AR24'</entry> diff --git a/Documentation/DocBook/media/v4l/pixfmt-sgrbg8.xml b/Documentation/DocBook/media/v4l/pixfmt-sgrbg8.xml index 19727ab4c757..7803b8c41b45 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-sgrbg8.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-sgrbg8.xml @@ -38,10 +38,10 @@ columns and rows.</para> </row> <row> <entry>start + 4:</entry> - <entry>R<subscript>10</subscript></entry> - <entry>B<subscript>11</subscript></entry> - <entry>R<subscript>12</subscript></entry> - <entry>B<subscript>13</subscript></entry> + <entry>B<subscript>10</subscript></entry> + <entry>G<subscript>11</subscript></entry> + <entry>B<subscript>12</subscript></entry> + <entry>G<subscript>13</subscript></entry> </row> <row> <entry>start + 8:</entry> @@ -52,10 +52,10 @@ columns and rows.</para> </row> <row> <entry>start + 12:</entry> - <entry>R<subscript>30</subscript></entry> - <entry>B<subscript>31</subscript></entry> - <entry>R<subscript>32</subscript></entry> - <entry>B<subscript>33</subscript></entry> + <entry>B<subscript>30</subscript></entry> + <entry>G<subscript>31</subscript></entry> + <entry>B<subscript>32</subscript></entry> + <entry>G<subscript>33</subscript></entry> </row> </tbody> </tgroup> diff --git a/Documentation/DocBook/media/v4l/pixfmt-srggb10p.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb10p.xml index 30aa63581fe3..a8cc102cde4f 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-srggb10p.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-srggb10p.xml @@ -38,7 +38,7 @@ <title>Byte Order.</title> <para>Each cell is one byte. <informaltable frame="topbot" colsep="1" rowsep="1"> - <tgroup cols="5" align="center" border="1"> + <tgroup cols="5" align="center"> <colspec align="left" colwidth="2*" /> <tbody valign="top"> <row> diff --git a/Documentation/DocBook/media/v4l/pixfmt-yuv420m.xml b/Documentation/DocBook/media/v4l/pixfmt-yuv420m.xml index 60308f1eefdf..e781cc61786c 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-yuv420m.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-yuv420m.xml @@ -29,12 +29,12 @@ and Cr planes have half as many pad bytes after their rows. In other words, two Cx rows (including padding) is exactly as long as one Y row (including padding).</para> - <para><constant>V4L2_PIX_FMT_NV12M</constant> is intended to be + <para><constant>V4L2_PIX_FMT_YUV420M</constant> is intended to be used only in drivers and applications that support the multi-planar API, described in <xref linkend="planar-apis"/>. </para> <example> - <title><constant>V4L2_PIX_FMT_YVU420M</constant> 4 × 4 + <title><constant>V4L2_PIX_FMT_YUV420M</constant> 4 × 4 pixel image</title> <formalpara> diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml index 5e0352c50324..fcde4e20205e 100644 --- a/Documentation/DocBook/media/v4l/pixfmt.xml +++ b/Documentation/DocBook/media/v4l/pixfmt.xml @@ -80,9 +80,9 @@ padding bytes after the last line of an image cross a system page boundary. Input devices may write padding bytes, the value is undefined. Output devices ignore the contents of padding bytes.</para><para>When the image format is planar the -<structfield>bytesperline</structfield> value applies to the largest +<structfield>bytesperline</structfield> value applies to the first plane and is divided by the same factor as the -<structfield>width</structfield> field for any smaller planes. For +<structfield>width</structfield> field for the other planes. For example the Cb and Cr planes of a YUV 4:2:0 image have half as many padding bytes following each line as the Y plane. To avoid ambiguities drivers must return a <structfield>bytesperline</structfield> value @@ -182,14 +182,14 @@ see <xref linkend="colorspaces" />.</entry> </entry> </row> <row> - <entry>__u16</entry> + <entry>__u32</entry> <entry><structfield>bytesperline</structfield></entry> <entry>Distance in bytes between the leftmost pixels in two adjacent lines. See &v4l2-pix-format;.</entry> </row> <row> <entry>__u16</entry> - <entry><structfield>reserved[7]</structfield></entry> + <entry><structfield>reserved[6]</structfield></entry> <entry>Reserved for future extensions. Should be zeroed by the application.</entry> </row> @@ -483,8 +483,8 @@ is the Y'CbCr encoding identifier (&v4l2-ycbcr-encoding;) to specify non-standar Y'CbCr encodings and the third is the quantization identifier (&v4l2-quantization;) to specify non-standard quantization methods. Most of the time only the colorspace field of &v4l2-pix-format; or &v4l2-pix-format-mplane; needs to be filled in. Note -that the default R'G'B' quantization is always full range for all colorspaces, -so this won't be mentioned explicitly for each colorspace description.</para> +that the default R'G'B' quantization is full range for all colorspaces except for +BT.2020 which uses limited range R'G'B' quantization.</para> <table pgwide="1" frame="none" id="v4l2-colorspace"> <title>V4L2 Colorspaces</title> @@ -598,7 +598,8 @@ so this won't be mentioned explicitly for each colorspace description.</para> <row> <entry><constant>V4L2_QUANTIZATION_DEFAULT</constant></entry> <entry>Use the default quantization encoding as defined by the colorspace. -This is always full range for R'G'B' and usually limited range for Y'CbCr.</entry> +This is always full range for R'G'B' (except for the BT.2020 colorspace) and usually +limited range for Y'CbCr.</entry> </row> <row> <entry><constant>V4L2_QUANTIZATION_FULL_RANGE</constant></entry> @@ -620,8 +621,8 @@ is mapped to [16…235]. Cb and Cr are mapped from [-0.5…0.5] to [16 <section> <title>Detailed Colorspace Descriptions</title> - <section> - <title id="col-smpte-170m">Colorspace SMPTE 170M (<constant>V4L2_COLORSPACE_SMPTE170M</constant>)</title> + <section id="col-smpte-170m"> + <title>Colorspace SMPTE 170M (<constant>V4L2_COLORSPACE_SMPTE170M</constant>)</title> <para>The <xref linkend="smpte170m" /> standard defines the colorspace used by NTSC and PAL and by SDTV in general. The default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_601</constant>. The default Y'CbCr quantization is limited range. The chromaticities of the primary colors and @@ -666,8 +667,7 @@ as the SMPTE C set, so this colorspace is sometimes called SMPTE C as well.</par <variablelist> <varlistentry> <term>The transfer function defined for SMPTE 170M is the same as the -one defined in Rec. 709. Normally L is in the range [0…1], but for the extended -gamut xvYCC encoding values outside that range are allowed.</term> +one defined in Rec. 709.</term> <listitem> <para>L' = -1.099(-L)<superscript>0.45</superscript> + 0.099 for L ≤ -0.018</para> <para>L' = 4.5L for -0.018 < L < 0.018</para> @@ -702,29 +702,10 @@ defined in the <xref linkend="itu601" /> standard and this colorspace is sometim though BT.601 does not mention any color primaries.</para> <para>The default quantization is limited range, but full range is possible although rarely seen.</para> - <para>The <constant>V4L2_YCBCR_ENC_601</constant> encoding as described above is the -default for this colorspace, but it can be overridden with <constant>V4L2_YCBCR_ENC_709</constant>, -in which case the Rec. 709 Y'CbCr encoding is used.</para> - <variablelist> - <varlistentry> - <term>The xvYCC 601 encoding (<constant>V4L2_YCBCR_ENC_XV601</constant>, <xref linkend="xvycc" />) is similar -to the BT.601 encoding, but it allows for R', G' and B' values that are outside the range -[0…1]. The resulting Y', Cb and Cr values are scaled and offset:</term> - <listitem> - <para>Y' = (219 / 255) * (0.299R' + 0.587G' + 0.114B') + (16 / 255)</para> - <para>Cb = (224 / 255) * (-0.169R' - 0.331G' + 0.5B')</para> - <para>Cr = (224 / 255) * (0.5R' - 0.419G' - 0.081B')</para> - </listitem> - </varlistentry> - </variablelist> - <para>Y' is clamped to the range [0…1] and Cb and Cr are clamped -to the range [-0.5…0.5]. The non-standard xvYCC 709 encoding can also be used by selecting -<constant>V4L2_YCBCR_ENC_XV709</constant>. The xvYCC encodings always use full range -quantization.</para> </section> - <section> - <title id="col-rec709">Colorspace Rec. 709 (<constant>V4L2_COLORSPACE_REC709</constant>)</title> + <section id="col-rec709"> + <title>Colorspace Rec. 709 (<constant>V4L2_COLORSPACE_REC709</constant>)</title> <para>The <xref linkend="itu709" /> standard defines the colorspace used by HDTV in general. The default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_709</constant>. The default Y'CbCr quantization is limited range. The chromaticities of the primary colors and the white reference are:</para> @@ -803,26 +784,39 @@ rarely seen.</para> <para>The <constant>V4L2_YCBCR_ENC_709</constant> encoding described above is the default for this colorspace, but it can be overridden with <constant>V4L2_YCBCR_ENC_601</constant>, in which case the BT.601 Y'CbCr encoding is used.</para> + <para>Two additional extended gamut Y'CbCr encodings are also possible with this colorspace:</para> <variablelist> <varlistentry> <term>The xvYCC 709 encoding (<constant>V4L2_YCBCR_ENC_XV709</constant>, <xref linkend="xvycc" />) is similar to the Rec. 709 encoding, but it allows for R', G' and B' values that are outside the range [0…1]. The resulting Y', Cb and Cr values are scaled and offset:</term> <listitem> - <para>Y' = (219 / 255) * (0.2126R' + 0.7152G' + 0.0722B') + (16 / 255)</para> - <para>Cb = (224 / 255) * (-0.1146R' - 0.3854G' + 0.5B')</para> - <para>Cr = (224 / 255) * (0.5R' - 0.4542G' - 0.0458B')</para> + <para>Y' = (219 / 256) * (0.2126R' + 0.7152G' + 0.0722B') + (16 / 256)</para> + <para>Cb = (224 / 256) * (-0.1146R' - 0.3854G' + 0.5B')</para> + <para>Cr = (224 / 256) * (0.5R' - 0.4542G' - 0.0458B')</para> + </listitem> + </varlistentry> + </variablelist> + <variablelist> + <varlistentry> + <term>The xvYCC 601 encoding (<constant>V4L2_YCBCR_ENC_XV601</constant>, <xref linkend="xvycc" />) is similar +to the BT.601 encoding, but it allows for R', G' and B' values that are outside the range +[0…1]. The resulting Y', Cb and Cr values are scaled and offset:</term> + <listitem> + <para>Y' = (219 / 256) * (0.299R' + 0.587G' + 0.114B') + (16 / 256)</para> + <para>Cb = (224 / 256) * (-0.169R' - 0.331G' + 0.5B')</para> + <para>Cr = (224 / 256) * (0.5R' - 0.419G' - 0.081B')</para> </listitem> </varlistentry> </variablelist> <para>Y' is clamped to the range [0…1] and Cb and Cr are clamped -to the range [-0.5…0.5]. The non-standard xvYCC 601 encoding can also be used by -selecting <constant>V4L2_YCBCR_ENC_XV601</constant>. The xvYCC encodings always use full -range quantization.</para> +to the range [-0.5…0.5]. The non-standard xvYCC 709 or xvYCC 601 encodings can be used by +selecting <constant>V4L2_YCBCR_ENC_XV709</constant> or <constant>V4L2_YCBCR_ENC_XV601</constant>. +The xvYCC encodings always use full range quantization.</para> </section> - <section> - <title id="col-srgb">Colorspace sRGB (<constant>V4L2_COLORSPACE_SRGB</constant>)</title> + <section id="col-srgb"> + <title>Colorspace sRGB (<constant>V4L2_COLORSPACE_SRGB</constant>)</title> <para>The <xref linkend="srgb" /> standard defines the colorspace used by most webcams and computer graphics. The default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_SYCC</constant>. The default Y'CbCr quantization is full range. The chromaticities of the primary colors and the white reference are:</para> @@ -898,8 +892,8 @@ encoding, it is not. The <constant>V4L2_YCBCR_ENC_XV601</constant> scales and of values before quantization, but this encoding does not do that.</para> </section> - <section> - <title id="col-adobergb">Colorspace Adobe RGB (<constant>V4L2_COLORSPACE_ADOBERGB</constant>)</title> + <section id="col-adobergb"> + <title>Colorspace Adobe RGB (<constant>V4L2_COLORSPACE_ADOBERGB</constant>)</title> <para>The <xref linkend="adobergb" /> standard defines the colorspace used by computer graphics that use the AdobeRGB colorspace. This is also known as the <xref linkend="oprgb" /> standard. The default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_601</constant>. The default Y'CbCr @@ -970,12 +964,12 @@ clamped to the range [-0.5…0.5]. This transform is identical to one defin SMPTE 170M/BT.601. The Y'CbCr quantization is limited range.</para> </section> - <section> - <title id="col-bt2020">Colorspace BT.2020 (<constant>V4L2_COLORSPACE_BT2020</constant>)</title> + <section id="col-bt2020"> + <title>Colorspace BT.2020 (<constant>V4L2_COLORSPACE_BT2020</constant>)</title> <para>The <xref linkend="itu2020" /> standard defines the colorspace used by Ultra-high definition television (UHDTV). The default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_BT2020</constant>. -The default Y'CbCr quantization is limited range. The chromaticities of the primary colors and -the white reference are:</para> +The default R'G'B' quantization is limited range (!), and so is the default Y'CbCr quantization. +The chromaticities of the primary colors and the white reference are:</para> <table frame="none"> <title>BT.2020 Chromaticities</title> <tgroup cols="3" align="left"> @@ -1032,7 +1026,7 @@ the white reference are:</para> <term>The luminance (Y') and color difference (Cb and Cr) are obtained with the following <constant>V4L2_YCBCR_ENC_BT2020</constant> encoding:</term> <listitem> - <para>Y' = 0.2627R' + 0.6789G' + 0.0593B'</para> + <para>Y' = 0.2627R' + 0.6780G' + 0.0593B'</para> <para>Cb = -0.1396R' - 0.3604G' + 0.5B'</para> <para>Cr = 0.5R' - 0.4598G' - 0.0402B'</para> </listitem> @@ -1046,7 +1040,7 @@ clamped to the range [-0.5…0.5]. The Y'CbCr quantization is limited range <varlistentry> <term>Luma:</term> <listitem> - <para>Yc' = (0.2627R + 0.6789G + 0.0593B)'</para> + <para>Yc' = (0.2627R + 0.6780G + 0.0593B)'</para> </listitem> </varlistentry> </variablelist> @@ -1054,7 +1048,7 @@ clamped to the range [-0.5…0.5]. The Y'CbCr quantization is limited range <varlistentry> <term>B' - Yc' ≤ 0:</term> <listitem> - <para>Cbc = (B' - Y') / 1.9404</para> + <para>Cbc = (B' - Yc') / 1.9404</para> </listitem> </varlistentry> </variablelist> @@ -1062,7 +1056,7 @@ clamped to the range [-0.5…0.5]. The Y'CbCr quantization is limited range <varlistentry> <term>B' - Yc' > 0:</term> <listitem> - <para>Cbc = (B' - Y') / 1.5816</para> + <para>Cbc = (B' - Yc') / 1.5816</para> </listitem> </varlistentry> </variablelist> @@ -1086,8 +1080,8 @@ clamped to the range [-0.5…0.5]. The Y'CbCr quantization is limited range clamped to the range [-0.5…0.5]. The Yc'CbcCrc quantization is limited range.</para> </section> - <section> - <title id="col-smpte-240m">Colorspace SMPTE 240M (<constant>V4L2_COLORSPACE_SMPTE240M</constant>)</title> + <section id="col-smpte-240m"> + <title>Colorspace SMPTE 240M (<constant>V4L2_COLORSPACE_SMPTE240M</constant>)</title> <para>The <xref linkend="smpte240m" /> standard was an interim standard used during the early days of HDTV (1988-1998). It has been superseded by Rec. 709. The default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_SMPTE240M</constant>. The default Y'CbCr quantization is limited range. The chromaticities of the primary colors and the @@ -1159,8 +1153,8 @@ following <constant>V4L2_YCBCR_ENC_SMPTE240M</constant> encoding:</term> clamped to the range [-0.5…0.5]. The Y'CbCr quantization is limited range.</para> </section> - <section> - <title id="col-sysm">Colorspace NTSC 1953 (<constant>V4L2_COLORSPACE_470_SYSTEM_M</constant>)</title> + <section id="col-sysm"> + <title>Colorspace NTSC 1953 (<constant>V4L2_COLORSPACE_470_SYSTEM_M</constant>)</title> <para>This standard defines the colorspace used by NTSC in 1953. In practice this colorspace is obsolete and SMPTE 170M should be used instead. The default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_601</constant>. The default Y'CbCr quantization is limited range. @@ -1237,8 +1231,8 @@ clamped to the range [-0.5…0.5]. The Y'CbCr quantization is limited range This transform is identical to one defined in SMPTE 170M/BT.601.</para> </section> - <section> - <title id="col-sysbg">Colorspace EBU Tech. 3213 (<constant>V4L2_COLORSPACE_470_SYSTEM_BG</constant>)</title> + <section id="col-sysbg"> + <title>Colorspace EBU Tech. 3213 (<constant>V4L2_COLORSPACE_470_SYSTEM_BG</constant>)</title> <para>The <xref linkend="tech3213" /> standard defines the colorspace used by PAL/SECAM in 1975. In practice this colorspace is obsolete and SMPTE 170M should be used instead. The default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_601</constant>. The default Y'CbCr quantization is limited range. @@ -1311,8 +1305,8 @@ clamped to the range [-0.5…0.5]. The Y'CbCr quantization is limited range This transform is identical to one defined in SMPTE 170M/BT.601.</para> </section> - <section> - <title id="col-jpeg">Colorspace JPEG (<constant>V4L2_COLORSPACE_JPEG</constant>)</title> + <section id="col-jpeg"> + <title>Colorspace JPEG (<constant>V4L2_COLORSPACE_JPEG</constant>)</title> <para>This colorspace defines the colorspace used by most (Motion-)JPEG formats. The chromaticities of the primary colors and the white reference are identical to sRGB. The Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_601</constant> with full range quantization where diff --git a/Documentation/DocBook/media/v4l/subdev-formats.xml b/Documentation/DocBook/media/v4l/subdev-formats.xml index c5ea868e3909..bc8d3fb9e4a9 100644 --- a/Documentation/DocBook/media/v4l/subdev-formats.xml +++ b/Documentation/DocBook/media/v4l/subdev-formats.xml @@ -440,6 +440,36 @@ see <xref linkend="colorspaces" />.</entry> <entry>b<subscript>1</subscript></entry> <entry>b<subscript>0</subscript></entry> </row> + <row id="MEDIA-BUS-FMT-RBG888-1X24"> + <entry>MEDIA_BUS_FMT_RBG888_1X24</entry> + <entry>0x100e</entry> + <entry></entry> + &dash-ent-8; + <entry>r<subscript>7</subscript></entry> + <entry>r<subscript>6</subscript></entry> + <entry>r<subscript>5</subscript></entry> + <entry>r<subscript>4</subscript></entry> + <entry>r<subscript>3</subscript></entry> + <entry>r<subscript>2</subscript></entry> + <entry>r<subscript>1</subscript></entry> + <entry>r<subscript>0</subscript></entry> + <entry>b<subscript>7</subscript></entry> + <entry>b<subscript>6</subscript></entry> + <entry>b<subscript>5</subscript></entry> + <entry>b<subscript>4</subscript></entry> + <entry>b<subscript>3</subscript></entry> + <entry>b<subscript>2</subscript></entry> + <entry>b<subscript>1</subscript></entry> + <entry>b<subscript>0</subscript></entry> + <entry>g<subscript>7</subscript></entry> + <entry>g<subscript>6</subscript></entry> + <entry>g<subscript>5</subscript></entry> + <entry>g<subscript>4</subscript></entry> + <entry>g<subscript>3</subscript></entry> + <entry>g<subscript>2</subscript></entry> + <entry>g<subscript>1</subscript></entry> + <entry>g<subscript>0</subscript></entry> + </row> <row id="MEDIA-BUS-FMT-RGB888-1X24"> <entry>MEDIA_BUS_FMT_RGB888_1X24</entry> <entry>0x100a</entry> @@ -579,6 +609,43 @@ see <xref linkend="colorspaces" />.</entry> <entry>b<subscript>1</subscript></entry> <entry>b<subscript>0</subscript></entry> </row> + <row id="MEDIA-BUS-FMT-RGB888-1X32-PADHI"> + <entry>MEDIA_BUS_FMT_RGB888_1X32_PADHI</entry> + <entry>0x100f</entry> + <entry></entry> + <entry>0</entry> + <entry>0</entry> + <entry>0</entry> + <entry>0</entry> + <entry>0</entry> + <entry>0</entry> + <entry>0</entry> + <entry>0</entry> + <entry>r<subscript>7</subscript></entry> + <entry>r<subscript>6</subscript></entry> + <entry>r<subscript>5</subscript></entry> + <entry>r<subscript>4</subscript></entry> + <entry>r<subscript>3</subscript></entry> + <entry>r<subscript>2</subscript></entry> + <entry>r<subscript>1</subscript></entry> + <entry>r<subscript>0</subscript></entry> + <entry>g<subscript>7</subscript></entry> + <entry>g<subscript>6</subscript></entry> + <entry>g<subscript>5</subscript></entry> + <entry>g<subscript>4</subscript></entry> + <entry>g<subscript>3</subscript></entry> + <entry>g<subscript>2</subscript></entry> + <entry>g<subscript>1</subscript></entry> + <entry>g<subscript>0</subscript></entry> + <entry>b<subscript>7</subscript></entry> + <entry>b<subscript>6</subscript></entry> + <entry>b<subscript>5</subscript></entry> + <entry>b<subscript>4</subscript></entry> + <entry>b<subscript>3</subscript></entry> + <entry>b<subscript>2</subscript></entry> + <entry>b<subscript>1</subscript></entry> + <entry>b<subscript>0</subscript></entry> + </row> </tbody> </tgroup> </table> @@ -2188,11 +2255,15 @@ see <xref linkend="colorspaces" />.</entry> <entry>y<subscript>1</subscript></entry> <entry>y<subscript>0</subscript></entry> </row> - <row id="MEDIA-BUS-FMT-UYVY8-1X16"> - <entry>MEDIA_BUS_FMT_UYVY8_1X16</entry> - <entry>0x200f</entry> + <row id="MEDIA-BUS-FMT-UYVY12-2X12"> + <entry>MEDIA_BUS_FMT_UYVY12_2X12</entry> + <entry>0x201c</entry> <entry></entry> - &dash-ent-16; + &dash-ent-20; + <entry>u<subscript>11</subscript></entry> + <entry>u<subscript>10</subscript></entry> + <entry>u<subscript>9</subscript></entry> + <entry>u<subscript>8</subscript></entry> <entry>u<subscript>7</subscript></entry> <entry>u<subscript>6</subscript></entry> <entry>u<subscript>5</subscript></entry> @@ -2201,6 +2272,16 @@ see <xref linkend="colorspaces" />.</entry> <entry>u<subscript>2</subscript></entry> <entry>u<subscript>1</subscript></entry> <entry>u<subscript>0</subscript></entry> + </row> + <row> + <entry></entry> + <entry></entry> + <entry></entry> + &dash-ent-20; + <entry>y<subscript>11</subscript></entry> + <entry>y<subscript>10</subscript></entry> + <entry>y<subscript>9</subscript></entry> + <entry>y<subscript>8</subscript></entry> <entry>y<subscript>7</subscript></entry> <entry>y<subscript>6</subscript></entry> <entry>y<subscript>5</subscript></entry> @@ -2214,7 +2295,11 @@ see <xref linkend="colorspaces" />.</entry> <entry></entry> <entry></entry> <entry></entry> - &dash-ent-16; + &dash-ent-20; + <entry>v<subscript>11</subscript></entry> + <entry>v<subscript>10</subscript></entry> + <entry>v<subscript>9</subscript></entry> + <entry>v<subscript>8</subscript></entry> <entry>v<subscript>7</subscript></entry> <entry>v<subscript>6</subscript></entry> <entry>v<subscript>5</subscript></entry> @@ -2223,6 +2308,16 @@ see <xref linkend="colorspaces" />.</entry> <entry>v<subscript>2</subscript></entry> <entry>v<subscript>1</subscript></entry> <entry>v<subscript>0</subscript></entry> + </row> + <row> + <entry></entry> + <entry></entry> + <entry></entry> + &dash-ent-20; + <entry>y<subscript>11</subscript></entry> + <entry>y<subscript>10</subscript></entry> + <entry>y<subscript>9</subscript></entry> + <entry>y<subscript>8</subscript></entry> <entry>y<subscript>7</subscript></entry> <entry>y<subscript>6</subscript></entry> <entry>y<subscript>5</subscript></entry> @@ -2232,11 +2327,15 @@ see <xref linkend="colorspaces" />.</entry> <entry>y<subscript>1</subscript></entry> <entry>y<subscript>0</subscript></entry> </row> - <row id="MEDIA-BUS-FMT-VYUY8-1X16"> - <entry>MEDIA_BUS_FMT_VYUY8_1X16</entry> - <entry>0x2010</entry> + <row id="MEDIA-BUS-FMT-VYUY12-2X12"> + <entry>MEDIA_BUS_FMT_VYUY12_2X12</entry> + <entry>0x201d</entry> <entry></entry> - &dash-ent-16; + &dash-ent-20; + <entry>v<subscript>11</subscript></entry> + <entry>v<subscript>10</subscript></entry> + <entry>v<subscript>9</subscript></entry> + <entry>v<subscript>8</subscript></entry> <entry>v<subscript>7</subscript></entry> <entry>v<subscript>6</subscript></entry> <entry>v<subscript>5</subscript></entry> @@ -2245,6 +2344,16 @@ see <xref linkend="colorspaces" />.</entry> <entry>v<subscript>2</subscript></entry> <entry>v<subscript>1</subscript></entry> <entry>v<subscript>0</subscript></entry> + </row> + <row> + <entry></entry> + <entry></entry> + <entry></entry> + &dash-ent-20; + <entry>y<subscript>11</subscript></entry> + <entry>y<subscript>10</subscript></entry> + <entry>y<subscript>9</subscript></entry> + <entry>y<subscript>8</subscript></entry> <entry>y<subscript>7</subscript></entry> <entry>y<subscript>6</subscript></entry> <entry>y<subscript>5</subscript></entry> @@ -2258,7 +2367,11 @@ see <xref linkend="colorspaces" />.</entry> <entry></entry> <entry></entry> <entry></entry> - &dash-ent-16; + &dash-ent-20; + <entry>u<subscript>11</subscript></entry> + <entry>u<subscript>10</subscript></entry> + <entry>u<subscript>9</subscript></entry> + <entry>u<subscript>8</subscript></entry> <entry>u<subscript>7</subscript></entry> <entry>u<subscript>6</subscript></entry> <entry>u<subscript>5</subscript></entry> @@ -2267,6 +2380,16 @@ see <xref linkend="colorspaces" />.</entry> <entry>u<subscript>2</subscript></entry> <entry>u<subscript>1</subscript></entry> <entry>u<subscript>0</subscript></entry> + </row> + <row> + <entry></entry> + <entry></entry> + <entry></entry> + &dash-ent-20; + <entry>y<subscript>11</subscript></entry> + <entry>y<subscript>10</subscript></entry> + <entry>y<subscript>9</subscript></entry> + <entry>y<subscript>8</subscript></entry> <entry>y<subscript>7</subscript></entry> <entry>y<subscript>6</subscript></entry> <entry>y<subscript>5</subscript></entry> @@ -2276,11 +2399,15 @@ see <xref linkend="colorspaces" />.</entry> <entry>y<subscript>1</subscript></entry> <entry>y<subscript>0</subscript></entry> </row> - <row id="MEDIA-BUS-FMT-YUYV8-1X16"> - <entry>MEDIA_BUS_FMT_YUYV8_1X16</entry> - <entry>0x2011</entry> + <row id="MEDIA-BUS-FMT-YUYV12-2X12"> + <entry>MEDIA_BUS_FMT_YUYV12_2X12</entry> + <entry>0x201e</entry> <entry></entry> - &dash-ent-16; + &dash-ent-20; + <entry>y<subscript>11</subscript></entry> + <entry>y<subscript>10</subscript></entry> + <entry>y<subscript>9</subscript></entry> + <entry>y<subscript>8</subscript></entry> <entry>y<subscript>7</subscript></entry> <entry>y<subscript>6</subscript></entry> <entry>y<subscript>5</subscript></entry> @@ -2289,6 +2416,16 @@ see <xref linkend="colorspaces" />.</entry> <entry>y<subscript>2</subscript></entry> <entry>y<subscript>1</subscript></entry> <entry>y<subscript>0</subscript></entry> + </row> + <row> + <entry></entry> + <entry></entry> + <entry></entry> + &dash-ent-20; + <entry>u<subscript>11</subscript></entry> + <entry>u<subscript>10</subscript></entry> + <entry>u<subscript>9</subscript></entry> + <entry>u<subscript>8</subscript></entry> <entry>u<subscript>7</subscript></entry> <entry>u<subscript>6</subscript></entry> <entry>u<subscript>5</subscript></entry> @@ -2302,7 +2439,11 @@ see <xref linkend="colorspaces" />.</entry> <entry></entry> <entry></entry> <entry></entry> - &dash-ent-16; + &dash-ent-20; + <entry>y<subscript>11</subscript></entry> + <entry>y<subscript>10</subscript></entry> + <entry>y<subscript>9</subscript></entry> + <entry>y<subscript>8</subscript></entry> <entry>y<subscript>7</subscript></entry> <entry>y<subscript>6</subscript></entry> <entry>y<subscript>5</subscript></entry> @@ -2311,6 +2452,16 @@ see <xref linkend="colorspaces" />.</entry> <entry>y<subscript>2</subscript></entry> <entry>y<subscript>1</subscript></entry> <entry>y<subscript>0</subscript></entry> + </row> + <row> + <entry></entry> + <entry></entry> + <entry></entry> + &dash-ent-20; + <entry>v<subscript>11</subscript></entry> + <entry>v<subscript>10</subscript></entry> + <entry>v<subscript>9</subscript></entry> + <entry>v<subscript>8</subscript></entry> <entry>v<subscript>7</subscript></entry> <entry>v<subscript>6</subscript></entry> <entry>v<subscript>5</subscript></entry> @@ -2320,11 +2471,15 @@ see <xref linkend="colorspaces" />.</entry> <entry>v<subscript>1</subscript></entry> <entry>v<subscript>0</subscript></entry> </row> - <row id="MEDIA-BUS-FMT-YVYU8-1X16"> - <entry>MEDIA_BUS_FMT_YVYU8_1X16</entry> - <entry>0x2012</entry> + <row id="MEDIA-BUS-FMT-YVYU12-2X12"> + <entry>MEDIA_BUS_FMT_YVYU12_2X12</entry> + <entry>0x201f</entry> <entry></entry> - &dash-ent-16; + &dash-ent-20; + <entry>y<subscript>11</subscript></entry> + <entry>y<subscript>10</subscript></entry> + <entry>y<subscript>9</subscript></entry> + <entry>y<subscript>8</subscript></entry> <entry>y<subscript>7</subscript></entry> <entry>y<subscript>6</subscript></entry> <entry>y<subscript>5</subscript></entry> @@ -2333,6 +2488,16 @@ see <xref linkend="colorspaces" />.</entry> <entry>y<subscript>2</subscript></entry> <entry>y<subscript>1</subscript></entry> <entry>y<subscript>0</subscript></entry> + </row> + <row> + <entry></entry> + <entry></entry> + <entry></entry> + &dash-ent-20; + <entry>v<subscript>11</subscript></entry> + <entry>v<subscript>10</subscript></entry> + <entry>v<subscript>9</subscript></entry> + <entry>v<subscript>8</subscript></entry> <entry>v<subscript>7</subscript></entry> <entry>v<subscript>6</subscript></entry> <entry>v<subscript>5</subscript></entry> @@ -2346,29 +2511,11 @@ see <xref linkend="colorspaces" />.</entry> <entry></entry> <entry></entry> <entry></entry> - &dash-ent-16; - <entry>y<subscript>7</subscript></entry> - <entry>y<subscript>6</subscript></entry> - <entry>y<subscript>5</subscript></entry> - <entry>y<subscript>4</subscript></entry> - <entry>y<subscript>3</subscript></entry> - <entry>y<subscript>2</subscript></entry> - <entry>y<subscript>1</subscript></entry> - <entry>y<subscript>0</subscript></entry> - <entry>u<subscript>7</subscript></entry> - <entry>u<subscript>6</subscript></entry> - <entry>u<subscript>5</subscript></entry> - <entry>u<subscript>4</subscript></entry> - <entry>u<subscript>3</subscript></entry> - <entry>u<subscript>2</subscript></entry> - <entry>u<subscript>1</subscript></entry> - <entry>u<subscript>0</subscript></entry> - </row> - <row id="MEDIA-BUS-FMT-YDYUYDYV8-1X16"> - <entry>MEDIA_BUS_FMT_YDYUYDYV8_1X16</entry> - <entry>0x2014</entry> - <entry></entry> - &dash-ent-16; + &dash-ent-20; + <entry>y<subscript>11</subscript></entry> + <entry>y<subscript>10</subscript></entry> + <entry>y<subscript>9</subscript></entry> + <entry>y<subscript>8</subscript></entry> <entry>y<subscript>7</subscript></entry> <entry>y<subscript>6</subscript></entry> <entry>y<subscript>5</subscript></entry> @@ -2377,28 +2524,16 @@ see <xref linkend="colorspaces" />.</entry> <entry>y<subscript>2</subscript></entry> <entry>y<subscript>1</subscript></entry> <entry>y<subscript>0</subscript></entry> - <entry>d</entry> - <entry>d</entry> - <entry>d</entry> - <entry>d</entry> - <entry>d</entry> - <entry>d</entry> - <entry>d</entry> - <entry>d</entry> </row> <row> <entry></entry> <entry></entry> <entry></entry> - &dash-ent-16; - <entry>y<subscript>7</subscript></entry> - <entry>y<subscript>6</subscript></entry> - <entry>y<subscript>5</subscript></entry> - <entry>y<subscript>4</subscript></entry> - <entry>y<subscript>3</subscript></entry> - <entry>y<subscript>2</subscript></entry> - <entry>y<subscript>1</subscript></entry> - <entry>y<subscript>0</subscript></entry> + &dash-ent-20; + <entry>u<subscript>11</subscript></entry> + <entry>u<subscript>10</subscript></entry> + <entry>u<subscript>9</subscript></entry> + <entry>u<subscript>8</subscript></entry> <entry>u<subscript>7</subscript></entry> <entry>u<subscript>6</subscript></entry> <entry>u<subscript>5</subscript></entry> @@ -2408,57 +2543,11 @@ see <xref linkend="colorspaces" />.</entry> <entry>u<subscript>1</subscript></entry> <entry>u<subscript>0</subscript></entry> </row> - <row> - <entry></entry> - <entry></entry> - <entry></entry> - &dash-ent-16; - <entry>y<subscript>7</subscript></entry> - <entry>y<subscript>6</subscript></entry> - <entry>y<subscript>5</subscript></entry> - <entry>y<subscript>4</subscript></entry> - <entry>y<subscript>3</subscript></entry> - <entry>y<subscript>2</subscript></entry> - <entry>y<subscript>1</subscript></entry> - <entry>y<subscript>0</subscript></entry> - <entry>d</entry> - <entry>d</entry> - <entry>d</entry> - <entry>d</entry> - <entry>d</entry> - <entry>d</entry> - <entry>d</entry> - <entry>d</entry> - </row> - <row> - <entry></entry> - <entry></entry> + <row id="MEDIA-BUS-FMT-UYVY8-1X16"> + <entry>MEDIA_BUS_FMT_UYVY8_1X16</entry> + <entry>0x200f</entry> <entry></entry> &dash-ent-16; - <entry>y<subscript>7</subscript></entry> - <entry>y<subscript>6</subscript></entry> - <entry>y<subscript>5</subscript></entry> - <entry>y<subscript>4</subscript></entry> - <entry>y<subscript>3</subscript></entry> - <entry>y<subscript>2</subscript></entry> - <entry>y<subscript>1</subscript></entry> - <entry>y<subscript>0</subscript></entry> - <entry>v<subscript>7</subscript></entry> - <entry>v<subscript>6</subscript></entry> - <entry>v<subscript>5</subscript></entry> - <entry>v<subscript>4</subscript></entry> - <entry>v<subscript>3</subscript></entry> - <entry>v<subscript>2</subscript></entry> - <entry>v<subscript>1</subscript></entry> - <entry>v<subscript>0</subscript></entry> - </row> - <row id="MEDIA-BUS-FMT-UYVY10-1X20"> - <entry>MEDIA_BUS_FMT_UYVY10_1X20</entry> - <entry>0x201a</entry> - <entry></entry> - &dash-ent-12; - <entry>u<subscript>9</subscript></entry> - <entry>u<subscript>8</subscript></entry> <entry>u<subscript>7</subscript></entry> <entry>u<subscript>6</subscript></entry> <entry>u<subscript>5</subscript></entry> @@ -2467,8 +2556,6 @@ see <xref linkend="colorspaces" />.</entry> <entry>u<subscript>2</subscript></entry> <entry>u<subscript>1</subscript></entry> <entry>u<subscript>0</subscript></entry> - <entry>y<subscript>9</subscript></entry> - <entry>y<subscript>8</subscript></entry> <entry>y<subscript>7</subscript></entry> <entry>y<subscript>6</subscript></entry> <entry>y<subscript>5</subscript></entry> @@ -2482,9 +2569,7 @@ see <xref linkend="colorspaces" />.</entry> <entry></entry> <entry></entry> <entry></entry> - &dash-ent-12; - <entry>v<subscript>9</subscript></entry> - <entry>v<subscript>8</subscript></entry> + &dash-ent-16; <entry>v<subscript>7</subscript></entry> <entry>v<subscript>6</subscript></entry> <entry>v<subscript>5</subscript></entry> @@ -2493,8 +2578,6 @@ see <xref linkend="colorspaces" />.</entry> <entry>v<subscript>2</subscript></entry> <entry>v<subscript>1</subscript></entry> <entry>v<subscript>0</subscript></entry> - <entry>y<subscript>9</subscript></entry> - <entry>y<subscript>8</subscript></entry> <entry>y<subscript>7</subscript></entry> <entry>y<subscript>6</subscript></entry> <entry>y<subscript>5</subscript></entry> @@ -2504,13 +2587,11 @@ see <xref linkend="colorspaces" />.</entry> <entry>y<subscript>1</subscript></entry> <entry>y<subscript>0</subscript></entry> </row> - <row id="MEDIA-BUS-FMT-VYUY10-1X20"> - <entry>MEDIA_BUS_FMT_VYUY10_1X20</entry> - <entry>0x201b</entry> + <row id="MEDIA-BUS-FMT-VYUY8-1X16"> + <entry>MEDIA_BUS_FMT_VYUY8_1X16</entry> + <entry>0x2010</entry> <entry></entry> - &dash-ent-12; - <entry>v<subscript>9</subscript></entry> - <entry>v<subscript>8</subscript></entry> + &dash-ent-16; <entry>v<subscript>7</subscript></entry> <entry>v<subscript>6</subscript></entry> <entry>v<subscript>5</subscript></entry> @@ -2519,8 +2600,6 @@ see <xref linkend="colorspaces" />.</entry> <entry>v<subscript>2</subscript></entry> <entry>v<subscript>1</subscript></entry> <entry>v<subscript>0</subscript></entry> - <entry>y<subscript>9</subscript></entry> - <entry>y<subscript>8</subscript></entry> <entry>y<subscript>7</subscript></entry> <entry>y<subscript>6</subscript></entry> <entry>y<subscript>5</subscript></entry> @@ -2534,9 +2613,7 @@ see <xref linkend="colorspaces" />.</entry> <entry></entry> <entry></entry> <entry></entry> - &dash-ent-12; - <entry>u<subscript>9</subscript></entry> - <entry>u<subscript>8</subscript></entry> + &dash-ent-16; <entry>u<subscript>7</subscript></entry> <entry>u<subscript>6</subscript></entry> <entry>u<subscript>5</subscript></entry> @@ -2545,8 +2622,6 @@ see <xref linkend="colorspaces" />.</entry> <entry>u<subscript>2</subscript></entry> <entry>u<subscript>1</subscript></entry> <entry>u<subscript>0</subscript></entry> - <entry>y<subscript>9</subscript></entry> - <entry>y<subscript>8</subscript></entry> <entry>y<subscript>7</subscript></entry> <entry>y<subscript>6</subscript></entry> <entry>y<subscript>5</subscript></entry> @@ -2556,13 +2631,11 @@ see <xref linkend="colorspaces" />.</entry> <entry>y<subscript>1</subscript></entry> <entry>y<subscript>0</subscript></entry> </row> - <row id="MEDIA-BUS-FMT-YUYV10-1X20"> - <entry>MEDIA_BUS_FMT_YUYV10_1X20</entry> - <entry>0x200d</entry> + <row id="MEDIA-BUS-FMT-YUYV8-1X16"> + <entry>MEDIA_BUS_FMT_YUYV8_1X16</entry> + <entry>0x2011</entry> <entry></entry> - &dash-ent-12; - <entry>y<subscript>9</subscript></entry> - <entry>y<subscript>8</subscript></entry> + &dash-ent-16; <entry>y<subscript>7</subscript></entry> <entry>y<subscript>6</subscript></entry> <entry>y<subscript>5</subscript></entry> @@ -2571,8 +2644,6 @@ see <xref linkend="colorspaces" />.</entry> <entry>y<subscript>2</subscript></entry> <entry>y<subscript>1</subscript></entry> <entry>y<subscript>0</subscript></entry> - <entry>u<subscript>9</subscript></entry> - <entry>u<subscript>8</subscript></entry> <entry>u<subscript>7</subscript></entry> <entry>u<subscript>6</subscript></entry> <entry>u<subscript>5</subscript></entry> @@ -2586,9 +2657,7 @@ see <xref linkend="colorspaces" />.</entry> <entry></entry> <entry></entry> <entry></entry> - &dash-ent-12; - <entry>y<subscript>9</subscript></entry> - <entry>y<subscript>8</subscript></entry> + &dash-ent-16; <entry>y<subscript>7</subscript></entry> <entry>y<subscript>6</subscript></entry> <entry>y<subscript>5</subscript></entry> @@ -2597,8 +2666,6 @@ see <xref linkend="colorspaces" />.</entry> <entry>y<subscript>2</subscript></entry> <entry>y<subscript>1</subscript></entry> <entry>y<subscript>0</subscript></entry> - <entry>v<subscript>9</subscript></entry> - <entry>v<subscript>8</subscript></entry> <entry>v<subscript>7</subscript></entry> <entry>v<subscript>6</subscript></entry> <entry>v<subscript>5</subscript></entry> @@ -2608,13 +2675,11 @@ see <xref linkend="colorspaces" />.</entry> <entry>v<subscript>1</subscript></entry> <entry>v<subscript>0</subscript></entry> </row> - <row id="MEDIA-BUS-FMT-YVYU10-1X20"> - <entry>MEDIA_BUS_FMT_YVYU10_1X20</entry> - <entry>0x200e</entry> + <row id="MEDIA-BUS-FMT-YVYU8-1X16"> + <entry>MEDIA_BUS_FMT_YVYU8_1X16</entry> + <entry>0x2012</entry> <entry></entry> - &dash-ent-12; - <entry>y<subscript>9</subscript></entry> - <entry>y<subscript>8</subscript></entry> + &dash-ent-16; <entry>y<subscript>7</subscript></entry> <entry>y<subscript>6</subscript></entry> <entry>y<subscript>5</subscript></entry> @@ -2623,8 +2688,6 @@ see <xref linkend="colorspaces" />.</entry> <entry>y<subscript>2</subscript></entry> <entry>y<subscript>1</subscript></entry> <entry>y<subscript>0</subscript></entry> - <entry>v<subscript>9</subscript></entry> - <entry>v<subscript>8</subscript></entry> <entry>v<subscript>7</subscript></entry> <entry>v<subscript>6</subscript></entry> <entry>v<subscript>5</subscript></entry> @@ -2638,9 +2701,7 @@ see <xref linkend="colorspaces" />.</entry> <entry></entry> <entry></entry> <entry></entry> - &dash-ent-12; - <entry>y<subscript>9</subscript></entry> - <entry>y<subscript>8</subscript></entry> + &dash-ent-16; <entry>y<subscript>7</subscript></entry> <entry>y<subscript>6</subscript></entry> <entry>y<subscript>5</subscript></entry> @@ -2649,8 +2710,6 @@ see <xref linkend="colorspaces" />.</entry> <entry>y<subscript>2</subscript></entry> <entry>y<subscript>1</subscript></entry> <entry>y<subscript>0</subscript></entry> - <entry>u<subscript>9</subscript></entry> - <entry>u<subscript>8</subscript></entry> <entry>u<subscript>7</subscript></entry> <entry>u<subscript>6</subscript></entry> <entry>u<subscript>5</subscript></entry> @@ -2660,14 +2719,11 @@ see <xref linkend="colorspaces" />.</entry> <entry>u<subscript>1</subscript></entry> <entry>u<subscript>0</subscript></entry> </row> - <row id="MEDIA-BUS-FMT-YUV10-1X30"> - <entry>MEDIA_BUS_FMT_YUV10_1X30</entry> - <entry>0x2016</entry> + <row id="MEDIA-BUS-FMT-YDYUYDYV8-1X16"> + <entry>MEDIA_BUS_FMT_YDYUYDYV8_1X16</entry> + <entry>0x2014</entry> <entry></entry> - <entry>-</entry> - <entry>-</entry> - <entry>y<subscript>9</subscript></entry> - <entry>y<subscript>8</subscript></entry> + &dash-ent-16; <entry>y<subscript>7</subscript></entry> <entry>y<subscript>6</subscript></entry> <entry>y<subscript>5</subscript></entry> @@ -2676,39 +2732,20 @@ see <xref linkend="colorspaces" />.</entry> <entry>y<subscript>2</subscript></entry> <entry>y<subscript>1</subscript></entry> <entry>y<subscript>0</subscript></entry> - <entry>u<subscript>9</subscript></entry> - <entry>u<subscript>8</subscript></entry> - <entry>u<subscript>7</subscript></entry> - <entry>u<subscript>6</subscript></entry> - <entry>u<subscript>5</subscript></entry> - <entry>u<subscript>4</subscript></entry> - <entry>u<subscript>3</subscript></entry> - <entry>u<subscript>2</subscript></entry> - <entry>u<subscript>1</subscript></entry> - <entry>u<subscript>0</subscript></entry> - <entry>v<subscript>9</subscript></entry> - <entry>v<subscript>8</subscript></entry> - <entry>v<subscript>7</subscript></entry> - <entry>v<subscript>6</subscript></entry> - <entry>v<subscript>5</subscript></entry> - <entry>v<subscript>4</subscript></entry> - <entry>v<subscript>3</subscript></entry> - <entry>v<subscript>2</subscript></entry> - <entry>v<subscript>1</subscript></entry> - <entry>v<subscript>0</subscript></entry> + <entry>d</entry> + <entry>d</entry> + <entry>d</entry> + <entry>d</entry> + <entry>d</entry> + <entry>d</entry> + <entry>d</entry> + <entry>d</entry> </row> - <row id="MEDIA-BUS-FMT-AYUV8-1X32"> - <entry>MEDIA_BUS_FMT_AYUV8_1X32</entry> - <entry>0x2017</entry> + <row> <entry></entry> - <entry>a<subscript>7</subscript></entry> - <entry>a<subscript>6</subscript></entry> - <entry>a<subscript>5</subscript></entry> - <entry>a<subscript>4</subscript></entry> - <entry>a<subscript>3</subscript></entry> - <entry>a<subscript>2</subscript></entry> - <entry>a<subscript>1</subscript></entry> - <entry>a<subscript>0</subscript></entry> + <entry></entry> + <entry></entry> + &dash-ent-16; <entry>y<subscript>7</subscript></entry> <entry>y<subscript>6</subscript></entry> <entry>y<subscript>5</subscript></entry> @@ -2725,6 +2762,42 @@ see <xref linkend="colorspaces" />.</entry> <entry>u<subscript>2</subscript></entry> <entry>u<subscript>1</subscript></entry> <entry>u<subscript>0</subscript></entry> + </row> + <row> + <entry></entry> + <entry></entry> + <entry></entry> + &dash-ent-16; + <entry>y<subscript>7</subscript></entry> + <entry>y<subscript>6</subscript></entry> + <entry>y<subscript>5</subscript></entry> + <entry>y<subscript>4</subscript></entry> + <entry>y<subscript>3</subscript></entry> + <entry>y<subscript>2</subscript></entry> + <entry>y<subscript>1</subscript></entry> + <entry>y<subscript>0</subscript></entry> + <entry>d</entry> + <entry>d</entry> + <entry>d</entry> + <entry>d</entry> + <entry>d</entry> + <entry>d</entry> + <entry>d</entry> + <entry>d</entry> + </row> + <row> + <entry></entry> + <entry></entry> + <entry></entry> + &dash-ent-16; + <entry>y<subscript>7</subscript></entry> + <entry>y<subscript>6</subscript></entry> + <entry>y<subscript>5</subscript></entry> + <entry>y<subscript>4</subscript></entry> + <entry>y<subscript>3</subscript></entry> + <entry>y<subscript>2</subscript></entry> + <entry>y<subscript>1</subscript></entry> + <entry>y<subscript>0</subscript></entry> <entry>v<subscript>7</subscript></entry> <entry>v<subscript>6</subscript></entry> <entry>v<subscript>5</subscript></entry> @@ -2734,13 +2807,11 @@ see <xref linkend="colorspaces" />.</entry> <entry>v<subscript>1</subscript></entry> <entry>v<subscript>0</subscript></entry> </row> - <row id="MEDIA-BUS-FMT-UYVY12-2X12"> - <entry>MEDIA_BUS_FMT_UYVY12_2X12</entry> - <entry>0x201c</entry> + <row id="MEDIA-BUS-FMT-UYVY10-1X20"> + <entry>MEDIA_BUS_FMT_UYVY10_1X20</entry> + <entry>0x201a</entry> <entry></entry> - &dash-ent-20; - <entry>u<subscript>11</subscript></entry> - <entry>u<subscript>10</subscript></entry> + &dash-ent-12; <entry>u<subscript>9</subscript></entry> <entry>u<subscript>8</subscript></entry> <entry>u<subscript>7</subscript></entry> @@ -2751,14 +2822,6 @@ see <xref linkend="colorspaces" />.</entry> <entry>u<subscript>2</subscript></entry> <entry>u<subscript>1</subscript></entry> <entry>u<subscript>0</subscript></entry> - </row> - <row> - <entry></entry> - <entry></entry> - <entry></entry> - &dash-ent-20; - <entry>y<subscript>11</subscript></entry> - <entry>y<subscript>10</subscript></entry> <entry>y<subscript>9</subscript></entry> <entry>y<subscript>8</subscript></entry> <entry>y<subscript>7</subscript></entry> @@ -2774,9 +2837,7 @@ see <xref linkend="colorspaces" />.</entry> <entry></entry> <entry></entry> <entry></entry> - &dash-ent-20; - <entry>v<subscript>11</subscript></entry> - <entry>v<subscript>10</subscript></entry> + &dash-ent-12; <entry>v<subscript>9</subscript></entry> <entry>v<subscript>8</subscript></entry> <entry>v<subscript>7</subscript></entry> @@ -2787,14 +2848,6 @@ see <xref linkend="colorspaces" />.</entry> <entry>v<subscript>2</subscript></entry> <entry>v<subscript>1</subscript></entry> <entry>v<subscript>0</subscript></entry> - </row> - <row> - <entry></entry> - <entry></entry> - <entry></entry> - &dash-ent-20; - <entry>y<subscript>11</subscript></entry> - <entry>y<subscript>10</subscript></entry> <entry>y<subscript>9</subscript></entry> <entry>y<subscript>8</subscript></entry> <entry>y<subscript>7</subscript></entry> @@ -2806,13 +2859,11 @@ see <xref linkend="colorspaces" />.</entry> <entry>y<subscript>1</subscript></entry> <entry>y<subscript>0</subscript></entry> </row> - <row id="MEDIA-BUS-FMT-VYUY12-2X12"> - <entry>MEDIA_BUS_FMT_VYUY12_2X12</entry> - <entry>0x201d</entry> + <row id="MEDIA-BUS-FMT-VYUY10-1X20"> + <entry>MEDIA_BUS_FMT_VYUY10_1X20</entry> + <entry>0x201b</entry> <entry></entry> - &dash-ent-20; - <entry>v<subscript>11</subscript></entry> - <entry>v<subscript>10</subscript></entry> + &dash-ent-12; <entry>v<subscript>9</subscript></entry> <entry>v<subscript>8</subscript></entry> <entry>v<subscript>7</subscript></entry> @@ -2823,14 +2874,6 @@ see <xref linkend="colorspaces" />.</entry> <entry>v<subscript>2</subscript></entry> <entry>v<subscript>1</subscript></entry> <entry>v<subscript>0</subscript></entry> - </row> - <row> - <entry></entry> - <entry></entry> - <entry></entry> - &dash-ent-20; - <entry>y<subscript>11</subscript></entry> - <entry>y<subscript>10</subscript></entry> <entry>y<subscript>9</subscript></entry> <entry>y<subscript>8</subscript></entry> <entry>y<subscript>7</subscript></entry> @@ -2846,9 +2889,7 @@ see <xref linkend="colorspaces" />.</entry> <entry></entry> <entry></entry> <entry></entry> - &dash-ent-20; - <entry>u<subscript>11</subscript></entry> - <entry>u<subscript>10</subscript></entry> + &dash-ent-12; <entry>u<subscript>9</subscript></entry> <entry>u<subscript>8</subscript></entry> <entry>u<subscript>7</subscript></entry> @@ -2859,14 +2900,6 @@ see <xref linkend="colorspaces" />.</entry> <entry>u<subscript>2</subscript></entry> <entry>u<subscript>1</subscript></entry> <entry>u<subscript>0</subscript></entry> - </row> - <row> - <entry></entry> - <entry></entry> - <entry></entry> - &dash-ent-20; - <entry>y<subscript>11</subscript></entry> - <entry>y<subscript>10</subscript></entry> <entry>y<subscript>9</subscript></entry> <entry>y<subscript>8</subscript></entry> <entry>y<subscript>7</subscript></entry> @@ -2878,13 +2911,11 @@ see <xref linkend="colorspaces" />.</entry> <entry>y<subscript>1</subscript></entry> <entry>y<subscript>0</subscript></entry> </row> - <row id="MEDIA-BUS-FMT-YUYV12-2X12"> - <entry>MEDIA_BUS_FMT_YUYV12_2X12</entry> - <entry>0x201e</entry> + <row id="MEDIA-BUS-FMT-YUYV10-1X20"> + <entry>MEDIA_BUS_FMT_YUYV10_1X20</entry> + <entry>0x200d</entry> <entry></entry> - &dash-ent-20; - <entry>y<subscript>11</subscript></entry> - <entry>y<subscript>10</subscript></entry> + &dash-ent-12; <entry>y<subscript>9</subscript></entry> <entry>y<subscript>8</subscript></entry> <entry>y<subscript>7</subscript></entry> @@ -2895,14 +2926,6 @@ see <xref linkend="colorspaces" />.</entry> <entry>y<subscript>2</subscript></entry> <entry>y<subscript>1</subscript></entry> <entry>y<subscript>0</subscript></entry> - </row> - <row> - <entry></entry> - <entry></entry> - <entry></entry> - &dash-ent-20; - <entry>u<subscript>11</subscript></entry> - <entry>u<subscript>10</subscript></entry> <entry>u<subscript>9</subscript></entry> <entry>u<subscript>8</subscript></entry> <entry>u<subscript>7</subscript></entry> @@ -2918,9 +2941,7 @@ see <xref linkend="colorspaces" />.</entry> <entry></entry> <entry></entry> <entry></entry> - &dash-ent-20; - <entry>y<subscript>11</subscript></entry> - <entry>y<subscript>10</subscript></entry> + &dash-ent-12; <entry>y<subscript>9</subscript></entry> <entry>y<subscript>8</subscript></entry> <entry>y<subscript>7</subscript></entry> @@ -2931,14 +2952,6 @@ see <xref linkend="colorspaces" />.</entry> <entry>y<subscript>2</subscript></entry> <entry>y<subscript>1</subscript></entry> <entry>y<subscript>0</subscript></entry> - </row> - <row> - <entry></entry> - <entry></entry> - <entry></entry> - &dash-ent-20; - <entry>v<subscript>11</subscript></entry> - <entry>v<subscript>10</subscript></entry> <entry>v<subscript>9</subscript></entry> <entry>v<subscript>8</subscript></entry> <entry>v<subscript>7</subscript></entry> @@ -2950,13 +2963,11 @@ see <xref linkend="colorspaces" />.</entry> <entry>v<subscript>1</subscript></entry> <entry>v<subscript>0</subscript></entry> </row> - <row id="MEDIA-BUS-FMT-YVYU12-2X12"> - <entry>MEDIA_BUS_FMT_YVYU12_2X12</entry> - <entry>0x201f</entry> + <row id="MEDIA-BUS-FMT-YVYU10-1X20"> + <entry>MEDIA_BUS_FMT_YVYU10_1X20</entry> + <entry>0x200e</entry> <entry></entry> - &dash-ent-20; - <entry>y<subscript>11</subscript></entry> - <entry>y<subscript>10</subscript></entry> + &dash-ent-12; <entry>y<subscript>9</subscript></entry> <entry>y<subscript>8</subscript></entry> <entry>y<subscript>7</subscript></entry> @@ -2967,14 +2978,6 @@ see <xref linkend="colorspaces" />.</entry> <entry>y<subscript>2</subscript></entry> <entry>y<subscript>1</subscript></entry> <entry>y<subscript>0</subscript></entry> - </row> - <row> - <entry></entry> - <entry></entry> - <entry></entry> - &dash-ent-20; - <entry>v<subscript>11</subscript></entry> - <entry>v<subscript>10</subscript></entry> <entry>v<subscript>9</subscript></entry> <entry>v<subscript>8</subscript></entry> <entry>v<subscript>7</subscript></entry> @@ -2990,9 +2993,7 @@ see <xref linkend="colorspaces" />.</entry> <entry></entry> <entry></entry> <entry></entry> - &dash-ent-20; - <entry>y<subscript>11</subscript></entry> - <entry>y<subscript>10</subscript></entry> + &dash-ent-12; <entry>y<subscript>9</subscript></entry> <entry>y<subscript>8</subscript></entry> <entry>y<subscript>7</subscript></entry> @@ -3003,14 +3004,6 @@ see <xref linkend="colorspaces" />.</entry> <entry>y<subscript>2</subscript></entry> <entry>y<subscript>1</subscript></entry> <entry>y<subscript>0</subscript></entry> - </row> - <row> - <entry></entry> - <entry></entry> - <entry></entry> - &dash-ent-20; - <entry>u<subscript>11</subscript></entry> - <entry>u<subscript>10</subscript></entry> <entry>u<subscript>9</subscript></entry> <entry>u<subscript>8</subscript></entry> <entry>u<subscript>7</subscript></entry> @@ -3022,6 +3015,36 @@ see <xref linkend="colorspaces" />.</entry> <entry>u<subscript>1</subscript></entry> <entry>u<subscript>0</subscript></entry> </row> + <row id="MEDIA-BUS-FMT-VUY8-1X24"> + <entry>MEDIA_BUS_FMT_VUY8_1X24</entry> + <entry>0x201a</entry> + <entry></entry> + &dash-ent-8; + <entry>v<subscript>7</subscript></entry> + <entry>v<subscript>6</subscript></entry> + <entry>v<subscript>5</subscript></entry> + <entry>v<subscript>4</subscript></entry> + <entry>v<subscript>3</subscript></entry> + <entry>v<subscript>2</subscript></entry> + <entry>v<subscript>1</subscript></entry> + <entry>v<subscript>0</subscript></entry> + <entry>u<subscript>7</subscript></entry> + <entry>u<subscript>6</subscript></entry> + <entry>u<subscript>5</subscript></entry> + <entry>u<subscript>4</subscript></entry> + <entry>u<subscript>3</subscript></entry> + <entry>u<subscript>2</subscript></entry> + <entry>u<subscript>1</subscript></entry> + <entry>u<subscript>0</subscript></entry> + <entry>y<subscript>7</subscript></entry> + <entry>y<subscript>6</subscript></entry> + <entry>y<subscript>5</subscript></entry> + <entry>y<subscript>4</subscript></entry> + <entry>y<subscript>3</subscript></entry> + <entry>y<subscript>2</subscript></entry> + <entry>y<subscript>1</subscript></entry> + <entry>y<subscript>0</subscript></entry> + </row> <row id="MEDIA-BUS-FMT-UYVY12-1X24"> <entry>MEDIA_BUS_FMT_UYVY12_1X24</entry> <entry>0x2020</entry> @@ -3262,6 +3285,80 @@ see <xref linkend="colorspaces" />.</entry> <entry>u<subscript>1</subscript></entry> <entry>u<subscript>0</subscript></entry> </row> + <row id="MEDIA-BUS-FMT-YUV10-1X30"> + <entry>MEDIA_BUS_FMT_YUV10_1X30</entry> + <entry>0x2016</entry> + <entry></entry> + <entry>-</entry> + <entry>-</entry> + <entry>y<subscript>9</subscript></entry> + <entry>y<subscript>8</subscript></entry> + <entry>y<subscript>7</subscript></entry> + <entry>y<subscript>6</subscript></entry> + <entry>y<subscript>5</subscript></entry> + <entry>y<subscript>4</subscript></entry> + <entry>y<subscript>3</subscript></entry> + <entry>y<subscript>2</subscript></entry> + <entry>y<subscript>1</subscript></entry> + <entry>y<subscript>0</subscript></entry> + <entry>u<subscript>9</subscript></entry> + <entry>u<subscript>8</subscript></entry> + <entry>u<subscript>7</subscript></entry> + <entry>u<subscript>6</subscript></entry> + <entry>u<subscript>5</subscript></entry> + <entry>u<subscript>4</subscript></entry> + <entry>u<subscript>3</subscript></entry> + <entry>u<subscript>2</subscript></entry> + <entry>u<subscript>1</subscript></entry> + <entry>u<subscript>0</subscript></entry> + <entry>v<subscript>9</subscript></entry> + <entry>v<subscript>8</subscript></entry> + <entry>v<subscript>7</subscript></entry> + <entry>v<subscript>6</subscript></entry> + <entry>v<subscript>5</subscript></entry> + <entry>v<subscript>4</subscript></entry> + <entry>v<subscript>3</subscript></entry> + <entry>v<subscript>2</subscript></entry> + <entry>v<subscript>1</subscript></entry> + <entry>v<subscript>0</subscript></entry> + </row> + <row id="MEDIA-BUS-FMT-AYUV8-1X32"> + <entry>MEDIA_BUS_FMT_AYUV8_1X32</entry> + <entry>0x2017</entry> + <entry></entry> + <entry>a<subscript>7</subscript></entry> + <entry>a<subscript>6</subscript></entry> + <entry>a<subscript>5</subscript></entry> + <entry>a<subscript>4</subscript></entry> + <entry>a<subscript>3</subscript></entry> + <entry>a<subscript>2</subscript></entry> + <entry>a<subscript>1</subscript></entry> + <entry>a<subscript>0</subscript></entry> + <entry>y<subscript>7</subscript></entry> + <entry>y<subscript>6</subscript></entry> + <entry>y<subscript>5</subscript></entry> + <entry>y<subscript>4</subscript></entry> + <entry>y<subscript>3</subscript></entry> + <entry>y<subscript>2</subscript></entry> + <entry>y<subscript>1</subscript></entry> + <entry>y<subscript>0</subscript></entry> + <entry>u<subscript>7</subscript></entry> + <entry>u<subscript>6</subscript></entry> + <entry>u<subscript>5</subscript></entry> + <entry>u<subscript>4</subscript></entry> + <entry>u<subscript>3</subscript></entry> + <entry>u<subscript>2</subscript></entry> + <entry>u<subscript>1</subscript></entry> + <entry>u<subscript>0</subscript></entry> + <entry>v<subscript>7</subscript></entry> + <entry>v<subscript>6</subscript></entry> + <entry>v<subscript>5</subscript></entry> + <entry>v<subscript>4</subscript></entry> + <entry>v<subscript>3</subscript></entry> + <entry>v<subscript>2</subscript></entry> + <entry>v<subscript>1</subscript></entry> + <entry>v<subscript>0</subscript></entry> + </row> </tbody> </tgroup> </table> diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml index ac0f8d9d2a49..e98caa1c39bd 100644 --- a/Documentation/DocBook/media/v4l/v4l2.xml +++ b/Documentation/DocBook/media/v4l/v4l2.xml @@ -136,6 +136,7 @@ Remote Controller chapter.</contrib> <year>2012</year> <year>2013</year> <year>2014</year> + <year>2015</year> <holder>Bill Dirks, Michael H. Schimek, Hans Verkuil, Martin Rubli, Andy Walls, Muralidharan Karicheri, Mauro Carvalho Chehab, Pawel Osciak</holder> @@ -152,6 +153,14 @@ structs, ioctls) must be noted in more detail in the history chapter applications. --> <revision> + <revnumber>3.21</revnumber> + <date>2015-02-13</date> + <authorinitials>mcc</authorinitials> + <revremark>Fix documentation for media controller device nodes and add support for DVB device nodes. +Add support for Tuner sub-device. + </revremark> + </revision> + <revision> <revnumber>3.19</revnumber> <date>2014-12-05</date> <authorinitials>hv</authorinitials> diff --git a/Documentation/DocBook/media/v4l/vidioc-cropcap.xml b/Documentation/DocBook/media/v4l/vidioc-cropcap.xml index 1f5ed64cd75a..50cb940cbe5c 100644 --- a/Documentation/DocBook/media/v4l/vidioc-cropcap.xml +++ b/Documentation/DocBook/media/v4l/vidioc-cropcap.xml @@ -59,6 +59,11 @@ constant except when switching the video standard. Remember this switch can occur implicit when switching the video input or output.</para> +<para>Do not use the multiplanar buffer types. Use <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant> +instead of <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE</constant> +and use <constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant> instead of +<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE</constant>.</para> + <para>This ioctl must be implemented for video capture or output devices that support cropping and/or scaling and/or have non-square pixels, and for overlay devices.</para> @@ -73,9 +78,7 @@ support cropping and/or scaling and/or have non-square pixels, and for overlay d <entry>Type of the data stream, set by the application. Only these types are valid here: <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant>, -<constant>V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE</constant>, -<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant>, -<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE</constant> and +<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant> and <constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant>. See <xref linkend="v4l2-buf-type" />.</entry> </row> <row> diff --git a/Documentation/DocBook/media/v4l/vidioc-dqevent.xml b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml index b036f8963353..50ccd33948c1 100644 --- a/Documentation/DocBook/media/v4l/vidioc-dqevent.xml +++ b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml @@ -64,7 +64,7 @@ <entry>__u32</entry> <entry><structfield>type</structfield></entry> <entry></entry> - <entry>Type of the event.</entry> + <entry>Type of the event, see <xref linkend="event-type" />.</entry> </row> <row> <entry>union</entry> @@ -154,6 +154,113 @@ </tgroup> </table> + <table frame="none" pgwide="1" id="event-type"> + <title>Event Types</title> + <tgroup cols="3"> + &cs-def; + <tbody valign="top"> + <row> + <entry><constant>V4L2_EVENT_ALL</constant></entry> + <entry>0</entry> + <entry>All events. V4L2_EVENT_ALL is valid only for + VIDIOC_UNSUBSCRIBE_EVENT for unsubscribing all events at once. + </entry> + </row> + <row> + <entry><constant>V4L2_EVENT_VSYNC</constant></entry> + <entry>1</entry> + <entry>This event is triggered on the vertical sync. + This event has a &v4l2-event-vsync; associated with it. + </entry> + </row> + <row> + <entry><constant>V4L2_EVENT_EOS</constant></entry> + <entry>2</entry> + <entry>This event is triggered when the end of a stream is reached. + This is typically used with MPEG decoders to report to the application + when the last of the MPEG stream has been decoded. + </entry> + </row> + <row> + <entry><constant>V4L2_EVENT_CTRL</constant></entry> + <entry>3</entry> + <entry><para>This event requires that the <structfield>id</structfield> + matches the control ID from which you want to receive events. + This event is triggered if the control's value changes, if a + button control is pressed or if the control's flags change. + This event has a &v4l2-event-ctrl; associated with it. This struct + contains much of the same information as &v4l2-queryctrl; and + &v4l2-control;.</para> + + <para>If the event is generated due to a call to &VIDIOC-S-CTRL; or + &VIDIOC-S-EXT-CTRLS;, then the event will <emphasis>not</emphasis> be sent to + the file handle that called the ioctl function. This prevents + nasty feedback loops. If you <emphasis>do</emphasis> want to get the + event, then set the <constant>V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK</constant> + flag. + </para> + + <para>This event type will ensure that no information is lost when + more events are raised than there is room internally. In that + case the &v4l2-event-ctrl; of the second-oldest event is kept, + but the <structfield>changes</structfield> field of the + second-oldest event is ORed with the <structfield>changes</structfield> + field of the oldest event.</para> + </entry> + </row> + <row> + <entry><constant>V4L2_EVENT_FRAME_SYNC</constant></entry> + <entry>4</entry> + <entry> + <para>Triggered immediately when the reception of a + frame has begun. This event has a + &v4l2-event-frame-sync; associated with it.</para> + + <para>If the hardware needs to be stopped in the case of a + buffer underrun it might not be able to generate this event. + In such cases the <structfield>frame_sequence</structfield> + field in &v4l2-event-frame-sync; will not be incremented. This + causes two consecutive frame sequence numbers to have n times + frame interval in between them.</para> + </entry> + </row> + <row> + <entry><constant>V4L2_EVENT_SOURCE_CHANGE</constant></entry> + <entry>5</entry> + <entry> + <para>This event is triggered when a source parameter change is + detected during runtime by the video device. It can be a + runtime resolution change triggered by a video decoder or the + format change happening on an input connector. + This event requires that the <structfield>id</structfield> + matches the input index (when used with a video device node) + or the pad index (when used with a subdevice node) from which + you want to receive events.</para> + + <para>This event has a &v4l2-event-src-change; associated + with it. The <structfield>changes</structfield> bitfield denotes + what has changed for the subscribed pad. If multiple events + occurred before application could dequeue them, then the changes + will have the ORed value of all the events generated.</para> + </entry> + </row> + <row> + <entry><constant>V4L2_EVENT_MOTION_DET</constant></entry> + <entry>6</entry> + <entry> + <para>Triggered whenever the motion detection state for one or more of the regions + changes. This event has a &v4l2-event-motion-det; associated with it.</para> + </entry> + </row> + <row> + <entry><constant>V4L2_EVENT_PRIVATE_START</constant></entry> + <entry>0x08000000</entry> + <entry>Base event number for driver-private events.</entry> + </row> + </tbody> + </tgroup> + </table> + <table frame="none" pgwide="1" id="v4l2-event-vsync"> <title>struct <structname>v4l2_event_vsync</structname></title> <tgroup cols="3"> @@ -177,7 +284,7 @@ <entry>__u32</entry> <entry><structfield>changes</structfield></entry> <entry></entry> - <entry>A bitmask that tells what has changed. See <xref linkend="changes-flags" />.</entry> + <entry>A bitmask that tells what has changed. See <xref linkend="ctrl-changes-flags" />.</entry> </row> <row> <entry>__u32</entry> @@ -309,8 +416,8 @@ </tgroup> </table> - <table pgwide="1" frame="none" id="changes-flags"> - <title>Changes</title> + <table pgwide="1" frame="none" id="ctrl-changes-flags"> + <title>Control Changes</title> <tgroup cols="3"> &cs-def; <tbody valign="top"> @@ -318,9 +425,9 @@ <entry><constant>V4L2_EVENT_CTRL_CH_VALUE</constant></entry> <entry>0x0001</entry> <entry>This control event was triggered because the value of the control - changed. Special case: if a button control is pressed, then this - event is sent as well, even though there is not explicit value - associated with a button control.</entry> + changed. Special cases: Volatile controls do no generate this event; + If a control has the <constant>V4L2_CTRL_FLAG_EXECUTE_ON_WRITE</constant> + flag set, then this event is sent as well, regardless its value.</entry> </row> <row> <entry><constant>V4L2_EVENT_CTRL_CH_FLAGS</constant></entry> diff --git a/Documentation/DocBook/media/v4l/vidioc-g-crop.xml b/Documentation/DocBook/media/v4l/vidioc-g-crop.xml index 75c6a93de3c1..e6c4efb9e8b4 100644 --- a/Documentation/DocBook/media/v4l/vidioc-g-crop.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-crop.xml @@ -70,6 +70,11 @@ structure or returns the &EINVAL; if cropping is not supported.</para> <constant>VIDIOC_S_CROP</constant> ioctl with a pointer to this structure.</para> +<para>Do not use the multiplanar buffer types. Use <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant> +instead of <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE</constant> +and use <constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant> instead of +<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE</constant>.</para> + <para>The driver first adjusts the requested dimensions against hardware limits, &ie; the bounds given by the capture/output window, and it rounds to the closest possible values of horizontal and diff --git a/Documentation/DocBook/media/v4l/vidioc-g-dv-timings.xml b/Documentation/DocBook/media/v4l/vidioc-g-dv-timings.xml index c4336577ff06..764b635ed4cf 100644 --- a/Documentation/DocBook/media/v4l/vidioc-g-dv-timings.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-dv-timings.xml @@ -318,10 +318,20 @@ can't generate such frequencies, then the flag will also be cleared. </row> <row> <entry>V4L2_DV_FL_HALF_LINE</entry> - <entry>Specific to interlaced formats: if set, then field 1 (aka the odd field) -is really one half-line longer and field 2 (aka the even field) is really one half-line -shorter, so each field has exactly the same number of half-lines. Whether half-lines can be -detected or used depends on the hardware. + <entry>Specific to interlaced formats: if set, then the vertical frontporch +of field 1 (aka the odd field) is really one half-line longer and the vertical backporch +of field 2 (aka the even field) is really one half-line shorter, so each field has exactly +the same number of half-lines. Whether half-lines can be detected or used depends on +the hardware. + </entry> + </row> + <row> + <entry>V4L2_DV_FL_IS_CE_VIDEO</entry> + <entry>If set, then this is a Consumer Electronics (CE) video format. +Such formats differ from other formats (commonly called IT formats) in that if +R'G'B' encoding is used then by default the R'G'B' values use limited range +(i.e. 16-235) as opposed to full range (i.e. 0-255). All formats defined in CEA-861 +except for the 640x480p59.94 format are CE formats. </entry> </row> </tbody> diff --git a/Documentation/DocBook/media/v4l/vidioc-g-fbuf.xml b/Documentation/DocBook/media/v4l/vidioc-g-fbuf.xml index 20460730b02c..77607cc19688 100644 --- a/Documentation/DocBook/media/v4l/vidioc-g-fbuf.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-fbuf.xml @@ -240,9 +240,9 @@ where padding bytes after the last line of an image cross a system page boundary. Capture devices may write padding bytes, the value is undefined. Output devices ignore the contents of padding bytes.</para><para>When the image format is planar the -<structfield>bytesperline</structfield> value applies to the largest +<structfield>bytesperline</structfield> value applies to the first plane and is divided by the same factor as the -<structfield>width</structfield> field for any smaller planes. For +<structfield>width</structfield> field for the other planes. For example the Cb and Cr planes of a YUV 4:2:0 image have half as many padding bytes following each line as the Y plane. To avoid ambiguities drivers must return a <structfield>bytesperline</structfield> value diff --git a/Documentation/DocBook/media/v4l/vidioc-g-selection.xml b/Documentation/DocBook/media/v4l/vidioc-g-selection.xml index 9c04ac8661b1..0bb5c060db27 100644 --- a/Documentation/DocBook/media/v4l/vidioc-g-selection.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-selection.xml @@ -60,8 +60,8 @@ <para>To query the cropping (composing) rectangle set &v4l2-selection; <structfield> type </structfield> field to the respective buffer type. -Do not use multiplanar buffers. Use <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant> -instead of <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE</constant>. Use +Do not use the multiplanar buffer types. Use <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant> +instead of <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE</constant> and use <constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant> instead of <constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE</constant>. The next step is setting the value of &v4l2-selection; <structfield>target</structfield> field diff --git a/Documentation/DocBook/media/v4l/vidioc-g-sliced-vbi-cap.xml b/Documentation/DocBook/media/v4l/vidioc-g-sliced-vbi-cap.xml index bd015d1563ff..d05623c55403 100644 --- a/Documentation/DocBook/media/v4l/vidioc-g-sliced-vbi-cap.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-sliced-vbi-cap.xml @@ -205,7 +205,7 @@ ETS 300 231, lsb first transmitted.</entry> <row> <entry><constant>V4L2_SLICED_CAPTION_525</constant></entry> <entry>0x1000</entry> - <entry><xref linkend="eia608" /></entry> + <entry><xref linkend="cea608" /></entry> <entry>NTSC line 21, 284 (second field 21)</entry> <entry>Two bytes in transmission order, including parity bit, lsb first transmitted.</entry> diff --git a/Documentation/DocBook/media/v4l/vidioc-querycap.xml b/Documentation/DocBook/media/v4l/vidioc-querycap.xml index d0c5e604f014..20fda75a012d 100644 --- a/Documentation/DocBook/media/v4l/vidioc-querycap.xml +++ b/Documentation/DocBook/media/v4l/vidioc-querycap.xml @@ -102,10 +102,10 @@ The bus_info must start with "PCI:" for PCI boards, "PCIe:" for PCI Express boar <entry>__u32</entry> <entry><structfield>version</structfield></entry> <entry><para>Version number of the driver.</para> -<para>Starting on kernel 3.1, the version reported is provided per -V4L2 subsystem, following the same Kernel numberation scheme. However, it -should not always return the same version as the kernel, if, for example, -an stable or distribution-modified kernel uses the V4L2 stack from a +<para>Starting with kernel 3.1, the version reported is provided by the +V4L2 subsystem following the kernel numbering scheme. However, it +may not always return the same version as the kernel if, for example, +a stable or distribution-modified kernel uses the V4L2 stack from a newer kernel.</para> <para>The version number is formatted using the <constant>KERNEL_VERSION()</constant> macro:</para></entry> diff --git a/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml b/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml index 2bd98fd7a4e5..dc83ad70f8dc 100644 --- a/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml +++ b/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml @@ -600,7 +600,9 @@ writing a value will cause the device to carry out a given action changes continuously. A typical example would be the current gain value if the device is in auto-gain mode. In such a case the hardware calculates the gain value based on the lighting conditions which can change over time. Note that setting a new value for -a volatile control will have no effect. The new value will just be ignored.</entry> +a volatile control will have no effect and no <constant>V4L2_EVENT_CTRL_CH_VALUE</constant> +will be sent, unless the <constant>V4L2_CTRL_FLAG_EXECUTE_ON_WRITE</constant> flag +(see below) is also set. Otherwise the new value will just be ignored.</entry> </row> <row> <entry><constant>V4L2_CTRL_FLAG_HAS_PAYLOAD</constant></entry> @@ -610,6 +612,14 @@ using one of the pointer fields of &v4l2-ext-control;. This flag is set for cont that are an array, string, or have a compound type. In all cases you have to set a pointer to memory containing the payload of the control.</entry> </row> + <row> + <entry><constant>V4L2_CTRL_FLAG_EXECUTE_ON_WRITE</constant></entry> + <entry>0x0200</entry> + <entry>The value provided to the control will be propagated to the driver +even if remains constant. This is required when the control represents an action +on the hardware. For example: clearing an error flag or triggering the flash. All the +controls of the type <constant>V4L2_CTRL_TYPE_BUTTON</constant> have this flag set.</entry> + </row> </tbody> </tgroup> </table> diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-interval.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-interval.xml index 2f8f4f0a0235..cff59f5cbf04 100644 --- a/Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-interval.xml +++ b/Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-interval.xml @@ -67,9 +67,9 @@ <para>To enumerate frame intervals applications initialize the <structfield>index</structfield>, <structfield>pad</structfield>, - <structfield>code</structfield>, <structfield>width</structfield> and - <structfield>height</structfield> fields of - &v4l2-subdev-frame-interval-enum; and call the + <structfield>which</structfield>, <structfield>code</structfield>, + <structfield>width</structfield> and <structfield>height</structfield> + fields of &v4l2-subdev-frame-interval-enum; and call the <constant>VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL</constant> ioctl with a pointer to this structure. Drivers fill the rest of the structure or return an &EINVAL; if one of the input fields is invalid. All frame intervals are @@ -123,7 +123,12 @@ </row> <row> <entry>__u32</entry> - <entry><structfield>reserved</structfield>[9]</entry> + <entry><structfield>which</structfield></entry> + <entry>Frame intervals to be enumerated, from &v4l2-subdev-format-whence;.</entry> + </row> + <row> + <entry>__u32</entry> + <entry><structfield>reserved</structfield>[8]</entry> <entry>Reserved for future extensions. Applications and drivers must set the array to zero.</entry> </row> diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-size.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-size.xml index 79ce42b7c60c..abd545ede67a 100644 --- a/Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-size.xml +++ b/Documentation/DocBook/media/v4l/vidioc-subdev-enum-frame-size.xml @@ -61,9 +61,9 @@ ioctl.</para> <para>To enumerate frame sizes applications initialize the - <structfield>pad</structfield>, <structfield>code</structfield> and - <structfield>index</structfield> fields of the - &v4l2-subdev-mbus-code-enum; and call the + <structfield>pad</structfield>, <structfield>which</structfield> , + <structfield>code</structfield> and <structfield>index</structfield> + fields of the &v4l2-subdev-mbus-code-enum; and call the <constant>VIDIOC_SUBDEV_ENUM_FRAME_SIZE</constant> ioctl with a pointer to the structure. Drivers fill the minimum and maximum frame sizes or return an &EINVAL; if one of the input parameters is invalid.</para> @@ -127,7 +127,12 @@ </row> <row> <entry>__u32</entry> - <entry><structfield>reserved</structfield>[9]</entry> + <entry><structfield>which</structfield></entry> + <entry>Frame sizes to be enumerated, from &v4l2-subdev-format-whence;.</entry> + </row> + <row> + <entry>__u32</entry> + <entry><structfield>reserved</structfield>[8]</entry> <entry>Reserved for future extensions. Applications and drivers must set the array to zero.</entry> </row> diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-enum-mbus-code.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-enum-mbus-code.xml index a6b3432449f6..0bcb278fd062 100644 --- a/Documentation/DocBook/media/v4l/vidioc-subdev-enum-mbus-code.xml +++ b/Documentation/DocBook/media/v4l/vidioc-subdev-enum-mbus-code.xml @@ -56,8 +56,8 @@ </note> <para>To enumerate media bus formats available at a given sub-device pad - applications initialize the <structfield>pad</structfield> and - <structfield>index</structfield> fields of &v4l2-subdev-mbus-code-enum; and + applications initialize the <structfield>pad</structfield>, <structfield>which</structfield> + and <structfield>index</structfield> fields of &v4l2-subdev-mbus-code-enum; and call the <constant>VIDIOC_SUBDEV_ENUM_MBUS_CODE</constant> ioctl with a pointer to this structure. Drivers fill the rest of the structure or return an &EINVAL; if either the <structfield>pad</structfield> or @@ -93,7 +93,12 @@ </row> <row> <entry>__u32</entry> - <entry><structfield>reserved</structfield>[9]</entry> + <entry><structfield>which</structfield></entry> + <entry>Media bus format codes to be enumerated, from &v4l2-subdev-format-whence;.</entry> + </row> + <row> + <entry>__u32</entry> + <entry><structfield>reserved</structfield>[8]</entry> <entry>Reserved for future extensions. Applications and drivers must set the array to zero.</entry> </row> diff --git a/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml b/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml index d7c9365ecdbe..d0332f610929 100644 --- a/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml +++ b/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml @@ -60,7 +60,9 @@ <row> <entry>__u32</entry> <entry><structfield>type</structfield></entry> - <entry>Type of the event.</entry> + <entry>Type of the event, see <xref linkend="event-type" />. Note that +<constant>V4L2_EVENT_ALL</constant> can be used with VIDIOC_UNSUBSCRIBE_EVENT +for unsubscribing all events at once.</entry> </row> <row> <entry>__u32</entry> @@ -84,113 +86,6 @@ </tgroup> </table> - <table frame="none" pgwide="1" id="event-type"> - <title>Event Types</title> - <tgroup cols="3"> - &cs-def; - <tbody valign="top"> - <row> - <entry><constant>V4L2_EVENT_ALL</constant></entry> - <entry>0</entry> - <entry>All events. V4L2_EVENT_ALL is valid only for - VIDIOC_UNSUBSCRIBE_EVENT for unsubscribing all events at once. - </entry> - </row> - <row> - <entry><constant>V4L2_EVENT_VSYNC</constant></entry> - <entry>1</entry> - <entry>This event is triggered on the vertical sync. - This event has a &v4l2-event-vsync; associated with it. - </entry> - </row> - <row> - <entry><constant>V4L2_EVENT_EOS</constant></entry> - <entry>2</entry> - <entry>This event is triggered when the end of a stream is reached. - This is typically used with MPEG decoders to report to the application - when the last of the MPEG stream has been decoded. - </entry> - </row> - <row> - <entry><constant>V4L2_EVENT_CTRL</constant></entry> - <entry>3</entry> - <entry><para>This event requires that the <structfield>id</structfield> - matches the control ID from which you want to receive events. - This event is triggered if the control's value changes, if a - button control is pressed or if the control's flags change. - This event has a &v4l2-event-ctrl; associated with it. This struct - contains much of the same information as &v4l2-queryctrl; and - &v4l2-control;.</para> - - <para>If the event is generated due to a call to &VIDIOC-S-CTRL; or - &VIDIOC-S-EXT-CTRLS;, then the event will <emphasis>not</emphasis> be sent to - the file handle that called the ioctl function. This prevents - nasty feedback loops. If you <emphasis>do</emphasis> want to get the - event, then set the <constant>V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK</constant> - flag. - </para> - - <para>This event type will ensure that no information is lost when - more events are raised than there is room internally. In that - case the &v4l2-event-ctrl; of the second-oldest event is kept, - but the <structfield>changes</structfield> field of the - second-oldest event is ORed with the <structfield>changes</structfield> - field of the oldest event.</para> - </entry> - </row> - <row> - <entry><constant>V4L2_EVENT_FRAME_SYNC</constant></entry> - <entry>4</entry> - <entry> - <para>Triggered immediately when the reception of a - frame has begun. This event has a - &v4l2-event-frame-sync; associated with it.</para> - - <para>If the hardware needs to be stopped in the case of a - buffer underrun it might not be able to generate this event. - In such cases the <structfield>frame_sequence</structfield> - field in &v4l2-event-frame-sync; will not be incremented. This - causes two consecutive frame sequence numbers to have n times - frame interval in between them.</para> - </entry> - </row> - <row> - <entry><constant>V4L2_EVENT_SOURCE_CHANGE</constant></entry> - <entry>5</entry> - <entry> - <para>This event is triggered when a source parameter change is - detected during runtime by the video device. It can be a - runtime resolution change triggered by a video decoder or the - format change happening on an input connector. - This event requires that the <structfield>id</structfield> - matches the input index (when used with a video device node) - or the pad index (when used with a subdevice node) from which - you want to receive events.</para> - - <para>This event has a &v4l2-event-src-change; associated - with it. The <structfield>changes</structfield> bitfield denotes - what has changed for the subscribed pad. If multiple events - occurred before application could dequeue them, then the changes - will have the ORed value of all the events generated.</para> - </entry> - </row> - <row> - <entry><constant>V4L2_EVENT_MOTION_DET</constant></entry> - <entry>6</entry> - <entry> - <para>Triggered whenever the motion detection state for one or more of the regions - changes. This event has a &v4l2-event-motion-det; associated with it.</para> - </entry> - </row> - <row> - <entry><constant>V4L2_EVENT_PRIVATE_START</constant></entry> - <entry>0x08000000</entry> - <entry>Base event number for driver-private events.</entry> - </row> - </tbody> - </tgroup> - </table> - <table pgwide="1" frame="none" id="event-flags"> <title>Event Flags</title> <tgroup cols="3"> diff --git a/Documentation/devicetree/bindings/media/exynos-jpeg-codec.txt b/Documentation/devicetree/bindings/media/exynos-jpeg-codec.txt index bf52ed4a5067..4ef45636ebde 100644 --- a/Documentation/devicetree/bindings/media/exynos-jpeg-codec.txt +++ b/Documentation/devicetree/bindings/media/exynos-jpeg-codec.txt @@ -4,7 +4,7 @@ Required properties: - compatible : should be one of: "samsung,s5pv210-jpeg", "samsung,exynos4210-jpeg", - "samsung,exynos3250-jpeg"; + "samsung,exynos3250-jpeg", "samsung,exynos5420-jpeg"; - reg : address and length of the JPEG codec IP register set; - interrupts : specifies the JPEG codec IP interrupt; - clock-names : should contain: diff --git a/Documentation/devicetree/bindings/media/i2c/mt9v032.txt b/Documentation/devicetree/bindings/media/i2c/mt9v032.txt new file mode 100644 index 000000000000..202565313e82 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/mt9v032.txt @@ -0,0 +1,39 @@ +* Aptina 1/3-Inch WVGA CMOS Digital Image Sensor + +The Aptina MT9V032 is a 1/3-inch CMOS active pixel digital image sensor with +an active array size of 752H x 480V. It is programmable through a simple +two-wire serial interface. + +Required Properties: + +- compatible: value should be either one among the following + (a) "aptina,mt9v022" for MT9V022 color sensor + (b) "aptina,mt9v022m" for MT9V022 monochrome sensor + (c) "aptina,mt9v024" for MT9V024 color sensor + (d) "aptina,mt9v024m" for MT9V024 monochrome sensor + (e) "aptina,mt9v032" for MT9V032 color sensor + (f) "aptina,mt9v032m" for MT9V032 monochrome sensor + (g) "aptina,mt9v034" for MT9V034 color sensor + (h) "aptina,mt9v034m" for MT9V034 monochrome sensor + +Optional Properties: + +- link-frequencies: List of allowed link frequencies in Hz. Each frequency is + expressed as a 64-bit big-endian integer. + +For further reading on port node refer to +Documentation/devicetree/bindings/media/video-interfaces.txt. + +Example: + + mt9v032@5c { + compatible = "aptina,mt9v032"; + reg = <0x5c>; + + port { + mt9v032_out: endpoint { + link-frequencies = /bits/ 64 + <13000000 26600000 27000000>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/media/i2c/ov2640.txt b/Documentation/devicetree/bindings/media/i2c/ov2640.txt new file mode 100644 index 000000000000..c429b5bdcaa0 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/ov2640.txt @@ -0,0 +1,46 @@ +* Omnivision OV2640 CMOS sensor + +The Omnivision OV2640 sensor support multiple resolutions output, such as +CIF, SVGA, UXGA. It also can support YUV422/420, RGB565/555 or raw RGB +output format. + +Required Properties: +- compatible: should be "ovti,ov2640" +- clocks: reference to the xvclk input clock. +- clock-names: should be "xvclk". + +Optional Properties: +- resetb-gpios: reference to the GPIO connected to the resetb pin, if any. +- pwdn-gpios: reference to the GPIO connected to the pwdn pin, if any. + +The device node must contain one 'port' child node for its digital output +video port, in accordance with the video interface bindings defined in +Documentation/devicetree/bindings/media/video-interfaces.txt. + +Example: + + i2c1: i2c@f0018000 { + ov2640: camera@0x30 { + compatible = "ovti,ov2640"; + reg = <0x30>; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pck1 &pinctrl_ov2640_pwdn &pinctrl_ov2640_resetb>; + + resetb-gpios = <&pioE 24 GPIO_ACTIVE_LOW>; + pwdn-gpios = <&pioE 29 GPIO_ACTIVE_HIGH>; + + clocks = <&pck1>; + clock-names = "xvclk"; + + assigned-clocks = <&pck1>; + assigned-clock-rates = <25000000>; + + port { + ov2640_0: endpoint { + remote-endpoint = <&isi_0>; + bus-width = <8>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/media/i2c/ov2659.txt b/Documentation/devicetree/bindings/media/i2c/ov2659.txt new file mode 100644 index 000000000000..cabc7d827dfb --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/ov2659.txt @@ -0,0 +1,38 @@ +* OV2659 1/5-Inch 2Mp SOC Camera + +The Omnivision OV2659 is a 1/5-inch SOC camera, with an active array size of +1632H x 1212V. It is programmable through a SCCB. The OV2659 sensor supports +multiple resolutions output, such as UXGA, SVGA, 720p. It also can support +YUV422, RGB565/555 or raw RGB output formats. + +Required Properties: +- compatible: Must be "ovti,ov2659" +- reg: I2C slave address +- clocks: reference to the xvclk input clock. +- clock-names: should be "xvclk". +- link-frequencies: target pixel clock frequency. + +For further reading on port node refer to +Documentation/devicetree/bindings/media/video-interfaces.txt. + +Example: + + i2c0@1c22000 { + ... + ... + ov2659@30 { + compatible = "ovti,ov2659"; + reg = <0x30>; + + clocks = <&clk_ov2659 0>; + clock-names = "xvclk"; + + port { + ov2659_0: endpoint { + remote-endpoint = <&vpfe_ep>; + link-frequencies = /bits/ 64 <70000000>; + }; + }; + }; + ... + }; diff --git a/Documentation/devicetree/bindings/media/video-interfaces.txt b/Documentation/devicetree/bindings/media/video-interfaces.txt index 571b4c60665f..9cd2a369125d 100644 --- a/Documentation/devicetree/bindings/media/video-interfaces.txt +++ b/Documentation/devicetree/bindings/media/video-interfaces.txt @@ -106,6 +106,12 @@ Optional endpoint properties - link-frequencies: Allowed data bus frequencies. For MIPI CSI-2, for instance, this is the actual frequency of the bus, not bits per clock per lane value. An array of 64-bit unsigned integers. +- lane-polarities: an array of polarities of the lanes starting from the clock + lane and followed by the data lanes in the same order as in data-lanes. + Valid values are 0 (normal) and 1 (inverted). The length of the array + should be the combined length of data-lanes and clock-lanes properties. + If the lane-polarities property is omitted, the value must be interpreted + as 0 (normal). This property is valid for serial busses only. Example diff --git a/Documentation/devicetree/bindings/media/xilinx/video.txt b/Documentation/devicetree/bindings/media/xilinx/video.txt new file mode 100644 index 000000000000..cbd46fa0988f --- /dev/null +++ b/Documentation/devicetree/bindings/media/xilinx/video.txt @@ -0,0 +1,35 @@ +DT bindings for Xilinx video IP cores +------------------------------------- + +Xilinx video IP cores process video streams by acting as video sinks and/or +sources. They are connected by links through their input and output ports, +creating a video pipeline. + +Each video IP core is represented by an AMBA bus child node in the device +tree using bindings documented in this directory. Connections between the IP +cores are represented as defined in ../video-interfaces.txt. + +The whole pipeline is represented by an AMBA bus child node in the device +tree using bindings documented in ./xlnx,video.txt. + +Common properties +----------------- + +The following properties are common to all Xilinx video IP cores. + +- xlnx,video-format: This property represents a video format transmitted on an + AXI bus between video IP cores, using its VF code as defined in "AXI4-Stream + Video IP and System Design Guide" [UG934]. How the format relates to the IP + core is decribed in the IP core bindings documentation. + +- xlnx,video-width: This property qualifies the video format with the sample + width expressed as a number of bits per pixel component. All components must + use the same width. + +- xlnx,cfa-pattern: When the video format is set to Mono/Sensor, this property + describes the sensor's color filter array pattern. Supported values are + "bggr", "gbrg", "grbg", "rggb" and "mono". If not specified, the pattern + defaults to "mono". + + +[UG934] http://www.xilinx.com/support/documentation/ip_documentation/axi_videoip/v1_0/ug934_axi_videoIP.pdf diff --git a/Documentation/devicetree/bindings/media/xilinx/xlnx,v-tc.txt b/Documentation/devicetree/bindings/media/xilinx/xlnx,v-tc.txt new file mode 100644 index 000000000000..2aed3b4a6cf1 --- /dev/null +++ b/Documentation/devicetree/bindings/media/xilinx/xlnx,v-tc.txt @@ -0,0 +1,33 @@ +Xilinx Video Timing Controller (VTC) +------------------------------------ + +The Video Timing Controller is a general purpose video timing generator and +detector. + +Required properties: + + - compatible: Must be "xlnx,v-tc-6.1". + + - reg: Physical base address and length of the registers set for the device. + + - clocks: Must contain a clock specifier for the VTC core and timing + interfaces clock. + +Optional properties: + + - xlnx,detector: The VTC has a timing detector + - xlnx,generator: The VTC has a timing generator + + At least one of the xlnx,detector and xlnx,generator properties must be + specified. + + +Example: + + vtc: vtc@43c40000 { + compatible = "xlnx,v-tc-6.1"; + reg = <0x43c40000 0x10000>; + + clocks = <&clkc 15>; + xlnx,generator; + }; diff --git a/Documentation/devicetree/bindings/media/xilinx/xlnx,v-tpg.txt b/Documentation/devicetree/bindings/media/xilinx/xlnx,v-tpg.txt new file mode 100644 index 000000000000..9dd86b3db937 --- /dev/null +++ b/Documentation/devicetree/bindings/media/xilinx/xlnx,v-tpg.txt @@ -0,0 +1,71 @@ +Xilinx Video Test Pattern Generator (TPG) +----------------------------------------- + +Required properties: + +- compatible: Must contain at least one of + + "xlnx,v-tpg-5.0" (TPG version 5.0) + "xlnx,v-tpg-6.0" (TPG version 6.0) + + TPG versions backward-compatible with previous versions should list all + compatible versions in the newer to older order. + +- reg: Physical base address and length of the registers set for the device. + +- clocks: Reference to the video core clock. + +- xlnx,video-format, xlnx,video-width: Video format and width, as defined in + video.txt. + +- port: Video port, using the DT bindings defined in ../video-interfaces.txt. + The TPG has a single output port numbered 0. + +Optional properties: + +- xlnx,vtc: A phandle referencing the Video Timing Controller that generates + video timings for the TPG test patterns. + +- timing-gpios: Specifier for a GPIO that controls the timing mux at the TPG + input. The GPIO active level corresponds to the selection of VTC-generated + video timings. + +The xlnx,vtc and timing-gpios properties are mandatory when the TPG is +synthesized with two ports and forbidden when synthesized with one port. + +Example: + + tpg_0: tpg@40050000 { + compatible = "xlnx,v-tpg-6.0", "xlnx,v-tpg-5.0"; + reg = <0x40050000 0x10000>; + clocks = <&clkc 15>; + + xlnx,vtc = <&vtc_3>; + timing-gpios = <&ps7_gpio_0 55 GPIO_ACTIVE_LOW>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + xlnx,video-format = <XVIP_VF_YUV_422>; + xlnx,video-width = <8>; + + tpg_in: endpoint { + remote-endpoint = <&adv7611_out>; + }; + }; + port@1 { + reg = <1>; + + xlnx,video-format = <XVIP_VF_YUV_422>; + xlnx,video-width = <8>; + + tpg1_out: endpoint { + remote-endpoint = <&switch_in0>; + }; + }: + }; + }; diff --git a/Documentation/devicetree/bindings/media/xilinx/xlnx,video.txt b/Documentation/devicetree/bindings/media/xilinx/xlnx,video.txt new file mode 100644 index 000000000000..5a0227023608 --- /dev/null +++ b/Documentation/devicetree/bindings/media/xilinx/xlnx,video.txt @@ -0,0 +1,55 @@ +Xilinx Video IP Pipeline (VIPP) +------------------------------- + +General concept +--------------- + +Xilinx video IP pipeline processes video streams through one or more Xilinx +video IP cores. Each video IP core is represented as documented in video.txt +and IP core specific documentation, xlnx,v-*.txt, in this directory. The DT +node of the VIPP represents as a top level node of the pipeline and defines +mappings between DMAs and the video IP cores. + +Required properties: + +- compatible: Must be "xlnx,video". + +- dmas, dma-names: List of one DMA specifier and identifier string (as defined + in Documentation/devicetree/bindings/dma/dma.txt) per port. Each port + requires a DMA channel with the identifier string set to "port" followed by + the port index. + +- ports: Video port, using the DT bindings defined in ../video-interfaces.txt. + +Required port properties: + +- direction: should be either "input" or "output" depending on the direction + of stream. + +Example: + + video_cap { + compatible = "xlnx,video"; + dmas = <&vdma_1 1>, <&vdma_3 1>; + dma-names = "port0", "port1"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + direction = "input"; + vcap0_in0: endpoint { + remote-endpoint = <&scaler0_out>; + }; + }; + port@1 { + reg = <1>; + direction = "input"; + vcap0_in1: endpoint { + remote-endpoint = <&switch_out1>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 389ca1347a77..4326f52eba73 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -20,6 +20,7 @@ amlogic Amlogic, Inc. ams AMS AG amstaos AMS-Taos Inc. apm Applied Micro Circuits Corporation (APM) +aptina Aptina Imaging arm ARM Ltd. armadeus ARMadeus Systems SARL asahi-kasei Asahi Kasei Corp. diff --git a/Documentation/video4linux/v4l2-controls.txt b/Documentation/video4linux/v4l2-controls.txt index 0f84ce8c9a7b..5517db602f37 100644 --- a/Documentation/video4linux/v4l2-controls.txt +++ b/Documentation/video4linux/v4l2-controls.txt @@ -344,7 +344,9 @@ implement g_volatile_ctrl like this: } Note that you use the 'new value' union as well in g_volatile_ctrl. In general -controls that need to implement g_volatile_ctrl are read-only controls. +controls that need to implement g_volatile_ctrl are read-only controls. If they +are not, a V4L2_EVENT_CTRL_CH_VALUE will not be generated when the control +changes. To mark a control as volatile you have to set V4L2_CTRL_FLAG_VOLATILE: diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt index f586e29ce221..59e619f9bbf5 100644 --- a/Documentation/video4linux/v4l2-framework.txt +++ b/Documentation/video4linux/v4l2-framework.txt @@ -793,8 +793,8 @@ video_register_device_no_warn() instead. Whenever a device node is created some attributes are also created for you. If you look in /sys/class/video4linux you see the devices. Go into e.g. -video0 and you will see 'name', 'debug' and 'index' attributes. The 'name' -attribute is the 'name' field of the video_device struct. The 'debug' attribute +video0 and you will see 'name', 'dev_debug' and 'index' attributes. The 'name' +attribute is the 'name' field of the video_device struct. The 'dev_debug' attribute can be used to enable core debugging. See the next section for more detailed information on this. @@ -821,7 +821,7 @@ unregister the device if the registration failed. video device debugging ---------------------- -The 'debug' attribute that is created for each video, vbi, radio or swradio +The 'dev_debug' attribute that is created for each video, vbi, radio or swradio device in /sys/class/video4linux/<devX>/ allows you to enable logging of file operations. diff --git a/Documentation/video4linux/vivid.txt b/Documentation/video4linux/vivid.txt index 6cfc8541a362..cd4b5a1ac529 100644 --- a/Documentation/video4linux/vivid.txt +++ b/Documentation/video4linux/vivid.txt @@ -912,6 +912,11 @@ looped to the video input provided that: sequence and field counting in struct v4l2_buffer on the capture side may not be 100% accurate. +- field settings V4L2_FIELD_SEQ_TB/BT are not supported. While it is possible to + implement this, it would mean a lot of work to get this right. Since these + field values are rarely used the decision was made not to implement this for + now. + - on the input side the "Standard Signal Mode" for the S-Video input or the "DV Timings Signal Mode" for the HDMI input should be configured so that a valid signal is passed to the video input. diff --git a/MAINTAINERS b/MAINTAINERS index ddc5a8cf9a8a..30e7e38ccad0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4420,7 +4420,7 @@ S: Maintained F: block/partitions/efi.* STK1160 USB VIDEO CAPTURE DRIVER -M: Ezequiel Garcia <elezegarcia@gmail.com> +M: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar> L: linux-media@vger.kernel.org T: git git://linuxtv.org/media_tree.git S: Maintained @@ -6103,16 +6103,6 @@ Q: http://patchwork.linuxtv.org/project/linux-media/list/ S: Maintained F: drivers/media/dvb-frontends/m88rs2000* -M88TS2022 MEDIA DRIVER -M: Antti Palosaari <crope@iki.fi> -L: linux-media@vger.kernel.org -W: http://linuxtv.org/ -W: http://palosaari.fi/linux/ -Q: http://patchwork.linuxtv.org/project/linux-media/list/ -T: git git://linuxtv.org/anttip/media_tree.git -S: Maintained -F: drivers/media/tuners/m88ts2022* - MA901 MASTERKIT USB FM RADIO DRIVER M: Alexey Klimov <klimov.linux@gmail.com> L: linux-media@vger.kernel.org @@ -6535,6 +6525,7 @@ M: Laurent Pinchart <laurent.pinchart@ideasonboard.com> L: linux-media@vger.kernel.org T: git git://linuxtv.org/media_tree.git S: Maintained +F: Documentation/devicetree/bindings/media/i2c/mt9v032.txt F: drivers/media/i2c/mt9v032.c F: include/media/mt9v032.h @@ -8910,6 +8901,16 @@ T: git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git S: Maintained F: drivers/media/platform/am437x/ +OV2659 OMNIVISION SENSOR DRIVER +M: Lad, Prabhakar <prabhakar.csengg@gmail.com> +L: linux-media@vger.kernel.org +W: http://linuxtv.org/ +Q: http://patchwork.linuxtv.org/project/linux-media/list/ +T: git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git +S: Maintained +F: drivers/media/i2c/ov2659.c +F: include/media/ov2659.h + SIS 190 ETHERNET DRIVER M: Francois Romieu <romieu@fr.zoreil.com> L: netdev@vger.kernel.org @@ -10817,6 +10818,16 @@ L: linux-serial@vger.kernel.org S: Maintained F: drivers/tty/serial/uartlite.c +XILINX VIDEO IP CORES +M: Hyun Kwon <hyun.kwon@xilinx.com> +M: Laurent Pinchart <laurent.pinchart@ideasonboard.com> +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Supported +F: Documentation/devicetree/bindings/media/xilinx/ +F: drivers/media/platform/xilinx/ +F: include/uapi/linux/xilinx-v4l2-controls.h + XILLYBUS DRIVER M: Eli Billauer <eli.billauer@gmail.com> L: linux-kernel@vger.kernel.org diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c index 91738a14ecbe..b5dfbc1b1fc6 100644 --- a/arch/arm/mach-omap2/board-cm-t35.c +++ b/arch/arm/mach-omap2/board-cm-t35.c @@ -492,51 +492,36 @@ static struct twl4030_platform_data cm_t35_twldata = { #include <media/omap3isp.h> #include "devices.h" -static struct i2c_board_info cm_t35_isp_i2c_boardinfo[] = { +static struct isp_platform_subdev cm_t35_isp_subdevs[] = { { - I2C_BOARD_INFO("mt9t001", 0x5d), - }, - { - I2C_BOARD_INFO("tvp5150", 0x5c), - }, -}; - -static struct isp_subdev_i2c_board_info cm_t35_isp_primary_subdevs[] = { - { - .board_info = &cm_t35_isp_i2c_boardinfo[0], - .i2c_adapter_id = 3, - }, - { NULL, 0, }, -}; - -static struct isp_subdev_i2c_board_info cm_t35_isp_secondary_subdevs[] = { - { - .board_info = &cm_t35_isp_i2c_boardinfo[1], + .board_info = &(struct i2c_board_info){ + I2C_BOARD_INFO("mt9t001", 0x5d) + }, .i2c_adapter_id = 3, - }, - { NULL, 0, }, -}; - -static struct isp_v4l2_subdevs_group cm_t35_isp_subdevs[] = { - { - .subdevs = cm_t35_isp_primary_subdevs, - .interface = ISP_INTERFACE_PARALLEL, - .bus = { - .parallel = { - .clk_pol = 1, + .bus = &(struct isp_bus_cfg){ + .interface = ISP_INTERFACE_PARALLEL, + .bus = { + .parallel = { + .clk_pol = 1, + }, }, }, }, { - .subdevs = cm_t35_isp_secondary_subdevs, - .interface = ISP_INTERFACE_PARALLEL, - .bus = { - .parallel = { - .clk_pol = 0, + .board_info = &(struct i2c_board_info){ + I2C_BOARD_INFO("tvp5150", 0x5c), + }, + .i2c_adapter_id = 3, + .bus = &(struct isp_bus_cfg){ + .interface = ISP_INTERFACE_PARALLEL, + .bus = { + .parallel = { + .clk_pol = 0, + }, }, }, }, - { NULL, 0, }, + { 0 }, }; static struct isp_platform_data cm_t35_isp_pdata = { diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index 1afb50d6d636..990338fbaa59 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -74,82 +74,12 @@ omap_postcore_initcall(omap3_l3_init); static struct resource omap3isp_resources[] = { { .start = OMAP3430_ISP_BASE, - .end = OMAP3430_ISP_END, + .end = OMAP3430_ISP_BASE + 0x12fc, .flags = IORESOURCE_MEM, }, { - .start = OMAP3430_ISP_CCP2_BASE, - .end = OMAP3430_ISP_CCP2_END, - .flags = IORESOURCE_MEM, - }, - { - .start = OMAP3430_ISP_CCDC_BASE, - .end = OMAP3430_ISP_CCDC_END, - .flags = IORESOURCE_MEM, - }, - { - .start = OMAP3430_ISP_HIST_BASE, - .end = OMAP3430_ISP_HIST_END, - .flags = IORESOURCE_MEM, - }, - { - .start = OMAP3430_ISP_H3A_BASE, - .end = OMAP3430_ISP_H3A_END, - .flags = IORESOURCE_MEM, - }, - { - .start = OMAP3430_ISP_PREV_BASE, - .end = OMAP3430_ISP_PREV_END, - .flags = IORESOURCE_MEM, - }, - { - .start = OMAP3430_ISP_RESZ_BASE, - .end = OMAP3430_ISP_RESZ_END, - .flags = IORESOURCE_MEM, - }, - { - .start = OMAP3430_ISP_SBL_BASE, - .end = OMAP3430_ISP_SBL_END, - .flags = IORESOURCE_MEM, - }, - { - .start = OMAP3430_ISP_CSI2A_REGS1_BASE, - .end = OMAP3430_ISP_CSI2A_REGS1_END, - .flags = IORESOURCE_MEM, - }, - { - .start = OMAP3430_ISP_CSIPHY2_BASE, - .end = OMAP3430_ISP_CSIPHY2_END, - .flags = IORESOURCE_MEM, - }, - { - .start = OMAP3630_ISP_CSI2A_REGS2_BASE, - .end = OMAP3630_ISP_CSI2A_REGS2_END, - .flags = IORESOURCE_MEM, - }, - { - .start = OMAP3630_ISP_CSI2C_REGS1_BASE, - .end = OMAP3630_ISP_CSI2C_REGS1_END, - .flags = IORESOURCE_MEM, - }, - { - .start = OMAP3630_ISP_CSIPHY1_BASE, - .end = OMAP3630_ISP_CSIPHY1_END, - .flags = IORESOURCE_MEM, - }, - { - .start = OMAP3630_ISP_CSI2C_REGS2_BASE, - .end = OMAP3630_ISP_CSI2C_REGS2_END, - .flags = IORESOURCE_MEM, - }, - { - .start = OMAP343X_CTRL_BASE + OMAP343X_CONTROL_CSIRXFE, - .end = OMAP343X_CTRL_BASE + OMAP343X_CONTROL_CSIRXFE + 3, - .flags = IORESOURCE_MEM, - }, - { - .start = OMAP343X_CTRL_BASE + OMAP3630_CONTROL_CAMERA_PHY_CTRL, - .end = OMAP343X_CTRL_BASE + OMAP3630_CONTROL_CAMERA_PHY_CTRL + 3, + .start = OMAP3430_ISP_BASE2, + .end = OMAP3430_ISP_BASE2 + 0x0600, .flags = IORESOURCE_MEM, }, { diff --git a/arch/arm/mach-omap2/omap34xx.h b/arch/arm/mach-omap2/omap34xx.h index c0d1b4b1653f..ed0024dda133 100644 --- a/arch/arm/mach-omap2/omap34xx.h +++ b/arch/arm/mach-omap2/omap34xx.h @@ -46,39 +46,9 @@ #define OMAP34XX_IC_BASE 0x48200000 -#define OMAP3430_ISP_BASE (L4_34XX_BASE + 0xBC000) -#define OMAP3430_ISP_CBUFF_BASE (OMAP3430_ISP_BASE + 0x0100) -#define OMAP3430_ISP_CCP2_BASE (OMAP3430_ISP_BASE + 0x0400) -#define OMAP3430_ISP_CCDC_BASE (OMAP3430_ISP_BASE + 0x0600) -#define OMAP3430_ISP_HIST_BASE (OMAP3430_ISP_BASE + 0x0A00) -#define OMAP3430_ISP_H3A_BASE (OMAP3430_ISP_BASE + 0x0C00) -#define OMAP3430_ISP_PREV_BASE (OMAP3430_ISP_BASE + 0x0E00) -#define OMAP3430_ISP_RESZ_BASE (OMAP3430_ISP_BASE + 0x1000) -#define OMAP3430_ISP_SBL_BASE (OMAP3430_ISP_BASE + 0x1200) -#define OMAP3430_ISP_MMU_BASE (OMAP3430_ISP_BASE + 0x1400) -#define OMAP3430_ISP_CSI2A_REGS1_BASE (OMAP3430_ISP_BASE + 0x1800) -#define OMAP3430_ISP_CSIPHY2_BASE (OMAP3430_ISP_BASE + 0x1970) -#define OMAP3630_ISP_CSI2A_REGS2_BASE (OMAP3430_ISP_BASE + 0x19C0) -#define OMAP3630_ISP_CSI2C_REGS1_BASE (OMAP3430_ISP_BASE + 0x1C00) -#define OMAP3630_ISP_CSIPHY1_BASE (OMAP3430_ISP_BASE + 0x1D70) -#define OMAP3630_ISP_CSI2C_REGS2_BASE (OMAP3430_ISP_BASE + 0x1DC0) - -#define OMAP3430_ISP_END (OMAP3430_ISP_BASE + 0x06F) -#define OMAP3430_ISP_CBUFF_END (OMAP3430_ISP_CBUFF_BASE + 0x077) -#define OMAP3430_ISP_CCP2_END (OMAP3430_ISP_CCP2_BASE + 0x1EF) -#define OMAP3430_ISP_CCDC_END (OMAP3430_ISP_CCDC_BASE + 0x0A7) -#define OMAP3430_ISP_HIST_END (OMAP3430_ISP_HIST_BASE + 0x047) -#define OMAP3430_ISP_H3A_END (OMAP3430_ISP_H3A_BASE + 0x05F) -#define OMAP3430_ISP_PREV_END (OMAP3430_ISP_PREV_BASE + 0x09F) -#define OMAP3430_ISP_RESZ_END (OMAP3430_ISP_RESZ_BASE + 0x0AB) -#define OMAP3430_ISP_SBL_END (OMAP3430_ISP_SBL_BASE + 0x0FB) -#define OMAP3430_ISP_MMU_END (OMAP3430_ISP_MMU_BASE + 0x06F) -#define OMAP3430_ISP_CSI2A_REGS1_END (OMAP3430_ISP_CSI2A_REGS1_BASE + 0x16F) -#define OMAP3430_ISP_CSIPHY2_END (OMAP3430_ISP_CSIPHY2_BASE + 0x00B) -#define OMAP3630_ISP_CSI2A_REGS2_END (OMAP3630_ISP_CSI2A_REGS2_BASE + 0x3F) -#define OMAP3630_ISP_CSI2C_REGS1_END (OMAP3630_ISP_CSI2C_REGS1_BASE + 0x16F) -#define OMAP3630_ISP_CSIPHY1_END (OMAP3630_ISP_CSIPHY1_BASE + 0x00B) -#define OMAP3630_ISP_CSI2C_REGS2_END (OMAP3630_ISP_CSI2C_REGS2_BASE + 0x3F) +#define OMAP3430_ISP_BASE (L4_34XX_BASE + 0xBC000) +#define OMAP3430_ISP_MMU_BASE (OMAP3430_ISP_BASE + 0x1400) +#define OMAP3430_ISP_BASE2 (OMAP3430_ISP_BASE + 0x1800) #define OMAP34XX_HSUSB_OTG_BASE (L4_34XX_BASE + 0xAB000) #define OMAP34XX_USBTLL_BASE (L4_34XX_BASE + 0x62000) diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c index 74c0d8c6002a..fcc6c3368182 100644 --- a/drivers/input/ff-memless.c +++ b/drivers/input/ff-memless.c @@ -237,6 +237,18 @@ static u16 ml_calculate_direction(u16 direction, u16 force, (force + new_force)) << 1; } +#define FRAC_N 8 +static inline s16 fixp_new16(s16 a) +{ + return ((s32)a) >> (16 - FRAC_N); +} + +static inline s16 fixp_mult(s16 a, s16 b) +{ + a = ((s32)a * 0x100) / 0x7fff; + return ((s32)(a * b)) >> FRAC_N; +} + /* * Combine two effects and apply gain. */ @@ -247,7 +259,7 @@ static void ml_combine_effects(struct ff_effect *effect, struct ff_effect *new = state->effect; unsigned int strong, weak, i; int x, y; - fixp_t level; + s16 level; switch (new->type) { case FF_CONSTANT: @@ -255,8 +267,8 @@ static void ml_combine_effects(struct ff_effect *effect, level = fixp_new16(apply_envelope(state, new->u.constant.level, &new->u.constant.envelope)); - x = fixp_mult(fixp_sin(i), level) * gain / 0xffff; - y = fixp_mult(-fixp_cos(i), level) * gain / 0xffff; + x = fixp_mult(fixp_sin16(i), level) * gain / 0xffff; + y = fixp_mult(-fixp_cos16(i), level) * gain / 0xffff; /* * here we abuse ff_ramp to hold x and y of constant force * If in future any driver wants something else than x and y diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 58917525126e..f8d16f15c1d1 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -953,7 +953,9 @@ config TOUCHSCREEN_SUN4I config TOUCHSCREEN_SUR40 tristate "Samsung SUR40 (Surface 2.0/PixelSense) touchscreen" depends on USB + depends on MEDIA_USB_SUPPORT select INPUT_POLLDEV + select VIDEOBUF2_DMA_SG help Say Y here if you want support for the Samsung SUR40 touchscreen (also known as Microsoft Surface 2.0 or Microsoft PixelSense). diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c index f1cb05148b46..a24eba5ea843 100644 --- a/drivers/input/touchscreen/sur40.c +++ b/drivers/input/touchscreen/sur40.c @@ -1,7 +1,7 @@ /* * Surface2.0/SUR40/PixelSense input driver * - * Copyright (c) 2013 by Florian 'floe' Echtler <floe@butterbrot.org> + * Copyright (c) 2014 by Florian 'floe' Echtler <floe@butterbrot.org> * * Derived from the USB Skeleton driver 1.1, * Copyright (c) 2003 Greg Kroah-Hartman (greg@kroah.com) @@ -12,6 +12,9 @@ * and from the generic hid-multitouch driver, * Copyright (c) 2010-2012 Stephane Chatty <chatty@enac.fr> * + * and from the v4l2-pci-skeleton driver, + * Copyright (c) Copyright 2014 Cisco Systems, Inc. + * * 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 Free Software Foundation; either version 2 of @@ -31,6 +34,11 @@ #include <linux/input-polldev.h> #include <linux/input/mt.h> #include <linux/usb/input.h> +#include <linux/videodev2.h> +#include <media/v4l2-device.h> +#include <media/v4l2-dev.h> +#include <media/v4l2-ioctl.h> +#include <media/videobuf2-dma-sg.h> /* read 512 bytes from endpoint 0x86 -> get header + blobs */ struct sur40_header { @@ -82,9 +90,19 @@ struct sur40_data { struct sur40_blob blobs[]; } __packed; +/* read 512 bytes from endpoint 0x82 -> get header below + * continue reading 16k blocks until header.size bytes read */ +struct sur40_image_header { + __le32 magic; /* "SUBF" */ + __le32 packet_id; + __le32 size; /* always 0x0007e900 = 960x540 */ + __le32 timestamp; /* milliseconds (increases by 16 or 17 each frame) */ + __le32 unknown; /* "epoch?" always 02/03 00 00 00 */ +} __packed; /* version information */ #define DRIVER_SHORT "sur40" +#define DRIVER_LONG "Samsung SUR40" #define DRIVER_AUTHOR "Florian 'floe' Echtler <floe@butterbrot.org>" #define DRIVER_DESC "Surface2.0/SUR40/PixelSense input driver" @@ -99,6 +117,13 @@ struct sur40_data { /* touch data endpoint */ #define TOUCH_ENDPOINT 0x86 +/* video data endpoint */ +#define VIDEO_ENDPOINT 0x82 + +/* video header fields */ +#define VIDEO_HEADER_MAGIC 0x46425553 +#define VIDEO_PACKET_SIZE 16384 + /* polling interval (ms) */ #define POLL_INTERVAL 10 @@ -113,21 +138,23 @@ struct sur40_data { #define SUR40_GET_STATE 0xc5 /* 4 bytes state (?) */ #define SUR40_GET_SENSORS 0xb1 /* 8 bytes sensors */ -/* - * Note: an earlier, non-public version of this driver used USB_RECIP_ENDPOINT - * here by mistake which is very likely to have corrupted the firmware EEPROM - * on two separate SUR40 devices. Thanks to Alan Stern who spotted this bug. - * Should you ever run into a similar problem, the background story to this - * incident and instructions on how to fix the corrupted EEPROM are available - * at https://floe.butterbrot.org/matrix/hacking/surface/brick.html -*/ - +/* master device state */ struct sur40_state { struct usb_device *usbdev; struct device *dev; struct input_polled_dev *input; + struct v4l2_device v4l2; + struct video_device vdev; + struct mutex lock; + + struct vb2_queue queue; + struct vb2_alloc_ctx *alloc_ctx; + struct list_head buf_list; + spinlock_t qlock; + int sequence; + struct sur40_data *bulk_in_buffer; size_t bulk_in_size; u8 bulk_in_epaddr; @@ -135,6 +162,27 @@ struct sur40_state { char phys[64]; }; +struct sur40_buffer { + struct vb2_buffer vb; + struct list_head list; +}; + +/* forward declarations */ +static const struct video_device sur40_video_device; +static const struct v4l2_pix_format sur40_video_format; +static const struct vb2_queue sur40_queue; +static void sur40_process_video(struct sur40_state *sur40); + +/* + * Note: an earlier, non-public version of this driver used USB_RECIP_ENDPOINT + * here by mistake which is very likely to have corrupted the firmware EEPROM + * on two separate SUR40 devices. Thanks to Alan Stern who spotted this bug. + * Should you ever run into a similar problem, the background story to this + * incident and instructions on how to fix the corrupted EEPROM are available + * at https://floe.butterbrot.org/matrix/hacking/surface/brick.html +*/ + +/* command wrapper */ static int sur40_command(struct sur40_state *dev, u8 command, u16 index, void *buffer, u16 size) { @@ -247,7 +295,6 @@ static void sur40_report_blob(struct sur40_blob *blob, struct input_dev *input) /* core function: poll for new input data */ static void sur40_poll(struct input_polled_dev *polldev) { - struct sur40_state *sur40 = polldev->private; struct input_dev *input = polldev->input; int result, bulk_read, need_blobs, packet_blobs, i; @@ -314,6 +361,86 @@ static void sur40_poll(struct input_polled_dev *polldev) input_mt_sync_frame(input); input_sync(input); + + sur40_process_video(sur40); +} + +/* deal with video data */ +static void sur40_process_video(struct sur40_state *sur40) +{ + + struct sur40_image_header *img = (void *)(sur40->bulk_in_buffer); + struct sur40_buffer *new_buf; + struct usb_sg_request sgr; + struct sg_table *sgt; + int result, bulk_read; + + if (!vb2_start_streaming_called(&sur40->queue)) + return; + + /* get a new buffer from the list */ + spin_lock(&sur40->qlock); + if (list_empty(&sur40->buf_list)) { + dev_dbg(sur40->dev, "buffer queue empty\n"); + spin_unlock(&sur40->qlock); + return; + } + new_buf = list_entry(sur40->buf_list.next, struct sur40_buffer, list); + list_del(&new_buf->list); + spin_unlock(&sur40->qlock); + + /* retrieve data via bulk read */ + result = usb_bulk_msg(sur40->usbdev, + usb_rcvbulkpipe(sur40->usbdev, VIDEO_ENDPOINT), + sur40->bulk_in_buffer, sur40->bulk_in_size, + &bulk_read, 1000); + + if (result < 0) { + dev_err(sur40->dev, "error in usb_bulk_read\n"); + goto err_poll; + } + + if (bulk_read != sizeof(struct sur40_image_header)) { + dev_err(sur40->dev, "received %d bytes (%zd expected)\n", + bulk_read, sizeof(struct sur40_image_header)); + goto err_poll; + } + + if (le32_to_cpu(img->magic) != VIDEO_HEADER_MAGIC) { + dev_err(sur40->dev, "image magic mismatch\n"); + goto err_poll; + } + + if (le32_to_cpu(img->size) != sur40_video_format.sizeimage) { + dev_err(sur40->dev, "image size mismatch\n"); + goto err_poll; + } + + sgt = vb2_dma_sg_plane_desc(&new_buf->vb, 0); + + result = usb_sg_init(&sgr, sur40->usbdev, + usb_rcvbulkpipe(sur40->usbdev, VIDEO_ENDPOINT), 0, + sgt->sgl, sgt->nents, sur40_video_format.sizeimage, 0); + if (result < 0) { + dev_err(sur40->dev, "error %d in usb_sg_init\n", result); + goto err_poll; + } + + usb_sg_wait(&sgr); + if (sgr.status < 0) { + dev_err(sur40->dev, "error %d in usb_sg_wait\n", sgr.status); + goto err_poll; + } + + /* mark as finished */ + v4l2_get_timestamp(&new_buf->vb.v4l2_buf.timestamp); + new_buf->vb.v4l2_buf.sequence = sur40->sequence++; + new_buf->vb.v4l2_buf.field = V4L2_FIELD_NONE; + vb2_buffer_done(&new_buf->vb, VB2_BUF_STATE_DONE); + return; + +err_poll: + vb2_buffer_done(&new_buf->vb, VB2_BUF_STATE_ERROR); } /* Initialize input device parameters. */ @@ -377,6 +504,11 @@ static int sur40_probe(struct usb_interface *interface, goto err_free_dev; } + /* initialize locks/lists */ + INIT_LIST_HEAD(&sur40->buf_list); + spin_lock_init(&sur40->qlock); + mutex_init(&sur40->lock); + /* Set up polled input device control structure */ poll_dev->private = sur40; poll_dev->poll_interval = POLL_INTERVAL; @@ -387,7 +519,7 @@ static int sur40_probe(struct usb_interface *interface, /* Set up regular input device structure */ sur40_input_setup(poll_dev->input); - poll_dev->input->name = "Samsung SUR40"; + poll_dev->input->name = DRIVER_LONG; usb_to_input_id(usbdev, &poll_dev->input->id); usb_make_path(usbdev, sur40->phys, sizeof(sur40->phys)); strlcat(sur40->phys, "/input0", sizeof(sur40->phys)); @@ -408,6 +540,7 @@ static int sur40_probe(struct usb_interface *interface, goto err_free_polldev; } + /* register the polled input device */ error = input_register_polled_device(poll_dev); if (error) { dev_err(&interface->dev, @@ -415,12 +548,54 @@ static int sur40_probe(struct usb_interface *interface, goto err_free_buffer; } + /* register the video master device */ + snprintf(sur40->v4l2.name, sizeof(sur40->v4l2.name), "%s", DRIVER_LONG); + error = v4l2_device_register(sur40->dev, &sur40->v4l2); + if (error) { + dev_err(&interface->dev, + "Unable to register video master device."); + goto err_unreg_v4l2; + } + + /* initialize the lock and subdevice */ + sur40->queue = sur40_queue; + sur40->queue.drv_priv = sur40; + sur40->queue.lock = &sur40->lock; + + /* initialize the queue */ + error = vb2_queue_init(&sur40->queue); + if (error) + goto err_unreg_v4l2; + + sur40->alloc_ctx = vb2_dma_sg_init_ctx(sur40->dev); + if (IS_ERR(sur40->alloc_ctx)) { + dev_err(sur40->dev, "Can't allocate buffer context"); + goto err_unreg_v4l2; + } + + sur40->vdev = sur40_video_device; + sur40->vdev.v4l2_dev = &sur40->v4l2; + sur40->vdev.lock = &sur40->lock; + sur40->vdev.queue = &sur40->queue; + video_set_drvdata(&sur40->vdev, sur40); + + error = video_register_device(&sur40->vdev, VFL_TYPE_GRABBER, -1); + if (error) { + dev_err(&interface->dev, + "Unable to register video subdevice."); + goto err_unreg_video; + } + /* we can register the device now, as it is ready */ usb_set_intfdata(interface, sur40); dev_dbg(&interface->dev, "%s is now attached\n", DRIVER_DESC); return 0; +err_unreg_video: + video_unregister_device(&sur40->vdev); +err_unreg_v4l2: + v4l2_device_unregister(&sur40->v4l2); err_free_buffer: kfree(sur40->bulk_in_buffer); err_free_polldev: @@ -436,6 +611,10 @@ static void sur40_disconnect(struct usb_interface *interface) { struct sur40_state *sur40 = usb_get_intfdata(interface); + video_unregister_device(&sur40->vdev); + v4l2_device_unregister(&sur40->v4l2); + vb2_dma_sg_cleanup_ctx(sur40->alloc_ctx); + input_unregister_polled_device(sur40->input); input_free_polled_device(sur40->input); kfree(sur40->bulk_in_buffer); @@ -445,12 +624,243 @@ static void sur40_disconnect(struct usb_interface *interface) dev_dbg(&interface->dev, "%s is now disconnected\n", DRIVER_DESC); } +/* + * Setup the constraints of the queue: besides setting the number of planes + * per buffer and the size and allocation context of each plane, it also + * checks if sufficient buffers have been allocated. Usually 3 is a good + * minimum number: many DMA engines need a minimum of 2 buffers in the + * queue and you need to have another available for userspace processing. + */ +static int sur40_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) +{ + struct sur40_state *sur40 = vb2_get_drv_priv(q); + + if (q->num_buffers + *nbuffers < 3) + *nbuffers = 3 - q->num_buffers; + + if (fmt && fmt->fmt.pix.sizeimage < sur40_video_format.sizeimage) + return -EINVAL; + + *nplanes = 1; + sizes[0] = fmt ? fmt->fmt.pix.sizeimage : sur40_video_format.sizeimage; + alloc_ctxs[0] = sur40->alloc_ctx; + + return 0; +} + +/* + * Prepare the buffer for queueing to the DMA engine: check and set the + * payload size. + */ +static int sur40_buffer_prepare(struct vb2_buffer *vb) +{ + struct sur40_state *sur40 = vb2_get_drv_priv(vb->vb2_queue); + unsigned long size = sur40_video_format.sizeimage; + + if (vb2_plane_size(vb, 0) < size) { + dev_err(&sur40->usbdev->dev, "buffer too small (%lu < %lu)\n", + vb2_plane_size(vb, 0), size); + return -EINVAL; + } + + vb2_set_plane_payload(vb, 0, size); + return 0; +} + +/* + * Queue this buffer to the DMA engine. + */ +static void sur40_buffer_queue(struct vb2_buffer *vb) +{ + struct sur40_state *sur40 = vb2_get_drv_priv(vb->vb2_queue); + struct sur40_buffer *buf = (struct sur40_buffer *)vb; + + spin_lock(&sur40->qlock); + list_add_tail(&buf->list, &sur40->buf_list); + spin_unlock(&sur40->qlock); +} + +static void return_all_buffers(struct sur40_state *sur40, + enum vb2_buffer_state state) +{ + struct sur40_buffer *buf, *node; + + spin_lock(&sur40->qlock); + list_for_each_entry_safe(buf, node, &sur40->buf_list, list) { + vb2_buffer_done(&buf->vb, state); + list_del(&buf->list); + } + spin_unlock(&sur40->qlock); +} + +/* + * Start streaming. First check if the minimum number of buffers have been + * queued. If not, then return -ENOBUFS and the vb2 framework will call + * this function again the next time a buffer has been queued until enough + * buffers are available to actually start the DMA engine. + */ +static int sur40_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct sur40_state *sur40 = vb2_get_drv_priv(vq); + + sur40->sequence = 0; + return 0; +} + +/* + * Stop the DMA engine. Any remaining buffers in the DMA queue are dequeued + * and passed on to the vb2 framework marked as STATE_ERROR. + */ +static void sur40_stop_streaming(struct vb2_queue *vq) +{ + struct sur40_state *sur40 = vb2_get_drv_priv(vq); + + /* Release all active buffers */ + return_all_buffers(sur40, VB2_BUF_STATE_ERROR); +} + +/* V4L ioctl */ +static int sur40_vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct sur40_state *sur40 = video_drvdata(file); + + strlcpy(cap->driver, DRIVER_SHORT, sizeof(cap->driver)); + strlcpy(cap->card, DRIVER_LONG, sizeof(cap->card)); + usb_make_path(sur40->usbdev, cap->bus_info, sizeof(cap->bus_info)); + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + return 0; +} + +static int sur40_vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + if (i->index != 0) + return -EINVAL; + i->type = V4L2_INPUT_TYPE_CAMERA; + i->std = V4L2_STD_UNKNOWN; + strlcpy(i->name, "In-Cell Sensor", sizeof(i->name)); + i->capabilities = 0; + return 0; +} + +static int sur40_vidioc_s_input(struct file *file, void *priv, unsigned int i) +{ + return (i == 0) ? 0 : -EINVAL; +} + +static int sur40_vidioc_g_input(struct file *file, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int sur40_vidioc_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + f->fmt.pix = sur40_video_format; + return 0; +} + +static int sur40_vidioc_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (f->index != 0) + return -EINVAL; + strlcpy(f->description, "8-bit greyscale", sizeof(f->description)); + f->pixelformat = V4L2_PIX_FMT_GREY; + f->flags = 0; + return 0; +} + static const struct usb_device_id sur40_table[] = { { USB_DEVICE(ID_MICROSOFT, ID_SUR40) }, /* Samsung SUR40 */ { } /* terminating null entry */ }; MODULE_DEVICE_TABLE(usb, sur40_table); +/* V4L2 structures */ +static const struct vb2_ops sur40_queue_ops = { + .queue_setup = sur40_queue_setup, + .buf_prepare = sur40_buffer_prepare, + .buf_queue = sur40_buffer_queue, + .start_streaming = sur40_start_streaming, + .stop_streaming = sur40_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +static const struct vb2_queue sur40_queue = { + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + /* + * VB2_USERPTR in currently not enabled: passing a user pointer to + * dma-sg will result in segment sizes that are not a multiple of + * 512 bytes, which is required by the host controller. + */ + .io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF, + .buf_struct_size = sizeof(struct sur40_buffer), + .ops = &sur40_queue_ops, + .mem_ops = &vb2_dma_sg_memops, + .timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC, + .min_buffers_needed = 3, +}; + +static const struct v4l2_file_operations sur40_video_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .unlocked_ioctl = video_ioctl2, + .read = vb2_fop_read, + .mmap = vb2_fop_mmap, + .poll = vb2_fop_poll, +}; + +static const struct v4l2_ioctl_ops sur40_video_ioctl_ops = { + + .vidioc_querycap = sur40_vidioc_querycap, + + .vidioc_enum_fmt_vid_cap = sur40_vidioc_enum_fmt, + .vidioc_try_fmt_vid_cap = sur40_vidioc_fmt, + .vidioc_s_fmt_vid_cap = sur40_vidioc_fmt, + .vidioc_g_fmt_vid_cap = sur40_vidioc_fmt, + + .vidioc_enum_input = sur40_vidioc_enum_input, + .vidioc_g_input = sur40_vidioc_g_input, + .vidioc_s_input = sur40_vidioc_s_input, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, +}; + +static const struct video_device sur40_video_device = { + .name = DRIVER_LONG, + .fops = &sur40_video_fops, + .ioctl_ops = &sur40_video_ioctl_ops, + .release = video_device_release_empty, +}; + +static const struct v4l2_pix_format sur40_video_format = { + .pixelformat = V4L2_PIX_FMT_GREY, + .width = SENSOR_RES_X / 2, + .height = SENSOR_RES_Y / 2, + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_SRGB, + .bytesperline = SENSOR_RES_X / 2, + .sizeimage = (SENSOR_RES_X/2) * (SENSOR_RES_Y/2), +}; + /* USB-specific object needed to register this driver with the USB subsystem. */ static struct usb_driver sur40_driver = { .name = DRIVER_SHORT, diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 49cd30870e0d..3ef0f90b128f 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -87,13 +87,21 @@ config MEDIA_RC_SUPPORT config MEDIA_CONTROLLER bool "Media Controller API" - depends on MEDIA_CAMERA_SUPPORT + depends on MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT ---help--- Enable the media controller API used to query media devices internal topology and configure it dynamically. This API is mostly used by camera interfaces in embedded platforms. +config MEDIA_CONTROLLER_DVB + bool "Enable Media controller for DVB" + depends on MEDIA_CONTROLLER + ---help--- + Enable the media controller API support for DVB. + + This is currently experimental. + # # Video4Linux support # Only enables if one of the V4L2 types (ATV, webcam, radio) is selected diff --git a/drivers/media/common/saa7146/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c index b7d63933dae6..df1e8c975cd8 100644 --- a/drivers/media/common/saa7146/saa7146_fops.c +++ b/drivers/media/common/saa7146/saa7146_fops.c @@ -587,26 +587,20 @@ int saa7146_vv_release(struct saa7146_dev* dev) } EXPORT_SYMBOL_GPL(saa7146_vv_release); -int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev, +int saa7146_register_device(struct video_device *vfd, struct saa7146_dev *dev, char *name, int type) { - struct video_device *vfd; int err; int i; DEB_EE("dev:%p, name:'%s', type:%d\n", dev, name, type); - // released by vfd->release - vfd = video_device_alloc(); - if (vfd == NULL) - return -ENOMEM; - vfd->fops = &video_fops; if (type == VFL_TYPE_GRABBER) vfd->ioctl_ops = &dev->ext_vv_data->vid_ops; else vfd->ioctl_ops = &dev->ext_vv_data->vbi_ops; - vfd->release = video_device_release; + vfd->release = video_device_release_empty; vfd->lock = &dev->v4l2_lock; vfd->v4l2_dev = &dev->v4l2_dev; vfd->tvnorms = 0; @@ -618,25 +612,20 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev, err = video_register_device(vfd, type, -1); if (err < 0) { ERR("cannot register v4l2 device. skipping.\n"); - video_device_release(vfd); return err; } pr_info("%s: registered device %s [v4l2]\n", dev->name, video_device_node_name(vfd)); - - *vid = vfd; return 0; } EXPORT_SYMBOL_GPL(saa7146_register_device); -int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev) +int saa7146_unregister_device(struct video_device *vfd, struct saa7146_dev *dev) { DEB_EE("dev:%p\n", dev); - video_unregister_device(*vid); - *vid = NULL; - + video_unregister_device(vfd); return 0; } EXPORT_SYMBOL_GPL(saa7146_unregister_device); diff --git a/drivers/media/common/saa7146/saa7146_vbi.c b/drivers/media/common/saa7146/saa7146_vbi.c index 1e71e374bbfe..2da995758778 100644 --- a/drivers/media/common/saa7146/saa7146_vbi.c +++ b/drivers/media/common/saa7146/saa7146_vbi.c @@ -95,7 +95,7 @@ static int vbi_workaround(struct saa7146_dev *dev) /* prepare to wait to be woken up by the irq-handler */ add_wait_queue(&vv->vbi_wq, &wait); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); /* start rps1 to enable workaround */ saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); @@ -106,7 +106,7 @@ static int vbi_workaround(struct saa7146_dev *dev) DEB_VBI("brs bug workaround %d/1\n", i); remove_wait_queue(&vv->vbi_wq, &wait); - current->state = TASK_RUNNING; + __set_current_state(TASK_RUNNING); /* disable rps1 irqs */ SAA7146_IER_DISABLE(dev,MASK_28); diff --git a/drivers/media/common/siano/sms-cards.c b/drivers/media/common/siano/sms-cards.c index 82c7a1289f05..ca2f80c7740c 100644 --- a/drivers/media/common/siano/sms-cards.c +++ b/drivers/media/common/siano/sms-cards.c @@ -21,10 +21,6 @@ #include "smsir.h" #include <linux/module.h> -static int sms_dbg; -module_param_named(cards_dbg, sms_dbg, int, 0644); -MODULE_PARM_DESC(cards_dbg, "set debug level (info=1, adv=2 (or-able))"); - static struct sms_board sms_boards[] = { [SMS_BOARD_UNKNOWN] = { .name = "Unknown board", @@ -232,7 +228,7 @@ int sms_board_event(struct smscore_device_t *coredev, break; /* BOARD_EVENT_MULTIPLEX_ERRORS */ default: - sms_err("Unknown SMS board event"); + pr_err("Unknown SMS board event\n"); break; } return 0; @@ -342,7 +338,7 @@ int sms_board_lna_control(struct smscore_device_t *coredev, int onoff) int board_id = smscore_get_board_id(coredev); struct sms_board *board = sms_get_board(board_id); - sms_debug("%s: LNA %s", __func__, onoff ? "enabled" : "disabled"); + pr_debug("%s: LNA %s\n", __func__, onoff ? "enabled" : "disabled"); switch (board_id) { case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: diff --git a/drivers/media/common/siano/sms-cards.h b/drivers/media/common/siano/sms-cards.h index 4c4caddf9869..bb3d733f092b 100644 --- a/drivers/media/common/siano/sms-cards.h +++ b/drivers/media/common/siano/sms-cards.h @@ -20,8 +20,9 @@ #ifndef __SMS_CARDS_H__ #define __SMS_CARDS_H__ -#include <linux/usb.h> #include "smscoreapi.h" + +#include <linux/usb.h> #include "smsir.h" #define SMS_BOARD_UNKNOWN 0 diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index a3677438205e..2a8d9a36d6f0 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -21,6 +21,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "smscoreapi.h" + #include <linux/kernel.h> #include <linux/init.h> #include <linux/module.h> @@ -34,14 +36,9 @@ #include <linux/wait.h> #include <asm/byteorder.h> -#include "smscoreapi.h" #include "sms-cards.h" #include "smsir.h" -static int sms_dbg; -module_param_named(debug, sms_dbg, int, 0644); -MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); - struct smscore_device_notifyee_t { struct list_head entry; hotplug_t hotplug; @@ -460,7 +457,7 @@ static struct smscore_registry_entry_t *smscore_find_registry(char *devpath) strcpy(entry->devpath, devpath); list_add(&entry->entry, &g_smscore_registry); } else - sms_err("failed to create smscore_registry."); + pr_err("failed to create smscore_registry.\n"); kmutex_unlock(&g_smscore_registrylock); return entry; } @@ -473,7 +470,7 @@ int smscore_registry_getmode(char *devpath) if (entry) return entry->mode; else - sms_err("No registry found."); + pr_err("No registry found.\n"); return default_mode; } @@ -487,7 +484,7 @@ static enum sms_device_type_st smscore_registry_gettype(char *devpath) if (entry) return entry->type; else - sms_err("No registry found."); + pr_err("No registry found.\n"); return -EINVAL; } @@ -500,7 +497,7 @@ static void smscore_registry_setmode(char *devpath, int mode) if (entry) entry->mode = mode; else - sms_err("No registry found."); + pr_err("No registry found.\n"); } static void smscore_registry_settype(char *devpath, @@ -512,7 +509,7 @@ static void smscore_registry_settype(char *devpath, if (entry) entry->type = type; else - sms_err("No registry found."); + pr_err("No registry found.\n"); } @@ -635,10 +632,8 @@ smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer, struct smscore_buffer_t *cb; cb = kzalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL); - if (!cb) { - sms_info("kzalloc(...) failed"); + if (!cb) return NULL; - } cb->p = buffer; cb->offset_in_common = buffer - (u8 *) common_buffer; @@ -658,16 +653,19 @@ smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer, * @return 0 on success, <0 on error. */ int smscore_register_device(struct smsdevice_params_t *params, - struct smscore_device_t **coredev) + struct smscore_device_t **coredev, + void *mdev) { struct smscore_device_t *dev; u8 *buffer; dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL); - if (!dev) { - sms_info("kzalloc(...) failed"); + if (!dev) return -ENOMEM; - } + +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + dev->media_dev = mdev; +#endif /* init list entry so it could be safe in smscore_unregister_device */ INIT_LIST_HEAD(&dev->entry); @@ -722,7 +720,7 @@ int smscore_register_device(struct smsdevice_params_t *params, smscore_putbuffer(dev, cb); } - sms_info("allocated %d buffers", dev->num_buffers); + pr_debug("allocated %d buffers\n", dev->num_buffers); dev->mode = DEVICE_MODE_NONE; dev->board_id = SMS_BOARD_UNKNOWN; @@ -746,7 +744,7 @@ int smscore_register_device(struct smsdevice_params_t *params, *coredev = dev; - sms_info("device %p created", dev); + pr_debug("device %p created\n", dev); return 0; } @@ -763,7 +761,7 @@ static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev, rc = coredev->sendrequest_handler(coredev->context, buffer, size); if (rc < 0) { - sms_info("sendrequest returned error %d", rc); + pr_info("sendrequest returned error %d\n", rc); return rc; } @@ -786,11 +784,11 @@ static int smscore_init_ir(struct smscore_device_t *coredev) coredev->ir.dev = NULL; ir_io = sms_get_board(smscore_get_board_id(coredev))->board_cfg.ir; if (ir_io) {/* only if IR port exist we use IR sub-module */ - sms_info("IR loading"); + pr_debug("IR loading\n"); rc = sms_ir_init(coredev); if (rc != 0) - sms_err("Error initialization DTV IR sub-module"); + pr_err("Error initialization DTV IR sub-module\n"); else { buffer = kmalloc(sizeof(struct sms_msg_data2) + SMS_DMA_ALIGNMENT, @@ -812,11 +810,10 @@ static int smscore_init_ir(struct smscore_device_t *coredev) kfree(buffer); } else - sms_err - ("Sending IR initialization message failed"); + pr_err("Sending IR initialization message failed\n"); } } else - sms_info("IR port has not been detected"); + pr_info("IR port has not been detected\n"); return 0; } @@ -835,13 +832,13 @@ static int smscore_configure_board(struct smscore_device_t *coredev) board = sms_get_board(coredev->board_id); if (!board) { - sms_err("no board configuration exist."); + pr_err("no board configuration exist.\n"); return -EINVAL; } if (board->mtu) { struct sms_msg_data mtu_msg; - sms_debug("set max transmit unit %d", board->mtu); + pr_debug("set max transmit unit %d\n", board->mtu); mtu_msg.x_msg_header.msg_src_id = 0; mtu_msg.x_msg_header.msg_dst_id = HIF_TASK; @@ -856,7 +853,7 @@ static int smscore_configure_board(struct smscore_device_t *coredev) if (board->crystal) { struct sms_msg_data crys_msg; - sms_debug("set crystal value %d", board->crystal); + pr_debug("set crystal value %d\n", board->crystal); SMS_INIT_MSG(&crys_msg.x_msg_header, MSG_SMS_NEW_CRYSTAL_REQ, @@ -890,12 +887,12 @@ int smscore_start_device(struct smscore_device_t *coredev) rc = smscore_set_device_mode(coredev, mode); if (rc < 0) { - sms_info("set device mode faile , rc %d", rc); + pr_info("set device mode failed , rc %d\n", rc); return rc; } rc = smscore_configure_board(coredev); if (rc < 0) { - sms_info("configure board failed , rc %d", rc); + pr_info("configure board failed , rc %d\n", rc); return rc; } @@ -904,7 +901,7 @@ int smscore_start_device(struct smscore_device_t *coredev) rc = smscore_notify_callbacks(coredev, coredev->device, 1); smscore_init_ir(coredev); - sms_info("device %p started, rc %d", coredev, rc); + pr_debug("device %p started, rc %d\n", coredev, rc); kmutex_unlock(&g_smscore_deviceslock); @@ -927,7 +924,7 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev, mem_address = firmware->start_address; - sms_info("loading FW to addr 0x%x size %d", + pr_debug("loading FW to addr 0x%x size %d\n", mem_address, firmware->length); if (coredev->preload_handler) { rc = coredev->preload_handler(coredev->context); @@ -941,14 +938,14 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev, return -ENOMEM; if (coredev->mode != DEVICE_MODE_NONE) { - sms_debug("sending reload command."); + pr_debug("sending reload command.\n"); SMS_INIT_MSG(&msg->x_msg_header, MSG_SW_RELOAD_START_REQ, sizeof(struct sms_msg_hdr)); rc = smscore_sendrequest_and_wait(coredev, msg, msg->x_msg_header.msg_length, &coredev->reload_start_done); if (rc < 0) { - sms_err("device reload failed, rc %d", rc); + pr_err("device reload failed, rc %d\n", rc); goto exit_fw_download; } mem_address = *(u32 *) &payload[20]; @@ -982,7 +979,7 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev, if (rc < 0) goto exit_fw_download; - sms_debug("sending MSG_SMS_DATA_VALIDITY_REQ expecting 0x%x", + pr_debug("sending MSG_SMS_DATA_VALIDITY_REQ expecting 0x%x\n", calc_checksum); SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_DATA_VALIDITY_REQ, sizeof(msg->x_msg_header) + @@ -1001,7 +998,7 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev, struct sms_msg_data *trigger_msg = (struct sms_msg_data *) msg; - sms_debug("sending MSG_SMS_SWDOWNLOAD_TRIGGER_REQ"); + pr_debug("sending MSG_SMS_SWDOWNLOAD_TRIGGER_REQ\n"); SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ, sizeof(struct sms_msg_hdr) + @@ -1037,12 +1034,13 @@ exit_fw_download: kfree(msg); if (coredev->postload_handler) { - sms_debug("rc=%d, postload=0x%p", rc, coredev->postload_handler); + pr_debug("rc=%d, postload=0x%p\n", + rc, coredev->postload_handler); if (rc >= 0) return coredev->postload_handler(coredev->context); } - sms_debug("rc=%d", rc); + pr_debug("rc=%d\n", rc); return rc; } @@ -1121,11 +1119,11 @@ static char *smscore_get_fw_filename(struct smscore_device_t *coredev, if (mode <= DEVICE_MODE_NONE || mode >= DEVICE_MODE_MAX) return NULL; - sms_debug("trying to get fw name from sms_boards board_id %d mode %d", + pr_debug("trying to get fw name from sms_boards board_id %d mode %d\n", board_id, mode); fw = sms_get_board(board_id)->fw; if (!fw || !fw[mode]) { - sms_debug("cannot find fw name in sms_boards, getting from lookup table mode %d type %d", + pr_debug("cannot find fw name in sms_boards, getting from lookup table mode %d type %d\n", mode, type); return smscore_fw_lkup[type][mode]; } @@ -1154,10 +1152,10 @@ static int smscore_load_firmware_from_file(struct smscore_device_t *coredev, char *fw_filename = smscore_get_fw_filename(coredev, mode); if (!fw_filename) { - sms_err("mode %d not supported on this device", mode); + pr_err("mode %d not supported on this device\n", mode); return -ENOENT; } - sms_debug("Firmware name: %s", fw_filename); + pr_debug("Firmware name: %s\n", fw_filename); if (loadfirmware_handler == NULL && !(coredev->device_flags & SMS_DEVICE_FAMILY2)) @@ -1165,14 +1163,14 @@ static int smscore_load_firmware_from_file(struct smscore_device_t *coredev, rc = request_firmware(&fw, fw_filename, coredev->device); if (rc < 0) { - sms_err("failed to open firmware file \"%s\"", fw_filename); + pr_err("failed to open firmware file '%s'\n", fw_filename); return rc; } - sms_info("read fw %s, buffer size=0x%zx", fw_filename, fw->size); + pr_debug("read fw %s, buffer size=0x%zx\n", fw_filename, fw->size); fw_buf = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT), GFP_KERNEL | GFP_DMA); if (!fw_buf) { - sms_err("failed to allocate firmware buffer"); + pr_err("failed to allocate firmware buffer\n"); rc = -ENOMEM; } else { memcpy(fw_buf, fw->data, fw->size); @@ -1226,18 +1224,18 @@ void smscore_unregister_device(struct smscore_device_t *coredev) if (num_buffers == coredev->num_buffers) break; if (++retry > 10) { - sms_info("exiting although not all buffers released."); + pr_info("exiting although not all buffers released.\n"); break; } - sms_info("waiting for %d buffer(s)", + pr_debug("waiting for %d buffer(s)\n", coredev->num_buffers - num_buffers); kmutex_unlock(&g_smscore_deviceslock); msleep(100); kmutex_lock(&g_smscore_deviceslock); } - sms_info("freed %d buffers", num_buffers); + pr_debug("freed %d buffers\n", num_buffers); if (coredev->common_buffer) dma_free_coherent(NULL, coredev->common_buffer_size, @@ -1250,7 +1248,7 @@ void smscore_unregister_device(struct smscore_device_t *coredev) kmutex_unlock(&g_smscore_deviceslock); - sms_info("device %p destroyed", coredev); + pr_debug("device %p destroyed\n", coredev); } EXPORT_SYMBOL_GPL(smscore_unregister_device); @@ -1271,7 +1269,7 @@ static int smscore_detect_mode(struct smscore_device_t *coredev) rc = smscore_sendrequest_and_wait(coredev, msg, msg->msg_length, &coredev->version_ex_done); if (rc == -ETIME) { - sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try"); + pr_err("MSG_SMS_GET_VERSION_EX_REQ failed first try\n"); if (wait_for_completion_timeout(&coredev->resume_done, msecs_to_jiffies(5000))) { @@ -1279,7 +1277,7 @@ static int smscore_detect_mode(struct smscore_device_t *coredev) coredev, msg, msg->msg_length, &coredev->version_ex_done); if (rc < 0) - sms_err("MSG_SMS_GET_VERSION_EX_REQ failed second try, rc %d", + pr_err("MSG_SMS_GET_VERSION_EX_REQ failed second try, rc %d\n", rc); } else rc = -ETIME; @@ -1308,7 +1306,7 @@ static int smscore_init_device(struct smscore_device_t *coredev, int mode) buffer = kmalloc(sizeof(struct sms_msg_data) + SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); if (!buffer) { - sms_err("Could not allocate buffer for init device message."); + pr_err("Could not allocate buffer for init device message.\n"); return -ENOMEM; } @@ -1339,10 +1337,10 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode) { int rc = 0; - sms_debug("set device mode to %d", mode); + pr_debug("set device mode to %d\n", mode); if (coredev->device_flags & SMS_DEVICE_FAMILY2) { if (mode <= DEVICE_MODE_NONE || mode >= DEVICE_MODE_MAX) { - sms_err("invalid mode specified %d", mode); + pr_err("invalid mode specified %d\n", mode); return -EINVAL; } @@ -1351,13 +1349,13 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode) if (!(coredev->device_flags & SMS_DEVICE_NOT_READY)) { rc = smscore_detect_mode(coredev); if (rc < 0) { - sms_err("mode detect failed %d", rc); + pr_err("mode detect failed %d\n", rc); return rc; } } if (coredev->mode == mode) { - sms_info("device mode %d already set", mode); + pr_debug("device mode %d already set\n", mode); return 0; } @@ -1365,19 +1363,19 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode) rc = smscore_load_firmware_from_file(coredev, mode, NULL); if (rc >= 0) - sms_info("firmware download success"); + pr_debug("firmware download success\n"); } else { - sms_info("mode %d is already supported by running firmware", + pr_debug("mode %d is already supported by running firmware\n", mode); } if (coredev->fw_version >= 0x800) { rc = smscore_init_device(coredev, mode); if (rc < 0) - sms_err("device init failed, rc %d.", rc); + pr_err("device init failed, rc %d.\n", rc); } } else { if (mode <= DEVICE_MODE_NONE || mode >= DEVICE_MODE_MAX) { - sms_err("invalid mode specified %d", mode); + pr_err("invalid mode specified %d\n", mode); return -EINVAL; } @@ -1414,9 +1412,9 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode) } if (rc < 0) - sms_err("return error code %d.", rc); + pr_err("return error code %d.\n", rc); else - sms_debug("Success setting device mode."); + pr_debug("Success setting device mode.\n"); return rc; } @@ -1495,7 +1493,7 @@ void smscore_onresponse(struct smscore_device_t *coredev, last_sample_time = time_now; if (time_now - last_sample_time > 10000) { - sms_debug("data rate %d bytes/secs", + pr_debug("data rate %d bytes/secs\n", (int)((data_total * 1000) / (time_now - last_sample_time))); @@ -1539,7 +1537,7 @@ void smscore_onresponse(struct smscore_device_t *coredev, { struct sms_version_res *ver = (struct sms_version_res *) phdr; - sms_debug("Firmware id %d prots 0x%x ver %d.%d", + pr_debug("Firmware id %d prots 0x%x ver %d.%d\n", ver->firmware_id, ver->supported_protocols, ver->rom_ver_major, ver->rom_ver_minor); @@ -1562,7 +1560,7 @@ void smscore_onresponse(struct smscore_device_t *coredev, { struct sms_msg_data *validity = (struct sms_msg_data *) phdr; - sms_debug("MSG_SMS_DATA_VALIDITY_RES, checksum = 0x%x", + pr_debug("MSG_SMS_DATA_VALIDITY_RES, checksum = 0x%x\n", validity->msg_data[0]); complete(&coredev->data_validity_done); break; @@ -1588,7 +1586,7 @@ void smscore_onresponse(struct smscore_device_t *coredev, { u32 *msgdata = (u32 *) phdr; coredev->gpio_get_res = msgdata[1]; - sms_debug("gpio level %d", + pr_debug("gpio level %d\n", coredev->gpio_get_res); complete(&coredev->gpio_get_level_done); break; @@ -1615,7 +1613,7 @@ void smscore_onresponse(struct smscore_device_t *coredev, break; default: - sms_debug("message %s(%d) not handled.", + pr_debug("message %s(%d) not handled.\n", smscore_translate_msg(phdr->msg_type), phdr->msg_type); break; @@ -1681,7 +1679,7 @@ static int smscore_validate_client(struct smscore_device_t *coredev, struct smscore_client_t *registered_client; if (!client) { - sms_err("bad parameter."); + pr_err("bad parameter.\n"); return -EINVAL; } registered_client = smscore_find_client(coredev, data_type, id); @@ -1689,12 +1687,12 @@ static int smscore_validate_client(struct smscore_device_t *coredev, return 0; if (registered_client) { - sms_err("The msg ID already registered to another client."); + pr_err("The msg ID already registered to another client.\n"); return -EEXIST; } listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL); if (!listentry) { - sms_err("Can't allocate memory for client id."); + pr_err("Can't allocate memory for client id.\n"); return -ENOMEM; } listentry->id = id; @@ -1726,13 +1724,13 @@ int smscore_register_client(struct smscore_device_t *coredev, /* check that no other channel with same parameters exists */ if (smscore_find_client(coredev, params->data_type, params->initial_id)) { - sms_err("Client already exist."); + pr_err("Client already exist.\n"); return -EEXIST; } newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL); if (!newclient) { - sms_err("Failed to allocate memory for client."); + pr_err("Failed to allocate memory for client.\n"); return -ENOMEM; } @@ -1746,7 +1744,7 @@ int smscore_register_client(struct smscore_device_t *coredev, smscore_validate_client(coredev, newclient, params->data_type, params->initial_id); *client = newclient; - sms_debug("%p %d %d", params->context, params->data_type, + pr_debug("%p %d %d\n", params->context, params->data_type, params->initial_id); return 0; @@ -1775,7 +1773,7 @@ void smscore_unregister_client(struct smscore_client_t *client) kfree(identry); } - sms_info("%p", client->context); + pr_debug("%p\n", client->context); list_del(&client->entry); kfree(client); @@ -1803,7 +1801,7 @@ int smsclient_sendrequest(struct smscore_client_t *client, int rc; if (client == NULL) { - sms_err("Got NULL client"); + pr_err("Got NULL client\n"); return -EINVAL; } @@ -1811,7 +1809,7 @@ int smsclient_sendrequest(struct smscore_client_t *client, /* check that no other channel with same id exists */ if (coredev == NULL) { - sms_err("Got NULL coredev"); + pr_err("Got NULL coredev\n"); return -EINVAL; } @@ -2016,9 +2014,9 @@ int smscore_gpio_configure(struct smscore_device_t *coredev, u8 pin_num, if (rc != 0) { if (rc == -ETIME) - sms_err("smscore_gpio_configure timeout"); + pr_err("smscore_gpio_configure timeout\n"); else - sms_err("smscore_gpio_configure error"); + pr_err("smscore_gpio_configure error\n"); } free: kfree(buffer); @@ -2065,9 +2063,9 @@ int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 pin_num, if (rc != 0) { if (rc == -ETIME) - sms_err("smscore_gpio_set_level timeout"); + pr_err("smscore_gpio_set_level timeout\n"); else - sms_err("smscore_gpio_set_level error"); + pr_err("smscore_gpio_set_level error\n"); } kfree(buffer); @@ -2113,9 +2111,9 @@ int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 pin_num, if (rc != 0) { if (rc == -ETIME) - sms_err("smscore_gpio_get_level timeout"); + pr_err("smscore_gpio_get_level timeout\n"); else - sms_err("smscore_gpio_get_level error"); + pr_err("smscore_gpio_get_level error\n"); } kfree(buffer); @@ -2163,7 +2161,7 @@ static void __exit smscore_module_exit(void) } kmutex_unlock(&g_smscore_registrylock); - sms_debug(""); + pr_debug("\n"); } module_init(smscore_module_init); diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index 9c9063cd3208..eb8bd689b936 100644 --- a/drivers/media/common/siano/smscoreapi.h +++ b/drivers/media/common/siano/smscoreapi.h @@ -22,6 +22,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #ifndef __SMS_CORE_API_H__ #define __SMS_CORE_API_H__ +#define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__ + #include <linux/device.h> #include <linux/list.h> #include <linux/mm.h> @@ -31,6 +33,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #include <linux/wait.h> #include <linux/timer.h> +#include <media/media-device.h> + #include <asm/page.h> #include "smsir.h" @@ -215,6 +219,10 @@ struct smscore_device_t { bool is_usb_device; int led_state; + +#if defined(CONFIG_MEDIA_CONTROLLER_DVB) + struct media_device *media_dev; +#endif }; /* GPIO definitions for antenna frequency domain control (SMS8021) */ @@ -1115,7 +1123,8 @@ extern int smscore_register_hotplug(hotplug_t hotplug); extern void smscore_unregister_hotplug(hotplug_t hotplug); extern int smscore_register_device(struct smsdevice_params_t *params, - struct smscore_device_t **coredev); + struct smscore_device_t **coredev, + void *mdev); extern void smscore_unregister_device(struct smscore_device_t *coredev); extern int smscore_start_device(struct smscore_device_t *coredev); @@ -1168,25 +1177,4 @@ int smscore_led_state(struct smscore_device_t *core, int led); /* ------------------------------------------------------------------------ */ -#define DBG_INFO 1 -#define DBG_ADV 2 - -#define sms_printk(kern, fmt, arg...) \ - printk(kern "%s: " fmt "\n", __func__, ##arg) - -#define dprintk(kern, lvl, fmt, arg...) do {\ - if (sms_dbg & lvl) \ - sms_printk(kern, fmt, ##arg); \ -} while (0) - -#define sms_log(fmt, arg...) sms_printk(KERN_INFO, fmt, ##arg) -#define sms_err(fmt, arg...) \ - sms_printk(KERN_ERR, "line: %d: " fmt, __LINE__, ##arg) -#define sms_warn(fmt, arg...) sms_printk(KERN_WARNING, fmt, ##arg) -#define sms_info(fmt, arg...) \ - dprintk(KERN_INFO, DBG_INFO, fmt, ##arg) -#define sms_debug(fmt, arg...) \ - dprintk(KERN_DEBUG, DBG_ADV, fmt, ##arg) - - #endif /* __SMS_CORE_API_H__ */ diff --git a/drivers/media/common/siano/smsdvb-debugfs.c b/drivers/media/common/siano/smsdvb-debugfs.c index 2408d7e9451e..1a8677ade391 100644 --- a/drivers/media/common/siano/smsdvb-debugfs.c +++ b/drivers/media/common/siano/smsdvb-debugfs.c @@ -17,7 +17,7 @@ * ***********************************************************************/ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include "smscoreapi.h" #include <linux/module.h> #include <linux/slab.h> @@ -31,8 +31,6 @@ #include "dvb_demux.h" #include "dvb_frontend.h" -#include "smscoreapi.h" - #include "smsdvb.h" static struct dentry *smsdvb_debugfs_usb_root; @@ -536,7 +534,7 @@ int smsdvb_debugfs_register(void) */ d = debugfs_create_dir("smsdvb", usb_debug_root); if (IS_ERR_OR_NULL(d)) { - sms_err("Couldn't create sysfs node for smsdvb"); + pr_err("Couldn't create sysfs node for smsdvb\n"); return PTR_ERR(d); } else { smsdvb_debugfs_usb_root = d; diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c index 85151efdd94c..367b8e77feb8 100644 --- a/drivers/media/common/siano/smsdvb-main.c +++ b/drivers/media/common/siano/smsdvb-main.c @@ -19,6 +19,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. ****************************************************************/ +#include "smscoreapi.h" + #include <linux/module.h> #include <linux/slab.h> #include <linux/init.h> @@ -29,7 +31,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #include "dvb_demux.h" #include "dvb_frontend.h" -#include "smscoreapi.h" #include "sms-cards.h" #include "smsdvb.h" @@ -39,11 +40,6 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); static struct list_head g_smsdvb_clients; static struct mutex g_smsdvb_clientslock; -static int sms_dbg; -module_param_named(debug, sms_dbg, int, 0644); -MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); - - static u32 sms_to_guard_interval_table[] = { [0] = GUARD_INTERVAL_1_32, [1] = GUARD_INTERVAL_1_16, @@ -82,48 +78,48 @@ static void sms_board_dvb3_event(struct smsdvb_client_t *client, struct smscore_device_t *coredev = client->coredev; switch (event) { case DVB3_EVENT_INIT: - sms_debug("DVB3_EVENT_INIT"); + pr_debug("DVB3_EVENT_INIT\n"); sms_board_event(coredev, BOARD_EVENT_BIND); break; case DVB3_EVENT_SLEEP: - sms_debug("DVB3_EVENT_SLEEP"); + pr_debug("DVB3_EVENT_SLEEP\n"); sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND); break; case DVB3_EVENT_HOTPLUG: - sms_debug("DVB3_EVENT_HOTPLUG"); + pr_debug("DVB3_EVENT_HOTPLUG\n"); sms_board_event(coredev, BOARD_EVENT_POWER_INIT); break; case DVB3_EVENT_FE_LOCK: if (client->event_fe_state != DVB3_EVENT_FE_LOCK) { client->event_fe_state = DVB3_EVENT_FE_LOCK; - sms_debug("DVB3_EVENT_FE_LOCK"); + pr_debug("DVB3_EVENT_FE_LOCK\n"); sms_board_event(coredev, BOARD_EVENT_FE_LOCK); } break; case DVB3_EVENT_FE_UNLOCK: if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) { client->event_fe_state = DVB3_EVENT_FE_UNLOCK; - sms_debug("DVB3_EVENT_FE_UNLOCK"); + pr_debug("DVB3_EVENT_FE_UNLOCK\n"); sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK); } break; case DVB3_EVENT_UNC_OK: if (client->event_unc_state != DVB3_EVENT_UNC_OK) { client->event_unc_state = DVB3_EVENT_UNC_OK; - sms_debug("DVB3_EVENT_UNC_OK"); + pr_debug("DVB3_EVENT_UNC_OK\n"); sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK); } break; case DVB3_EVENT_UNC_ERR: if (client->event_unc_state != DVB3_EVENT_UNC_ERR) { client->event_unc_state = DVB3_EVENT_UNC_ERR; - sms_debug("DVB3_EVENT_UNC_ERR"); + pr_debug("DVB3_EVENT_UNC_ERR\n"); sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS); } break; default: - sms_err("Unknown dvb3 api event"); + pr_err("Unknown dvb3 api event\n"); break; } } @@ -590,7 +586,7 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) is_status_update = true; break; default: - sms_info("message not handled"); + pr_debug("message not handled\n"); } smscore_putbuffer(client->coredev, cb); @@ -613,6 +609,19 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) return 0; } +static void smsdvb_media_device_unregister(struct smsdvb_client_t *client) +{ +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + struct smscore_device_t *coredev = client->coredev; + + if (!coredev->media_dev) + return; + media_device_unregister(coredev->media_dev); + kfree(coredev->media_dev); + coredev->media_dev = NULL; +#endif +} + static void smsdvb_unregister_client(struct smsdvb_client_t *client) { /* must be called under clientslock */ @@ -624,6 +633,7 @@ static void smsdvb_unregister_client(struct smsdvb_client_t *client) dvb_unregister_frontend(&client->frontend); dvb_dmxdev_release(&client->dmxdev); dvb_dmx_release(&client->demux); + smsdvb_media_device_unregister(client); dvb_unregister_adapter(&client->adapter); kfree(client); } @@ -643,7 +653,7 @@ static int smsdvb_start_feed(struct dvb_demux_feed *feed) container_of(feed->demux, struct smsdvb_client_t, demux); struct sms_msg_data pid_msg; - sms_debug("add pid %d(%x)", + pr_debug("add pid %d(%x)\n", feed->pid, feed->pid); client->feed_users++; @@ -665,7 +675,7 @@ static int smsdvb_stop_feed(struct dvb_demux_feed *feed) container_of(feed->demux, struct smsdvb_client_t, demux); struct sms_msg_data pid_msg; - sms_debug("remove pid %d(%x)", + pr_debug("remove pid %d(%x)\n", feed->pid, feed->pid); client->feed_users--; @@ -835,7 +845,7 @@ static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) static int smsdvb_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune) { - sms_debug(""); + pr_debug("\n"); tune->min_delay_ms = 400; tune->step_size = 250000; @@ -869,7 +879,7 @@ static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe) msg.Data[0] = c->frequency; msg.Data[2] = 12000000; - sms_info("%s: freq %d band %d", __func__, c->frequency, + pr_debug("%s: freq %d band %d\n", __func__, c->frequency, c->bandwidth_hz); switch (c->bandwidth_hz / 1000000) { @@ -954,7 +964,7 @@ static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe) c->bandwidth_hz = 6000000; - sms_info("%s: freq %d segwidth %d segindex %d", __func__, + pr_debug("freq %d segwidth %d segindex %d\n", c->frequency, c->isdbt_sb_segment_count, c->isdbt_sb_segment_idx); @@ -1082,10 +1092,8 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev, if (!arrival) return 0; client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL); - if (!client) { - sms_err("kmalloc() failed"); + if (!client) return -ENOMEM; - } /* register dvb adapter */ rc = dvb_register_adapter(&client->adapter, @@ -1093,9 +1101,10 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev, smscore_get_board_id(coredev))->name, THIS_MODULE, device, adapter_nr); if (rc < 0) { - sms_err("dvb_register_adapter() failed %d", rc); + pr_err("dvb_register_adapter() failed %d\n", rc); goto adapter_error; } + dvb_register_media_controller(&client->adapter, coredev->media_dev); /* init dvb demux */ client->demux.dmx.capabilities = DMX_TS_FILTERING; @@ -1106,7 +1115,7 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev, rc = dvb_dmx_init(&client->demux); if (rc < 0) { - sms_err("dvb_dmx_init failed %d", rc); + pr_err("dvb_dmx_init failed %d\n", rc); goto dvbdmx_error; } @@ -1117,7 +1126,7 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev, rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter); if (rc < 0) { - sms_err("dvb_dmxdev_init failed %d", rc); + pr_err("dvb_dmxdev_init failed %d\n", rc); goto dmxdev_error; } @@ -1138,7 +1147,7 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev, rc = dvb_register_frontend(&client->adapter, &client->frontend); if (rc < 0) { - sms_err("frontend registration failed %d", rc); + pr_err("frontend registration failed %d\n", rc); goto frontend_error; } @@ -1150,7 +1159,7 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev, rc = smscore_register_client(coredev, ¶ms, &client->smsclient); if (rc < 0) { - sms_err("smscore_register_client() failed %d", rc); + pr_err("smscore_register_client() failed %d\n", rc); goto client_error; } @@ -1169,12 +1178,14 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev, client->event_unc_state = -1; sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG); - sms_info("success"); sms_board_setup(coredev); if (smsdvb_debugfs_create(client) < 0) - sms_info("failed to create debugfs node"); + pr_info("failed to create debugfs node\n"); + + dvb_create_media_graph(&client->adapter); + pr_info("DVB interface registered.\n"); return 0; client_error: @@ -1187,6 +1198,7 @@ dmxdev_error: dvb_dmx_release(&client->demux); dvbdmx_error: + smsdvb_media_device_unregister(client); dvb_unregister_adapter(&client->adapter); adapter_error: @@ -1205,7 +1217,7 @@ static int __init smsdvb_module_init(void) rc = smscore_register_hotplug(smsdvb_hotplug); - sms_debug(""); + pr_debug("\n"); return rc; } diff --git a/drivers/media/common/siano/smsir.c b/drivers/media/common/siano/smsir.c index 35d0e887bd65..1d60d200d9ab 100644 --- a/drivers/media/common/siano/smsir.c +++ b/drivers/media/common/siano/smsir.c @@ -25,10 +25,11 @@ ****************************************************************/ +#include "smscoreapi.h" + #include <linux/types.h> #include <linux/input.h> -#include "smscoreapi.h" #include "smsir.h" #include "sms-cards.h" @@ -56,16 +57,14 @@ int sms_ir_init(struct smscore_device_t *coredev) int board_id = smscore_get_board_id(coredev); struct rc_dev *dev; - sms_log("Allocating rc device"); + pr_debug("Allocating rc device\n"); dev = rc_allocate_device(); - if (!dev) { - sms_err("Not enough memory"); + if (!dev) return -ENOMEM; - } coredev->ir.controller = 0; /* Todo: vega/nova SPI number */ coredev->ir.timeout = IR_DEFAULT_TIMEOUT; - sms_log("IR port %d, timeout %d ms", + pr_debug("IR port %d, timeout %d ms\n", coredev->ir.controller, coredev->ir.timeout); snprintf(coredev->ir.name, sizeof(coredev->ir.name), @@ -92,11 +91,12 @@ int sms_ir_init(struct smscore_device_t *coredev) dev->map_name = sms_get_board(board_id)->rc_codes; dev->driver_name = MODULE_NAME; - sms_log("Input device (IR) %s is set for key events", dev->input_name); + pr_debug("Input device (IR) %s is set for key events\n", + dev->input_name); err = rc_register_device(dev); if (err < 0) { - sms_err("Failed to register device"); + pr_err("Failed to register device\n"); rc_free_device(dev); return err; } @@ -109,5 +109,5 @@ void sms_ir_exit(struct smscore_device_t *coredev) { rc_unregister_device(coredev->ir.dev); - sms_log(""); + pr_debug("\n"); } diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index abff803ad69a..d0e3f9d85f34 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -1136,10 +1136,13 @@ static const struct file_operations dvb_demux_fops = { .llseek = default_llseek, }; -static struct dvb_device dvbdev_demux = { +static const struct dvb_device dvbdev_demux = { .priv = NULL, .users = 1, .writers = 1, +#if defined(CONFIG_MEDIA_CONTROLLER_DVB) + .name = "dvb-demux", +#endif .fops = &dvb_demux_fops }; @@ -1209,13 +1212,15 @@ static const struct file_operations dvb_dvr_fops = { .llseek = default_llseek, }; -static struct dvb_device dvbdev_dvr = { +static const struct dvb_device dvbdev_dvr = { .priv = NULL, .readers = 1, .users = 1, +#if defined(CONFIG_MEDIA_CONTROLLER_DVB) + .name = "dvb-dvr", +#endif .fops = &dvb_dvr_fops }; - int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter) { int i; diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h index 80ab8d0ff6e0..c117fb3b4aff 100644 --- a/drivers/media/dvb-core/dvb-usb-ids.h +++ b/drivers/media/dvb-core/dvb-usb-ids.h @@ -245,6 +245,7 @@ #define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006 #define USB_PID_TECHNOTREND_CONNECT_S2400_8KEEPROM 0x3009 #define USB_PID_TECHNOTREND_CONNECT_CT3650 0x300d +#define USB_PID_TECHNOTREND_CONNECT_S2_4600 0x3011 #define USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI 0x3012 #define USB_PID_TECHNOTREND_TVSTICK_CT2_4400 0x3014 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a @@ -318,6 +319,7 @@ #define USB_PID_GRANDTEC_DVBT_USB2_COLD 0x0bc6 #define USB_PID_GRANDTEC_DVBT_USB2_WARM 0x0bc7 #define USB_PID_WINFAST_DTV2000DS 0x6a04 +#define USB_PID_WINFAST_DTV2000DS_PLUS 0x6f12 #define USB_PID_WINFAST_DTV_DONGLE_COLD 0x6025 #define USB_PID_WINFAST_DTV_DONGLE_WARM 0x6026 #define USB_PID_WINFAST_DTV_DONGLE_STK7700P 0x6f00 @@ -385,4 +387,5 @@ #define USB_PID_PCTV_2002E 0x025c #define USB_PID_PCTV_2002E_SE 0x025d #define USB_PID_SVEON_STV27 0xd3af +#define USB_PID_TURBOX_DTT_2000 0xd3a4 #endif diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c index 0aac3096728e..72937756f60c 100644 --- a/drivers/media/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb-core/dvb_ca_en50221.c @@ -1638,15 +1638,17 @@ static const struct file_operations dvb_ca_fops = { .llseek = noop_llseek, }; -static struct dvb_device dvbdev_ca = { +static const struct dvb_device dvbdev_ca = { .priv = NULL, .users = 1, .readers = 1, .writers = 1, +#if defined(CONFIG_MEDIA_CONTROLLER_DVB) + .name = "dvb-ca-en50221", +#endif .fops = &dvb_ca_fops, }; - /* ******************************************************************************** */ /* Initialisation/shutdown functions */ @@ -1676,14 +1678,14 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, /* initialise the system data */ if ((ca = kzalloc(sizeof(struct dvb_ca_private), GFP_KERNEL)) == NULL) { ret = -ENOMEM; - goto error; + goto exit; } ca->pub = pubca; ca->flags = flags; ca->slot_count = slot_count; if ((ca->slot_info = kcalloc(slot_count, sizeof(struct dvb_ca_slot), GFP_KERNEL)) == NULL) { ret = -ENOMEM; - goto error; + goto free_ca; } init_waitqueue_head(&ca->wait_queue); ca->open = 0; @@ -1694,7 +1696,7 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, /* register the DVB device */ ret = dvb_register_device(dvb_adapter, &ca->dvbdev, &dvbdev_ca, ca, DVB_DEVICE_CA); if (ret) - goto error; + goto free_slot_info; /* now initialise each slot */ for (i = 0; i < slot_count; i++) { @@ -1709,7 +1711,7 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, if (signal_pending(current)) { ret = -EINTR; - goto error; + goto unregister_device; } mb(); @@ -1720,17 +1722,17 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, ret = PTR_ERR(ca->thread); printk("dvb_ca_init: failed to start kernel_thread (%d)\n", ret); - goto error; + goto unregister_device; } return 0; -error: - if (ca != NULL) { - if (ca->dvbdev != NULL) - dvb_unregister_device(ca->dvbdev); - kfree(ca->slot_info); - kfree(ca); - } +unregister_device: + dvb_unregister_device(ca->dvbdev); +free_slot_info: + kfree(ca->slot_info); +free_ca: + kfree(ca); +exit: pubca->private = NULL; return ret; } diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 2cf30576bf39..882ca417f328 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -131,6 +131,11 @@ struct dvb_frontend_private { int quality; unsigned int check_wrapped; enum dvbfe_search algo_status; + +#if defined(CONFIG_MEDIA_CONTROLLER_DVB) + struct media_pipeline pipe; + struct media_entity *pipe_start_entity; +#endif }; static void dvb_frontend_wakeup(struct dvb_frontend *fe); @@ -590,12 +595,106 @@ static void dvb_frontend_wakeup(struct dvb_frontend *fe) wake_up_interruptible(&fepriv->wait_queue); } +/** + * dvb_enable_media_tuner() - tries to enable the DVB tuner + * + * @fe: struct dvb_frontend pointer + * + * This function ensures that just one media tuner is enabled for a given + * frontend. It has two different behaviors: + * - For trivial devices with just one tuner: + * it just enables the existing tuner->fe link + * - For devices with more than one tuner: + * It is up to the driver to implement the logic that will enable one tuner + * and disable the other ones. However, if more than one tuner is enabled for + * the same frontend, it will print an error message and return -EINVAL. + * + * At return, it will return the error code returned by media_entity_setup_link, + * or 0 if everything is OK, if no tuner is linked to the frontend or if the + * mdev is NULL. + */ +#ifdef CONFIG_MEDIA_CONTROLLER_DVB +static int dvb_enable_media_tuner(struct dvb_frontend *fe) +{ + struct dvb_frontend_private *fepriv = fe->frontend_priv; + struct dvb_adapter *adapter = fe->dvb; + struct media_device *mdev = adapter->mdev; + struct media_entity *entity, *source; + struct media_link *link, *found_link = NULL; + int i, ret, n_links = 0, active_links = 0; + + fepriv->pipe_start_entity = NULL; + + if (!mdev) + return 0; + + entity = fepriv->dvbdev->entity; + fepriv->pipe_start_entity = entity; + + for (i = 0; i < entity->num_links; i++) { + link = &entity->links[i]; + if (link->sink->entity == entity) { + found_link = link; + n_links++; + if (link->flags & MEDIA_LNK_FL_ENABLED) + active_links++; + } + } + + if (!n_links || active_links == 1 || !found_link) + return 0; + + /* + * If a frontend has more than one tuner linked, it is up to the driver + * to select with one will be the active one, as the frontend core can't + * guess. If the driver doesn't do that, it is a bug. + */ + if (n_links > 1 && active_links != 1) { + dev_err(fe->dvb->device, + "WARNING: there are %d active links among %d tuners. This is a driver's bug!\n", + active_links, n_links); + return -EINVAL; + } + + source = found_link->source->entity; + fepriv->pipe_start_entity = source; + for (i = 0; i < source->num_links; i++) { + struct media_entity *sink; + int flags = 0; + + link = &source->links[i]; + sink = link->sink->entity; + + if (sink == entity) + flags = MEDIA_LNK_FL_ENABLED; + + ret = media_entity_setup_link(link, flags); + if (ret) { + dev_err(fe->dvb->device, + "Couldn't change link %s->%s to %s. Error %d\n", + source->name, sink->name, + flags ? "enabled" : "disabled", + ret); + return ret; + } else + dev_dbg(fe->dvb->device, + "link %s->%s was %s\n", + source->name, sink->name, + flags ? "ENABLED" : "disabled"); + } + return 0; +} +#endif + static int dvb_frontend_thread(void *data) { struct dvb_frontend *fe = data; struct dvb_frontend_private *fepriv = fe->frontend_priv; fe_status_t s; enum dvbfe_algo algo; +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + int ret; +#endif bool re_tune = false; bool semheld = false; @@ -609,6 +708,20 @@ static int dvb_frontend_thread(void *data) fepriv->wakeup = 0; fepriv->reinitialise = 0; +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + ret = dvb_enable_media_tuner(fe); + if (ret) { + /* FIXME: return an error if it fails */ + dev_info(fe->dvb->device, + "proceeding with FE task\n"); + } else if (fepriv->pipe_start_entity) { + ret = media_entity_pipeline_start(fepriv->pipe_start_entity, + &fepriv->pipe); + if (ret) + return ret; + } +#endif + dvb_frontend_init(fe); set_freezable(); @@ -718,6 +831,12 @@ restart: } } +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + if (fepriv->pipe_start_entity) + media_entity_pipeline_stop(fepriv->pipe_start_entity); + fepriv->pipe_start_entity = NULL; +#endif + if (dvb_powerdown_on_sleep) { if (fe->ops.set_voltage) fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF); @@ -2612,11 +2731,14 @@ int dvb_register_frontend(struct dvb_adapter* dvb, struct dvb_frontend* fe) { struct dvb_frontend_private *fepriv; - static const struct dvb_device dvbdev_template = { + const struct dvb_device dvbdev_template = { .users = ~0, .writers = 1, .readers = (~0)-1, .fops = &dvb_frontend_fops, +#if defined(CONFIG_MEDIA_CONTROLLER_DVB) + .name = fe->ops.info.name, +#endif .kernel_ioctl = dvb_frontend_ioctl }; diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c index 686d3277dad1..1508d918205d 100644 --- a/drivers/media/dvb-core/dvb_net.c +++ b/drivers/media/dvb-core/dvb_net.c @@ -1462,14 +1462,16 @@ static const struct file_operations dvb_net_fops = { .llseek = noop_llseek, }; -static struct dvb_device dvbdev_net = { +static const struct dvb_device dvbdev_net = { .priv = NULL, .users = 1, .writers = 1, +#if defined(CONFIG_MEDIA_CONTROLLER_DVB) + .name = "dvb-net", +#endif .fops = &dvb_net_fops, }; - void dvb_net_release (struct dvb_net *dvbnet) { int i; diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c index 983db75de350..13bb57f0457f 100644 --- a/drivers/media/dvb-core/dvbdev.c +++ b/drivers/media/dvb-core/dvbdev.c @@ -180,6 +180,93 @@ skip: return -ENFILE; } +static void dvb_register_media_device(struct dvb_device *dvbdev, + int type, int minor) +{ +#if defined(CONFIG_MEDIA_CONTROLLER_DVB) + int ret = 0, npads; + + if (!dvbdev->adapter->mdev) + return; + + dvbdev->entity = kzalloc(sizeof(*dvbdev->entity), GFP_KERNEL); + if (!dvbdev->entity) + return; + + dvbdev->entity->info.dev.major = DVB_MAJOR; + dvbdev->entity->info.dev.minor = minor; + dvbdev->entity->name = dvbdev->name; + + switch (type) { + case DVB_DEVICE_CA: + case DVB_DEVICE_DEMUX: + case DVB_DEVICE_FRONTEND: + npads = 2; + break; + case DVB_DEVICE_NET: + npads = 0; + break; + default: + npads = 1; + } + + if (npads) { + dvbdev->pads = kcalloc(npads, sizeof(*dvbdev->pads), + GFP_KERNEL); + if (!dvbdev->pads) { + kfree(dvbdev->entity); + return; + } + } + + switch (type) { + case DVB_DEVICE_FRONTEND: + dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_FE; + dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK; + dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE; + break; + case DVB_DEVICE_DEMUX: + dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_DEMUX; + dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK; + dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE; + break; + case DVB_DEVICE_DVR: + dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_DVR; + dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK; + break; + case DVB_DEVICE_CA: + dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_CA; + dvbdev->pads[0].flags = MEDIA_PAD_FL_SINK; + dvbdev->pads[1].flags = MEDIA_PAD_FL_SOURCE; + break; + case DVB_DEVICE_NET: + dvbdev->entity->type = MEDIA_ENT_T_DEVNODE_DVB_NET; + break; + default: + kfree(dvbdev->entity); + dvbdev->entity = NULL; + return; + } + + if (npads) + ret = media_entity_init(dvbdev->entity, npads, dvbdev->pads, 0); + if (!ret) + ret = media_device_register_entity(dvbdev->adapter->mdev, + dvbdev->entity); + if (ret < 0) { + printk(KERN_ERR + "%s: media_device_register_entity failed for %s\n", + __func__, dvbdev->entity->name); + kfree(dvbdev->pads); + kfree(dvbdev->entity); + dvbdev->entity = NULL; + return; + } + + printk(KERN_DEBUG "%s: media device '%s' registered.\n", + __func__, dvbdev->entity->name); +#endif +} int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, const struct dvb_device *template, void *priv, int type) @@ -258,10 +345,11 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, __func__, adap->num, dnames[type], id, PTR_ERR(clsdev)); return PTR_ERR(clsdev); } - dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", adap->num, dnames[type], id, minor, minor); + dvb_register_media_device(dvbdev, type, minor); + return 0; } EXPORT_SYMBOL(dvb_register_device); @@ -278,12 +366,66 @@ void dvb_unregister_device(struct dvb_device *dvbdev) device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor)); +#if defined(CONFIG_MEDIA_CONTROLLER_DVB) + if (dvbdev->entity) { + media_device_unregister_entity(dvbdev->entity); + kfree(dvbdev->entity); + kfree(dvbdev->pads); + } +#endif + list_del (&dvbdev->list_head); kfree (dvbdev->fops); kfree (dvbdev); } EXPORT_SYMBOL(dvb_unregister_device); + +#ifdef CONFIG_MEDIA_CONTROLLER_DVB +void dvb_create_media_graph(struct dvb_adapter *adap) +{ + struct media_device *mdev = adap->mdev; + struct media_entity *entity, *tuner = NULL, *fe = NULL; + struct media_entity *demux = NULL, *dvr = NULL, *ca = NULL; + + if (!mdev) + return; + + media_device_for_each_entity(entity, mdev) { + switch (entity->type) { + case MEDIA_ENT_T_V4L2_SUBDEV_TUNER: + tuner = entity; + break; + case MEDIA_ENT_T_DEVNODE_DVB_FE: + fe = entity; + break; + case MEDIA_ENT_T_DEVNODE_DVB_DEMUX: + demux = entity; + break; + case MEDIA_ENT_T_DEVNODE_DVB_DVR: + dvr = entity; + break; + case MEDIA_ENT_T_DEVNODE_DVB_CA: + ca = entity; + break; + } + } + + if (tuner && fe) + media_entity_create_link(tuner, 0, fe, 0, 0); + + if (fe && demux) + media_entity_create_link(fe, 1, demux, 0, MEDIA_LNK_FL_ENABLED); + + if (demux && dvr) + media_entity_create_link(demux, 1, dvr, 0, MEDIA_LNK_FL_ENABLED); + + if (demux && ca) + media_entity_create_link(demux, 1, ca, 0, MEDIA_LNK_FL_ENABLED); +} +EXPORT_SYMBOL_GPL(dvb_create_media_graph); +#endif + static int dvbdev_check_free_adapter_num(int num) { struct list_head *entry; diff --git a/drivers/media/dvb-core/dvbdev.h b/drivers/media/dvb-core/dvbdev.h index f96b28e7fc95..12629b8ecb0c 100644 --- a/drivers/media/dvb-core/dvbdev.h +++ b/drivers/media/dvb-core/dvbdev.h @@ -27,6 +27,7 @@ #include <linux/poll.h> #include <linux/fs.h> #include <linux/list.h> +#include <media/media-device.h> #define DVB_MAJOR 212 @@ -71,6 +72,10 @@ struct dvb_adapter { int mfe_shared; /* indicates mutually exclusive frontends */ struct dvb_device *mfe_dvbdev; /* frontend device in use */ struct mutex mfe_lock; /* access lock for thread creation */ + +#if defined(CONFIG_MEDIA_CONTROLLER_DVB) + struct media_device *mdev; +#endif }; @@ -92,6 +97,15 @@ struct dvb_device { /* don't really need those !? -- FIXME: use video_usercopy */ int (*kernel_ioctl)(struct file *file, unsigned int cmd, void *arg); + /* Needed for media controller register/unregister */ +#if defined(CONFIG_MEDIA_CONTROLLER_DVB) + const char *name; + + /* Allocated and filled inside dvbdev.c */ + struct media_entity *entity; + struct media_pad *pads; +#endif + void *priv; }; @@ -109,6 +123,19 @@ extern int dvb_register_device (struct dvb_adapter *adap, extern void dvb_unregister_device (struct dvb_device *dvbdev); +#ifdef CONFIG_MEDIA_CONTROLLER_DVB +void dvb_create_media_graph(struct dvb_adapter *adap); +static inline void dvb_register_media_controller(struct dvb_adapter *adap, + struct media_device *mdev) +{ + adap->mdev = mdev; +} + +#else +static inline void dvb_create_media_graph(struct dvb_adapter *adap) {} +#define dvb_register_media_controller(a, b) {} +#endif + extern int dvb_generic_open (struct inode *inode, struct file *file); extern int dvb_generic_release (struct inode *inode, struct file *file); extern long dvb_generic_ioctl (struct file *file, diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index bb76727d924e..97c151d5b2e1 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -577,6 +577,14 @@ config DVB_LGDT3305 An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. +config DVB_LGDT3306A + tristate "LG Electronics LGDT3306A based" + depends on DVB_CORE && I2C + default m if !MEDIA_SUBDRV_AUTOSELECT + help + An ATSC 8VSB and QAM-B 64/256 demodulator module. Say Y when you want + to support this frontend. + config DVB_LG2160 tristate "LG Electronics LG216x based" depends on DVB_CORE && I2C diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile index ba59df63d050..23d399bec804 100644 --- a/drivers/media/dvb-frontends/Makefile +++ b/drivers/media/dvb-frontends/Makefile @@ -54,6 +54,7 @@ obj-$(CONFIG_DVB_BCM3510) += bcm3510.o obj-$(CONFIG_DVB_S5H1420) += s5h1420.o obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o +obj-$(CONFIG_DVB_LGDT3306A) += lgdt3306a.o obj-$(CONFIG_DVB_LG2160) += lg2160.o obj-$(CONFIG_DVB_CX24123) += cx24123.o obj-$(CONFIG_DVB_LNBP21) += lnbp21.o diff --git a/drivers/media/dvb-frontends/a8293.h b/drivers/media/dvb-frontends/a8293.h index b6ef6427cfa5..5f0411939ffc 100644 --- a/drivers/media/dvb-frontends/a8293.h +++ b/drivers/media/dvb-frontends/a8293.h @@ -27,7 +27,7 @@ struct a8293_config { u8 i2c_addr; }; -#if IS_ENABLED(CONFIG_DVB_A8293) +#if IS_REACHABLE(CONFIG_DVB_A8293) extern struct dvb_frontend *a8293_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct a8293_config *cfg); #else diff --git a/drivers/media/dvb-frontends/af9013.h b/drivers/media/dvb-frontends/af9013.h index 09273b2cd310..1dcc936e1661 100644 --- a/drivers/media/dvb-frontends/af9013.h +++ b/drivers/media/dvb-frontends/af9013.h @@ -103,7 +103,7 @@ struct af9013_config { u8 gpio[4]; }; -#if IS_ENABLED(CONFIG_DVB_AF9013) +#if IS_REACHABLE(CONFIG_DVB_AF9013) extern struct dvb_frontend *af9013_attach(const struct af9013_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/atbm8830.h b/drivers/media/dvb-frontends/atbm8830.h index 8e0ac98f8d08..5446d13fdfe8 100644 --- a/drivers/media/dvb-frontends/atbm8830.h +++ b/drivers/media/dvb-frontends/atbm8830.h @@ -61,7 +61,7 @@ struct atbm8830_config { u8 agc_hold_loop; }; -#if IS_ENABLED(CONFIG_DVB_ATBM8830) +#if IS_REACHABLE(CONFIG_DVB_ATBM8830) extern struct dvb_frontend *atbm8830_attach(const struct atbm8830_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/au8522.h b/drivers/media/dvb-frontends/au8522.h index 612251958855..dde61582c158 100644 --- a/drivers/media/dvb-frontends/au8522.h +++ b/drivers/media/dvb-frontends/au8522.h @@ -61,7 +61,7 @@ struct au8522_config { enum au8522_if_freq qam_if; }; -#if IS_ENABLED(CONFIG_DVB_AU8522_DTV) +#if IS_REACHABLE(CONFIG_DVB_AU8522_DTV) extern struct dvb_frontend *au8522_attach(const struct au8522_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/bcm3510.h b/drivers/media/dvb-frontends/bcm3510.h index 5bd56b1623bf..ff66492fb940 100644 --- a/drivers/media/dvb-frontends/bcm3510.h +++ b/drivers/media/dvb-frontends/bcm3510.h @@ -34,7 +34,7 @@ struct bcm3510_config int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); }; -#if IS_ENABLED(CONFIG_DVB_BCM3510) +#if IS_REACHABLE(CONFIG_DVB_BCM3510) extern struct dvb_frontend* bcm3510_attach(const struct bcm3510_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/cx22700.h b/drivers/media/dvb-frontends/cx22700.h index 382a7b1f3618..e0a764868e6f 100644 --- a/drivers/media/dvb-frontends/cx22700.h +++ b/drivers/media/dvb-frontends/cx22700.h @@ -31,7 +31,7 @@ struct cx22700_config u8 demod_address; }; -#if IS_ENABLED(CONFIG_DVB_CX22700) +#if IS_REACHABLE(CONFIG_DVB_CX22700) extern struct dvb_frontend* cx22700_attach(const struct cx22700_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/cx22702.h b/drivers/media/dvb-frontends/cx22702.h index 0b1a6c2f9d5f..68b69a7660d2 100644 --- a/drivers/media/dvb-frontends/cx22702.h +++ b/drivers/media/dvb-frontends/cx22702.h @@ -41,7 +41,7 @@ struct cx22702_config { u8 output_mode; }; -#if IS_ENABLED(CONFIG_DVB_CX22702) +#if IS_REACHABLE(CONFIG_DVB_CX22702) extern struct dvb_frontend *cx22702_attach( const struct cx22702_config *config, struct i2c_adapter *i2c); diff --git a/drivers/media/dvb-frontends/cx24110.h b/drivers/media/dvb-frontends/cx24110.h index 527aff1f2723..d5453ed20b28 100644 --- a/drivers/media/dvb-frontends/cx24110.h +++ b/drivers/media/dvb-frontends/cx24110.h @@ -46,7 +46,7 @@ static inline int cx24110_pll_write(struct dvb_frontend *fe, u32 val) return 0; } -#if IS_ENABLED(CONFIG_DVB_CX24110) +#if IS_REACHABLE(CONFIG_DVB_CX24110) extern struct dvb_frontend* cx24110_attach(const struct cx24110_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/cx24113.h b/drivers/media/dvb-frontends/cx24113.h index 782711ba1a32..962919b9b6e6 100644 --- a/drivers/media/dvb-frontends/cx24113.h +++ b/drivers/media/dvb-frontends/cx24113.h @@ -32,7 +32,7 @@ struct cx24113_config { u32 xtal_khz; }; -#if IS_ENABLED(CONFIG_DVB_TUNER_CX24113) +#if IS_REACHABLE(CONFIG_DVB_TUNER_CX24113) extern struct dvb_frontend *cx24113_attach(struct dvb_frontend *, const struct cx24113_config *config, struct i2c_adapter *i2c); diff --git a/drivers/media/dvb-frontends/cx24116.h b/drivers/media/dvb-frontends/cx24116.h index 2ec84fae3f9f..f6dbabc1d62b 100644 --- a/drivers/media/dvb-frontends/cx24116.h +++ b/drivers/media/dvb-frontends/cx24116.h @@ -41,7 +41,7 @@ struct cx24116_config { u16 i2c_wr_max; }; -#if IS_ENABLED(CONFIG_DVB_CX24116) +#if IS_REACHABLE(CONFIG_DVB_CX24116) extern struct dvb_frontend *cx24116_attach( const struct cx24116_config *config, struct i2c_adapter *i2c); diff --git a/drivers/media/dvb-frontends/cx24117.h b/drivers/media/dvb-frontends/cx24117.h index 4e59e9574fa7..1648ab432168 100644 --- a/drivers/media/dvb-frontends/cx24117.h +++ b/drivers/media/dvb-frontends/cx24117.h @@ -30,7 +30,7 @@ struct cx24117_config { u8 demod_address; }; -#if IS_ENABLED(CONFIG_DVB_CX24117) +#if IS_REACHABLE(CONFIG_DVB_CX24117) extern struct dvb_frontend *cx24117_attach( const struct cx24117_config *config, struct i2c_adapter *i2c); diff --git a/drivers/media/dvb-frontends/cx24123.h b/drivers/media/dvb-frontends/cx24123.h index 102e70d17c43..758aee5a072f 100644 --- a/drivers/media/dvb-frontends/cx24123.h +++ b/drivers/media/dvb-frontends/cx24123.h @@ -39,7 +39,7 @@ struct cx24123_config { void (*agc_callback) (struct dvb_frontend *); }; -#if IS_ENABLED(CONFIG_DVB_CX24123) +#if IS_REACHABLE(CONFIG_DVB_CX24123) extern struct dvb_frontend *cx24123_attach(const struct cx24123_config *config, struct i2c_adapter *i2c); extern struct i2c_adapter *cx24123_get_tuner_i2c_adapter(struct dvb_frontend *); diff --git a/drivers/media/dvb-frontends/cxd2820r.h b/drivers/media/dvb-frontends/cxd2820r.h index 6095dbcf7850..56d42760263d 100644 --- a/drivers/media/dvb-frontends/cxd2820r.h +++ b/drivers/media/dvb-frontends/cxd2820r.h @@ -72,7 +72,7 @@ struct cxd2820r_config { }; -#if IS_ENABLED(CONFIG_DVB_CXD2820R) +#if IS_REACHABLE(CONFIG_DVB_CXD2820R) extern struct dvb_frontend *cxd2820r_attach( const struct cxd2820r_config *config, struct i2c_adapter *i2c, diff --git a/drivers/media/dvb-frontends/dib0070.h b/drivers/media/dvb-frontends/dib0070.h index 0c6befcc9143..6c0b6672b1d9 100644 --- a/drivers/media/dvb-frontends/dib0070.h +++ b/drivers/media/dvb-frontends/dib0070.h @@ -48,7 +48,7 @@ struct dib0070_config { u8 vga_filter; }; -#if IS_ENABLED(CONFIG_DVB_TUNER_DIB0070) +#if IS_REACHABLE(CONFIG_DVB_TUNER_DIB0070) extern struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg); extern u16 dib0070_wbd_offset(struct dvb_frontend *); extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, u8 open); diff --git a/drivers/media/dvb-frontends/dib0090.h b/drivers/media/dvb-frontends/dib0090.h index 6a090954fa10..ad74bc823f08 100644 --- a/drivers/media/dvb-frontends/dib0090.h +++ b/drivers/media/dvb-frontends/dib0090.h @@ -75,7 +75,7 @@ struct dib0090_config { u8 force_crystal_mode; }; -#if IS_ENABLED(CONFIG_DVB_TUNER_DIB0090) +#if IS_REACHABLE(CONFIG_DVB_TUNER_DIB0090) extern struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config); extern struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config); extern void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast); diff --git a/drivers/media/dvb-frontends/dib3000.h b/drivers/media/dvb-frontends/dib3000.h index 9b6c3bbc983a..6ae9899b5b45 100644 --- a/drivers/media/dvb-frontends/dib3000.h +++ b/drivers/media/dvb-frontends/dib3000.h @@ -41,7 +41,7 @@ struct dib_fe_xfer_ops int (*tuner_pass_ctrl)(struct dvb_frontend *fe, int onoff, u8 pll_ctrl); }; -#if IS_ENABLED(CONFIG_DVB_DIB3000MB) +#if IS_REACHABLE(CONFIG_DVB_DIB3000MB) extern struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config, struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops); #else diff --git a/drivers/media/dvb-frontends/dib3000mc.h b/drivers/media/dvb-frontends/dib3000mc.h index 129d1425516a..74816f793611 100644 --- a/drivers/media/dvb-frontends/dib3000mc.h +++ b/drivers/media/dvb-frontends/dib3000mc.h @@ -41,7 +41,7 @@ struct dib3000mc_config { #define DEFAULT_DIB3000MC_I2C_ADDRESS 16 #define DEFAULT_DIB3000P_I2C_ADDRESS 24 -#if IS_ENABLED(CONFIG_DVB_DIB3000MC) +#if IS_REACHABLE(CONFIG_DVB_DIB3000MC) extern struct dvb_frontend *dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib3000mc_config *cfg); diff --git a/drivers/media/dvb-frontends/dib7000m.h b/drivers/media/dvb-frontends/dib7000m.h index b585413f9a29..6468c278cc4d 100644 --- a/drivers/media/dvb-frontends/dib7000m.h +++ b/drivers/media/dvb-frontends/dib7000m.h @@ -40,7 +40,7 @@ struct dib7000m_config { #define DEFAULT_DIB7000M_I2C_ADDRESS 18 -#if IS_ENABLED(CONFIG_DVB_DIB7000M) +#if IS_REACHABLE(CONFIG_DVB_DIB7000M) extern struct dvb_frontend *dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000m_config *cfg); diff --git a/drivers/media/dvb-frontends/dib7000p.h b/drivers/media/dvb-frontends/dib7000p.h index 1fea0e972654..baa278928cf3 100644 --- a/drivers/media/dvb-frontends/dib7000p.h +++ b/drivers/media/dvb-frontends/dib7000p.h @@ -66,7 +66,7 @@ struct dib7000p_ops { struct dvb_frontend *(*init)(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg); }; -#if IS_ENABLED(CONFIG_DVB_DIB7000P) +#if IS_REACHABLE(CONFIG_DVB_DIB7000P) void *dib7000p_attach(struct dib7000p_ops *ops); #else static inline void *dib7000p_attach(struct dib7000p_ops *ops) diff --git a/drivers/media/dvb-frontends/dib8000.h b/drivers/media/dvb-frontends/dib8000.h index 84cc10383dcd..780c37bdcb72 100644 --- a/drivers/media/dvb-frontends/dib8000.h +++ b/drivers/media/dvb-frontends/dib8000.h @@ -63,7 +63,7 @@ struct dib8000_ops { struct dvb_frontend *(*init)(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg); }; -#if IS_ENABLED(CONFIG_DVB_DIB8000) +#if IS_REACHABLE(CONFIG_DVB_DIB8000) void *dib8000_attach(struct dib8000_ops *ops); #else static inline int dib8000_attach(struct dib8000_ops *ops) diff --git a/drivers/media/dvb-frontends/dib9000.h b/drivers/media/dvb-frontends/dib9000.h index f3639f045ff0..b10a70aa7c9f 100644 --- a/drivers/media/dvb-frontends/dib9000.h +++ b/drivers/media/dvb-frontends/dib9000.h @@ -27,7 +27,7 @@ struct dib9000_config { #define DEFAULT_DIB9000_I2C_ADDRESS 18 -#if IS_ENABLED(CONFIG_DVB_DIB9000) +#if IS_REACHABLE(CONFIG_DVB_DIB9000) extern struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, const struct dib9000_config *cfg); extern int dib9000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr); extern struct i2c_adapter *dib9000_get_tuner_interface(struct dvb_frontend *fe); diff --git a/drivers/media/dvb-frontends/drx39xyj/drx39xxj.h b/drivers/media/dvb-frontends/drx39xyj/drx39xxj.h index cfd0b96b6939..8188062953af 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drx39xxj.h +++ b/drivers/media/dvb-frontends/drx39xyj/drx39xxj.h @@ -34,7 +34,7 @@ struct drx39xxj_state { const struct firmware *fw; }; -#if IS_ENABLED(CONFIG_DVB_DRX39XYJ) +#if IS_REACHABLE(CONFIG_DVB_DRX39XYJ) struct dvb_frontend *drx39xxj_attach(struct i2c_adapter *i2c); #else static inline struct dvb_frontend *drx39xxj_attach(struct i2c_adapter *i2c) { diff --git a/drivers/media/dvb-frontends/drxd.h b/drivers/media/dvb-frontends/drxd.h index d998e4d5a7fc..a47c22d6667e 100644 --- a/drivers/media/dvb-frontends/drxd.h +++ b/drivers/media/dvb-frontends/drxd.h @@ -52,7 +52,7 @@ struct drxd_config { s16(*osc_deviation) (void *priv, s16 dev, int flag); }; -#if IS_ENABLED(CONFIG_DVB_DRXD) +#if IS_REACHABLE(CONFIG_DVB_DRXD) extern struct dvb_frontend *drxd_attach(const struct drxd_config *config, void *priv, struct i2c_adapter *i2c, diff --git a/drivers/media/dvb-frontends/drxk.h b/drivers/media/dvb-frontends/drxk.h index f6cb34660327..8f0b9eec528f 100644 --- a/drivers/media/dvb-frontends/drxk.h +++ b/drivers/media/dvb-frontends/drxk.h @@ -51,7 +51,7 @@ struct drxk_config { int qam_demod_parameter_count; }; -#if IS_ENABLED(CONFIG_DVB_DRXK) +#if IS_REACHABLE(CONFIG_DVB_DRXK) extern struct dvb_frontend *drxk_attach(const struct drxk_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/ds3000.h b/drivers/media/dvb-frontends/ds3000.h index f9c21fb7af13..153169da9017 100644 --- a/drivers/media/dvb-frontends/ds3000.h +++ b/drivers/media/dvb-frontends/ds3000.h @@ -35,7 +35,7 @@ struct ds3000_config { void (*set_lock_led)(struct dvb_frontend *fe, int offon); }; -#if IS_ENABLED(CONFIG_DVB_DS3000) +#if IS_REACHABLE(CONFIG_DVB_DS3000) extern struct dvb_frontend *ds3000_attach(const struct ds3000_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/dvb-pll.h b/drivers/media/dvb-frontends/dvb-pll.h index f4b5a0601c3a..bf9602a88b6c 100644 --- a/drivers/media/dvb-frontends/dvb-pll.h +++ b/drivers/media/dvb-frontends/dvb-pll.h @@ -38,7 +38,7 @@ * @param pll_desc_id dvb_pll_desc to use. * @return Frontend pointer on success, NULL on failure */ -#if IS_ENABLED(CONFIG_DVB_PLL) +#if IS_REACHABLE(CONFIG_DVB_PLL) extern struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, diff --git a/drivers/media/dvb-frontends/dvb_dummy_fe.h b/drivers/media/dvb-frontends/dvb_dummy_fe.h index 0cbf96105631..15e4ceab869a 100644 --- a/drivers/media/dvb-frontends/dvb_dummy_fe.h +++ b/drivers/media/dvb-frontends/dvb_dummy_fe.h @@ -26,7 +26,7 @@ #include <linux/dvb/frontend.h> #include "dvb_frontend.h" -#if IS_ENABLED(CONFIG_DVB_DUMMY_FE) +#if IS_REACHABLE(CONFIG_DVB_DUMMY_FE) extern struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void); extern struct dvb_frontend* dvb_dummy_fe_qpsk_attach(void); extern struct dvb_frontend* dvb_dummy_fe_qam_attach(void); diff --git a/drivers/media/dvb-frontends/ec100.h b/drivers/media/dvb-frontends/ec100.h index 37558403068d..9544bab5cd1d 100644 --- a/drivers/media/dvb-frontends/ec100.h +++ b/drivers/media/dvb-frontends/ec100.h @@ -31,7 +31,7 @@ struct ec100_config { }; -#if IS_ENABLED(CONFIG_DVB_EC100) +#if IS_REACHABLE(CONFIG_DVB_EC100) extern struct dvb_frontend *ec100_attach(const struct ec100_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/hd29l2.h b/drivers/media/dvb-frontends/hd29l2.h index 05cd13028a91..48e9ab74c883 100644 --- a/drivers/media/dvb-frontends/hd29l2.h +++ b/drivers/media/dvb-frontends/hd29l2.h @@ -51,7 +51,7 @@ struct hd29l2_config { }; -#if IS_ENABLED(CONFIG_DVB_HD29L2) +#if IS_REACHABLE(CONFIG_DVB_HD29L2) extern struct dvb_frontend *hd29l2_attach(const struct hd29l2_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/isl6405.h b/drivers/media/dvb-frontends/isl6405.h index 8abb70c26fd9..3c148b830bd1 100644 --- a/drivers/media/dvb-frontends/isl6405.h +++ b/drivers/media/dvb-frontends/isl6405.h @@ -55,7 +55,7 @@ #define ISL6405_ENT2 0x20 #define ISL6405_ISEL2 0x40 -#if IS_ENABLED(CONFIG_DVB_ISL6405) +#if IS_REACHABLE(CONFIG_DVB_ISL6405) /* override_set and override_clear control which system register bits (above) * to always set & clear */ diff --git a/drivers/media/dvb-frontends/isl6421.h b/drivers/media/dvb-frontends/isl6421.h index 630e7f8a150e..3273597833fd 100644 --- a/drivers/media/dvb-frontends/isl6421.h +++ b/drivers/media/dvb-frontends/isl6421.h @@ -39,7 +39,7 @@ #define ISL6421_ISEL1 0x20 #define ISL6421_DCL 0x40 -#if IS_ENABLED(CONFIG_DVB_ISL6421) +#if IS_REACHABLE(CONFIG_DVB_ISL6421) /* override_set and override_clear control which system register bits (above) to always set & clear */ extern struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr, u8 override_set, u8 override_clear, bool override_tone); diff --git a/drivers/media/dvb-frontends/isl6423.h b/drivers/media/dvb-frontends/isl6423.h index 80dfd9cc4f41..a64df0ee256b 100644 --- a/drivers/media/dvb-frontends/isl6423.h +++ b/drivers/media/dvb-frontends/isl6423.h @@ -42,7 +42,7 @@ struct isl6423_config { u8 mod_extern; }; -#if IS_ENABLED(CONFIG_DVB_ISL6423) +#if IS_REACHABLE(CONFIG_DVB_ISL6423) extern struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe, diff --git a/drivers/media/dvb-frontends/itd1000.h b/drivers/media/dvb-frontends/itd1000.h index edae0902f4fd..a691bb6f26de 100644 --- a/drivers/media/dvb-frontends/itd1000.h +++ b/drivers/media/dvb-frontends/itd1000.h @@ -29,7 +29,7 @@ struct itd1000_config { u8 i2c_address; }; -#if IS_ENABLED(CONFIG_DVB_TUNER_ITD1000) +#if IS_REACHABLE(CONFIG_DVB_TUNER_ITD1000) extern struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct itd1000_config *cfg); #else static inline struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct itd1000_config *cfg) diff --git a/drivers/media/dvb-frontends/ix2505v.h b/drivers/media/dvb-frontends/ix2505v.h index 1a735a75aa98..af107a2dd357 100644 --- a/drivers/media/dvb-frontends/ix2505v.h +++ b/drivers/media/dvb-frontends/ix2505v.h @@ -49,7 +49,7 @@ struct ix2505v_config { }; -#if IS_ENABLED(CONFIG_DVB_IX2505V) +#if IS_REACHABLE(CONFIG_DVB_IX2505V) extern struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe, const struct ix2505v_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/l64781.h b/drivers/media/dvb-frontends/l64781.h index 6813b08a774d..8697e2c2ba36 100644 --- a/drivers/media/dvb-frontends/l64781.h +++ b/drivers/media/dvb-frontends/l64781.h @@ -31,7 +31,7 @@ struct l64781_config u8 demod_address; }; -#if IS_ENABLED(CONFIG_DVB_L64781) +#if IS_REACHABLE(CONFIG_DVB_L64781) extern struct dvb_frontend* l64781_attach(const struct l64781_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/lg2160.h b/drivers/media/dvb-frontends/lg2160.h index 194a07a78dc1..d20bd909de39 100644 --- a/drivers/media/dvb-frontends/lg2160.h +++ b/drivers/media/dvb-frontends/lg2160.h @@ -67,7 +67,7 @@ struct lg2160_config { enum lg_chip_type lg_chip; }; -#if IS_ENABLED(CONFIG_DVB_LG2160) +#if IS_REACHABLE(CONFIG_DVB_LG2160) extern struct dvb_frontend *lg2160_attach(const struct lg2160_config *config, struct i2c_adapter *i2c_adap); diff --git a/drivers/media/dvb-frontends/lgdt3305.h b/drivers/media/dvb-frontends/lgdt3305.h index 9c03e530e01b..f91a1b49ce2f 100644 --- a/drivers/media/dvb-frontends/lgdt3305.h +++ b/drivers/media/dvb-frontends/lgdt3305.h @@ -80,7 +80,7 @@ struct lgdt3305_config { enum lgdt_demod_chip_type demod_chip; }; -#if IS_ENABLED(CONFIG_DVB_LGDT3305) +#if IS_REACHABLE(CONFIG_DVB_LGDT3305) extern struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config, struct i2c_adapter *i2c_adap); diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c new file mode 100644 index 000000000000..d9a2b0e768e0 --- /dev/null +++ b/drivers/media/dvb-frontends/lgdt3306a.c @@ -0,0 +1,2144 @@ +/* + * Support for LGDT3306A - 8VSB/QAM-B + * + * Copyright (C) 2013 Fred Richter <frichter@hauppauge.com> + * - driver structure based on lgdt3305.[ch] by Michael Krufky + * - code based on LG3306_V0.35 API by LG Electronics Inc. + * + * 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 Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <asm/div64.h> +#include <linux/dvb/frontend.h> +#include "dvb_math.h" +#include "lgdt3306a.h" + + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "set debug level (info=1, reg=2 (or-able))"); + +#define DBG_INFO 1 +#define DBG_REG 2 +#define DBG_DUMP 4 /* FGR - comment out to remove dump code */ + +#define lg_debug(fmt, arg...) \ + printk(KERN_DEBUG pr_fmt(fmt), ## arg) + +#define dbg_info(fmt, arg...) \ + do { \ + if (debug & DBG_INFO) \ + lg_debug(fmt, ## arg); \ + } while (0) + +#define dbg_reg(fmt, arg...) \ + do { \ + if (debug & DBG_REG) \ + lg_debug(fmt, ## arg); \ + } while (0) + +#define lg_chkerr(ret) \ +({ \ + int __ret; \ + __ret = (ret < 0); \ + if (__ret) \ + pr_err("error %d on line %d\n", ret, __LINE__); \ + __ret; \ +}) + +struct lgdt3306a_state { + struct i2c_adapter *i2c_adap; + const struct lgdt3306a_config *cfg; + + struct dvb_frontend frontend; + + fe_modulation_t current_modulation; + u32 current_frequency; + u32 snr; +}; + +/* + * LG3306A Register Usage + * (LG does not really name the registers, so this code does not either) + * + * 0000 -> 00FF Common control and status + * 1000 -> 10FF Synchronizer control and status + * 1F00 -> 1FFF Smart Antenna control and status + * 2100 -> 21FF VSB Equalizer control and status + * 2800 -> 28FF QAM Equalizer control and status + * 3000 -> 30FF FEC control and status + */ + +enum lgdt3306a_lock_status { + LG3306_UNLOCK = 0x00, + LG3306_LOCK = 0x01, + LG3306_UNKNOWN_LOCK = 0xff +}; + +enum lgdt3306a_neverlock_status { + LG3306_NL_INIT = 0x00, + LG3306_NL_PROCESS = 0x01, + LG3306_NL_LOCK = 0x02, + LG3306_NL_FAIL = 0x03, + LG3306_NL_UNKNOWN = 0xff +}; + +enum lgdt3306a_modulation { + LG3306_VSB = 0x00, + LG3306_QAM64 = 0x01, + LG3306_QAM256 = 0x02, + LG3306_UNKNOWN_MODE = 0xff +}; + +enum lgdt3306a_lock_check { + LG3306_SYNC_LOCK, + LG3306_FEC_LOCK, + LG3306_TR_LOCK, + LG3306_AGC_LOCK, +}; + + +#ifdef DBG_DUMP +static void lgdt3306a_DumpAllRegs(struct lgdt3306a_state *state); +static void lgdt3306a_DumpRegs(struct lgdt3306a_state *state); +#endif + + +static int lgdt3306a_write_reg(struct lgdt3306a_state *state, u16 reg, u8 val) +{ + int ret; + u8 buf[] = { reg >> 8, reg & 0xff, val }; + struct i2c_msg msg = { + .addr = state->cfg->i2c_addr, .flags = 0, + .buf = buf, .len = 3, + }; + + dbg_reg("reg: 0x%04x, val: 0x%02x\n", reg, val); + + ret = i2c_transfer(state->i2c_adap, &msg, 1); + + if (ret != 1) { + pr_err("error (addr %02x %02x <- %02x, err = %i)\n", + msg.buf[0], msg.buf[1], msg.buf[2], ret); + if (ret < 0) + return ret; + else + return -EREMOTEIO; + } + return 0; +} + +static int lgdt3306a_read_reg(struct lgdt3306a_state *state, u16 reg, u8 *val) +{ + int ret; + u8 reg_buf[] = { reg >> 8, reg & 0xff }; + struct i2c_msg msg[] = { + { .addr = state->cfg->i2c_addr, + .flags = 0, .buf = reg_buf, .len = 2 }, + { .addr = state->cfg->i2c_addr, + .flags = I2C_M_RD, .buf = val, .len = 1 }, + }; + + ret = i2c_transfer(state->i2c_adap, msg, 2); + + if (ret != 2) { + pr_err("error (addr %02x reg %04x error (ret == %i)\n", + state->cfg->i2c_addr, reg, ret); + if (ret < 0) + return ret; + else + return -EREMOTEIO; + } + dbg_reg("reg: 0x%04x, val: 0x%02x\n", reg, *val); + + return 0; +} + +#define read_reg(state, reg) \ +({ \ + u8 __val; \ + int ret = lgdt3306a_read_reg(state, reg, &__val); \ + if (lg_chkerr(ret)) \ + __val = 0; \ + __val; \ +}) + +static int lgdt3306a_set_reg_bit(struct lgdt3306a_state *state, + u16 reg, int bit, int onoff) +{ + u8 val; + int ret; + + dbg_reg("reg: 0x%04x, bit: %d, level: %d\n", reg, bit, onoff); + + ret = lgdt3306a_read_reg(state, reg, &val); + if (lg_chkerr(ret)) + goto fail; + + val &= ~(1 << bit); + val |= (onoff & 1) << bit; + + ret = lgdt3306a_write_reg(state, reg, val); + lg_chkerr(ret); +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +static int lgdt3306a_soft_reset(struct lgdt3306a_state *state) +{ + int ret; + + dbg_info("\n"); + + ret = lgdt3306a_set_reg_bit(state, 0x0000, 7, 0); + if (lg_chkerr(ret)) + goto fail; + + msleep(20); + ret = lgdt3306a_set_reg_bit(state, 0x0000, 7, 1); + lg_chkerr(ret); + +fail: + return ret; +} + +static int lgdt3306a_mpeg_mode(struct lgdt3306a_state *state, + enum lgdt3306a_mpeg_mode mode) +{ + u8 val; + int ret; + + dbg_info("(%d)\n", mode); + /* transport packet format - TPSENB=0x80 */ + ret = lgdt3306a_set_reg_bit(state, 0x0071, 7, + mode == LGDT3306A_MPEG_PARALLEL ? 1 : 0); + if (lg_chkerr(ret)) + goto fail; + + /* + * start of packet signal duration + * TPSSOPBITEN=0x40; 0=byte duration, 1=bit duration + */ + ret = lgdt3306a_set_reg_bit(state, 0x0071, 6, 0); + if (lg_chkerr(ret)) + goto fail; + + ret = lgdt3306a_read_reg(state, 0x0070, &val); + if (lg_chkerr(ret)) + goto fail; + + val |= 0x10; /* TPCLKSUPB=0x10 */ + + if (mode == LGDT3306A_MPEG_PARALLEL) + val &= ~0x10; + + ret = lgdt3306a_write_reg(state, 0x0070, val); + lg_chkerr(ret); + +fail: + return ret; +} + +static int lgdt3306a_mpeg_mode_polarity(struct lgdt3306a_state *state, + enum lgdt3306a_tp_clock_edge edge, + enum lgdt3306a_tp_valid_polarity valid) +{ + u8 val; + int ret; + + dbg_info("edge=%d, valid=%d\n", edge, valid); + + ret = lgdt3306a_read_reg(state, 0x0070, &val); + if (lg_chkerr(ret)) + goto fail; + + val &= ~0x06; /* TPCLKPOL=0x04, TPVALPOL=0x02 */ + + if (edge == LGDT3306A_TPCLK_RISING_EDGE) + val |= 0x04; + if (valid == LGDT3306A_TP_VALID_HIGH) + val |= 0x02; + + ret = lgdt3306a_write_reg(state, 0x0070, val); + lg_chkerr(ret); + +fail: + return ret; +} + +static int lgdt3306a_mpeg_tristate(struct lgdt3306a_state *state, + int mode) +{ + u8 val; + int ret; + + dbg_info("(%d)\n", mode); + + if (mode) { + ret = lgdt3306a_read_reg(state, 0x0070, &val); + if (lg_chkerr(ret)) + goto fail; + /* + * Tristate bus; TPOUTEN=0x80, TPCLKOUTEN=0x20, + * TPDATAOUTEN=0x08 + */ + val &= ~0xa8; + ret = lgdt3306a_write_reg(state, 0x0070, val); + if (lg_chkerr(ret)) + goto fail; + + /* AGCIFOUTENB=0x40; 1=Disable IFAGC pin */ + ret = lgdt3306a_set_reg_bit(state, 0x0003, 6, 1); + if (lg_chkerr(ret)) + goto fail; + + } else { + /* enable IFAGC pin */ + ret = lgdt3306a_set_reg_bit(state, 0x0003, 6, 0); + if (lg_chkerr(ret)) + goto fail; + + ret = lgdt3306a_read_reg(state, 0x0070, &val); + if (lg_chkerr(ret)) + goto fail; + + val |= 0xa8; /* enable bus */ + ret = lgdt3306a_write_reg(state, 0x0070, val); + if (lg_chkerr(ret)) + goto fail; + } + +fail: + return ret; +} + +static int lgdt3306a_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) +{ + struct lgdt3306a_state *state = fe->demodulator_priv; + + dbg_info("acquire=%d\n", acquire); + + return lgdt3306a_mpeg_tristate(state, acquire ? 0 : 1); + +} + +static int lgdt3306a_power(struct lgdt3306a_state *state, + int mode) +{ + int ret; + + dbg_info("(%d)\n", mode); + + if (mode == 0) { + /* into reset */ + ret = lgdt3306a_set_reg_bit(state, 0x0000, 7, 0); + if (lg_chkerr(ret)) + goto fail; + + /* power down */ + ret = lgdt3306a_set_reg_bit(state, 0x0000, 0, 0); + if (lg_chkerr(ret)) + goto fail; + + } else { + /* out of reset */ + ret = lgdt3306a_set_reg_bit(state, 0x0000, 7, 1); + if (lg_chkerr(ret)) + goto fail; + + /* power up */ + ret = lgdt3306a_set_reg_bit(state, 0x0000, 0, 1); + if (lg_chkerr(ret)) + goto fail; + } + +#ifdef DBG_DUMP + lgdt3306a_DumpAllRegs(state); +#endif +fail: + return ret; +} + + +static int lgdt3306a_set_vsb(struct lgdt3306a_state *state) +{ + u8 val; + int ret; + + dbg_info("\n"); + + /* 0. Spectrum inversion detection manual; spectrum inverted */ + ret = lgdt3306a_read_reg(state, 0x0002, &val); + val &= 0xf7; /* SPECINVAUTO Off */ + val |= 0x04; /* SPECINV On */ + ret = lgdt3306a_write_reg(state, 0x0002, val); + if (lg_chkerr(ret)) + goto fail; + + /* 1. Selection of standard mode(0x08=QAM, 0x80=VSB) */ + ret = lgdt3306a_write_reg(state, 0x0008, 0x80); + if (lg_chkerr(ret)) + goto fail; + + /* 2. Bandwidth mode for VSB(6MHz) */ + ret = lgdt3306a_read_reg(state, 0x0009, &val); + val &= 0xe3; + val |= 0x0c; /* STDOPDETTMODE[2:0]=3 */ + ret = lgdt3306a_write_reg(state, 0x0009, val); + if (lg_chkerr(ret)) + goto fail; + + /* 3. QAM mode detection mode(None) */ + ret = lgdt3306a_read_reg(state, 0x0009, &val); + val &= 0xfc; /* STDOPDETCMODE[1:0]=0 */ + ret = lgdt3306a_write_reg(state, 0x0009, val); + if (lg_chkerr(ret)) + goto fail; + + /* 4. ADC sampling frequency rate(2x sampling) */ + ret = lgdt3306a_read_reg(state, 0x000d, &val); + val &= 0xbf; /* SAMPLING4XFEN=0 */ + ret = lgdt3306a_write_reg(state, 0x000d, val); + if (lg_chkerr(ret)) + goto fail; + +#if 0 + /* FGR - disable any AICC filtering, testing only */ + + ret = lgdt3306a_write_reg(state, 0x0024, 0x00); + if (lg_chkerr(ret)) + goto fail; + + /* AICCFIXFREQ0 NT N-1(Video rejection) */ + ret = lgdt3306a_write_reg(state, 0x002e, 0x00); + ret = lgdt3306a_write_reg(state, 0x002f, 0x00); + ret = lgdt3306a_write_reg(state, 0x0030, 0x00); + + /* AICCFIXFREQ1 NT N-1(Audio rejection) */ + ret = lgdt3306a_write_reg(state, 0x002b, 0x00); + ret = lgdt3306a_write_reg(state, 0x002c, 0x00); + ret = lgdt3306a_write_reg(state, 0x002d, 0x00); + + /* AICCFIXFREQ2 NT Co-Channel(Video rejection) */ + ret = lgdt3306a_write_reg(state, 0x0028, 0x00); + ret = lgdt3306a_write_reg(state, 0x0029, 0x00); + ret = lgdt3306a_write_reg(state, 0x002a, 0x00); + + /* AICCFIXFREQ3 NT Co-Channel(Audio rejection) */ + ret = lgdt3306a_write_reg(state, 0x0025, 0x00); + ret = lgdt3306a_write_reg(state, 0x0026, 0x00); + ret = lgdt3306a_write_reg(state, 0x0027, 0x00); + +#else + /* FGR - this works well for HVR-1955,1975 */ + + /* 5. AICCOPMODE NT N-1 Adj. */ + ret = lgdt3306a_write_reg(state, 0x0024, 0x5A); + if (lg_chkerr(ret)) + goto fail; + + /* AICCFIXFREQ0 NT N-1(Video rejection) */ + ret = lgdt3306a_write_reg(state, 0x002e, 0x5A); + ret = lgdt3306a_write_reg(state, 0x002f, 0x00); + ret = lgdt3306a_write_reg(state, 0x0030, 0x00); + + /* AICCFIXFREQ1 NT N-1(Audio rejection) */ + ret = lgdt3306a_write_reg(state, 0x002b, 0x36); + ret = lgdt3306a_write_reg(state, 0x002c, 0x00); + ret = lgdt3306a_write_reg(state, 0x002d, 0x00); + + /* AICCFIXFREQ2 NT Co-Channel(Video rejection) */ + ret = lgdt3306a_write_reg(state, 0x0028, 0x2A); + ret = lgdt3306a_write_reg(state, 0x0029, 0x00); + ret = lgdt3306a_write_reg(state, 0x002a, 0x00); + + /* AICCFIXFREQ3 NT Co-Channel(Audio rejection) */ + ret = lgdt3306a_write_reg(state, 0x0025, 0x06); + ret = lgdt3306a_write_reg(state, 0x0026, 0x00); + ret = lgdt3306a_write_reg(state, 0x0027, 0x00); +#endif + + ret = lgdt3306a_read_reg(state, 0x001e, &val); + val &= 0x0f; + val |= 0xa0; + ret = lgdt3306a_write_reg(state, 0x001e, val); + + ret = lgdt3306a_write_reg(state, 0x0022, 0x08); + + ret = lgdt3306a_write_reg(state, 0x0023, 0xFF); + + ret = lgdt3306a_read_reg(state, 0x211f, &val); + val &= 0xef; + ret = lgdt3306a_write_reg(state, 0x211f, val); + + ret = lgdt3306a_write_reg(state, 0x2173, 0x01); + + ret = lgdt3306a_read_reg(state, 0x1061, &val); + val &= 0xf8; + val |= 0x04; + ret = lgdt3306a_write_reg(state, 0x1061, val); + + ret = lgdt3306a_read_reg(state, 0x103d, &val); + val &= 0xcf; + ret = lgdt3306a_write_reg(state, 0x103d, val); + + ret = lgdt3306a_write_reg(state, 0x2122, 0x40); + + ret = lgdt3306a_read_reg(state, 0x2141, &val); + val &= 0x3f; + ret = lgdt3306a_write_reg(state, 0x2141, val); + + ret = lgdt3306a_read_reg(state, 0x2135, &val); + val &= 0x0f; + val |= 0x70; + ret = lgdt3306a_write_reg(state, 0x2135, val); + + ret = lgdt3306a_read_reg(state, 0x0003, &val); + val &= 0xf7; + ret = lgdt3306a_write_reg(state, 0x0003, val); + + ret = lgdt3306a_read_reg(state, 0x001c, &val); + val &= 0x7f; + ret = lgdt3306a_write_reg(state, 0x001c, val); + + /* 6. EQ step size */ + ret = lgdt3306a_read_reg(state, 0x2179, &val); + val &= 0xf8; + ret = lgdt3306a_write_reg(state, 0x2179, val); + + ret = lgdt3306a_read_reg(state, 0x217a, &val); + val &= 0xf8; + ret = lgdt3306a_write_reg(state, 0x217a, val); + + /* 7. Reset */ + ret = lgdt3306a_soft_reset(state); + if (lg_chkerr(ret)) + goto fail; + + dbg_info("complete\n"); +fail: + return ret; +} + +static int lgdt3306a_set_qam(struct lgdt3306a_state *state, int modulation) +{ + u8 val; + int ret; + + dbg_info("modulation=%d\n", modulation); + + /* 1. Selection of standard mode(0x08=QAM, 0x80=VSB) */ + ret = lgdt3306a_write_reg(state, 0x0008, 0x08); + if (lg_chkerr(ret)) + goto fail; + + /* 1a. Spectrum inversion detection to Auto */ + ret = lgdt3306a_read_reg(state, 0x0002, &val); + val &= 0xfb; /* SPECINV Off */ + val |= 0x08; /* SPECINVAUTO On */ + ret = lgdt3306a_write_reg(state, 0x0002, val); + if (lg_chkerr(ret)) + goto fail; + + /* 2. Bandwidth mode for QAM */ + ret = lgdt3306a_read_reg(state, 0x0009, &val); + val &= 0xe3; /* STDOPDETTMODE[2:0]=0 VSB Off */ + ret = lgdt3306a_write_reg(state, 0x0009, val); + if (lg_chkerr(ret)) + goto fail; + + /* 3. : 64QAM/256QAM detection(manual, auto) */ + ret = lgdt3306a_read_reg(state, 0x0009, &val); + val &= 0xfc; + val |= 0x02; /* STDOPDETCMODE[1:0]=1=Manual 2=Auto */ + ret = lgdt3306a_write_reg(state, 0x0009, val); + if (lg_chkerr(ret)) + goto fail; + + /* 3a. : 64QAM/256QAM selection for manual */ + ret = lgdt3306a_read_reg(state, 0x101a, &val); + val &= 0xf8; + if (modulation == QAM_64) + val |= 0x02; /* QMDQMODE[2:0]=2=QAM64 */ + else + val |= 0x04; /* QMDQMODE[2:0]=4=QAM256 */ + + ret = lgdt3306a_write_reg(state, 0x101a, val); + if (lg_chkerr(ret)) + goto fail; + + /* 4. ADC sampling frequency rate(4x sampling) */ + ret = lgdt3306a_read_reg(state, 0x000d, &val); + val &= 0xbf; + val |= 0x40; /* SAMPLING4XFEN=1 */ + ret = lgdt3306a_write_reg(state, 0x000d, val); + if (lg_chkerr(ret)) + goto fail; + + /* 5. No AICC operation in QAM mode */ + ret = lgdt3306a_read_reg(state, 0x0024, &val); + val &= 0x00; + ret = lgdt3306a_write_reg(state, 0x0024, val); + if (lg_chkerr(ret)) + goto fail; + + /* 6. Reset */ + ret = lgdt3306a_soft_reset(state); + if (lg_chkerr(ret)) + goto fail; + + dbg_info("complete\n"); +fail: + return ret; +} + +static int lgdt3306a_set_modulation(struct lgdt3306a_state *state, + struct dtv_frontend_properties *p) +{ + int ret; + + dbg_info("\n"); + + switch (p->modulation) { + case VSB_8: + ret = lgdt3306a_set_vsb(state); + break; + case QAM_64: + ret = lgdt3306a_set_qam(state, QAM_64); + break; + case QAM_256: + ret = lgdt3306a_set_qam(state, QAM_256); + break; + default: + return -EINVAL; + } + if (lg_chkerr(ret)) + goto fail; + + state->current_modulation = p->modulation; + +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +static int lgdt3306a_agc_setup(struct lgdt3306a_state *state, + struct dtv_frontend_properties *p) +{ + /* TODO: anything we want to do here??? */ + dbg_info("\n"); + + switch (p->modulation) { + case VSB_8: + break; + case QAM_64: + case QAM_256: + break; + default: + return -EINVAL; + } + return 0; +} + +/* ------------------------------------------------------------------------ */ + +static int lgdt3306a_set_inversion(struct lgdt3306a_state *state, + int inversion) +{ + int ret; + + dbg_info("(%d)\n", inversion); + + ret = lgdt3306a_set_reg_bit(state, 0x0002, 2, inversion ? 1 : 0); + return ret; +} + +static int lgdt3306a_set_inversion_auto(struct lgdt3306a_state *state, + int enabled) +{ + int ret; + + dbg_info("(%d)\n", enabled); + + /* 0=Manual 1=Auto(QAM only) - SPECINVAUTO=0x04 */ + ret = lgdt3306a_set_reg_bit(state, 0x0002, 3, enabled); + return ret; +} + +static int lgdt3306a_spectral_inversion(struct lgdt3306a_state *state, + struct dtv_frontend_properties *p, + int inversion) +{ + int ret = 0; + + dbg_info("(%d)\n", inversion); +#if 0 + /* + * FGR - spectral_inversion defaults already set for VSB and QAM; + * can enable later if desired + */ + + ret = lgdt3306a_set_inversion(state, inversion); + + switch (p->modulation) { + case VSB_8: + /* Manual only for VSB */ + ret = lgdt3306a_set_inversion_auto(state, 0); + break; + case QAM_64: + case QAM_256: + /* Auto ok for QAM */ + ret = lgdt3306a_set_inversion_auto(state, 1); + break; + default: + ret = -EINVAL; + } +#endif + return ret; +} + +static int lgdt3306a_set_if(struct lgdt3306a_state *state, + struct dtv_frontend_properties *p) +{ + int ret; + u16 if_freq_khz; + u8 nco1, nco2; + + switch (p->modulation) { + case VSB_8: + if_freq_khz = state->cfg->vsb_if_khz; + break; + case QAM_64: + case QAM_256: + if_freq_khz = state->cfg->qam_if_khz; + break; + default: + return -EINVAL; + } + + switch (if_freq_khz) { + default: + pr_warn("IF=%d KHz is not supportted, 3250 assumed\n", + if_freq_khz); + /* fallthrough */ + case 3250: /* 3.25Mhz */ + nco1 = 0x34; + nco2 = 0x00; + break; + case 3500: /* 3.50Mhz */ + nco1 = 0x38; + nco2 = 0x00; + break; + case 4000: /* 4.00Mhz */ + nco1 = 0x40; + nco2 = 0x00; + break; + case 5000: /* 5.00Mhz */ + nco1 = 0x50; + nco2 = 0x00; + break; + case 5380: /* 5.38Mhz */ + nco1 = 0x56; + nco2 = 0x14; + break; + } + ret = lgdt3306a_write_reg(state, 0x0010, nco1); + if (ret) + return ret; + ret = lgdt3306a_write_reg(state, 0x0011, nco2); + if (ret) + return ret; + + dbg_info("if_freq=%d KHz->[%04x]\n", if_freq_khz, nco1<<8 | nco2); + + return 0; +} + +/* ------------------------------------------------------------------------ */ + +static int lgdt3306a_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct lgdt3306a_state *state = fe->demodulator_priv; + + if (state->cfg->deny_i2c_rptr) { + dbg_info("deny_i2c_rptr=%d\n", state->cfg->deny_i2c_rptr); + return 0; + } + dbg_info("(%d)\n", enable); + + /* NI2CRPTEN=0x80 */ + return lgdt3306a_set_reg_bit(state, 0x0002, 7, enable ? 0 : 1); +} + +static int lgdt3306a_sleep(struct lgdt3306a_state *state) +{ + int ret; + + dbg_info("\n"); + state->current_frequency = -1; /* force re-tune, when we wake */ + + ret = lgdt3306a_mpeg_tristate(state, 1); /* disable data bus */ + if (lg_chkerr(ret)) + goto fail; + + ret = lgdt3306a_power(state, 0); /* power down */ + lg_chkerr(ret); + +fail: + return 0; +} + +static int lgdt3306a_fe_sleep(struct dvb_frontend *fe) +{ + struct lgdt3306a_state *state = fe->demodulator_priv; + + return lgdt3306a_sleep(state); +} + +static int lgdt3306a_init(struct dvb_frontend *fe) +{ + struct lgdt3306a_state *state = fe->demodulator_priv; + u8 val; + int ret; + + dbg_info("\n"); + + /* 1. Normal operation mode */ + ret = lgdt3306a_set_reg_bit(state, 0x0001, 0, 1); /* SIMFASTENB=0x01 */ + if (lg_chkerr(ret)) + goto fail; + + /* 2. Spectrum inversion auto detection (Not valid for VSB) */ + ret = lgdt3306a_set_inversion_auto(state, 0); + if (lg_chkerr(ret)) + goto fail; + + /* 3. Spectrum inversion(According to the tuner configuration) */ + ret = lgdt3306a_set_inversion(state, 1); + if (lg_chkerr(ret)) + goto fail; + + /* 4. Peak-to-peak voltage of ADC input signal */ + + /* ADCSEL1V=0x80=1Vpp; 0x00=2Vpp */ + ret = lgdt3306a_set_reg_bit(state, 0x0004, 7, 1); + if (lg_chkerr(ret)) + goto fail; + + /* 5. ADC output data capture clock phase */ + + /* 0=same phase as ADC clock */ + ret = lgdt3306a_set_reg_bit(state, 0x0004, 2, 0); + if (lg_chkerr(ret)) + goto fail; + + /* 5a. ADC sampling clock source */ + + /* ADCCLKPLLSEL=0x08; 0=use ext clock, not PLL */ + ret = lgdt3306a_set_reg_bit(state, 0x0004, 3, 0); + if (lg_chkerr(ret)) + goto fail; + + /* 6. Automatic PLL set */ + + /* PLLSETAUTO=0x40; 0=off */ + ret = lgdt3306a_set_reg_bit(state, 0x0005, 6, 0); + if (lg_chkerr(ret)) + goto fail; + + if (state->cfg->xtalMHz == 24) { /* 24MHz */ + /* 7. Frequency for PLL output(0x2564 for 192MHz for 24MHz) */ + ret = lgdt3306a_read_reg(state, 0x0005, &val); + if (lg_chkerr(ret)) + goto fail; + val &= 0xc0; + val |= 0x25; + ret = lgdt3306a_write_reg(state, 0x0005, val); + if (lg_chkerr(ret)) + goto fail; + ret = lgdt3306a_write_reg(state, 0x0006, 0x64); + if (lg_chkerr(ret)) + goto fail; + + /* 8. ADC sampling frequency(0x180000 for 24MHz sampling) */ + ret = lgdt3306a_read_reg(state, 0x000d, &val); + if (lg_chkerr(ret)) + goto fail; + val &= 0xc0; + val |= 0x18; + ret = lgdt3306a_write_reg(state, 0x000d, val); + if (lg_chkerr(ret)) + goto fail; + + } else if (state->cfg->xtalMHz == 25) { /* 25MHz */ + /* 7. Frequency for PLL output */ + ret = lgdt3306a_read_reg(state, 0x0005, &val); + if (lg_chkerr(ret)) + goto fail; + val &= 0xc0; + val |= 0x25; + ret = lgdt3306a_write_reg(state, 0x0005, val); + if (lg_chkerr(ret)) + goto fail; + ret = lgdt3306a_write_reg(state, 0x0006, 0x64); + if (lg_chkerr(ret)) + goto fail; + + /* 8. ADC sampling frequency(0x190000 for 25MHz sampling) */ + ret = lgdt3306a_read_reg(state, 0x000d, &val); + if (lg_chkerr(ret)) + goto fail; + val &= 0xc0; + val |= 0x19; + ret = lgdt3306a_write_reg(state, 0x000d, val); + if (lg_chkerr(ret)) + goto fail; + } else { + pr_err("Bad xtalMHz=%d\n", state->cfg->xtalMHz); + } +#if 0 + ret = lgdt3306a_write_reg(state, 0x000e, 0x00); + ret = lgdt3306a_write_reg(state, 0x000f, 0x00); +#endif + + /* 9. Center frequency of input signal of ADC */ + ret = lgdt3306a_write_reg(state, 0x0010, 0x34); /* 3.25MHz */ + ret = lgdt3306a_write_reg(state, 0x0011, 0x00); + + /* 10. Fixed gain error value */ + ret = lgdt3306a_write_reg(state, 0x0014, 0); /* gain error=0 */ + + /* 10a. VSB TR BW gear shift initial step */ + ret = lgdt3306a_read_reg(state, 0x103c, &val); + val &= 0x0f; + val |= 0x20; /* SAMGSAUTOSTL_V[3:0] = 2 */ + ret = lgdt3306a_write_reg(state, 0x103c, val); + + /* 10b. Timing offset calibration in low temperature for VSB */ + ret = lgdt3306a_read_reg(state, 0x103d, &val); + val &= 0xfc; + val |= 0x03; + ret = lgdt3306a_write_reg(state, 0x103d, val); + + /* 10c. Timing offset calibration in low temperature for QAM */ + ret = lgdt3306a_read_reg(state, 0x1036, &val); + val &= 0xf0; + val |= 0x0c; + ret = lgdt3306a_write_reg(state, 0x1036, val); + + /* 11. Using the imaginary part of CIR in CIR loading */ + ret = lgdt3306a_read_reg(state, 0x211f, &val); + val &= 0xef; /* do not use imaginary of CIR */ + ret = lgdt3306a_write_reg(state, 0x211f, val); + + /* 12. Control of no signal detector function */ + ret = lgdt3306a_read_reg(state, 0x2849, &val); + val &= 0xef; /* NOUSENOSIGDET=0, enable no signal detector */ + ret = lgdt3306a_write_reg(state, 0x2849, val); + + /* FGR - put demod in some known mode */ + ret = lgdt3306a_set_vsb(state); + + /* 13. TP stream format */ + ret = lgdt3306a_mpeg_mode(state, state->cfg->mpeg_mode); + + /* 14. disable output buses */ + ret = lgdt3306a_mpeg_tristate(state, 1); + + /* 15. Sleep (in reset) */ + ret = lgdt3306a_sleep(state); + lg_chkerr(ret); + +fail: + return ret; +} + +static int lgdt3306a_set_parameters(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + struct lgdt3306a_state *state = fe->demodulator_priv; + int ret; + + dbg_info("(%d, %d)\n", p->frequency, p->modulation); + + if (state->current_frequency == p->frequency && + state->current_modulation == p->modulation) { + dbg_info(" (already set, skipping ...)\n"); + return 0; + } + state->current_frequency = -1; + state->current_modulation = -1; + + ret = lgdt3306a_power(state, 1); /* power up */ + if (lg_chkerr(ret)) + goto fail; + + if (fe->ops.tuner_ops.set_params) { + ret = fe->ops.tuner_ops.set_params(fe); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); +#if 0 + if (lg_chkerr(ret)) + goto fail; + state->current_frequency = p->frequency; +#endif + } + + ret = lgdt3306a_set_modulation(state, p); + if (lg_chkerr(ret)) + goto fail; + + ret = lgdt3306a_agc_setup(state, p); + if (lg_chkerr(ret)) + goto fail; + + ret = lgdt3306a_set_if(state, p); + if (lg_chkerr(ret)) + goto fail; + + ret = lgdt3306a_spectral_inversion(state, p, + state->cfg->spectral_inversion ? 1 : 0); + if (lg_chkerr(ret)) + goto fail; + + ret = lgdt3306a_mpeg_mode(state, state->cfg->mpeg_mode); + if (lg_chkerr(ret)) + goto fail; + + ret = lgdt3306a_mpeg_mode_polarity(state, + state->cfg->tpclk_edge, + state->cfg->tpvalid_polarity); + if (lg_chkerr(ret)) + goto fail; + + ret = lgdt3306a_mpeg_tristate(state, 0); /* enable data bus */ + if (lg_chkerr(ret)) + goto fail; + + ret = lgdt3306a_soft_reset(state); + if (lg_chkerr(ret)) + goto fail; + +#ifdef DBG_DUMP + lgdt3306a_DumpAllRegs(state); +#endif + state->current_frequency = p->frequency; +fail: + return ret; +} + +static int lgdt3306a_get_frontend(struct dvb_frontend *fe) +{ + struct lgdt3306a_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + + dbg_info("(%u, %d)\n", + state->current_frequency, state->current_modulation); + + p->modulation = state->current_modulation; + p->frequency = state->current_frequency; + return 0; +} + +static enum dvbfe_algo lgdt3306a_get_frontend_algo(struct dvb_frontend *fe) +{ +#if 1 + return DVBFE_ALGO_CUSTOM; +#else + return DVBFE_ALGO_HW; +#endif +} + +/* ------------------------------------------------------------------------ */ +static int lgdt3306a_monitor_vsb(struct lgdt3306a_state *state) +{ + u8 val; + int ret; + u8 snrRef, maxPowerMan, nCombDet; + u16 fbDlyCir; + + ret = lgdt3306a_read_reg(state, 0x21a1, &val); + if (ret) + return ret; + snrRef = val & 0x3f; + + ret = lgdt3306a_read_reg(state, 0x2185, &maxPowerMan); + if (ret) + return ret; + + ret = lgdt3306a_read_reg(state, 0x2191, &val); + if (ret) + return ret; + nCombDet = (val & 0x80) >> 7; + + ret = lgdt3306a_read_reg(state, 0x2180, &val); + if (ret) + return ret; + fbDlyCir = (val & 0x03) << 8; + + ret = lgdt3306a_read_reg(state, 0x2181, &val); + if (ret) + return ret; + fbDlyCir |= val; + + dbg_info("snrRef=%d maxPowerMan=0x%x nCombDet=%d fbDlyCir=0x%x\n", + snrRef, maxPowerMan, nCombDet, fbDlyCir); + + /* Carrier offset sub loop bandwidth */ + ret = lgdt3306a_read_reg(state, 0x1061, &val); + if (ret) + return ret; + val &= 0xf8; + if ((snrRef > 18) && (maxPowerMan > 0x68) + && (nCombDet == 0x01) + && ((fbDlyCir == 0x03FF) || (fbDlyCir < 0x6C))) { + /* SNR is over 18dB and no ghosting */ + val |= 0x00; /* final bandwidth = 0 */ + } else { + val |= 0x04; /* final bandwidth = 4 */ + } + ret = lgdt3306a_write_reg(state, 0x1061, val); + if (ret) + return ret; + + /* Adjust Notch Filter */ + ret = lgdt3306a_read_reg(state, 0x0024, &val); + if (ret) + return ret; + val &= 0x0f; + if (nCombDet == 0) { /* Turn on the Notch Filter */ + val |= 0x50; + } + ret = lgdt3306a_write_reg(state, 0x0024, val); + if (ret) + return ret; + + /* VSB Timing Recovery output normalization */ + ret = lgdt3306a_read_reg(state, 0x103d, &val); + if (ret) + return ret; + val &= 0xcf; + val |= 0x20; + ret = lgdt3306a_write_reg(state, 0x103d, val); + + return ret; +} + +static enum lgdt3306a_modulation +lgdt3306a_check_oper_mode(struct lgdt3306a_state *state) +{ + u8 val = 0; + int ret; + + ret = lgdt3306a_read_reg(state, 0x0081, &val); + if (ret) + goto err; + + if (val & 0x80) { + dbg_info("VSB\n"); + return LG3306_VSB; + } + if (val & 0x08) { + ret = lgdt3306a_read_reg(state, 0x00a6, &val); + if (ret) + goto err; + val = val >> 2; + if (val & 0x01) { + dbg_info("QAM256\n"); + return LG3306_QAM256; + } + dbg_info("QAM64\n"); + return LG3306_QAM64; + } +err: + pr_warn("UNKNOWN\n"); + return LG3306_UNKNOWN_MODE; +} + +static enum lgdt3306a_lock_status +lgdt3306a_check_lock_status(struct lgdt3306a_state *state, + enum lgdt3306a_lock_check whatLock) +{ + u8 val = 0; + int ret; + enum lgdt3306a_modulation modeOper; + enum lgdt3306a_lock_status lockStatus; + + modeOper = LG3306_UNKNOWN_MODE; + + switch (whatLock) { + case LG3306_SYNC_LOCK: + { + ret = lgdt3306a_read_reg(state, 0x00a6, &val); + if (ret) + return ret; + + if ((val & 0x80) == 0x80) + lockStatus = LG3306_LOCK; + else + lockStatus = LG3306_UNLOCK; + + dbg_info("SYNC_LOCK=%x\n", lockStatus); + break; + } + case LG3306_AGC_LOCK: + { + ret = lgdt3306a_read_reg(state, 0x0080, &val); + if (ret) + return ret; + + if ((val & 0x40) == 0x40) + lockStatus = LG3306_LOCK; + else + lockStatus = LG3306_UNLOCK; + + dbg_info("AGC_LOCK=%x\n", lockStatus); + break; + } + case LG3306_TR_LOCK: + { + modeOper = lgdt3306a_check_oper_mode(state); + if ((modeOper == LG3306_QAM64) || (modeOper == LG3306_QAM256)) { + ret = lgdt3306a_read_reg(state, 0x1094, &val); + if (ret) + return ret; + + if ((val & 0x80) == 0x80) + lockStatus = LG3306_LOCK; + else + lockStatus = LG3306_UNLOCK; + } else + lockStatus = LG3306_UNKNOWN_LOCK; + + dbg_info("TR_LOCK=%x\n", lockStatus); + break; + } + case LG3306_FEC_LOCK: + { + modeOper = lgdt3306a_check_oper_mode(state); + if ((modeOper == LG3306_QAM64) || (modeOper == LG3306_QAM256)) { + ret = lgdt3306a_read_reg(state, 0x0080, &val); + if (ret) + return ret; + + if ((val & 0x10) == 0x10) + lockStatus = LG3306_LOCK; + else + lockStatus = LG3306_UNLOCK; + } else + lockStatus = LG3306_UNKNOWN_LOCK; + + dbg_info("FEC_LOCK=%x\n", lockStatus); + break; + } + + default: + lockStatus = LG3306_UNKNOWN_LOCK; + pr_warn("UNKNOWN whatLock=%d\n", whatLock); + break; + } + + return lockStatus; +} + +static enum lgdt3306a_neverlock_status +lgdt3306a_check_neverlock_status(struct lgdt3306a_state *state) +{ + u8 val = 0; + int ret; + enum lgdt3306a_neverlock_status lockStatus; + + ret = lgdt3306a_read_reg(state, 0x0080, &val); + if (ret) + return ret; + lockStatus = (enum lgdt3306a_neverlock_status)(val & 0x03); + + dbg_info("NeverLock=%d", lockStatus); + + return lockStatus; +} + +static int lgdt3306a_pre_monitoring(struct lgdt3306a_state *state) +{ + u8 val = 0; + int ret; + u8 currChDiffACQ, snrRef, mainStrong, aiccrejStatus; + + /* Channel variation */ + ret = lgdt3306a_read_reg(state, 0x21bc, &currChDiffACQ); + if (ret) + return ret; + + /* SNR of Frame sync */ + ret = lgdt3306a_read_reg(state, 0x21a1, &val); + if (ret) + return ret; + snrRef = val & 0x3f; + + /* Strong Main CIR */ + ret = lgdt3306a_read_reg(state, 0x2199, &val); + if (ret) + return ret; + mainStrong = (val & 0x40) >> 6; + + ret = lgdt3306a_read_reg(state, 0x0090, &val); + if (ret) + return ret; + aiccrejStatus = (val & 0xf0) >> 4; + + dbg_info("snrRef=%d mainStrong=%d aiccrejStatus=%d currChDiffACQ=0x%x\n", + snrRef, mainStrong, aiccrejStatus, currChDiffACQ); + +#if 0 + /* Dynamic ghost exists */ + if ((mainStrong == 0) && (currChDiffACQ > 0x70)) +#endif + if (mainStrong == 0) { + ret = lgdt3306a_read_reg(state, 0x2135, &val); + if (ret) + return ret; + val &= 0x0f; + val |= 0xa0; + ret = lgdt3306a_write_reg(state, 0x2135, val); + if (ret) + return ret; + + ret = lgdt3306a_read_reg(state, 0x2141, &val); + if (ret) + return ret; + val &= 0x3f; + val |= 0x80; + ret = lgdt3306a_write_reg(state, 0x2141, val); + if (ret) + return ret; + + ret = lgdt3306a_write_reg(state, 0x2122, 0x70); + if (ret) + return ret; + } else { /* Weak ghost or static channel */ + ret = lgdt3306a_read_reg(state, 0x2135, &val); + if (ret) + return ret; + val &= 0x0f; + val |= 0x70; + ret = lgdt3306a_write_reg(state, 0x2135, val); + if (ret) + return ret; + + ret = lgdt3306a_read_reg(state, 0x2141, &val); + if (ret) + return ret; + val &= 0x3f; + val |= 0x40; + ret = lgdt3306a_write_reg(state, 0x2141, val); + if (ret) + return ret; + + ret = lgdt3306a_write_reg(state, 0x2122, 0x40); + if (ret) + return ret; + } + return 0; +} + +static enum lgdt3306a_lock_status +lgdt3306a_sync_lock_poll(struct lgdt3306a_state *state) +{ + enum lgdt3306a_lock_status syncLockStatus = LG3306_UNLOCK; + int i; + + for (i = 0; i < 2; i++) { + msleep(30); + + syncLockStatus = lgdt3306a_check_lock_status(state, + LG3306_SYNC_LOCK); + + if (syncLockStatus == LG3306_LOCK) { + dbg_info("locked(%d)\n", i); + return LG3306_LOCK; + } + } + dbg_info("not locked\n"); + return LG3306_UNLOCK; +} + +static enum lgdt3306a_lock_status +lgdt3306a_fec_lock_poll(struct lgdt3306a_state *state) +{ + enum lgdt3306a_lock_status FECLockStatus = LG3306_UNLOCK; + int i; + + for (i = 0; i < 2; i++) { + msleep(30); + + FECLockStatus = lgdt3306a_check_lock_status(state, + LG3306_FEC_LOCK); + + if (FECLockStatus == LG3306_LOCK) { + dbg_info("locked(%d)\n", i); + return FECLockStatus; + } + } + dbg_info("not locked\n"); + return FECLockStatus; +} + +static enum lgdt3306a_neverlock_status +lgdt3306a_neverlock_poll(struct lgdt3306a_state *state) +{ + enum lgdt3306a_neverlock_status NLLockStatus = LG3306_NL_FAIL; + int i; + + for (i = 0; i < 5; i++) { + msleep(30); + + NLLockStatus = lgdt3306a_check_neverlock_status(state); + + if (NLLockStatus == LG3306_NL_LOCK) { + dbg_info("NL_LOCK(%d)\n", i); + return NLLockStatus; + } + } + dbg_info("NLLockStatus=%d\n", NLLockStatus); + return NLLockStatus; +} + +static u8 lgdt3306a_get_packet_error(struct lgdt3306a_state *state) +{ + u8 val; + int ret; + + ret = lgdt3306a_read_reg(state, 0x00fa, &val); + if (ret) + return ret; + + return val; +} + +static const u32 valx_x10[] = { + 10, 11, 13, 15, 17, 20, 25, 33, 41, 50, 59, 73, 87, 100 +}; +static const u32 log10x_x1000[] = { + 0, 41, 114, 176, 230, 301, 398, 518, 613, 699, 771, 863, 939, 1000 +}; + +static u32 log10_x1000(u32 x) +{ + u32 diff_val, step_val, step_log10; + u32 log_val = 0; + u32 i; + + if (x <= 0) + return -1000000; /* signal error */ + + if (x == 10) + return 0; /* log(1)=0 */ + + if (x < 10) { + while (x < 10) { + x = x * 10; + log_val--; + } + } else { /* x > 10 */ + while (x >= 100) { + x = x / 10; + log_val++; + } + } + log_val *= 1000; + + if (x == 10) /* was our input an exact multiple of 10 */ + return log_val; /* don't need to interpolate */ + + /* find our place on the log curve */ + for (i = 1; i < ARRAY_SIZE(valx_x10); i++) { + if (valx_x10[i] >= x) + break; + } + if (i == ARRAY_SIZE(valx_x10)) + return log_val + log10x_x1000[i - 1]; + + diff_val = x - valx_x10[i-1]; + step_val = valx_x10[i] - valx_x10[i - 1]; + step_log10 = log10x_x1000[i] - log10x_x1000[i - 1]; + + /* do a linear interpolation to get in-between values */ + return log_val + log10x_x1000[i - 1] + + ((diff_val*step_log10) / step_val); +} + +static u32 lgdt3306a_calculate_snr_x100(struct lgdt3306a_state *state) +{ + u32 mse; /* Mean-Square Error */ + u32 pwr; /* Constelation power */ + u32 snr_x100; + + mse = (read_reg(state, 0x00ec) << 8) | + (read_reg(state, 0x00ed)); + pwr = (read_reg(state, 0x00e8) << 8) | + (read_reg(state, 0x00e9)); + + if (mse == 0) /* no signal */ + return 0; + + snr_x100 = log10_x1000((pwr * 10000) / mse) - 3000; + dbg_info("mse=%u, pwr=%u, snr_x100=%d\n", mse, pwr, snr_x100); + + return snr_x100; +} + +static enum lgdt3306a_lock_status +lgdt3306a_vsb_lock_poll(struct lgdt3306a_state *state) +{ + int ret; + u8 cnt = 0; + u8 packet_error; + u32 snr; + + for (cnt = 0; cnt < 10; cnt++) { + if (lgdt3306a_sync_lock_poll(state) == LG3306_UNLOCK) { + dbg_info("no sync lock!\n"); + return LG3306_UNLOCK; + } + + msleep(20); + ret = lgdt3306a_pre_monitoring(state); + if (ret) + break; + + packet_error = lgdt3306a_get_packet_error(state); + snr = lgdt3306a_calculate_snr_x100(state); + dbg_info("cnt=%d errors=%d snr=%d\n", cnt, packet_error, snr); + + if ((snr >= 1500) && (packet_error < 0xff)) + return LG3306_LOCK; + } + + dbg_info("not locked!\n"); + return LG3306_UNLOCK; +} + +static enum lgdt3306a_lock_status +lgdt3306a_qam_lock_poll(struct lgdt3306a_state *state) +{ + u8 cnt; + u8 packet_error; + u32 snr; + + for (cnt = 0; cnt < 10; cnt++) { + if (lgdt3306a_fec_lock_poll(state) == LG3306_UNLOCK) { + dbg_info("no fec lock!\n"); + return LG3306_UNLOCK; + } + + msleep(20); + + packet_error = lgdt3306a_get_packet_error(state); + snr = lgdt3306a_calculate_snr_x100(state); + dbg_info("cnt=%d errors=%d snr=%d\n", cnt, packet_error, snr); + + if ((snr >= 1500) && (packet_error < 0xff)) + return LG3306_LOCK; + } + + dbg_info("not locked!\n"); + return LG3306_UNLOCK; +} + +static int lgdt3306a_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct lgdt3306a_state *state = fe->demodulator_priv; + u16 strength = 0; + int ret = 0; + + if (fe->ops.tuner_ops.get_rf_strength) { + ret = fe->ops.tuner_ops.get_rf_strength(fe, &strength); + if (ret == 0) + dbg_info("strength=%d\n", strength); + else + dbg_info("fe->ops.tuner_ops.get_rf_strength() failed\n"); + } + + *status = 0; + if (lgdt3306a_neverlock_poll(state) == LG3306_NL_LOCK) { + *status |= FE_HAS_SIGNAL; + *status |= FE_HAS_CARRIER; + + switch (state->current_modulation) { + case QAM_256: + case QAM_64: + if (lgdt3306a_qam_lock_poll(state) == LG3306_LOCK) { + *status |= FE_HAS_VITERBI; + *status |= FE_HAS_SYNC; + + *status |= FE_HAS_LOCK; + } + break; + case VSB_8: + if (lgdt3306a_vsb_lock_poll(state) == LG3306_LOCK) { + *status |= FE_HAS_VITERBI; + *status |= FE_HAS_SYNC; + + *status |= FE_HAS_LOCK; + + ret = lgdt3306a_monitor_vsb(state); + } + break; + default: + ret = -EINVAL; + } + } + return ret; +} + + +static int lgdt3306a_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct lgdt3306a_state *state = fe->demodulator_priv; + + state->snr = lgdt3306a_calculate_snr_x100(state); + /* report SNR in dB * 10 */ + *snr = state->snr/10; + + return 0; +} + +static int lgdt3306a_read_signal_strength(struct dvb_frontend *fe, + u16 *strength) +{ + /* + * Calculate some sort of "strength" from SNR + */ + struct lgdt3306a_state *state = fe->demodulator_priv; + u16 snr; /* snr_x10 */ + int ret; + u32 ref_snr; /* snr*100 */ + u32 str; + + *strength = 0; + + switch (state->current_modulation) { + case VSB_8: + ref_snr = 1600; /* 16dB */ + break; + case QAM_64: + ref_snr = 2200; /* 22dB */ + break; + case QAM_256: + ref_snr = 2800; /* 28dB */ + break; + default: + return -EINVAL; + } + + ret = fe->ops.read_snr(fe, &snr); + if (lg_chkerr(ret)) + goto fail; + + if (state->snr <= (ref_snr - 100)) + str = 0; + else if (state->snr <= ref_snr) + str = (0xffff * 65) / 100; /* 65% */ + else { + str = state->snr - ref_snr; + str /= 50; + str += 78; /* 78%-100% */ + if (str > 100) + str = 100; + str = (0xffff * str) / 100; + } + *strength = (u16)str; + dbg_info("strength=%u\n", *strength); + +fail: + return ret; +} + +/* ------------------------------------------------------------------------ */ + +static int lgdt3306a_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct lgdt3306a_state *state = fe->demodulator_priv; + u32 tmp; + + *ber = 0; +#if 1 + /* FGR - FIXME - I don't know what value is expected by dvb_core + * what is the scale of the value?? */ + tmp = read_reg(state, 0x00fc); /* NBERVALUE[24-31] */ + tmp = (tmp << 8) | read_reg(state, 0x00fd); /* NBERVALUE[16-23] */ + tmp = (tmp << 8) | read_reg(state, 0x00fe); /* NBERVALUE[8-15] */ + tmp = (tmp << 8) | read_reg(state, 0x00ff); /* NBERVALUE[0-7] */ + *ber = tmp; + dbg_info("ber=%u\n", tmp); +#endif + return 0; +} + +static int lgdt3306a_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct lgdt3306a_state *state = fe->demodulator_priv; + + *ucblocks = 0; +#if 1 + /* FGR - FIXME - I don't know what value is expected by dvb_core + * what happens when value wraps? */ + *ucblocks = read_reg(state, 0x00f4); /* TPIFTPERRCNT[0-7] */ + dbg_info("ucblocks=%u\n", *ucblocks); +#endif + + return 0; +} + +static int lgdt3306a_tune(struct dvb_frontend *fe, bool re_tune, + unsigned int mode_flags, unsigned int *delay, + fe_status_t *status) +{ + int ret = 0; + struct lgdt3306a_state *state = fe->demodulator_priv; + + dbg_info("re_tune=%u\n", re_tune); + + if (re_tune) { + state->current_frequency = -1; /* force re-tune */ + ret = lgdt3306a_set_parameters(fe); + if (ret != 0) + return ret; + } + *delay = 125; + ret = lgdt3306a_read_status(fe, status); + + return ret; +} + +static int lgdt3306a_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings + *fe_tune_settings) +{ + fe_tune_settings->min_delay_ms = 100; + dbg_info("\n"); + return 0; +} + +static int lgdt3306a_search(struct dvb_frontend *fe) +{ + fe_status_t status = 0; + int i, ret; + + /* set frontend */ + ret = lgdt3306a_set_parameters(fe); + if (ret) + goto error; + + /* wait frontend lock */ + for (i = 20; i > 0; i--) { + dbg_info(": loop=%d\n", i); + msleep(50); + ret = lgdt3306a_read_status(fe, &status); + if (ret) + goto error; + + if (status & FE_HAS_LOCK) + break; + } + + /* check if we have a valid signal */ + if (status & FE_HAS_LOCK) + return DVBFE_ALGO_SEARCH_SUCCESS; + else + return DVBFE_ALGO_SEARCH_AGAIN; + +error: + dbg_info("failed (%d)\n", ret); + return DVBFE_ALGO_SEARCH_ERROR; +} + +static void lgdt3306a_release(struct dvb_frontend *fe) +{ + struct lgdt3306a_state *state = fe->demodulator_priv; + + dbg_info("\n"); + kfree(state); +} + +static struct dvb_frontend_ops lgdt3306a_ops; + +struct dvb_frontend *lgdt3306a_attach(const struct lgdt3306a_config *config, + struct i2c_adapter *i2c_adap) +{ + struct lgdt3306a_state *state = NULL; + int ret; + u8 val; + + dbg_info("(%d-%04x)\n", + i2c_adap ? i2c_adapter_id(i2c_adap) : 0, + config ? config->i2c_addr : 0); + + state = kzalloc(sizeof(struct lgdt3306a_state), GFP_KERNEL); + if (state == NULL) + goto fail; + + state->cfg = config; + state->i2c_adap = i2c_adap; + + memcpy(&state->frontend.ops, &lgdt3306a_ops, + sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + + /* verify that we're talking to a lg3306a */ + /* FGR - NOTE - there is no obvious ChipId to check; we check + * some "known" bits after reset, but it's still just a guess */ + ret = lgdt3306a_read_reg(state, 0x0000, &val); + if (lg_chkerr(ret)) + goto fail; + if ((val & 0x74) != 0x74) { + pr_warn("expected 0x74, got 0x%x\n", (val & 0x74)); +#if 0 + /* FIXME - re-enable when we know this is right */ + goto fail; +#endif + } + ret = lgdt3306a_read_reg(state, 0x0001, &val); + if (lg_chkerr(ret)) + goto fail; + if ((val & 0xf6) != 0xc6) { + pr_warn("expected 0xc6, got 0x%x\n", (val & 0xf6)); +#if 0 + /* FIXME - re-enable when we know this is right */ + goto fail; +#endif + } + ret = lgdt3306a_read_reg(state, 0x0002, &val); + if (lg_chkerr(ret)) + goto fail; + if ((val & 0x73) != 0x03) { + pr_warn("expected 0x03, got 0x%x\n", (val & 0x73)); +#if 0 + /* FIXME - re-enable when we know this is right */ + goto fail; +#endif + } + + state->current_frequency = -1; + state->current_modulation = -1; + + lgdt3306a_sleep(state); + + return &state->frontend; + +fail: + pr_warn("unable to detect LGDT3306A hardware\n"); + kfree(state); + return NULL; +} +EXPORT_SYMBOL(lgdt3306a_attach); + +#ifdef DBG_DUMP + +static const short regtab[] = { + 0x0000, /* SOFTRSTB 1'b1 1'b1 1'b1 ADCPDB 1'b1 PLLPDB GBBPDB 11111111 */ + 0x0001, /* 1'b1 1'b1 1'b0 1'b0 AUTORPTRS */ + 0x0002, /* NI2CRPTEN 1'b0 1'b0 1'b0 SPECINVAUT */ + 0x0003, /* AGCRFOUT */ + 0x0004, /* ADCSEL1V ADCCNT ADCCNF ADCCNS ADCCLKPLL */ + 0x0005, /* PLLINDIVSE */ + 0x0006, /* PLLCTRL[7:0] 11100001 */ + 0x0007, /* SYSINITWAITTIME[7:0] (msec) 00001000 */ + 0x0008, /* STDOPMODE[7:0] 10000000 */ + 0x0009, /* 1'b0 1'b0 1'b0 STDOPDETTMODE[2:0] STDOPDETCMODE[1:0] 00011110 */ + 0x000a, /* DAFTEN 1'b1 x x SCSYSLOCK */ + 0x000b, /* SCSYSLOCKCHKTIME[7:0] (10msec) 01100100 */ + 0x000d, /* x SAMPLING4 */ + 0x000e, /* SAMFREQ[15:8] 00000000 */ + 0x000f, /* SAMFREQ[7:0] 00000000 */ + 0x0010, /* IFFREQ[15:8] 01100000 */ + 0x0011, /* IFFREQ[7:0] 00000000 */ + 0x0012, /* AGCEN AGCREFMO */ + 0x0013, /* AGCRFFIXB AGCIFFIXB AGCLOCKDETRNGSEL[1:0] 1'b1 1'b0 1'b0 1'b0 11101000 */ + 0x0014, /* AGCFIXVALUE[7:0] 01111111 */ + 0x0015, /* AGCREF[15:8] 00001010 */ + 0x0016, /* AGCREF[7:0] 11100100 */ + 0x0017, /* AGCDELAY[7:0] 00100000 */ + 0x0018, /* AGCRFBW[3:0] AGCIFBW[3:0] 10001000 */ + 0x0019, /* AGCUDOUTMODE[1:0] AGCUDCTRLLEN[1:0] AGCUDCTRL */ + 0x001c, /* 1'b1 PFEN MFEN AICCVSYNC */ + 0x001d, /* 1'b0 1'b1 1'b0 1'b1 AICCVSYNC */ + 0x001e, /* AICCALPHA[3:0] 1'b1 1'b0 1'b1 1'b0 01111010 */ + 0x001f, /* AICCDETTH[19:16] AICCOFFTH[19:16] 00000000 */ + 0x0020, /* AICCDETTH[15:8] 01111100 */ + 0x0021, /* AICCDETTH[7:0] 00000000 */ + 0x0022, /* AICCOFFTH[15:8] 00000101 */ + 0x0023, /* AICCOFFTH[7:0] 11100000 */ + 0x0024, /* AICCOPMODE3[1:0] AICCOPMODE2[1:0] AICCOPMODE1[1:0] AICCOPMODE0[1:0] 00000000 */ + 0x0025, /* AICCFIXFREQ3[23:16] 00000000 */ + 0x0026, /* AICCFIXFREQ3[15:8] 00000000 */ + 0x0027, /* AICCFIXFREQ3[7:0] 00000000 */ + 0x0028, /* AICCFIXFREQ2[23:16] 00000000 */ + 0x0029, /* AICCFIXFREQ2[15:8] 00000000 */ + 0x002a, /* AICCFIXFREQ2[7:0] 00000000 */ + 0x002b, /* AICCFIXFREQ1[23:16] 00000000 */ + 0x002c, /* AICCFIXFREQ1[15:8] 00000000 */ + 0x002d, /* AICCFIXFREQ1[7:0] 00000000 */ + 0x002e, /* AICCFIXFREQ0[23:16] 00000000 */ + 0x002f, /* AICCFIXFREQ0[15:8] 00000000 */ + 0x0030, /* AICCFIXFREQ0[7:0] 00000000 */ + 0x0031, /* 1'b0 1'b1 1'b0 1'b0 x DAGC1STER */ + 0x0032, /* DAGC1STEN DAGC1STER */ + 0x0033, /* DAGC1STREF[15:8] 00001010 */ + 0x0034, /* DAGC1STREF[7:0] 11100100 */ + 0x0035, /* DAGC2NDE */ + 0x0036, /* DAGC2NDREF[15:8] 00001010 */ + 0x0037, /* DAGC2NDREF[7:0] 10000000 */ + 0x0038, /* DAGC2NDLOCKDETRNGSEL[1:0] */ + 0x003d, /* 1'b1 SAMGEARS */ + 0x0040, /* SAMLFGMA */ + 0x0041, /* SAMLFBWM */ + 0x0044, /* 1'b1 CRGEARSHE */ + 0x0045, /* CRLFGMAN */ + 0x0046, /* CFLFBWMA */ + 0x0047, /* CRLFGMAN */ + 0x0048, /* x x x x CRLFGSTEP_VS[3:0] xxxx1001 */ + 0x0049, /* CRLFBWMA */ + 0x004a, /* CRLFBWMA */ + 0x0050, /* 1'b0 1'b1 1'b1 1'b0 MSECALCDA */ + 0x0070, /* TPOUTEN TPIFEN TPCLKOUTE */ + 0x0071, /* TPSENB TPSSOPBITE */ + 0x0073, /* TP47HINS x x CHBERINT PERMODE[1:0] PERINT[1:0] 1xx11100 */ + 0x0075, /* x x x x x IQSWAPCTRL[2:0] xxxxx000 */ + 0x0076, /* NBERCON NBERST NBERPOL NBERWSYN */ + 0x0077, /* x NBERLOSTTH[2:0] NBERACQTH[3:0] x0000000 */ + 0x0078, /* NBERPOLY[31:24] 00000000 */ + 0x0079, /* NBERPOLY[23:16] 00000000 */ + 0x007a, /* NBERPOLY[15:8] 00000000 */ + 0x007b, /* NBERPOLY[7:0] 00000000 */ + 0x007c, /* NBERPED[31:24] 00000000 */ + 0x007d, /* NBERPED[23:16] 00000000 */ + 0x007e, /* NBERPED[15:8] 00000000 */ + 0x007f, /* NBERPED[7:0] 00000000 */ + 0x0080, /* x AGCLOCK DAGCLOCK SYSLOCK x x NEVERLOCK[1:0] */ + 0x0085, /* SPECINVST */ + 0x0088, /* SYSLOCKTIME[15:8] */ + 0x0089, /* SYSLOCKTIME[7:0] */ + 0x008c, /* FECLOCKTIME[15:8] */ + 0x008d, /* FECLOCKTIME[7:0] */ + 0x008e, /* AGCACCOUT[15:8] */ + 0x008f, /* AGCACCOUT[7:0] */ + 0x0090, /* AICCREJSTATUS[3:0] AICCREJBUSY[3:0] */ + 0x0091, /* AICCVSYNC */ + 0x009c, /* CARRFREQOFFSET[15:8] */ + 0x009d, /* CARRFREQOFFSET[7:0] */ + 0x00a1, /* SAMFREQOFFSET[23:16] */ + 0x00a2, /* SAMFREQOFFSET[15:8] */ + 0x00a3, /* SAMFREQOFFSET[7:0] */ + 0x00a6, /* SYNCLOCK SYNCLOCKH */ +#if 0 /* covered elsewhere */ + 0x00e8, /* CONSTPWR[15:8] */ + 0x00e9, /* CONSTPWR[7:0] */ + 0x00ea, /* BMSE[15:8] */ + 0x00eb, /* BMSE[7:0] */ + 0x00ec, /* MSE[15:8] */ + 0x00ed, /* MSE[7:0] */ + 0x00ee, /* CONSTI[7:0] */ + 0x00ef, /* CONSTQ[7:0] */ +#endif + 0x00f4, /* TPIFTPERRCNT[7:0] */ + 0x00f5, /* TPCORREC */ + 0x00f6, /* VBBER[15:8] */ + 0x00f7, /* VBBER[7:0] */ + 0x00f8, /* VABER[15:8] */ + 0x00f9, /* VABER[7:0] */ + 0x00fa, /* TPERRCNT[7:0] */ + 0x00fb, /* NBERLOCK x x x x x x x */ + 0x00fc, /* NBERVALUE[31:24] */ + 0x00fd, /* NBERVALUE[23:16] */ + 0x00fe, /* NBERVALUE[15:8] */ + 0x00ff, /* NBERVALUE[7:0] */ + 0x1000, /* 1'b0 WODAGCOU */ + 0x1005, /* x x 1'b1 1'b1 x SRD_Q_QM */ + 0x1009, /* SRDWAITTIME[7:0] (10msec) 00100011 */ + 0x100a, /* SRDWAITTIME_CQS[7:0] (msec) 01100100 */ + 0x101a, /* x 1'b1 1'b0 1'b0 x QMDQAMMODE[2:0] x100x010 */ + 0x1036, /* 1'b0 1'b1 1'b0 1'b0 SAMGSEND_CQS[3:0] 01001110 */ + 0x103c, /* SAMGSAUTOSTL_V[3:0] SAMGSAUTOEDL_V[3:0] 01000110 */ + 0x103d, /* 1'b1 1'b1 SAMCNORMBP_V[1:0] 1'b0 1'b0 SAMMODESEL_V[1:0] 11100001 */ + 0x103f, /* SAMZTEDSE */ + 0x105d, /* EQSTATUSE */ + 0x105f, /* x PMAPG2_V[2:0] x DMAPG2_V[2:0] x001x011 */ + 0x1060, /* 1'b1 EQSTATUSE */ + 0x1061, /* CRMAPBWSTL_V[3:0] CRMAPBWEDL_V[3:0] 00000100 */ + 0x1065, /* 1'b0 x CRMODE_V[1:0] 1'b1 x 1'b1 x 0x111x1x */ + 0x1066, /* 1'b0 1'b0 1'b1 1'b0 1'b1 PNBOOSTSE */ + 0x1068, /* CREPHNGAIN2_V[3:0] CREPHNPBW_V[3:0] 10010001 */ + 0x106e, /* x x x x x CREPHNEN_ */ + 0x106f, /* CREPHNTH_V[7:0] 00010101 */ + 0x1072, /* CRSWEEPN */ + 0x1073, /* CRPGAIN_V[3:0] x x 1'b1 1'b1 1001xx11 */ + 0x1074, /* CRPBW_V[3:0] x x 1'b1 1'b1 0001xx11 */ + 0x1080, /* DAFTSTATUS[1:0] x x x x x x */ + 0x1081, /* SRDSTATUS[1:0] x x x x x SRDLOCK */ + 0x10a9, /* EQSTATUS_CQS[1:0] x x x x x x */ + 0x10b7, /* EQSTATUS_V[1:0] x x x x x x */ +#if 0 /* SMART_ANT */ + 0x1f00, /* MODEDETE */ + 0x1f01, /* x x x x x x x SFNRST xxxxxxx0 */ + 0x1f03, /* NUMOFANT[7:0] 10000000 */ + 0x1f04, /* x SELMASK[6:0] x0000000 */ + 0x1f05, /* x SETMASK[6:0] x0000000 */ + 0x1f06, /* x TXDATA[6:0] x0000000 */ + 0x1f07, /* x CHNUMBER[6:0] x0000000 */ + 0x1f09, /* AGCTIME[23:16] 10011000 */ + 0x1f0a, /* AGCTIME[15:8] 10010110 */ + 0x1f0b, /* AGCTIME[7:0] 10000000 */ + 0x1f0c, /* ANTTIME[31:24] 00000000 */ + 0x1f0d, /* ANTTIME[23:16] 00000011 */ + 0x1f0e, /* ANTTIME[15:8] 10010000 */ + 0x1f0f, /* ANTTIME[7:0] 10010000 */ + 0x1f11, /* SYNCTIME[23:16] 10011000 */ + 0x1f12, /* SYNCTIME[15:8] 10010110 */ + 0x1f13, /* SYNCTIME[7:0] 10000000 */ + 0x1f14, /* SNRTIME[31:24] 00000001 */ + 0x1f15, /* SNRTIME[23:16] 01111101 */ + 0x1f16, /* SNRTIME[15:8] 01111000 */ + 0x1f17, /* SNRTIME[7:0] 01000000 */ + 0x1f19, /* FECTIME[23:16] 00000000 */ + 0x1f1a, /* FECTIME[15:8] 01110010 */ + 0x1f1b, /* FECTIME[7:0] 01110000 */ + 0x1f1d, /* FECTHD[7:0] 00000011 */ + 0x1f1f, /* SNRTHD[23:16] 00001000 */ + 0x1f20, /* SNRTHD[15:8] 01111111 */ + 0x1f21, /* SNRTHD[7:0] 10000101 */ + 0x1f80, /* IRQFLG x x SFSDRFLG MODEBFLG SAVEFLG SCANFLG TRACKFLG */ + 0x1f81, /* x SYNCCON SNRCON FECCON x STDBUSY SYNCRST AGCFZCO */ + 0x1f82, /* x x x SCANOPCD[4:0] */ + 0x1f83, /* x x x x MAINOPCD[3:0] */ + 0x1f84, /* x x RXDATA[13:8] */ + 0x1f85, /* RXDATA[7:0] */ + 0x1f86, /* x x SDTDATA[13:8] */ + 0x1f87, /* SDTDATA[7:0] */ + 0x1f89, /* ANTSNR[23:16] */ + 0x1f8a, /* ANTSNR[15:8] */ + 0x1f8b, /* ANTSNR[7:0] */ + 0x1f8c, /* x x x x ANTFEC[13:8] */ + 0x1f8d, /* ANTFEC[7:0] */ + 0x1f8e, /* MAXCNT[7:0] */ + 0x1f8f, /* SCANCNT[7:0] */ + 0x1f91, /* MAXPW[23:16] */ + 0x1f92, /* MAXPW[15:8] */ + 0x1f93, /* MAXPW[7:0] */ + 0x1f95, /* CURPWMSE[23:16] */ + 0x1f96, /* CURPWMSE[15:8] */ + 0x1f97, /* CURPWMSE[7:0] */ +#endif /* SMART_ANT */ + 0x211f, /* 1'b1 1'b1 1'b1 CIRQEN x x 1'b0 1'b0 1111xx00 */ + 0x212a, /* EQAUTOST */ + 0x2122, /* CHFAST[7:0] 01100000 */ + 0x212b, /* FFFSTEP_V[3:0] x FBFSTEP_V[2:0] 0001x001 */ + 0x212c, /* PHDEROTBWSEL[3:0] 1'b1 1'b1 1'b1 1'b0 10001110 */ + 0x212d, /* 1'b1 1'b1 1'b1 1'b1 x x TPIFLOCKS */ + 0x2135, /* DYNTRACKFDEQ[3:0] x 1'b0 1'b0 1'b0 1010x000 */ + 0x2141, /* TRMODE[1:0] 1'b1 1'b1 1'b0 1'b1 1'b1 1'b1 01110111 */ + 0x2162, /* AICCCTRLE */ + 0x2173, /* PHNCNFCNT[7:0] 00000100 */ + 0x2179, /* 1'b0 1'b0 1'b0 1'b1 x BADSINGLEDYNTRACKFBF[2:0] 0001x001 */ + 0x217a, /* 1'b0 1'b0 1'b0 1'b1 x BADSLOWSINGLEDYNTRACKFBF[2:0] 0001x001 */ + 0x217e, /* CNFCNTTPIF[7:0] 00001000 */ + 0x217f, /* TPERRCNTTPIF[7:0] 00000001 */ + 0x2180, /* x x x x x x FBDLYCIR[9:8] */ + 0x2181, /* FBDLYCIR[7:0] */ + 0x2185, /* MAXPWRMAIN[7:0] */ + 0x2191, /* NCOMBDET x x x x x x x */ + 0x2199, /* x MAINSTRON */ + 0x219a, /* FFFEQSTEPOUT_V[3:0] FBFSTEPOUT_V[2:0] */ + 0x21a1, /* x x SNRREF[5:0] */ + 0x2845, /* 1'b0 1'b1 x x FFFSTEP_CQS[1:0] FFFCENTERTAP[1:0] 01xx1110 */ + 0x2846, /* 1'b0 x 1'b0 1'b1 FBFSTEP_CQS[1:0] 1'b1 1'b0 0x011110 */ + 0x2847, /* ENNOSIGDE */ + 0x2849, /* 1'b1 1'b1 NOUSENOSI */ + 0x284a, /* EQINITWAITTIME[7:0] 01100100 */ + 0x3000, /* 1'b1 1'b1 1'b1 x x x 1'b0 RPTRSTM */ + 0x3001, /* RPTRSTWAITTIME[7:0] (100msec) 00110010 */ + 0x3031, /* FRAMELOC */ + 0x3032, /* 1'b1 1'b0 1'b0 1'b0 x x FRAMELOCKMODE_CQS[1:0] 1000xx11 */ + 0x30a9, /* VDLOCK_Q FRAMELOCK */ + 0x30aa, /* MPEGLOCK */ +}; + +#define numDumpRegs (sizeof(regtab)/sizeof(regtab[0])) +static u8 regval1[numDumpRegs] = {0, }; +static u8 regval2[numDumpRegs] = {0, }; + +static void lgdt3306a_DumpAllRegs(struct lgdt3306a_state *state) +{ + memset(regval2, 0xff, sizeof(regval2)); + lgdt3306a_DumpRegs(state); +} + +static void lgdt3306a_DumpRegs(struct lgdt3306a_state *state) +{ + int i; + int sav_debug = debug; + + if ((debug & DBG_DUMP) == 0) + return; + debug &= ~DBG_REG; /* suppress DBG_REG during reg dump */ + + lg_debug("\n"); + + for (i = 0; i < numDumpRegs; i++) { + lgdt3306a_read_reg(state, regtab[i], ®val1[i]); + if (regval1[i] != regval2[i]) { + lg_debug(" %04X = %02X\n", regtab[i], regval1[i]); + regval2[i] = regval1[i]; + } + } + debug = sav_debug; +} +#endif /* DBG_DUMP */ + + + +static struct dvb_frontend_ops lgdt3306a_ops = { + .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, + .info = { + .name = "LG Electronics LGDT3306A VSB/QAM Frontend", + .frequency_min = 54000000, + .frequency_max = 858000000, + .frequency_stepsize = 62500, + .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB + }, + .i2c_gate_ctrl = lgdt3306a_i2c_gate_ctrl, + .init = lgdt3306a_init, + .sleep = lgdt3306a_fe_sleep, + /* if this is set, it overrides the default swzigzag */ + .tune = lgdt3306a_tune, + .set_frontend = lgdt3306a_set_parameters, + .get_frontend = lgdt3306a_get_frontend, + .get_frontend_algo = lgdt3306a_get_frontend_algo, + .get_tune_settings = lgdt3306a_get_tune_settings, + .read_status = lgdt3306a_read_status, + .read_ber = lgdt3306a_read_ber, + .read_signal_strength = lgdt3306a_read_signal_strength, + .read_snr = lgdt3306a_read_snr, + .read_ucblocks = lgdt3306a_read_ucblocks, + .release = lgdt3306a_release, + .ts_bus_ctrl = lgdt3306a_ts_bus_ctrl, + .search = lgdt3306a_search, +}; + +MODULE_DESCRIPTION("LG Electronics LGDT3306A ATSC/QAM-B Demodulator Driver"); +MODULE_AUTHOR("Fred Richter <frichter@hauppauge.com>"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.2"); diff --git a/drivers/media/dvb-frontends/lgdt3306a.h b/drivers/media/dvb-frontends/lgdt3306a.h new file mode 100644 index 000000000000..9dbb2dced1fe --- /dev/null +++ b/drivers/media/dvb-frontends/lgdt3306a.h @@ -0,0 +1,74 @@ +/* + * Support for LGDT3306A - 8VSB/QAM-B + * + * Copyright (C) 2013,2014 Fred Richter <frichter@hauppauge.com> + * based on lgdt3305.[ch] by Michael Krufky + * + * 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 Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 _LGDT3306A_H_ +#define _LGDT3306A_H_ + +#include <linux/i2c.h> +#include "dvb_frontend.h" + + +enum lgdt3306a_mpeg_mode { + LGDT3306A_MPEG_PARALLEL = 0, + LGDT3306A_MPEG_SERIAL = 1, +}; + +enum lgdt3306a_tp_clock_edge { + LGDT3306A_TPCLK_RISING_EDGE = 0, + LGDT3306A_TPCLK_FALLING_EDGE = 1, +}; + +enum lgdt3306a_tp_valid_polarity { + LGDT3306A_TP_VALID_LOW = 0, + LGDT3306A_TP_VALID_HIGH = 1, +}; + +struct lgdt3306a_config { + u8 i2c_addr; + + /* user defined IF frequency in KHz */ + u16 qam_if_khz; + u16 vsb_if_khz; + + /* disable i2c repeater - 0:repeater enabled 1:repeater disabled */ + unsigned int deny_i2c_rptr:1; + + /* spectral inversion - 0:disabled 1:enabled */ + unsigned int spectral_inversion:1; + + enum lgdt3306a_mpeg_mode mpeg_mode; + enum lgdt3306a_tp_clock_edge tpclk_edge; + enum lgdt3306a_tp_valid_polarity tpvalid_polarity; + + /* demod clock freq in MHz; 24 or 25 supported */ + int xtalMHz; +}; + +#if IS_REACHABLE(CONFIG_DVB_LGDT3306A) +struct dvb_frontend *lgdt3306a_attach(const struct lgdt3306a_config *config, + struct i2c_adapter *i2c_adap); +#else +static inline +struct dvb_frontend *lgdt3306a_attach(const struct lgdt3306a_config *config, + struct i2c_adapter *i2c_adap) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_LGDT3306A */ + +#endif /* _LGDT3306A_H_ */ diff --git a/drivers/media/dvb-frontends/lgdt330x.h b/drivers/media/dvb-frontends/lgdt330x.h index 8bb332219fc4..c73eeb45e330 100644 --- a/drivers/media/dvb-frontends/lgdt330x.h +++ b/drivers/media/dvb-frontends/lgdt330x.h @@ -52,7 +52,7 @@ struct lgdt330x_config int clock_polarity_flip; }; -#if IS_ENABLED(CONFIG_DVB_LGDT330X) +#if IS_REACHABLE(CONFIG_DVB_LGDT330X) extern struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/lgs8gl5.h b/drivers/media/dvb-frontends/lgs8gl5.h index c2da59614727..a5b3faf121f0 100644 --- a/drivers/media/dvb-frontends/lgs8gl5.h +++ b/drivers/media/dvb-frontends/lgs8gl5.h @@ -31,7 +31,7 @@ struct lgs8gl5_config { u8 demod_address; }; -#if IS_ENABLED(CONFIG_DVB_LGS8GL5) +#if IS_REACHABLE(CONFIG_DVB_LGS8GL5) extern struct dvb_frontend *lgs8gl5_attach( const struct lgs8gl5_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/lgs8gxx.h b/drivers/media/dvb-frontends/lgs8gxx.h index dadb78bf61a9..368c9928ef7f 100644 --- a/drivers/media/dvb-frontends/lgs8gxx.h +++ b/drivers/media/dvb-frontends/lgs8gxx.h @@ -80,7 +80,7 @@ struct lgs8gxx_config { u8 tuner_address; }; -#if IS_ENABLED(CONFIG_DVB_LGS8GXX) +#if IS_REACHABLE(CONFIG_DVB_LGS8GXX) extern struct dvb_frontend *lgs8gxx_attach(const struct lgs8gxx_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/lnbh24.h b/drivers/media/dvb-frontends/lnbh24.h index b327a4f31d16..a088b8ec1e53 100644 --- a/drivers/media/dvb-frontends/lnbh24.h +++ b/drivers/media/dvb-frontends/lnbh24.h @@ -37,7 +37,7 @@ #include <linux/dvb/frontend.h> -#if IS_ENABLED(CONFIG_DVB_LNBP21) +#if IS_REACHABLE(CONFIG_DVB_LNBP21) /* override_set and override_clear control which system register bits (above) to always set & clear */ extern struct dvb_frontend *lnbh24_attach(struct dvb_frontend *fe, diff --git a/drivers/media/dvb-frontends/lnbp21.h b/drivers/media/dvb-frontends/lnbp21.h index dbcbcc2f20a3..a9b530de62a6 100644 --- a/drivers/media/dvb-frontends/lnbp21.h +++ b/drivers/media/dvb-frontends/lnbp21.h @@ -57,7 +57,7 @@ #include <linux/dvb/frontend.h> -#if IS_ENABLED(CONFIG_DVB_LNBP21) +#if IS_REACHABLE(CONFIG_DVB_LNBP21) /* override_set and override_clear control which system register bits (above) to always set & clear */ extern struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe, diff --git a/drivers/media/dvb-frontends/lnbp22.h b/drivers/media/dvb-frontends/lnbp22.h index 63861b311dd8..628148385182 100644 --- a/drivers/media/dvb-frontends/lnbp22.h +++ b/drivers/media/dvb-frontends/lnbp22.h @@ -39,7 +39,7 @@ #include <linux/dvb/frontend.h> -#if IS_ENABLED(CONFIG_DVB_LNBP22) +#if IS_REACHABLE(CONFIG_DVB_LNBP22) /* * override_set and override_clear control which system register bits (above) * to always set & clear diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c index ba4ee0b48834..d3d928e1c0ce 100644 --- a/drivers/media/dvb-frontends/m88ds3103.c +++ b/drivers/media/dvb-frontends/m88ds3103.c @@ -630,7 +630,7 @@ static int m88ds3103_init(struct dvb_frontend *fe) /* request the firmware, this will block and timeout */ ret = request_firmware(&fw, fw_file, priv->i2c->dev.parent); if (ret) { - dev_err(&priv->i2c->dev, "%s: firmare file '%s' not found\n", + dev_err(&priv->i2c->dev, "%s: firmware file '%s' not found\n", KBUILD_MODNAME, fw_file); goto err; } diff --git a/drivers/media/dvb-frontends/m88rs2000.h b/drivers/media/dvb-frontends/m88rs2000.h index 0a50ea90736b..de7430178e9e 100644 --- a/drivers/media/dvb-frontends/m88rs2000.h +++ b/drivers/media/dvb-frontends/m88rs2000.h @@ -41,7 +41,7 @@ enum { CALL_IS_READ, }; -#if IS_ENABLED(CONFIG_DVB_M88RS2000) +#if IS_REACHABLE(CONFIG_DVB_M88RS2000) extern struct dvb_frontend *m88rs2000_attach( const struct m88rs2000_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/mb86a16.h b/drivers/media/dvb-frontends/mb86a16.h index 277ce061acf9..e486dc0d8e60 100644 --- a/drivers/media/dvb-frontends/mb86a16.h +++ b/drivers/media/dvb-frontends/mb86a16.h @@ -33,7 +33,7 @@ struct mb86a16_config { -#if IS_ENABLED(CONFIG_DVB_MB86A16) +#if IS_REACHABLE(CONFIG_DVB_MB86A16) extern struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config, struct i2c_adapter *i2c_adap); diff --git a/drivers/media/dvb-frontends/mb86a20s.h b/drivers/media/dvb-frontends/mb86a20s.h index cbeb941fba7c..f749c8ac5f39 100644 --- a/drivers/media/dvb-frontends/mb86a20s.h +++ b/drivers/media/dvb-frontends/mb86a20s.h @@ -34,7 +34,7 @@ struct mb86a20s_config { bool is_serial; }; -#if IS_ENABLED(CONFIG_DVB_MB86A20S) +#if IS_REACHABLE(CONFIG_DVB_MB86A20S) extern struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config, struct i2c_adapter *i2c); extern struct i2c_adapter *mb86a20s_get_tuner_i2c_adapter(struct dvb_frontend *); diff --git a/drivers/media/dvb-frontends/mn88472.h b/drivers/media/dvb-frontends/mn88472.h index e4e0b80d3091..095294d292f3 100644 --- a/drivers/media/dvb-frontends/mn88472.h +++ b/drivers/media/dvb-frontends/mn88472.h @@ -19,6 +19,16 @@ #include <linux/dvb/frontend.h> +enum ts_clock { + VARIABLE_TS_CLOCK, + FIXED_TS_CLOCK, +}; + +enum ts_mode { + SERIAL_TS_MODE, + PARALLEL_TS_MODE, +}; + struct mn88472_config { /* * Max num of bytes given I2C adapter could write at once. @@ -39,6 +49,8 @@ struct mn88472_config { * Hz */ u32 xtal; + int ts_mode; + int ts_clock; }; #endif diff --git a/drivers/media/dvb-frontends/mn88473.h b/drivers/media/dvb-frontends/mn88473.h index a373ec93cbe0..c717ebed0e03 100644 --- a/drivers/media/dvb-frontends/mn88473.h +++ b/drivers/media/dvb-frontends/mn88473.h @@ -33,6 +33,12 @@ struct mn88473_config { * DVB frontend. */ struct dvb_frontend **fe; + + /* + * Xtal frequency. + * Hz + */ + u32 xtal; }; #endif diff --git a/drivers/media/dvb-frontends/mt312.h b/drivers/media/dvb-frontends/mt312.h index 5706621ad79d..386939a90555 100644 --- a/drivers/media/dvb-frontends/mt312.h +++ b/drivers/media/dvb-frontends/mt312.h @@ -36,7 +36,7 @@ struct mt312_config { unsigned int voltage_inverted:1; }; -#if IS_ENABLED(CONFIG_DVB_MT312) +#if IS_REACHABLE(CONFIG_DVB_MT312) struct dvb_frontend *mt312_attach(const struct mt312_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/mt352.h b/drivers/media/dvb-frontends/mt352.h index 451d904e1500..5873263bd1af 100644 --- a/drivers/media/dvb-frontends/mt352.h +++ b/drivers/media/dvb-frontends/mt352.h @@ -51,7 +51,7 @@ struct mt352_config int (*demod_init)(struct dvb_frontend* fe); }; -#if IS_ENABLED(CONFIG_DVB_MT352) +#if IS_REACHABLE(CONFIG_DVB_MT352) extern struct dvb_frontend* mt352_attach(const struct mt352_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/nxt200x.h b/drivers/media/dvb-frontends/nxt200x.h index e38d01fb6c2b..825b928ef542 100644 --- a/drivers/media/dvb-frontends/nxt200x.h +++ b/drivers/media/dvb-frontends/nxt200x.h @@ -42,7 +42,7 @@ struct nxt200x_config int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); }; -#if IS_ENABLED(CONFIG_DVB_NXT200X) +#if IS_REACHABLE(CONFIG_DVB_NXT200X) extern struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/nxt6000.h b/drivers/media/dvb-frontends/nxt6000.h index b5867c2ae681..a94cefcc6dfd 100644 --- a/drivers/media/dvb-frontends/nxt6000.h +++ b/drivers/media/dvb-frontends/nxt6000.h @@ -33,7 +33,7 @@ struct nxt6000_config u8 clock_inversion:1; }; -#if IS_ENABLED(CONFIG_DVB_NXT6000) +#if IS_REACHABLE(CONFIG_DVB_NXT6000) extern struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/or51132.h b/drivers/media/dvb-frontends/or51132.h index cdb5be3c65d6..9acf8dc87413 100644 --- a/drivers/media/dvb-frontends/or51132.h +++ b/drivers/media/dvb-frontends/or51132.h @@ -34,7 +34,7 @@ struct or51132_config int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); }; -#if IS_ENABLED(CONFIG_DVB_OR51132) +#if IS_REACHABLE(CONFIG_DVB_OR51132) extern struct dvb_frontend* or51132_attach(const struct or51132_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/or51211.h b/drivers/media/dvb-frontends/or51211.h index 9a8ae936b62d..cc6adab63249 100644 --- a/drivers/media/dvb-frontends/or51211.h +++ b/drivers/media/dvb-frontends/or51211.h @@ -37,7 +37,7 @@ struct or51211_config void (*sleep)(struct dvb_frontend * fe); }; -#if IS_ENABLED(CONFIG_DVB_OR51211) +#if IS_REACHABLE(CONFIG_DVB_OR51211) extern struct dvb_frontend* or51211_attach(const struct or51211_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c index 67faa8d6950e..b400f7b3c2e7 100644 --- a/drivers/media/dvb-frontends/rtl2832.c +++ b/drivers/media/dvb-frontends/rtl2832.c @@ -685,7 +685,7 @@ static int rtl2832_read_status(struct dvb_frontend *fe, fe_status_t *status) struct rtl2832_dev *dev = fe->demodulator_priv; struct i2c_client *client = dev->client; int ret; - u32 tmp; + u32 uninitialized_var(tmp); dev_dbg(&client->dev, "\n"); diff --git a/drivers/media/dvb-frontends/s5h1409.h b/drivers/media/dvb-frontends/s5h1409.h index 9e143f5c8107..f58b9ca5557a 100644 --- a/drivers/media/dvb-frontends/s5h1409.h +++ b/drivers/media/dvb-frontends/s5h1409.h @@ -67,7 +67,7 @@ struct s5h1409_config { u8 hvr1600_opt; }; -#if IS_ENABLED(CONFIG_DVB_S5H1409) +#if IS_REACHABLE(CONFIG_DVB_S5H1409) extern struct dvb_frontend *s5h1409_attach(const struct s5h1409_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/s5h1411.h b/drivers/media/dvb-frontends/s5h1411.h index 1d7deb615674..f3a87f7ec360 100644 --- a/drivers/media/dvb-frontends/s5h1411.h +++ b/drivers/media/dvb-frontends/s5h1411.h @@ -69,7 +69,7 @@ struct s5h1411_config { u8 status_mode; }; -#if IS_ENABLED(CONFIG_DVB_S5H1411) +#if IS_REACHABLE(CONFIG_DVB_S5H1411) extern struct dvb_frontend *s5h1411_attach(const struct s5h1411_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/s5h1420.h b/drivers/media/dvb-frontends/s5h1420.h index 210049b5cf30..142d93e7d02b 100644 --- a/drivers/media/dvb-frontends/s5h1420.h +++ b/drivers/media/dvb-frontends/s5h1420.h @@ -40,7 +40,7 @@ struct s5h1420_config u8 serial_mpeg:1; }; -#if IS_ENABLED(CONFIG_DVB_S5H1420) +#if IS_REACHABLE(CONFIG_DVB_S5H1420) extern struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config, struct i2c_adapter *i2c); extern struct i2c_adapter *s5h1420_get_tuner_i2c_adapter(struct dvb_frontend *fe); diff --git a/drivers/media/dvb-frontends/s5h1432.h b/drivers/media/dvb-frontends/s5h1432.h index 70917dd2533a..f490c5ee5801 100644 --- a/drivers/media/dvb-frontends/s5h1432.h +++ b/drivers/media/dvb-frontends/s5h1432.h @@ -75,7 +75,7 @@ struct s5h1432_config { u8 status_mode; }; -#if IS_ENABLED(CONFIG_DVB_S5H1432) +#if IS_REACHABLE(CONFIG_DVB_S5H1432) extern struct dvb_frontend *s5h1432_attach(const struct s5h1432_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/s921.h b/drivers/media/dvb-frontends/s921.h index 9b20c9e0eb88..7d3999a4e974 100644 --- a/drivers/media/dvb-frontends/s921.h +++ b/drivers/media/dvb-frontends/s921.h @@ -25,7 +25,7 @@ struct s921_config { u8 demod_address; }; -#if IS_ENABLED(CONFIG_DVB_S921) +#if IS_REACHABLE(CONFIG_DVB_S921) extern struct dvb_frontend *s921_attach(const struct s921_config *config, struct i2c_adapter *i2c); extern struct i2c_adapter *s921_get_tuner_i2c_adapter(struct dvb_frontend *); diff --git a/drivers/media/dvb-frontends/si2165.c b/drivers/media/dvb-frontends/si2165.c index 98ddb49ad52b..4cc5d10ed0d4 100644 --- a/drivers/media/dvb-frontends/si2165.c +++ b/drivers/media/dvb-frontends/si2165.c @@ -505,7 +505,7 @@ static int si2165_upload_firmware(struct si2165_state *state) /* reset crc */ ret = si2165_writereg8(state, 0x0379, 0x01); if (ret) - return ret; + goto error; ret = si2165_upload_firmware_block(state, data, len, &offset, block_count); diff --git a/drivers/media/dvb-frontends/si2165.h b/drivers/media/dvb-frontends/si2165.h index efaa08123b92..8a15d6a9c552 100644 --- a/drivers/media/dvb-frontends/si2165.h +++ b/drivers/media/dvb-frontends/si2165.h @@ -45,7 +45,7 @@ struct si2165_config { bool inversion; }; -#if IS_ENABLED(CONFIG_DVB_SI2165) +#if IS_REACHABLE(CONFIG_DVB_SI2165) struct dvb_frontend *si2165_attach( const struct si2165_config *config, struct i2c_adapter *i2c); diff --git a/drivers/media/dvb-frontends/si2168_priv.h b/drivers/media/dvb-frontends/si2168_priv.h index aadd1367673f..d7efce8043ed 100644 --- a/drivers/media/dvb-frontends/si2168_priv.h +++ b/drivers/media/dvb-frontends/si2168_priv.h @@ -40,7 +40,7 @@ struct si2168_dev { bool ts_clock_inv; }; -/* firmare command struct */ +/* firmware command struct */ #define SI2168_ARGLEN 30 struct si2168_cmd { u8 args[SI2168_ARGLEN]; diff --git a/drivers/media/dvb-frontends/si21xx.h b/drivers/media/dvb-frontends/si21xx.h index 1509fed44a3a..ef5f351ca68e 100644 --- a/drivers/media/dvb-frontends/si21xx.h +++ b/drivers/media/dvb-frontends/si21xx.h @@ -13,7 +13,7 @@ struct si21xx_config { int min_delay_ms; }; -#if IS_ENABLED(CONFIG_DVB_SI21XX) +#if IS_REACHABLE(CONFIG_DVB_SI21XX) extern struct dvb_frontend *si21xx_attach(const struct si21xx_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/sp2.c b/drivers/media/dvb-frontends/sp2.c index cc1ef966f99f..8fd42767e263 100644 --- a/drivers/media/dvb-frontends/sp2.c +++ b/drivers/media/dvb-frontends/sp2.c @@ -413,11 +413,8 @@ static int sp2_remove(struct i2c_client *client) struct sp2 *s = i2c_get_clientdata(client); dev_dbg(&client->dev, "\n"); - sp2_exit(client); - if (s != NULL) - kfree(s); - + kfree(s); return 0; } diff --git a/drivers/media/dvb-frontends/sp8870.h b/drivers/media/dvb-frontends/sp8870.h index 065ec67d4e30..f507b9fd707b 100644 --- a/drivers/media/dvb-frontends/sp8870.h +++ b/drivers/media/dvb-frontends/sp8870.h @@ -35,7 +35,7 @@ struct sp8870_config int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); }; -#if IS_ENABLED(CONFIG_DVB_SP8870) +#if IS_REACHABLE(CONFIG_DVB_SP8870) extern struct dvb_frontend* sp8870_attach(const struct sp8870_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/sp887x.h b/drivers/media/dvb-frontends/sp887x.h index 2cdc4e8bc9cd..412f011e6dfd 100644 --- a/drivers/media/dvb-frontends/sp887x.h +++ b/drivers/media/dvb-frontends/sp887x.h @@ -17,7 +17,7 @@ struct sp887x_config int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); }; -#if IS_ENABLED(CONFIG_DVB_SP887X) +#if IS_REACHABLE(CONFIG_DVB_SP887X) extern struct dvb_frontend* sp887x_attach(const struct sp887x_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/stb0899_drv.h b/drivers/media/dvb-frontends/stb0899_drv.h index 139264d19263..0a72131a57db 100644 --- a/drivers/media/dvb-frontends/stb0899_drv.h +++ b/drivers/media/dvb-frontends/stb0899_drv.h @@ -141,7 +141,7 @@ struct stb0899_config { int (*tuner_set_rfsiggain)(struct dvb_frontend *fe, u32 rf_gain); }; -#if IS_ENABLED(CONFIG_DVB_STB0899) +#if IS_REACHABLE(CONFIG_DVB_STB0899) extern struct dvb_frontend *stb0899_attach(struct stb0899_config *config, struct i2c_adapter *i2c); diff --git a/drivers/media/dvb-frontends/stb6000.h b/drivers/media/dvb-frontends/stb6000.h index a768189bfaad..da581b652cb9 100644 --- a/drivers/media/dvb-frontends/stb6000.h +++ b/drivers/media/dvb-frontends/stb6000.h @@ -35,7 +35,7 @@ * @param i2c i2c adapter to use. * @return FE pointer on success, NULL on failure. */ -#if IS_ENABLED(CONFIG_DVB_STB6000) +#if IS_REACHABLE(CONFIG_DVB_STB6000) extern struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/stb6100.h b/drivers/media/dvb-frontends/stb6100.h index 3a1e40f3b8be..218c8188865d 100644 --- a/drivers/media/dvb-frontends/stb6100.h +++ b/drivers/media/dvb-frontends/stb6100.h @@ -94,7 +94,7 @@ struct stb6100_state { u32 reference; }; -#if IS_ENABLED(CONFIG_DVB_STB6100) +#if IS_REACHABLE(CONFIG_DVB_STB6100) extern struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe, const struct stb6100_config *config, diff --git a/drivers/media/dvb-frontends/stv0288.h b/drivers/media/dvb-frontends/stv0288.h index a0bd93107154..b58603c00c80 100644 --- a/drivers/media/dvb-frontends/stv0288.h +++ b/drivers/media/dvb-frontends/stv0288.h @@ -43,7 +43,7 @@ struct stv0288_config { int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured); }; -#if IS_ENABLED(CONFIG_DVB_STV0288) +#if IS_REACHABLE(CONFIG_DVB_STV0288) extern struct dvb_frontend *stv0288_attach(const struct stv0288_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/stv0297.h b/drivers/media/dvb-frontends/stv0297.h index c8ff3639ce00..b30632a67333 100644 --- a/drivers/media/dvb-frontends/stv0297.h +++ b/drivers/media/dvb-frontends/stv0297.h @@ -42,7 +42,7 @@ struct stv0297_config u8 stop_during_read:1; }; -#if IS_ENABLED(CONFIG_DVB_STV0297) +#if IS_REACHABLE(CONFIG_DVB_STV0297) extern struct dvb_frontend* stv0297_attach(const struct stv0297_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/stv0299.h b/drivers/media/dvb-frontends/stv0299.h index 06f70fc8327b..0aca30a8ec25 100644 --- a/drivers/media/dvb-frontends/stv0299.h +++ b/drivers/media/dvb-frontends/stv0299.h @@ -95,7 +95,7 @@ struct stv0299_config int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured); }; -#if IS_ENABLED(CONFIG_DVB_STV0299) +#if IS_REACHABLE(CONFIG_DVB_STV0299) extern struct dvb_frontend *stv0299_attach(const struct stv0299_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/stv0367.h b/drivers/media/dvb-frontends/stv0367.h index ea80b341f094..92b3e85fb818 100644 --- a/drivers/media/dvb-frontends/stv0367.h +++ b/drivers/media/dvb-frontends/stv0367.h @@ -39,7 +39,7 @@ struct stv0367_config { int clk_pol; }; -#if IS_ENABLED(CONFIG_DVB_STV0367) +#if IS_REACHABLE(CONFIG_DVB_STV0367) extern struct dvb_frontend *stv0367ter_attach(const struct stv0367_config *config, struct i2c_adapter *i2c); diff --git a/drivers/media/dvb-frontends/stv0900.h b/drivers/media/dvb-frontends/stv0900.h index e2a6dc69ecb4..c90bf00ea9ce 100644 --- a/drivers/media/dvb-frontends/stv0900.h +++ b/drivers/media/dvb-frontends/stv0900.h @@ -58,7 +58,7 @@ struct stv0900_config { void (*set_lock_led)(struct dvb_frontend *fe, int offon); }; -#if IS_ENABLED(CONFIG_DVB_STV0900) +#if IS_REACHABLE(CONFIG_DVB_STV0900) extern struct dvb_frontend *stv0900_attach(const struct stv0900_config *config, struct i2c_adapter *i2c, int demod); #else diff --git a/drivers/media/dvb-frontends/stv090x.h b/drivers/media/dvb-frontends/stv090x.h index 742eeda99000..012e55e5032e 100644 --- a/drivers/media/dvb-frontends/stv090x.h +++ b/drivers/media/dvb-frontends/stv090x.h @@ -107,7 +107,7 @@ struct stv090x_config { u8 xor_value); }; -#if IS_ENABLED(CONFIG_DVB_STV090x) +#if IS_REACHABLE(CONFIG_DVB_STV090x) struct dvb_frontend *stv090x_attach(struct stv090x_config *config, struct i2c_adapter *i2c, diff --git a/drivers/media/dvb-frontends/stv6110.h b/drivers/media/dvb-frontends/stv6110.h index 8fa07e6a6745..f3c8a5c6b77d 100644 --- a/drivers/media/dvb-frontends/stv6110.h +++ b/drivers/media/dvb-frontends/stv6110.h @@ -46,7 +46,7 @@ struct stv6110_config { u8 clk_div; /* divisor value for the output clock */ }; -#if IS_ENABLED(CONFIG_DVB_STV6110) +#if IS_REACHABLE(CONFIG_DVB_STV6110) extern struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe, const struct stv6110_config *config, struct i2c_adapter *i2c); diff --git a/drivers/media/dvb-frontends/stv6110x.h b/drivers/media/dvb-frontends/stv6110x.h index bc4766db29c5..9f7eb251aec3 100644 --- a/drivers/media/dvb-frontends/stv6110x.h +++ b/drivers/media/dvb-frontends/stv6110x.h @@ -53,7 +53,7 @@ struct stv6110x_devctl { }; -#if IS_ENABLED(CONFIG_DVB_STV6110x) +#if IS_REACHABLE(CONFIG_DVB_STV6110x) extern struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe, const struct stv6110x_config *config, diff --git a/drivers/media/dvb-frontends/tda1002x.h b/drivers/media/dvb-frontends/tda1002x.h index e404b6e44802..0d334613de1b 100644 --- a/drivers/media/dvb-frontends/tda1002x.h +++ b/drivers/media/dvb-frontends/tda1002x.h @@ -57,7 +57,7 @@ struct tda10023_config { u16 deltaf; }; -#if IS_ENABLED(CONFIG_DVB_TDA10021) +#if IS_REACHABLE(CONFIG_DVB_TDA10021) extern struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config, struct i2c_adapter* i2c, u8 pwm); #else @@ -69,7 +69,7 @@ static inline struct dvb_frontend* tda10021_attach(const struct tda1002x_config* } #endif // CONFIG_DVB_TDA10021 -#if IS_ENABLED(CONFIG_DVB_TDA10023) +#if IS_REACHABLE(CONFIG_DVB_TDA10023) extern struct dvb_frontend *tda10023_attach( const struct tda10023_config *config, struct i2c_adapter *i2c, u8 pwm); diff --git a/drivers/media/dvb-frontends/tda10048.h b/drivers/media/dvb-frontends/tda10048.h index 5e7bf4e47cb3..bc77a7311de1 100644 --- a/drivers/media/dvb-frontends/tda10048.h +++ b/drivers/media/dvb-frontends/tda10048.h @@ -73,7 +73,7 @@ struct tda10048_config { u8 pll_n; }; -#if IS_ENABLED(CONFIG_DVB_TDA10048) +#if IS_REACHABLE(CONFIG_DVB_TDA10048) extern struct dvb_frontend *tda10048_attach( const struct tda10048_config *config, struct i2c_adapter *i2c); diff --git a/drivers/media/dvb-frontends/tda1004x.h b/drivers/media/dvb-frontends/tda1004x.h index dd283fbb61c0..efd7659dace9 100644 --- a/drivers/media/dvb-frontends/tda1004x.h +++ b/drivers/media/dvb-frontends/tda1004x.h @@ -117,7 +117,7 @@ struct tda1004x_state { enum tda1004x_demod demod_type; }; -#if IS_ENABLED(CONFIG_DVB_TDA1004X) +#if IS_REACHABLE(CONFIG_DVB_TDA1004X) extern struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config, struct i2c_adapter* i2c); diff --git a/drivers/media/dvb-frontends/tda10071.h b/drivers/media/dvb-frontends/tda10071.h index 331b5a819383..da89f4249846 100644 --- a/drivers/media/dvb-frontends/tda10071.h +++ b/drivers/media/dvb-frontends/tda10071.h @@ -72,7 +72,7 @@ struct tda10071_config { }; -#if IS_ENABLED(CONFIG_DVB_TDA10071) +#if IS_REACHABLE(CONFIG_DVB_TDA10071) extern struct dvb_frontend *tda10071_attach( const struct tda10071_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/tda10071_priv.h b/drivers/media/dvb-frontends/tda10071_priv.h index 420486192736..03f839c431e9 100644 --- a/drivers/media/dvb-frontends/tda10071_priv.h +++ b/drivers/media/dvb-frontends/tda10071_priv.h @@ -99,7 +99,7 @@ struct tda10071_reg_val_mask { #define CMD_BER_CONTROL 0x3e #define CMD_BER_UPDATE_COUNTERS 0x3f -/* firmare command struct */ +/* firmware command struct */ #define TDA10071_ARGLEN 30 struct tda10071_cmd { u8 args[TDA10071_ARGLEN]; diff --git a/drivers/media/dvb-frontends/tda10086.h b/drivers/media/dvb-frontends/tda10086.h index 458fe91c1b88..690e469995b6 100644 --- a/drivers/media/dvb-frontends/tda10086.h +++ b/drivers/media/dvb-frontends/tda10086.h @@ -46,7 +46,7 @@ struct tda10086_config enum tda10086_xtal xtal_freq; }; -#if IS_ENABLED(CONFIG_DVB_TDA10086) +#if IS_REACHABLE(CONFIG_DVB_TDA10086) extern struct dvb_frontend* tda10086_attach(const struct tda10086_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/tda18271c2dd.h b/drivers/media/dvb-frontends/tda18271c2dd.h index dd84f7b69bec..7ebd8eaff4eb 100644 --- a/drivers/media/dvb-frontends/tda18271c2dd.h +++ b/drivers/media/dvb-frontends/tda18271c2dd.h @@ -3,7 +3,7 @@ #include <linux/kconfig.h> -#if IS_ENABLED(CONFIG_DVB_TDA18271C2DD) +#if IS_REACHABLE(CONFIG_DVB_TDA18271C2DD) struct dvb_frontend *tda18271c2dd_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 adr); #else diff --git a/drivers/media/dvb-frontends/tda665x.h b/drivers/media/dvb-frontends/tda665x.h index 03a0da6d5cf2..baf520baa42e 100644 --- a/drivers/media/dvb-frontends/tda665x.h +++ b/drivers/media/dvb-frontends/tda665x.h @@ -31,7 +31,7 @@ struct tda665x_config { u32 ref_divider; }; -#if IS_ENABLED(CONFIG_DVB_TDA665x) +#if IS_REACHABLE(CONFIG_DVB_TDA665x) extern struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe, const struct tda665x_config *config, diff --git a/drivers/media/dvb-frontends/tda8083.h b/drivers/media/dvb-frontends/tda8083.h index de6b1860dfdd..46be06fa7e0d 100644 --- a/drivers/media/dvb-frontends/tda8083.h +++ b/drivers/media/dvb-frontends/tda8083.h @@ -35,7 +35,7 @@ struct tda8083_config u8 demod_address; }; -#if IS_ENABLED(CONFIG_DVB_TDA8083) +#if IS_REACHABLE(CONFIG_DVB_TDA8083) extern struct dvb_frontend* tda8083_attach(const struct tda8083_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/tda8261.h b/drivers/media/dvb-frontends/tda8261.h index 55cf4ffcbfdf..9fa5b3076d5b 100644 --- a/drivers/media/dvb-frontends/tda8261.h +++ b/drivers/media/dvb-frontends/tda8261.h @@ -34,7 +34,7 @@ struct tda8261_config { enum tda8261_step step_size; }; -#if IS_ENABLED(CONFIG_DVB_TDA8261) +#if IS_REACHABLE(CONFIG_DVB_TDA8261) extern struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe, const struct tda8261_config *config, diff --git a/drivers/media/dvb-frontends/tda826x.h b/drivers/media/dvb-frontends/tda826x.h index 5f0f20e7e4f8..81abe1aebe9f 100644 --- a/drivers/media/dvb-frontends/tda826x.h +++ b/drivers/media/dvb-frontends/tda826x.h @@ -35,7 +35,7 @@ * @param has_loopthrough Set to 1 if the card has a loopthrough RF connector. * @return FE pointer on success, NULL on failure. */ -#if IS_ENABLED(CONFIG_DVB_TDA826X) +#if IS_REACHABLE(CONFIG_DVB_TDA826X) extern struct dvb_frontend* tda826x_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c, int has_loopthrough); diff --git a/drivers/media/dvb-frontends/ts2020.c b/drivers/media/dvb-frontends/ts2020.c index 9aba044dabed..90164a38cd36 100644 --- a/drivers/media/dvb-frontends/ts2020.c +++ b/drivers/media/dvb-frontends/ts2020.c @@ -26,12 +26,23 @@ #define FREQ_OFFSET_LOW_SYM_RATE 3000 struct ts2020_priv { + struct dvb_frontend *fe; /* i2c details */ int i2c_address; struct i2c_adapter *i2c; - u8 clk_out_div; + u8 clk_out:2; + u8 clk_out_div:5; u32 frequency; u32 frequency_div; +#define TS2020_M88TS2020 0 +#define TS2020_M88TS2022 1 + u8 tuner; + u8 loop_through:1; +}; + +struct ts2020_reg_val { + u8 reg; + u8 val; }; static int ts2020_release(struct dvb_frontend *fe) @@ -112,40 +123,77 @@ static int ts2020_readreg(struct dvb_frontend *fe, u8 reg) static int ts2020_sleep(struct dvb_frontend *fe) { struct ts2020_priv *priv = fe->tuner_priv; - int ret; - u8 buf[] = { 10, 0 }; - struct i2c_msg msg = { - .addr = priv->i2c_address, - .flags = 0, - .buf = buf, - .len = 2 - }; + u8 u8tmp; - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - - ret = i2c_transfer(priv->i2c, &msg, 1); - if (ret != 1) - printk(KERN_ERR "%s: i2c error\n", __func__); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); + if (priv->tuner == TS2020_M88TS2020) + u8tmp = 0x0a; /* XXX: probably wrong */ + else + u8tmp = 0x00; - return (ret == 1) ? 0 : ret; + return ts2020_writereg(fe, u8tmp, 0x00); } static int ts2020_init(struct dvb_frontend *fe) { struct ts2020_priv *priv = fe->tuner_priv; + int i; + u8 u8tmp; + + if (priv->tuner == TS2020_M88TS2020) { + ts2020_writereg(fe, 0x42, 0x73); + ts2020_writereg(fe, 0x05, priv->clk_out_div); + ts2020_writereg(fe, 0x20, 0x27); + ts2020_writereg(fe, 0x07, 0x02); + ts2020_writereg(fe, 0x11, 0xff); + ts2020_writereg(fe, 0x60, 0xf9); + ts2020_writereg(fe, 0x08, 0x01); + ts2020_writereg(fe, 0x00, 0x41); + } else { + static const struct ts2020_reg_val reg_vals[] = { + {0x7d, 0x9d}, + {0x7c, 0x9a}, + {0x7a, 0x76}, + {0x3b, 0x01}, + {0x63, 0x88}, + {0x61, 0x85}, + {0x22, 0x30}, + {0x30, 0x40}, + {0x20, 0x23}, + {0x24, 0x02}, + {0x12, 0xa0}, + }; + + ts2020_writereg(fe, 0x00, 0x01); + ts2020_writereg(fe, 0x00, 0x03); + + switch (priv->clk_out) { + case TS2020_CLK_OUT_DISABLED: + u8tmp = 0x60; + break; + case TS2020_CLK_OUT_ENABLED: + u8tmp = 0x70; + ts2020_writereg(fe, 0x05, priv->clk_out_div); + break; + case TS2020_CLK_OUT_ENABLED_XTALOUT: + u8tmp = 0x6c; + break; + default: + u8tmp = 0x60; + break; + } - ts2020_writereg(fe, 0x42, 0x73); - ts2020_writereg(fe, 0x05, priv->clk_out_div); - ts2020_writereg(fe, 0x20, 0x27); - ts2020_writereg(fe, 0x07, 0x02); - ts2020_writereg(fe, 0x11, 0xff); - ts2020_writereg(fe, 0x60, 0xf9); - ts2020_writereg(fe, 0x08, 0x01); - ts2020_writereg(fe, 0x00, 0x41); + ts2020_writereg(fe, 0x42, u8tmp); + + if (priv->loop_through) + u8tmp = 0xec; + else + u8tmp = 0x6c; + + ts2020_writereg(fe, 0x62, u8tmp); + + for (i = 0; i < ARRAY_SIZE(reg_vals); i++) + ts2020_writereg(fe, reg_vals[i].reg, reg_vals[i].val); + } return 0; } @@ -203,7 +251,14 @@ static int ts2020_set_params(struct dvb_frontend *fe) ndiv = ndiv + ndiv % 2; ndiv = ndiv - 1024; - ret = ts2020_writereg(fe, 0x10, 0x80 | lo); + if (priv->tuner == TS2020_M88TS2020) { + lpf_coeff = 2766; + ret = ts2020_writereg(fe, 0x10, 0x80 | lo); + } else { + lpf_coeff = 3200; + ret = ts2020_writereg(fe, 0x10, 0x0b); + ret |= ts2020_writereg(fe, 0x11, 0x40); + } /* Set frequency divider */ ret |= ts2020_writereg(fe, 0x01, (ndiv >> 8) & 0xf); @@ -220,7 +275,8 @@ static int ts2020_set_params(struct dvb_frontend *fe) ret |= ts2020_tuner_gate_ctrl(fe, 0x08); /* Tuner RF */ - ret |= ts2020_set_tuner_rf(fe); + if (priv->tuner == TS2020_M88TS2020) + ret |= ts2020_set_tuner_rf(fe); gdiv28 = (TS2020_XTAL_FREQ / 1000 * 1694 + 500) / 1000; ret |= ts2020_writereg(fe, 0x04, gdiv28 & 0xff); @@ -228,6 +284,15 @@ static int ts2020_set_params(struct dvb_frontend *fe) if (ret < 0) return -ENODEV; + if (priv->tuner == TS2020_M88TS2022) { + ret = ts2020_writereg(fe, 0x25, 0x00); + ret |= ts2020_writereg(fe, 0x27, 0x70); + ret |= ts2020_writereg(fe, 0x41, 0x09); + ret |= ts2020_writereg(fe, 0x08, 0x0b); + if (ret < 0) + return -ENODEV; + } + value = ts2020_readreg(fe, 0x26); f3db = (symbol_rate * 135) / 200 + 2000; @@ -243,8 +308,6 @@ static int ts2020_set_params(struct dvb_frontend *fe) if (mlpf_max > 63) mlpf_max = 63; - lpf_coeff = 2766; - nlpf = (f3db * gdiv28 * 2 / lpf_coeff / (TS2020_XTAL_FREQ / 1000) + 1) / 2; if (nlpf > 23) @@ -285,6 +348,13 @@ static int ts2020_get_frequency(struct dvb_frontend *fe, u32 *frequency) { struct ts2020_priv *priv = fe->tuner_priv; *frequency = priv->frequency; + + return 0; +} + +static int ts2020_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + *frequency = 0; /* Zero-IF */ return 0; } @@ -324,6 +394,7 @@ static struct dvb_tuner_ops ts2020_tuner_ops = { .sleep = ts2020_sleep, .set_params = ts2020_set_params, .get_frequency = ts2020_get_frequency, + .get_if_frequency = ts2020_get_if_frequency, .get_rf_strength = ts2020_read_signal_strength, }; @@ -340,8 +411,10 @@ struct dvb_frontend *ts2020_attach(struct dvb_frontend *fe, priv->i2c_address = config->tuner_address; priv->i2c = i2c; + priv->clk_out = config->clk_out; priv->clk_out_div = config->clk_out_div; priv->frequency_div = config->frequency_div; + priv->fe = fe; fe->tuner_priv = priv; if (!priv->frequency_div) @@ -358,9 +431,13 @@ struct dvb_frontend *ts2020_attach(struct dvb_frontend *fe, /* Check the tuner version */ buf = ts2020_readreg(fe, 0x00); - if ((buf == 0x01) || (buf == 0x41) || (buf == 0x81)) + if ((buf == 0x01) || (buf == 0x41) || (buf == 0x81)) { printk(KERN_INFO "%s: Find tuner TS2020!\n", __func__); - else { + priv->tuner = TS2020_M88TS2020; + } else if ((buf == 0x83) || (buf == 0xc3)) { + printk(KERN_INFO "%s: Find tuner TS2022!\n", __func__); + priv->tuner = TS2020_M88TS2022; + } else { printk(KERN_ERR "%s: Read tuner reg[0] = %d\n", __func__, buf); kfree(priv); return NULL; @@ -373,6 +450,165 @@ struct dvb_frontend *ts2020_attach(struct dvb_frontend *fe, } EXPORT_SYMBOL(ts2020_attach); +static int ts2020_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ts2020_config *pdata = client->dev.platform_data; + struct dvb_frontend *fe = pdata->fe; + struct ts2020_priv *dev; + int ret; + u8 u8tmp; + unsigned int utmp; + char *chip_str; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + ret = -ENOMEM; + goto err; + } + + dev->i2c = client->adapter; + dev->i2c_address = client->addr; + dev->clk_out = pdata->clk_out; + dev->clk_out_div = pdata->clk_out_div; + dev->frequency_div = pdata->frequency_div; + dev->fe = fe; + fe->tuner_priv = dev; + + /* check if the tuner is there */ + ret = ts2020_readreg(fe, 0x00); + if (ret < 0) + goto err; + utmp = ret; + + if ((utmp & 0x03) == 0x00) { + ret = ts2020_writereg(fe, 0x00, 0x01); + if (ret) + goto err; + + usleep_range(2000, 50000); + } + + ret = ts2020_writereg(fe, 0x00, 0x03); + if (ret) + goto err; + + usleep_range(2000, 50000); + + ret = ts2020_readreg(fe, 0x00); + if (ret < 0) + goto err; + utmp = ret; + + dev_dbg(&client->dev, "chip_id=%02x\n", utmp); + + switch (utmp) { + case 0x01: + case 0x41: + case 0x81: + dev->tuner = TS2020_M88TS2020; + chip_str = "TS2020"; + if (!dev->frequency_div) + dev->frequency_div = 1060000; + break; + case 0xc3: + case 0x83: + dev->tuner = TS2020_M88TS2022; + chip_str = "TS2022"; + if (!dev->frequency_div) + dev->frequency_div = 1103000; + break; + default: + ret = -ENODEV; + goto err; + } + + if (dev->tuner == TS2020_M88TS2022) { + switch (dev->clk_out) { + case TS2020_CLK_OUT_DISABLED: + u8tmp = 0x60; + break; + case TS2020_CLK_OUT_ENABLED: + u8tmp = 0x70; + ret = ts2020_writereg(fe, 0x05, dev->clk_out_div); + if (ret) + goto err; + break; + case TS2020_CLK_OUT_ENABLED_XTALOUT: + u8tmp = 0x6c; + break; + default: + ret = -EINVAL; + goto err; + } + + ret = ts2020_writereg(fe, 0x42, u8tmp); + if (ret) + goto err; + + if (dev->loop_through) + u8tmp = 0xec; + else + u8tmp = 0x6c; + + ret = ts2020_writereg(fe, 0x62, u8tmp); + if (ret) + goto err; + } + + /* sleep */ + ret = ts2020_writereg(fe, 0x00, 0x00); + if (ret) + goto err; + + dev_info(&client->dev, + "Montage Technology %s successfully identified\n", chip_str); + + memcpy(&fe->ops.tuner_ops, &ts2020_tuner_ops, + sizeof(struct dvb_tuner_ops)); + fe->ops.tuner_ops.release = NULL; + + i2c_set_clientdata(client, dev); + return 0; +err: + dev_dbg(&client->dev, "failed=%d\n", ret); + kfree(dev); + return ret; +} + +static int ts2020_remove(struct i2c_client *client) +{ + struct ts2020_priv *dev = i2c_get_clientdata(client); + struct dvb_frontend *fe = dev->fe; + + dev_dbg(&client->dev, "\n"); + + memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); + fe->tuner_priv = NULL; + kfree(dev); + + return 0; +} + +static const struct i2c_device_id ts2020_id_table[] = { + {"ts2020", 0}, + {"ts2022", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, ts2020_id_table); + +static struct i2c_driver ts2020_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "ts2020", + }, + .probe = ts2020_probe, + .remove = ts2020_remove, + .id_table = ts2020_id_table, +}; + +module_i2c_driver(ts2020_driver); + MODULE_AUTHOR("Konstantin Dimitrov <kosio.dimitrov@gmail.com>"); MODULE_DESCRIPTION("Montage Technology TS2020 - Silicon tuner driver module"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb-frontends/ts2020.h b/drivers/media/dvb-frontends/ts2020.h index b2fe6bb3a38b..1714af94eca2 100644 --- a/drivers/media/dvb-frontends/ts2020.h +++ b/drivers/media/dvb-frontends/ts2020.h @@ -27,11 +27,34 @@ struct ts2020_config { u8 tuner_address; - u8 clk_out_div; u32 frequency_div; + + /* + * RF loop-through + */ + u8 loop_through:1; + + /* + * clock output + */ +#define TS2020_CLK_OUT_DISABLED 0 +#define TS2020_CLK_OUT_ENABLED 1 +#define TS2020_CLK_OUT_ENABLED_XTALOUT 2 + u8 clk_out:2; + + /* + * clock output divider + * 1 - 31 + */ + u8 clk_out_div:5; + + /* + * pointer to DVB frontend + */ + struct dvb_frontend *fe; }; -#if IS_ENABLED(CONFIG_DVB_TS2020) +#if IS_REACHABLE(CONFIG_DVB_TS2020) extern struct dvb_frontend *ts2020_attach( struct dvb_frontend *fe, diff --git a/drivers/media/dvb-frontends/tua6100.h b/drivers/media/dvb-frontends/tua6100.h index 83a9c30e67ca..52919e04e258 100644 --- a/drivers/media/dvb-frontends/tua6100.h +++ b/drivers/media/dvb-frontends/tua6100.h @@ -34,7 +34,7 @@ #include <linux/i2c.h> #include "dvb_frontend.h" -#if IS_ENABLED(CONFIG_DVB_TUA6100) +#if IS_REACHABLE(CONFIG_DVB_TUA6100) extern struct dvb_frontend *tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c); #else static inline struct dvb_frontend* tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c) diff --git a/drivers/media/dvb-frontends/ves1820.h b/drivers/media/dvb-frontends/ves1820.h index c073f353ac38..ece46fdcd714 100644 --- a/drivers/media/dvb-frontends/ves1820.h +++ b/drivers/media/dvb-frontends/ves1820.h @@ -41,7 +41,7 @@ struct ves1820_config u8 selagc:1; }; -#if IS_ENABLED(CONFIG_DVB_VES1820) +#if IS_REACHABLE(CONFIG_DVB_VES1820) extern struct dvb_frontend* ves1820_attach(const struct ves1820_config* config, struct i2c_adapter* i2c, u8 pwm); #else diff --git a/drivers/media/dvb-frontends/ves1x93.h b/drivers/media/dvb-frontends/ves1x93.h index 2307caea6aec..4510fe2f6676 100644 --- a/drivers/media/dvb-frontends/ves1x93.h +++ b/drivers/media/dvb-frontends/ves1x93.h @@ -40,7 +40,7 @@ struct ves1x93_config u8 invert_pwm:1; }; -#if IS_ENABLED(CONFIG_DVB_VES1X93) +#if IS_REACHABLE(CONFIG_DVB_VES1X93) extern struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config, struct i2c_adapter* i2c); #else diff --git a/drivers/media/dvb-frontends/zl10036.h b/drivers/media/dvb-frontends/zl10036.h index 5f1e8217eeb6..670e76a654ee 100644 --- a/drivers/media/dvb-frontends/zl10036.h +++ b/drivers/media/dvb-frontends/zl10036.h @@ -38,7 +38,7 @@ struct zl10036_config { int rf_loop_enable; }; -#if IS_ENABLED(CONFIG_DVB_ZL10036) +#if IS_REACHABLE(CONFIG_DVB_ZL10036) extern struct dvb_frontend *zl10036_attach(struct dvb_frontend *fe, const struct zl10036_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/zl10039.h b/drivers/media/dvb-frontends/zl10039.h index 750b9bca9d02..070929444e71 100644 --- a/drivers/media/dvb-frontends/zl10039.h +++ b/drivers/media/dvb-frontends/zl10039.h @@ -24,7 +24,7 @@ #include <linux/kconfig.h> -#if IS_ENABLED(CONFIG_DVB_ZL10039) +#if IS_REACHABLE(CONFIG_DVB_ZL10039) struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe, u8 i2c_addr, struct i2c_adapter *i2c); diff --git a/drivers/media/dvb-frontends/zl10353.h b/drivers/media/dvb-frontends/zl10353.h index 50c1004aef36..37aa6e8f454a 100644 --- a/drivers/media/dvb-frontends/zl10353.h +++ b/drivers/media/dvb-frontends/zl10353.h @@ -47,7 +47,7 @@ struct zl10353_config u8 pll_0; /* default: 0x15 */ }; -#if IS_ENABLED(CONFIG_DVB_ZL10353) +#if IS_REACHABLE(CONFIG_DVB_ZL10353) extern struct dvb_frontend* zl10353_attach(const struct zl10353_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index da58c9bb67c2..6f30ea76151a 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -466,6 +466,17 @@ config VIDEO_APTINA_PLL config VIDEO_SMIAPP_PLL tristate +config VIDEO_OV2659 + tristate "OmniVision OV2659 sensor support" + depends on VIDEO_V4L2 && I2C + depends on MEDIA_CAMERA_SUPPORT + ---help--- + This is a Video4Linux2 sensor-level driver for the OmniVision + OV2659 camera. + + To compile this driver as a module, choose M here: the + module will be called ov2659. + config VIDEO_OV7640 tristate "OmniVision OV7640 sensor support" depends on I2C && VIDEO_V4L2 diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 9858900168bf..f165faea5b3f 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -77,3 +77,4 @@ obj-$(CONFIG_VIDEO_SMIAPP_PLL) += smiapp-pll.o obj-$(CONFIG_VIDEO_AK881X) += ak881x.o obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o +obj-$(CONFIG_VIDEO_OV2659) += ov2659.o diff --git a/drivers/media/i2c/ad9389b.c b/drivers/media/i2c/ad9389b.c index fada17566205..69094ab047b1 100644 --- a/drivers/media/i2c/ad9389b.c +++ b/drivers/media/i2c/ad9389b.c @@ -239,8 +239,8 @@ static void ad9389b_set_IT_content_AVI_InfoFrame(struct v4l2_subdev *sd) { struct ad9389b_state *state = get_ad9389b_state(sd); - if (state->dv_timings.bt.standards & V4L2_DV_BT_STD_CEA861) { - /* CEA format, not IT */ + if (state->dv_timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) { + /* CE format, not IT */ ad9389b_wr_and_or(sd, 0xcd, 0xbf, 0x00); } else { /* IT format */ @@ -255,11 +255,11 @@ static int ad9389b_set_rgb_quantization_mode(struct v4l2_subdev *sd, struct v4l2 switch (ctrl->val) { case V4L2_DV_RGB_RANGE_AUTO: /* automatic */ - if (state->dv_timings.bt.standards & V4L2_DV_BT_STD_CEA861) { - /* cea format, RGB limited range (16-235) */ + if (state->dv_timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) { + /* CE format, RGB limited range (16-235) */ ad9389b_csc_rgb_full2limit(sd, true); } else { - /* not cea format, RGB full range (0-255) */ + /* not CE format, RGB full range (0-255) */ ad9389b_csc_rgb_full2limit(sd, false); } break; diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index b75878c27c2a..a493c0b0b5fe 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -582,7 +582,7 @@ static void adv7180_exit_controls(struct adv7180_state *state) } static int adv7180_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->index != 0) @@ -645,13 +645,13 @@ static int adv7180_set_field_mode(struct adv7180_state *state) } static int adv7180_get_pad_format(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { struct adv7180_state *state = to_state(sd); if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - format->format = *v4l2_subdev_get_try_format(fh, 0); + format->format = *v4l2_subdev_get_try_format(sd, cfg, 0); } else { adv7180_mbus_fmt(sd, &format->format); format->format.field = state->field; @@ -661,7 +661,7 @@ static int adv7180_get_pad_format(struct v4l2_subdev *sd, } static int adv7180_set_pad_format(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { struct adv7180_state *state = to_state(sd); @@ -686,7 +686,7 @@ static int adv7180_set_pad_format(struct v4l2_subdev *sd, adv7180_set_power(state, true); } } else { - framefmt = v4l2_subdev_get_try_format(fh, 0); + framefmt = v4l2_subdev_get_try_format(sd, cfg, 0); *framefmt = format->format; } diff --git a/drivers/media/i2c/adv7343.c b/drivers/media/i2c/adv7343.c index 9d38f7b36cd1..7c50833e7d17 100644 --- a/drivers/media/i2c/adv7343.c +++ b/drivers/media/i2c/adv7343.c @@ -506,7 +506,6 @@ static int adv7343_remove(struct i2c_client *client) struct adv7343_state *state = to_state(sd); v4l2_async_unregister_subdev(&state->sd); - v4l2_device_unregister_subdev(sd); v4l2_ctrl_handler_free(&state->hdl); return 0; diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c index 81736aaf0f31..12d93203d405 100644 --- a/drivers/media/i2c/adv7511.c +++ b/drivers/media/i2c/adv7511.c @@ -312,8 +312,8 @@ static void adv7511_csc_rgb_full2limit(struct v4l2_subdev *sd, bool enable) static void adv7511_set_IT_content_AVI_InfoFrame(struct v4l2_subdev *sd) { struct adv7511_state *state = get_adv7511_state(sd); - if (state->dv_timings.bt.standards & V4L2_DV_BT_STD_CEA861) { - /* CEA format, not IT */ + if (state->dv_timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) { + /* CE format, not IT */ adv7511_wr_and_or(sd, 0x57, 0x7f, 0x00); } else { /* IT format */ @@ -331,11 +331,11 @@ static int adv7511_set_rgb_quantization_mode(struct v4l2_subdev *sd, struct v4l2 /* automatic */ struct adv7511_state *state = get_adv7511_state(sd); - if (state->dv_timings.bt.standards & V4L2_DV_BT_STD_CEA861) { - /* cea format, RGB limited range (16-235) */ + if (state->dv_timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) { + /* CE format, RGB limited range (16-235) */ adv7511_csc_rgb_full2limit(sd, true); } else { - /* not cea format, RGB full range (0-255) */ + /* not CE format, RGB full range (0-255) */ adv7511_csc_rgb_full2limit(sd, false); } } @@ -810,7 +810,7 @@ static int adv7511_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) } static int adv7511_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->pad != 0) @@ -842,8 +842,9 @@ static void adv7511_fill_format(struct adv7511_state *state, format->field = V4L2_FIELD_NONE; } -static int adv7511_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_format *format) +static int adv7511_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { struct adv7511_state *state = get_adv7511_state(sd); @@ -855,7 +856,7 @@ static int adv7511_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, if (format->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *fmt; - fmt = v4l2_subdev_get_try_format(fh, format->pad); + fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); format->format.code = fmt->code; format->format.colorspace = fmt->colorspace; format->format.ycbcr_enc = fmt->ycbcr_enc; @@ -870,8 +871,9 @@ static int adv7511_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, return 0; } -static int adv7511_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_format *format) +static int adv7511_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { struct adv7511_state *state = get_adv7511_state(sd); /* @@ -905,7 +907,7 @@ static int adv7511_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, if (format->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *fmt; - fmt = v4l2_subdev_get_try_format(fh, format->pad); + fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); fmt->code = format->format.code; fmt->colorspace = format->format.colorspace; fmt->ycbcr_enc = format->format.ycbcr_enc; diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index d228b7c82310..60ffcf098bef 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -53,41 +53,41 @@ MODULE_AUTHOR("Mats Randgaard <mats.randgaard@cisco.com>"); MODULE_LICENSE("GPL"); /* ADV7604 system clock frequency */ -#define ADV7604_fsc (28636360) +#define ADV76XX_FSC (28636360) -#define ADV7604_RGB_OUT (1 << 1) +#define ADV76XX_RGB_OUT (1 << 1) -#define ADV7604_OP_FORMAT_SEL_8BIT (0 << 0) +#define ADV76XX_OP_FORMAT_SEL_8BIT (0 << 0) #define ADV7604_OP_FORMAT_SEL_10BIT (1 << 0) -#define ADV7604_OP_FORMAT_SEL_12BIT (2 << 0) +#define ADV76XX_OP_FORMAT_SEL_12BIT (2 << 0) -#define ADV7604_OP_MODE_SEL_SDR_422 (0 << 5) +#define ADV76XX_OP_MODE_SEL_SDR_422 (0 << 5) #define ADV7604_OP_MODE_SEL_DDR_422 (1 << 5) -#define ADV7604_OP_MODE_SEL_SDR_444 (2 << 5) +#define ADV76XX_OP_MODE_SEL_SDR_444 (2 << 5) #define ADV7604_OP_MODE_SEL_DDR_444 (3 << 5) -#define ADV7604_OP_MODE_SEL_SDR_422_2X (4 << 5) +#define ADV76XX_OP_MODE_SEL_SDR_422_2X (4 << 5) #define ADV7604_OP_MODE_SEL_ADI_CM (5 << 5) -#define ADV7604_OP_CH_SEL_GBR (0 << 5) -#define ADV7604_OP_CH_SEL_GRB (1 << 5) -#define ADV7604_OP_CH_SEL_BGR (2 << 5) -#define ADV7604_OP_CH_SEL_RGB (3 << 5) -#define ADV7604_OP_CH_SEL_BRG (4 << 5) -#define ADV7604_OP_CH_SEL_RBG (5 << 5) +#define ADV76XX_OP_CH_SEL_GBR (0 << 5) +#define ADV76XX_OP_CH_SEL_GRB (1 << 5) +#define ADV76XX_OP_CH_SEL_BGR (2 << 5) +#define ADV76XX_OP_CH_SEL_RGB (3 << 5) +#define ADV76XX_OP_CH_SEL_BRG (4 << 5) +#define ADV76XX_OP_CH_SEL_RBG (5 << 5) -#define ADV7604_OP_SWAP_CB_CR (1 << 0) +#define ADV76XX_OP_SWAP_CB_CR (1 << 0) -enum adv7604_type { +enum adv76xx_type { ADV7604, ADV7611, }; -struct adv7604_reg_seq { +struct adv76xx_reg_seq { unsigned int reg; u8 val; }; -struct adv7604_format_info { +struct adv76xx_format_info { u32 code; u8 op_ch_sel; bool rgb_out; @@ -95,8 +95,8 @@ struct adv7604_format_info { u8 op_format_sel; }; -struct adv7604_chip_info { - enum adv7604_type type; +struct adv76xx_chip_info { + enum adv76xx_type type; bool has_afe; unsigned int max_port; @@ -109,8 +109,9 @@ struct adv7604_chip_info { unsigned int cable_det_mask; unsigned int tdms_lock_mask; unsigned int fmt_change_digital_mask; + unsigned int cp_csc; - const struct adv7604_format_info *formats; + const struct adv76xx_format_info *formats; unsigned int nformats; void (*set_termination)(struct v4l2_subdev *sd, bool enable); @@ -119,7 +120,7 @@ struct adv7604_chip_info { unsigned int (*read_cable_det)(struct v4l2_subdev *sd); /* 0 = AFE, 1 = HDMI */ - const struct adv7604_reg_seq *recommended_settings[2]; + const struct adv76xx_reg_seq *recommended_settings[2]; unsigned int num_recommended_settings[2]; unsigned long page_mask; @@ -133,22 +134,22 @@ struct adv7604_chip_info { ********************************************************************** */ -struct adv7604_state { - const struct adv7604_chip_info *info; - struct adv7604_platform_data pdata; +struct adv76xx_state { + const struct adv76xx_chip_info *info; + struct adv76xx_platform_data pdata; struct gpio_desc *hpd_gpio[4]; struct v4l2_subdev sd; - struct media_pad pads[ADV7604_PAD_MAX]; + struct media_pad pads[ADV76XX_PAD_MAX]; unsigned int source_pad; struct v4l2_ctrl_handler hdl; - enum adv7604_pad selected_input; + enum adv76xx_pad selected_input; struct v4l2_dv_timings timings; - const struct adv7604_format_info *format; + const struct adv76xx_format_info *format; struct { u8 edid[256]; @@ -163,7 +164,7 @@ struct adv7604_state { bool restart_stdi_once; /* i2c clients */ - struct i2c_client *i2c_clients[ADV7604_PAGE_MAX]; + struct i2c_client *i2c_clients[ADV76XX_PAGE_MAX]; /* controls */ struct v4l2_ctrl *detect_tx_5v_ctrl; @@ -173,13 +174,13 @@ struct adv7604_state { struct v4l2_ctrl *rgb_quantization_range_ctrl; }; -static bool adv7604_has_afe(struct adv7604_state *state) +static bool adv76xx_has_afe(struct adv76xx_state *state) { return state->info->has_afe; } /* Supported CEA and DMT timings */ -static const struct v4l2_dv_timings adv7604_timings[] = { +static const struct v4l2_dv_timings adv76xx_timings[] = { V4L2_DV_BT_CEA_720X480P59_94, V4L2_DV_BT_CEA_720X576P50, V4L2_DV_BT_CEA_1280X720P24, @@ -243,14 +244,14 @@ static const struct v4l2_dv_timings adv7604_timings[] = { { }, }; -struct adv7604_video_standards { +struct adv76xx_video_standards { struct v4l2_dv_timings timings; u8 vid_std; u8 v_freq; }; /* sorted by number of lines */ -static const struct adv7604_video_standards adv7604_prim_mode_comp[] = { +static const struct adv76xx_video_standards adv7604_prim_mode_comp[] = { /* { V4L2_DV_BT_CEA_720X480P59_94, 0x0a, 0x00 }, TODO flickering */ { V4L2_DV_BT_CEA_720X576P50, 0x0b, 0x00 }, { V4L2_DV_BT_CEA_1280X720P50, 0x19, 0x01 }, @@ -265,7 +266,7 @@ static const struct adv7604_video_standards adv7604_prim_mode_comp[] = { }; /* sorted by number of lines */ -static const struct adv7604_video_standards adv7604_prim_mode_gr[] = { +static const struct adv76xx_video_standards adv7604_prim_mode_gr[] = { { V4L2_DV_BT_DMT_640X480P60, 0x08, 0x00 }, { V4L2_DV_BT_DMT_640X480P72, 0x09, 0x00 }, { V4L2_DV_BT_DMT_640X480P75, 0x0a, 0x00 }, @@ -293,7 +294,7 @@ static const struct adv7604_video_standards adv7604_prim_mode_gr[] = { }; /* sorted by number of lines */ -static const struct adv7604_video_standards adv7604_prim_mode_hdmi_comp[] = { +static const struct adv76xx_video_standards adv76xx_prim_mode_hdmi_comp[] = { { V4L2_DV_BT_CEA_720X480P59_94, 0x0a, 0x00 }, { V4L2_DV_BT_CEA_720X576P50, 0x0b, 0x00 }, { V4L2_DV_BT_CEA_1280X720P50, 0x13, 0x01 }, @@ -307,7 +308,7 @@ static const struct adv7604_video_standards adv7604_prim_mode_hdmi_comp[] = { }; /* sorted by number of lines */ -static const struct adv7604_video_standards adv7604_prim_mode_hdmi_gr[] = { +static const struct adv76xx_video_standards adv76xx_prim_mode_hdmi_gr[] = { { V4L2_DV_BT_DMT_640X480P60, 0x08, 0x00 }, { V4L2_DV_BT_DMT_640X480P72, 0x09, 0x00 }, { V4L2_DV_BT_DMT_640X480P75, 0x0a, 0x00 }, @@ -328,9 +329,9 @@ static const struct adv7604_video_standards adv7604_prim_mode_hdmi_gr[] = { /* ----------------------------------------------------------------------- */ -static inline struct adv7604_state *to_state(struct v4l2_subdev *sd) +static inline struct adv76xx_state *to_state(struct v4l2_subdev *sd) { - return container_of(sd, struct adv7604_state, sd); + return container_of(sd, struct adv76xx_state, sd); } static inline unsigned htotal(const struct v4l2_bt_timings *t) @@ -360,15 +361,15 @@ static s32 adv_smbus_read_byte_data_check(struct i2c_client *client, return -EIO; } -static s32 adv_smbus_read_byte_data(struct adv7604_state *state, - enum adv7604_page page, u8 command) +static s32 adv_smbus_read_byte_data(struct adv76xx_state *state, + enum adv76xx_page page, u8 command) { return adv_smbus_read_byte_data_check(state->i2c_clients[page], command, true); } -static s32 adv_smbus_write_byte_data(struct adv7604_state *state, - enum adv7604_page page, u8 command, +static s32 adv_smbus_write_byte_data(struct adv76xx_state *state, + enum adv76xx_page page, u8 command, u8 value) { struct i2c_client *client = state->i2c_clients[page]; @@ -391,8 +392,8 @@ static s32 adv_smbus_write_byte_data(struct adv7604_state *state, return err; } -static s32 adv_smbus_write_i2c_block_data(struct adv7604_state *state, - enum adv7604_page page, u8 command, +static s32 adv_smbus_write_i2c_block_data(struct adv76xx_state *state, + enum adv76xx_page page, u8 command, unsigned length, const u8 *values) { struct i2c_client *client = state->i2c_clients[page]; @@ -411,16 +412,16 @@ static s32 adv_smbus_write_i2c_block_data(struct adv7604_state *state, static inline int io_read(struct v4l2_subdev *sd, u8 reg) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV7604_PAGE_IO, reg); + return adv_smbus_read_byte_data(state, ADV76XX_PAGE_IO, reg); } static inline int io_write(struct v4l2_subdev *sd, u8 reg, u8 val) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV7604_PAGE_IO, reg, val); + return adv_smbus_write_byte_data(state, ADV76XX_PAGE_IO, reg, val); } static inline int io_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) @@ -430,73 +431,73 @@ static inline int io_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 v static inline int avlink_read(struct v4l2_subdev *sd, u8 reg) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); return adv_smbus_read_byte_data(state, ADV7604_PAGE_AVLINK, reg); } static inline int avlink_write(struct v4l2_subdev *sd, u8 reg, u8 val) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); return adv_smbus_write_byte_data(state, ADV7604_PAGE_AVLINK, reg, val); } static inline int cec_read(struct v4l2_subdev *sd, u8 reg) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV7604_PAGE_CEC, reg); + return adv_smbus_read_byte_data(state, ADV76XX_PAGE_CEC, reg); } static inline int cec_write(struct v4l2_subdev *sd, u8 reg, u8 val) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV7604_PAGE_CEC, reg, val); + return adv_smbus_write_byte_data(state, ADV76XX_PAGE_CEC, reg, val); } static inline int infoframe_read(struct v4l2_subdev *sd, u8 reg) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV7604_PAGE_INFOFRAME, reg); + return adv_smbus_read_byte_data(state, ADV76XX_PAGE_INFOFRAME, reg); } static inline int infoframe_write(struct v4l2_subdev *sd, u8 reg, u8 val) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV7604_PAGE_INFOFRAME, + return adv_smbus_write_byte_data(state, ADV76XX_PAGE_INFOFRAME, reg, val); } static inline int afe_read(struct v4l2_subdev *sd, u8 reg) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV7604_PAGE_AFE, reg); + return adv_smbus_read_byte_data(state, ADV76XX_PAGE_AFE, reg); } static inline int afe_write(struct v4l2_subdev *sd, u8 reg, u8 val) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV7604_PAGE_AFE, reg, val); + return adv_smbus_write_byte_data(state, ADV76XX_PAGE_AFE, reg, val); } static inline int rep_read(struct v4l2_subdev *sd, u8 reg) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV7604_PAGE_REP, reg); + return adv_smbus_read_byte_data(state, ADV76XX_PAGE_REP, reg); } static inline int rep_write(struct v4l2_subdev *sd, u8 reg, u8 val) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV7604_PAGE_REP, reg, val); + return adv_smbus_write_byte_data(state, ADV76XX_PAGE_REP, reg, val); } static inline int rep_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) @@ -506,64 +507,60 @@ static inline int rep_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 static inline int edid_read(struct v4l2_subdev *sd, u8 reg) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV7604_PAGE_EDID, reg); + return adv_smbus_read_byte_data(state, ADV76XX_PAGE_EDID, reg); } static inline int edid_write(struct v4l2_subdev *sd, u8 reg, u8 val) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV7604_PAGE_EDID, reg, val); + return adv_smbus_write_byte_data(state, ADV76XX_PAGE_EDID, reg, val); } static inline int edid_write_block(struct v4l2_subdev *sd, unsigned len, const u8 *val) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); int err = 0; int i; v4l2_dbg(2, debug, sd, "%s: write EDID block (%d byte)\n", __func__, len); for (i = 0; !err && i < len; i += I2C_SMBUS_BLOCK_MAX) - err = adv_smbus_write_i2c_block_data(state, ADV7604_PAGE_EDID, + err = adv_smbus_write_i2c_block_data(state, ADV76XX_PAGE_EDID, i, I2C_SMBUS_BLOCK_MAX, val + i); return err; } -static void adv7604_set_hpd(struct adv7604_state *state, unsigned int hpd) +static void adv76xx_set_hpd(struct adv76xx_state *state, unsigned int hpd) { unsigned int i; - for (i = 0; i < state->info->num_dv_ports; ++i) { - if (IS_ERR(state->hpd_gpio[i])) - continue; - + for (i = 0; i < state->info->num_dv_ports; ++i) gpiod_set_value_cansleep(state->hpd_gpio[i], hpd & BIT(i)); - } - v4l2_subdev_notify(&state->sd, ADV7604_HOTPLUG, &hpd); + v4l2_subdev_notify(&state->sd, ADV76XX_HOTPLUG, &hpd); } -static void adv7604_delayed_work_enable_hotplug(struct work_struct *work) +static void adv76xx_delayed_work_enable_hotplug(struct work_struct *work) { struct delayed_work *dwork = to_delayed_work(work); - struct adv7604_state *state = container_of(dwork, struct adv7604_state, + struct adv76xx_state *state = container_of(dwork, struct adv76xx_state, delayed_work_enable_hotplug); struct v4l2_subdev *sd = &state->sd; v4l2_dbg(2, debug, sd, "%s: enable hotplug\n", __func__); - adv7604_set_hpd(state, state->edid.present); + adv76xx_set_hpd(state, state->edid.present); } static inline int hdmi_read(struct v4l2_subdev *sd, u8 reg) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV7604_PAGE_HDMI, reg); + return adv_smbus_read_byte_data(state, ADV76XX_PAGE_HDMI, reg); } static u16 hdmi_read16(struct v4l2_subdev *sd, u8 reg, u16 mask) @@ -573,9 +570,9 @@ static u16 hdmi_read16(struct v4l2_subdev *sd, u8 reg, u16 mask) static inline int hdmi_write(struct v4l2_subdev *sd, u8 reg, u8 val) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV7604_PAGE_HDMI, reg, val); + return adv_smbus_write_byte_data(state, ADV76XX_PAGE_HDMI, reg, val); } static inline int hdmi_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) @@ -585,16 +582,16 @@ static inline int hdmi_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 static inline int test_write(struct v4l2_subdev *sd, u8 reg, u8 val) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV7604_PAGE_TEST, reg, val); + return adv_smbus_write_byte_data(state, ADV76XX_PAGE_TEST, reg, val); } static inline int cp_read(struct v4l2_subdev *sd, u8 reg) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV7604_PAGE_CP, reg); + return adv_smbus_read_byte_data(state, ADV76XX_PAGE_CP, reg); } static u16 cp_read16(struct v4l2_subdev *sd, u8 reg, u16 mask) @@ -604,9 +601,9 @@ static u16 cp_read16(struct v4l2_subdev *sd, u8 reg, u16 mask) static inline int cp_write(struct v4l2_subdev *sd, u8 reg, u8 val) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV7604_PAGE_CP, reg, val); + return adv_smbus_write_byte_data(state, ADV76XX_PAGE_CP, reg, val); } static inline int cp_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) @@ -616,25 +613,25 @@ static inline int cp_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 v static inline int vdp_read(struct v4l2_subdev *sd, u8 reg) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); return adv_smbus_read_byte_data(state, ADV7604_PAGE_VDP, reg); } static inline int vdp_write(struct v4l2_subdev *sd, u8 reg, u8 val) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); return adv_smbus_write_byte_data(state, ADV7604_PAGE_VDP, reg, val); } -#define ADV7604_REG(page, offset) (((page) << 8) | (offset)) -#define ADV7604_REG_SEQ_TERM 0xffff +#define ADV76XX_REG(page, offset) (((page) << 8) | (offset)) +#define ADV76XX_REG_SEQ_TERM 0xffff #ifdef CONFIG_VIDEO_ADV_DEBUG -static int adv7604_read_reg(struct v4l2_subdev *sd, unsigned int reg) +static int adv76xx_read_reg(struct v4l2_subdev *sd, unsigned int reg) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); unsigned int page = reg >> 8; if (!(BIT(page) & state->info->page_mask)) @@ -646,9 +643,9 @@ static int adv7604_read_reg(struct v4l2_subdev *sd, unsigned int reg) } #endif -static int adv7604_write_reg(struct v4l2_subdev *sd, unsigned int reg, u8 val) +static int adv76xx_write_reg(struct v4l2_subdev *sd, unsigned int reg, u8 val) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); unsigned int page = reg >> 8; if (!(BIT(page) & state->info->page_mask)) @@ -659,91 +656,91 @@ static int adv7604_write_reg(struct v4l2_subdev *sd, unsigned int reg, u8 val) return adv_smbus_write_byte_data(state, page, reg, val); } -static void adv7604_write_reg_seq(struct v4l2_subdev *sd, - const struct adv7604_reg_seq *reg_seq) +static void adv76xx_write_reg_seq(struct v4l2_subdev *sd, + const struct adv76xx_reg_seq *reg_seq) { unsigned int i; - for (i = 0; reg_seq[i].reg != ADV7604_REG_SEQ_TERM; i++) - adv7604_write_reg(sd, reg_seq[i].reg, reg_seq[i].val); + for (i = 0; reg_seq[i].reg != ADV76XX_REG_SEQ_TERM; i++) + adv76xx_write_reg(sd, reg_seq[i].reg, reg_seq[i].val); } /* ----------------------------------------------------------------------------- * Format helpers */ -static const struct adv7604_format_info adv7604_formats[] = { - { MEDIA_BUS_FMT_RGB888_1X24, ADV7604_OP_CH_SEL_RGB, true, false, - ADV7604_OP_MODE_SEL_SDR_444 | ADV7604_OP_FORMAT_SEL_8BIT }, - { MEDIA_BUS_FMT_YUYV8_2X8, ADV7604_OP_CH_SEL_RGB, false, false, - ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_8BIT }, - { MEDIA_BUS_FMT_YVYU8_2X8, ADV7604_OP_CH_SEL_RGB, false, true, - ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_8BIT }, - { MEDIA_BUS_FMT_YUYV10_2X10, ADV7604_OP_CH_SEL_RGB, false, false, - ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_10BIT }, - { MEDIA_BUS_FMT_YVYU10_2X10, ADV7604_OP_CH_SEL_RGB, false, true, - ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_10BIT }, - { MEDIA_BUS_FMT_YUYV12_2X12, ADV7604_OP_CH_SEL_RGB, false, false, - ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_12BIT }, - { MEDIA_BUS_FMT_YVYU12_2X12, ADV7604_OP_CH_SEL_RGB, false, true, - ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_12BIT }, - { MEDIA_BUS_FMT_UYVY8_1X16, ADV7604_OP_CH_SEL_RBG, false, false, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, - { MEDIA_BUS_FMT_VYUY8_1X16, ADV7604_OP_CH_SEL_RBG, false, true, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, - { MEDIA_BUS_FMT_YUYV8_1X16, ADV7604_OP_CH_SEL_RGB, false, false, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, - { MEDIA_BUS_FMT_YVYU8_1X16, ADV7604_OP_CH_SEL_RGB, false, true, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, - { MEDIA_BUS_FMT_UYVY10_1X20, ADV7604_OP_CH_SEL_RBG, false, false, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT }, - { MEDIA_BUS_FMT_VYUY10_1X20, ADV7604_OP_CH_SEL_RBG, false, true, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT }, - { MEDIA_BUS_FMT_YUYV10_1X20, ADV7604_OP_CH_SEL_RGB, false, false, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT }, - { MEDIA_BUS_FMT_YVYU10_1X20, ADV7604_OP_CH_SEL_RGB, false, true, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT }, - { MEDIA_BUS_FMT_UYVY12_1X24, ADV7604_OP_CH_SEL_RBG, false, false, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, - { MEDIA_BUS_FMT_VYUY12_1X24, ADV7604_OP_CH_SEL_RBG, false, true, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, - { MEDIA_BUS_FMT_YUYV12_1X24, ADV7604_OP_CH_SEL_RGB, false, false, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, - { MEDIA_BUS_FMT_YVYU12_1X24, ADV7604_OP_CH_SEL_RGB, false, true, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, +static const struct adv76xx_format_info adv7604_formats[] = { + { MEDIA_BUS_FMT_RGB888_1X24, ADV76XX_OP_CH_SEL_RGB, true, false, + ADV76XX_OP_MODE_SEL_SDR_444 | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YUYV8_2X8, ADV76XX_OP_CH_SEL_RGB, false, false, + ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YVYU8_2X8, ADV76XX_OP_CH_SEL_RGB, false, true, + ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YUYV10_2X10, ADV76XX_OP_CH_SEL_RGB, false, false, + ADV76XX_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_10BIT }, + { MEDIA_BUS_FMT_YVYU10_2X10, ADV76XX_OP_CH_SEL_RGB, false, true, + ADV76XX_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_10BIT }, + { MEDIA_BUS_FMT_YUYV12_2X12, ADV76XX_OP_CH_SEL_RGB, false, false, + ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_12BIT }, + { MEDIA_BUS_FMT_YVYU12_2X12, ADV76XX_OP_CH_SEL_RGB, false, true, + ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_12BIT }, + { MEDIA_BUS_FMT_UYVY8_1X16, ADV76XX_OP_CH_SEL_RBG, false, false, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_VYUY8_1X16, ADV76XX_OP_CH_SEL_RBG, false, true, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YUYV8_1X16, ADV76XX_OP_CH_SEL_RGB, false, false, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YVYU8_1X16, ADV76XX_OP_CH_SEL_RGB, false, true, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_UYVY10_1X20, ADV76XX_OP_CH_SEL_RBG, false, false, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT }, + { MEDIA_BUS_FMT_VYUY10_1X20, ADV76XX_OP_CH_SEL_RBG, false, true, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT }, + { MEDIA_BUS_FMT_YUYV10_1X20, ADV76XX_OP_CH_SEL_RGB, false, false, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT }, + { MEDIA_BUS_FMT_YVYU10_1X20, ADV76XX_OP_CH_SEL_RGB, false, true, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT }, + { MEDIA_BUS_FMT_UYVY12_1X24, ADV76XX_OP_CH_SEL_RBG, false, false, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_12BIT }, + { MEDIA_BUS_FMT_VYUY12_1X24, ADV76XX_OP_CH_SEL_RBG, false, true, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_12BIT }, + { MEDIA_BUS_FMT_YUYV12_1X24, ADV76XX_OP_CH_SEL_RGB, false, false, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_12BIT }, + { MEDIA_BUS_FMT_YVYU12_1X24, ADV76XX_OP_CH_SEL_RGB, false, true, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_12BIT }, }; -static const struct adv7604_format_info adv7611_formats[] = { - { MEDIA_BUS_FMT_RGB888_1X24, ADV7604_OP_CH_SEL_RGB, true, false, - ADV7604_OP_MODE_SEL_SDR_444 | ADV7604_OP_FORMAT_SEL_8BIT }, - { MEDIA_BUS_FMT_YUYV8_2X8, ADV7604_OP_CH_SEL_RGB, false, false, - ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_8BIT }, - { MEDIA_BUS_FMT_YVYU8_2X8, ADV7604_OP_CH_SEL_RGB, false, true, - ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_8BIT }, - { MEDIA_BUS_FMT_YUYV12_2X12, ADV7604_OP_CH_SEL_RGB, false, false, - ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_12BIT }, - { MEDIA_BUS_FMT_YVYU12_2X12, ADV7604_OP_CH_SEL_RGB, false, true, - ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_12BIT }, - { MEDIA_BUS_FMT_UYVY8_1X16, ADV7604_OP_CH_SEL_RBG, false, false, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, - { MEDIA_BUS_FMT_VYUY8_1X16, ADV7604_OP_CH_SEL_RBG, false, true, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, - { MEDIA_BUS_FMT_YUYV8_1X16, ADV7604_OP_CH_SEL_RGB, false, false, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, - { MEDIA_BUS_FMT_YVYU8_1X16, ADV7604_OP_CH_SEL_RGB, false, true, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, - { MEDIA_BUS_FMT_UYVY12_1X24, ADV7604_OP_CH_SEL_RBG, false, false, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, - { MEDIA_BUS_FMT_VYUY12_1X24, ADV7604_OP_CH_SEL_RBG, false, true, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, - { MEDIA_BUS_FMT_YUYV12_1X24, ADV7604_OP_CH_SEL_RGB, false, false, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, - { MEDIA_BUS_FMT_YVYU12_1X24, ADV7604_OP_CH_SEL_RGB, false, true, - ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, +static const struct adv76xx_format_info adv7611_formats[] = { + { MEDIA_BUS_FMT_RGB888_1X24, ADV76XX_OP_CH_SEL_RGB, true, false, + ADV76XX_OP_MODE_SEL_SDR_444 | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YUYV8_2X8, ADV76XX_OP_CH_SEL_RGB, false, false, + ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YVYU8_2X8, ADV76XX_OP_CH_SEL_RGB, false, true, + ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YUYV12_2X12, ADV76XX_OP_CH_SEL_RGB, false, false, + ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_12BIT }, + { MEDIA_BUS_FMT_YVYU12_2X12, ADV76XX_OP_CH_SEL_RGB, false, true, + ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_12BIT }, + { MEDIA_BUS_FMT_UYVY8_1X16, ADV76XX_OP_CH_SEL_RBG, false, false, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_VYUY8_1X16, ADV76XX_OP_CH_SEL_RBG, false, true, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YUYV8_1X16, ADV76XX_OP_CH_SEL_RGB, false, false, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YVYU8_1X16, ADV76XX_OP_CH_SEL_RGB, false, true, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_UYVY12_1X24, ADV76XX_OP_CH_SEL_RBG, false, false, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_12BIT }, + { MEDIA_BUS_FMT_VYUY12_1X24, ADV76XX_OP_CH_SEL_RBG, false, true, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_12BIT }, + { MEDIA_BUS_FMT_YUYV12_1X24, ADV76XX_OP_CH_SEL_RGB, false, false, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_12BIT }, + { MEDIA_BUS_FMT_YVYU12_1X24, ADV76XX_OP_CH_SEL_RGB, false, true, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_12BIT }, }; -static const struct adv7604_format_info * -adv7604_format_info(struct adv7604_state *state, u32 code) +static const struct adv76xx_format_info * +adv76xx_format_info(struct adv76xx_state *state, u32 code) { unsigned int i; @@ -759,7 +756,7 @@ adv7604_format_info(struct adv7604_state *state, u32 code) static inline bool is_analog_input(struct v4l2_subdev *sd) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); return state->selected_input == ADV7604_PAD_VGA_RGB || state->selected_input == ADV7604_PAD_VGA_COMP; @@ -767,9 +764,9 @@ static inline bool is_analog_input(struct v4l2_subdev *sd) static inline bool is_digital_input(struct v4l2_subdev *sd) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - return state->selected_input == ADV7604_PAD_HDMI_PORT_A || + return state->selected_input == ADV76XX_PAD_HDMI_PORT_A || state->selected_input == ADV7604_PAD_HDMI_PORT_B || state->selected_input == ADV7604_PAD_HDMI_PORT_C || state->selected_input == ADV7604_PAD_HDMI_PORT_D; @@ -778,7 +775,7 @@ static inline bool is_digital_input(struct v4l2_subdev *sd) /* ----------------------------------------------------------------------- */ #ifdef CONFIG_VIDEO_ADV_DEBUG -static void adv7604_inv_register(struct v4l2_subdev *sd) +static void adv76xx_inv_register(struct v4l2_subdev *sd) { v4l2_info(sd, "0x000-0x0ff: IO Map\n"); v4l2_info(sd, "0x100-0x1ff: AVLink Map\n"); @@ -795,15 +792,15 @@ static void adv7604_inv_register(struct v4l2_subdev *sd) v4l2_info(sd, "0xc00-0xcff: VDP Map\n"); } -static int adv7604_g_register(struct v4l2_subdev *sd, +static int adv76xx_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) { int ret; - ret = adv7604_read_reg(sd, reg->reg); + ret = adv76xx_read_reg(sd, reg->reg); if (ret < 0) { v4l2_info(sd, "Register %03llx not supported\n", reg->reg); - adv7604_inv_register(sd); + adv76xx_inv_register(sd); return ret; } @@ -813,15 +810,15 @@ static int adv7604_g_register(struct v4l2_subdev *sd, return 0; } -static int adv7604_s_register(struct v4l2_subdev *sd, +static int adv76xx_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { int ret; - ret = adv7604_write_reg(sd, reg->reg, reg->val); + ret = adv76xx_write_reg(sd, reg->reg, reg->val); if (ret < 0) { v4l2_info(sd, "Register %03llx not supported\n", reg->reg); - adv7604_inv_register(sd); + adv76xx_inv_register(sd); return ret; } @@ -846,10 +843,10 @@ static unsigned int adv7611_read_cable_det(struct v4l2_subdev *sd) return value & 1; } -static int adv7604_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd) +static int adv76xx_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd) { - struct adv7604_state *state = to_state(sd); - const struct adv7604_chip_info *info = state->info; + struct adv76xx_state *state = to_state(sd); + const struct adv76xx_chip_info *info = state->info; return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl, info->read_cable_det(sd)); @@ -857,7 +854,7 @@ static int adv7604_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd) static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd, u8 prim_mode, - const struct adv7604_video_standards *predef_vid_timings, + const struct adv76xx_video_standards *predef_vid_timings, const struct v4l2_dv_timings *timings) { int i; @@ -878,12 +875,12 @@ static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd, static int configure_predefined_video_timings(struct v4l2_subdev *sd, struct v4l2_dv_timings *timings) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); int err; v4l2_dbg(1, debug, sd, "%s", __func__); - if (adv7604_has_afe(state)) { + if (adv76xx_has_afe(state)) { /* reset to default values */ io_write(sd, 0x16, 0x43); io_write(sd, 0x17, 0x5a); @@ -909,10 +906,10 @@ static int configure_predefined_video_timings(struct v4l2_subdev *sd, 0x02, adv7604_prim_mode_gr, timings); } else if (is_digital_input(sd)) { err = find_and_set_predefined_video_timings(sd, - 0x05, adv7604_prim_mode_hdmi_comp, timings); + 0x05, adv76xx_prim_mode_hdmi_comp, timings); if (err) err = find_and_set_predefined_video_timings(sd, - 0x06, adv7604_prim_mode_hdmi_gr, timings); + 0x06, adv76xx_prim_mode_hdmi_gr, timings); } else { v4l2_dbg(2, debug, sd, "%s: Unknown port %d selected\n", __func__, state->selected_input); @@ -926,7 +923,7 @@ static int configure_predefined_video_timings(struct v4l2_subdev *sd, static void configure_custom_video_timings(struct v4l2_subdev *sd, const struct v4l2_bt_timings *bt) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); u32 width = htotal(bt); u32 height = vtotal(bt); u16 cp_start_sav = bt->hsync + bt->hbackporch - 4; @@ -934,7 +931,7 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd, u16 cp_start_vbi = height - bt->vfrontporch; u16 cp_end_vbi = bt->vsync + bt->vbackporch; u16 ch1_fr_ll = (((u32)bt->pixelclock / 100) > 0) ? - ((width * (ADV7604_fsc / 100)) / ((u32)bt->pixelclock / 100)) : 0; + ((width * (ADV76XX_FSC / 100)) / ((u32)bt->pixelclock / 100)) : 0; const u8 pll[2] = { 0xc0 | ((width >> 8) & 0x1f), width & 0xff @@ -952,7 +949,7 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd, /* Should only be set in auto-graphics mode [REF_02, p. 91-92] */ /* setup PLL_DIV_MAN_EN and PLL_DIV_RATIO */ /* IO-map reg. 0x16 and 0x17 should be written in sequence */ - if (adv_smbus_write_i2c_block_data(state, ADV7604_PAGE_IO, + if (adv_smbus_write_i2c_block_data(state, ADV76XX_PAGE_IO, 0x16, 2, pll)) v4l2_err(sd, "writing to reg 0x16 and 0x17 failed\n"); @@ -983,9 +980,9 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd, cp_write(sd, 0xac, (height & 0x0f) << 4); } -static void adv7604_set_offset(struct v4l2_subdev *sd, bool auto_offset, u16 offset_a, u16 offset_b, u16 offset_c) +static void adv76xx_set_offset(struct v4l2_subdev *sd, bool auto_offset, u16 offset_a, u16 offset_b, u16 offset_c) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); u8 offset_buf[4]; if (auto_offset) { @@ -1004,14 +1001,14 @@ static void adv7604_set_offset(struct v4l2_subdev *sd, bool auto_offset, u16 off offset_buf[3] = offset_c & 0x0ff; /* Registers must be written in this order with no i2c access in between */ - if (adv_smbus_write_i2c_block_data(state, ADV7604_PAGE_CP, + if (adv_smbus_write_i2c_block_data(state, ADV76XX_PAGE_CP, 0x77, 4, offset_buf)) v4l2_err(sd, "%s: i2c error writing to CP reg 0x77, 0x78, 0x79, 0x7a\n", __func__); } -static void adv7604_set_gain(struct v4l2_subdev *sd, bool auto_gain, u16 gain_a, u16 gain_b, u16 gain_c) +static void adv76xx_set_gain(struct v4l2_subdev *sd, bool auto_gain, u16 gain_a, u16 gain_b, u16 gain_c) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); u8 gain_buf[4]; u8 gain_man = 1; u8 agc_mode_man = 1; @@ -1034,14 +1031,14 @@ static void adv7604_set_gain(struct v4l2_subdev *sd, bool auto_gain, u16 gain_a, gain_buf[3] = ((gain_c & 0x0ff)); /* Registers must be written in this order with no i2c access in between */ - if (adv_smbus_write_i2c_block_data(state, ADV7604_PAGE_CP, + if (adv_smbus_write_i2c_block_data(state, ADV76XX_PAGE_CP, 0x73, 4, gain_buf)) v4l2_err(sd, "%s: i2c error writing to CP reg 0x73, 0x74, 0x75, 0x76\n", __func__); } static void set_rgb_quantization_range(struct v4l2_subdev *sd) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); bool rgb_output = io_read(sd, 0x02) & 0x02; bool hdmi_signal = hdmi_read(sd, 0x05) & 0x80; @@ -1049,8 +1046,8 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) __func__, state->rgb_quantization_range, rgb_output, hdmi_signal); - adv7604_set_gain(sd, true, 0x0, 0x0, 0x0); - adv7604_set_offset(sd, true, 0x0, 0x0, 0x0); + adv76xx_set_gain(sd, true, 0x0, 0x0, 0x0); + adv76xx_set_offset(sd, true, 0x0, 0x0, 0x0); switch (state->rgb_quantization_range) { case V4L2_DV_RGB_RANGE_AUTO: @@ -1078,7 +1075,7 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) /* Receiving DVI-D signal * ADV7604 selects RGB limited range regardless of * input format (CE/IT) in automatic mode */ - if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861) { + if (state->timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) { /* RGB limited range (16-235) */ io_write_clr_set(sd, 0x02, 0xf0, 0x00); } else { @@ -1086,10 +1083,10 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) io_write_clr_set(sd, 0x02, 0xf0, 0x10); if (is_digital_input(sd) && rgb_output) { - adv7604_set_offset(sd, false, 0x40, 0x40, 0x40); + adv76xx_set_offset(sd, false, 0x40, 0x40, 0x40); } else { - adv7604_set_gain(sd, false, 0xe0, 0xe0, 0xe0); - adv7604_set_offset(sd, false, 0x70, 0x70, 0x70); + adv76xx_set_gain(sd, false, 0xe0, 0xe0, 0xe0); + adv76xx_set_offset(sd, false, 0x70, 0x70, 0x70); } } break; @@ -1119,21 +1116,21 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) /* Adjust gain/offset for DVI-D signals only */ if (rgb_output) { - adv7604_set_offset(sd, false, 0x40, 0x40, 0x40); + adv76xx_set_offset(sd, false, 0x40, 0x40, 0x40); } else { - adv7604_set_gain(sd, false, 0xe0, 0xe0, 0xe0); - adv7604_set_offset(sd, false, 0x70, 0x70, 0x70); + adv76xx_set_gain(sd, false, 0xe0, 0xe0, 0xe0); + adv76xx_set_offset(sd, false, 0x70, 0x70, 0x70); } break; } } -static int adv7604_s_ctrl(struct v4l2_ctrl *ctrl) +static int adv76xx_s_ctrl(struct v4l2_ctrl *ctrl) { struct v4l2_subdev *sd = - &container_of(ctrl->handler, struct adv7604_state, hdl)->sd; + &container_of(ctrl->handler, struct adv76xx_state, hdl)->sd; - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: @@ -1153,7 +1150,7 @@ static int adv7604_s_ctrl(struct v4l2_ctrl *ctrl) set_rgb_quantization_range(sd); return 0; case V4L2_CID_ADV_RX_ANALOG_SAMPLING_PHASE: - if (!adv7604_has_afe(state)) + if (!adv76xx_has_afe(state)) return -EINVAL; /* Set the analog sampling phase. This is needed to find the best sampling phase for analog video: an application or @@ -1185,15 +1182,15 @@ static inline bool no_power(struct v4l2_subdev *sd) static inline bool no_signal_tmds(struct v4l2_subdev *sd) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); return !(io_read(sd, 0x6a) & (0x10 >> state->selected_input)); } static inline bool no_lock_tmds(struct v4l2_subdev *sd) { - struct adv7604_state *state = to_state(sd); - const struct adv7604_chip_info *info = state->info; + struct adv76xx_state *state = to_state(sd); + const struct adv76xx_chip_info *info = state->info; return (io_read(sd, 0x6a) & info->tdms_lock_mask) != info->tdms_lock_mask; } @@ -1205,13 +1202,13 @@ static inline bool is_hdmi(struct v4l2_subdev *sd) static inline bool no_lock_sspd(struct v4l2_subdev *sd) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); /* * Chips without a AFE don't expose registers for the SSPD, so just assume * that we have a lock. */ - if (adv7604_has_afe(state)) + if (adv76xx_has_afe(state)) return false; /* TODO channel 2 */ @@ -1243,9 +1240,9 @@ static inline bool no_signal(struct v4l2_subdev *sd) static inline bool no_lock_cp(struct v4l2_subdev *sd) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - if (!adv7604_has_afe(state)) + if (!adv76xx_has_afe(state)) return false; /* CP has detected a non standard number of lines on the incoming @@ -1253,13 +1250,19 @@ static inline bool no_lock_cp(struct v4l2_subdev *sd) return io_read(sd, 0x12) & 0x01; } -static int adv7604_g_input_status(struct v4l2_subdev *sd, u32 *status) +static inline bool in_free_run(struct v4l2_subdev *sd) +{ + return cp_read(sd, 0xff) & 0x10; +} + +static int adv76xx_g_input_status(struct v4l2_subdev *sd, u32 *status) { *status = 0; *status |= no_power(sd) ? V4L2_IN_ST_NO_POWER : 0; *status |= no_signal(sd) ? V4L2_IN_ST_NO_SIGNAL : 0; - if (no_lock_cp(sd)) - *status |= is_digital_input(sd) ? V4L2_IN_ST_NO_SYNC : V4L2_IN_ST_NO_H_LOCK; + if (!in_free_run(sd) && no_lock_cp(sd)) + *status |= is_digital_input(sd) ? + V4L2_IN_ST_NO_SYNC : V4L2_IN_ST_NO_H_LOCK; v4l2_dbg(1, debug, sd, "%s: status = 0x%x\n", __func__, *status); @@ -1278,22 +1281,22 @@ static int stdi2dv_timings(struct v4l2_subdev *sd, struct stdi_readback *stdi, struct v4l2_dv_timings *timings) { - struct adv7604_state *state = to_state(sd); - u32 hfreq = (ADV7604_fsc * 8) / stdi->bl; + struct adv76xx_state *state = to_state(sd); + u32 hfreq = (ADV76XX_FSC * 8) / stdi->bl; u32 pix_clk; int i; - for (i = 0; adv7604_timings[i].bt.height; i++) { - if (vtotal(&adv7604_timings[i].bt) != stdi->lcf + 1) + for (i = 0; adv76xx_timings[i].bt.height; i++) { + if (vtotal(&adv76xx_timings[i].bt) != stdi->lcf + 1) continue; - if (adv7604_timings[i].bt.vsync != stdi->lcvs) + if (adv76xx_timings[i].bt.vsync != stdi->lcvs) continue; - pix_clk = hfreq * htotal(&adv7604_timings[i].bt); + pix_clk = hfreq * htotal(&adv76xx_timings[i].bt); - if ((pix_clk < adv7604_timings[i].bt.pixelclock + 1000000) && - (pix_clk > adv7604_timings[i].bt.pixelclock - 1000000)) { - *timings = adv7604_timings[i]; + if ((pix_clk < adv76xx_timings[i].bt.pixelclock + 1000000) && + (pix_clk > adv76xx_timings[i].bt.pixelclock - 1000000)) { + *timings = adv76xx_timings[i]; return 0; } } @@ -1319,8 +1322,8 @@ static int stdi2dv_timings(struct v4l2_subdev *sd, static int read_stdi(struct v4l2_subdev *sd, struct stdi_readback *stdi) { - struct adv7604_state *state = to_state(sd); - const struct adv7604_chip_info *info = state->info; + struct adv76xx_state *state = to_state(sd); + const struct adv76xx_chip_info *info = state->info; u8 polarity; if (no_lock_stdi(sd) || no_lock_sspd(sd)) { @@ -1334,7 +1337,7 @@ static int read_stdi(struct v4l2_subdev *sd, struct stdi_readback *stdi) stdi->lcvs = cp_read(sd, 0xb3) >> 3; stdi->interlaced = io_read(sd, 0x12) & 0x10; - if (adv7604_has_afe(state)) { + if (adv76xx_has_afe(state)) { /* read SSPD */ polarity = cp_read(sd, 0xb5); if ((polarity & 0x03) == 0x01) { @@ -1373,26 +1376,26 @@ static int read_stdi(struct v4l2_subdev *sd, struct stdi_readback *stdi) return 0; } -static int adv7604_enum_dv_timings(struct v4l2_subdev *sd, +static int adv76xx_enum_dv_timings(struct v4l2_subdev *sd, struct v4l2_enum_dv_timings *timings) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); - if (timings->index >= ARRAY_SIZE(adv7604_timings) - 1) + if (timings->index >= ARRAY_SIZE(adv76xx_timings) - 1) return -EINVAL; if (timings->pad >= state->source_pad) return -EINVAL; memset(timings->reserved, 0, sizeof(timings->reserved)); - timings->timings = adv7604_timings[timings->index]; + timings->timings = adv76xx_timings[timings->index]; return 0; } -static int adv7604_dv_timings_cap(struct v4l2_subdev *sd, +static int adv76xx_dv_timings_cap(struct v4l2_subdev *sd, struct v4l2_dv_timings_cap *cap) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); if (cap->pad >= state->source_pad) return -EINVAL; @@ -1403,7 +1406,7 @@ static int adv7604_dv_timings_cap(struct v4l2_subdev *sd, cap->bt.min_pixelclock = 25000000; switch (cap->pad) { - case ADV7604_PAD_HDMI_PORT_A: + case ADV76XX_PAD_HDMI_PORT_A: case ADV7604_PAD_HDMI_PORT_B: case ADV7604_PAD_HDMI_PORT_C: case ADV7604_PAD_HDMI_PORT_D: @@ -1424,16 +1427,16 @@ static int adv7604_dv_timings_cap(struct v4l2_subdev *sd, } /* Fill the optional fields .standards and .flags in struct v4l2_dv_timings - if the format is listed in adv7604_timings[] */ -static void adv7604_fill_optional_dv_timings_fields(struct v4l2_subdev *sd, + if the format is listed in adv76xx_timings[] */ +static void adv76xx_fill_optional_dv_timings_fields(struct v4l2_subdev *sd, struct v4l2_dv_timings *timings) { int i; - for (i = 0; adv7604_timings[i].bt.width; i++) { - if (v4l2_match_dv_timings(timings, &adv7604_timings[i], + for (i = 0; adv76xx_timings[i].bt.width; i++) { + if (v4l2_match_dv_timings(timings, &adv76xx_timings[i], is_digital_input(sd) ? 250000 : 1000000)) { - *timings = adv7604_timings[i]; + *timings = adv76xx_timings[i]; break; } } @@ -1471,11 +1474,11 @@ static unsigned int adv7611_read_hdmi_pixelclock(struct v4l2_subdev *sd) return ((a << 1) | (b >> 7)) * 1000000 + (b & 0x7f) * 1000000 / 128; } -static int adv7604_query_dv_timings(struct v4l2_subdev *sd, +static int adv76xx_query_dv_timings(struct v4l2_subdev *sd, struct v4l2_dv_timings *timings) { - struct adv7604_state *state = to_state(sd); - const struct adv7604_chip_info *info = state->info; + struct adv76xx_state *state = to_state(sd); + const struct adv76xx_chip_info *info = state->info; struct v4l2_bt_timings *bt = &timings->bt; struct stdi_readback stdi; @@ -1519,7 +1522,7 @@ static int adv7604_query_dv_timings(struct v4l2_subdev *sd, bt->il_vsync = hdmi_read16(sd, 0x30, 0x1fff) / 2; bt->il_vbackporch = hdmi_read16(sd, 0x34, 0x1fff) / 2; } - adv7604_fill_optional_dv_timings_fields(sd, timings); + adv76xx_fill_optional_dv_timings_fields(sd, timings); } else { /* find format * Since LCVS values are inaccurate [REF_03, p. 275-276], @@ -1576,16 +1579,16 @@ found: } if (debug > 1) - v4l2_print_dv_timings(sd->name, "adv7604_query_dv_timings: ", + v4l2_print_dv_timings(sd->name, "adv76xx_query_dv_timings: ", timings, true); return 0; } -static int adv7604_s_dv_timings(struct v4l2_subdev *sd, +static int adv76xx_s_dv_timings(struct v4l2_subdev *sd, struct v4l2_dv_timings *timings) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); struct v4l2_bt_timings *bt; int err; @@ -1606,7 +1609,7 @@ static int adv7604_s_dv_timings(struct v4l2_subdev *sd, return -ERANGE; } - adv7604_fill_optional_dv_timings_fields(sd, timings); + adv76xx_fill_optional_dv_timings_fields(sd, timings); state->timings = *timings; @@ -1623,15 +1626,15 @@ static int adv7604_s_dv_timings(struct v4l2_subdev *sd, set_rgb_quantization_range(sd); if (debug > 1) - v4l2_print_dv_timings(sd->name, "adv7604_s_dv_timings: ", + v4l2_print_dv_timings(sd->name, "adv76xx_s_dv_timings: ", timings, true); return 0; } -static int adv7604_g_dv_timings(struct v4l2_subdev *sd, +static int adv76xx_g_dv_timings(struct v4l2_subdev *sd, struct v4l2_dv_timings *timings) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); *timings = state->timings; return 0; @@ -1649,7 +1652,7 @@ static void adv7611_set_termination(struct v4l2_subdev *sd, bool enable) static void enable_input(struct v4l2_subdev *sd) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); if (is_analog_input(sd)) { io_write(sd, 0x15, 0xb0); /* Disable Tristate of Pins (no audio) */ @@ -1666,7 +1669,7 @@ static void enable_input(struct v4l2_subdev *sd) static void disable_input(struct v4l2_subdev *sd) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); hdmi_write_clr_set(sd, 0x1a, 0x10, 0x10); /* Mute audio */ msleep(16); /* 512 samples with >= 32 kHz sample rate [REF_03, c. 7.16.10] */ @@ -1676,11 +1679,11 @@ static void disable_input(struct v4l2_subdev *sd) static void select_input(struct v4l2_subdev *sd) { - struct adv7604_state *state = to_state(sd); - const struct adv7604_chip_info *info = state->info; + struct adv76xx_state *state = to_state(sd); + const struct adv76xx_chip_info *info = state->info; if (is_analog_input(sd)) { - adv7604_write_reg_seq(sd, info->recommended_settings[0]); + adv76xx_write_reg_seq(sd, info->recommended_settings[0]); afe_write(sd, 0x00, 0x08); /* power up ADC */ afe_write(sd, 0x01, 0x06); /* power up Analog Front End */ @@ -1688,9 +1691,9 @@ static void select_input(struct v4l2_subdev *sd) } else if (is_digital_input(sd)) { hdmi_write(sd, 0x00, state->selected_input & 0x03); - adv7604_write_reg_seq(sd, info->recommended_settings[1]); + adv76xx_write_reg_seq(sd, info->recommended_settings[1]); - if (adv7604_has_afe(state)) { + if (adv76xx_has_afe(state)) { afe_write(sd, 0x00, 0xff); /* power down ADC */ afe_write(sd, 0x01, 0xfe); /* power down Analog Front End */ afe_write(sd, 0xc8, 0x40); /* phase control */ @@ -1705,10 +1708,10 @@ static void select_input(struct v4l2_subdev *sd) } } -static int adv7604_s_routing(struct v4l2_subdev *sd, +static int adv76xx_s_routing(struct v4l2_subdev *sd, u32 input, u32 output, u32 config) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); v4l2_dbg(2, debug, sd, "%s: input %d, selected input %d", __func__, input, state->selected_input); @@ -1730,11 +1733,11 @@ static int adv7604_s_routing(struct v4l2_subdev *sd, return 0; } -static int adv7604_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, +static int adv76xx_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); if (code->index >= state->info->nformats) return -EINVAL; @@ -1744,7 +1747,7 @@ static int adv7604_enum_mbus_code(struct v4l2_subdev *sd, return 0; } -static void adv7604_fill_format(struct adv7604_state *state, +static void adv76xx_fill_format(struct adv76xx_state *state, struct v4l2_mbus_framefmt *format) { memset(format, 0, sizeof(*format)); @@ -1752,8 +1755,9 @@ static void adv7604_fill_format(struct adv7604_state *state, format->width = state->timings.bt.width; format->height = state->timings.bt.height; format->field = V4L2_FIELD_NONE; + format->colorspace = V4L2_COLORSPACE_SRGB; - if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861) + if (state->timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) format->colorspace = (state->timings.bt.height <= 576) ? V4L2_COLORSPACE_SMPTE170M : V4L2_COLORSPACE_REC709; } @@ -1765,7 +1769,7 @@ static void adv7604_fill_format(struct adv7604_state *state, * * The following table gives the op_ch_value from the format component order * (expressed as op_ch_sel value in column) and the bus reordering (expressed as - * adv7604_bus_order value in row). + * adv76xx_bus_order value in row). * * | GBR(0) GRB(1) BGR(2) RGB(3) BRG(4) RBG(5) * ----------+------------------------------------------------- @@ -1776,11 +1780,11 @@ static void adv7604_fill_format(struct adv7604_state *state, * BRG (ROR) | BRG RBG GRB GBR RGB BGR * GBR (ROL) | RGB BGR RBG BRG GBR GRB */ -static unsigned int adv7604_op_ch_sel(struct adv7604_state *state) +static unsigned int adv76xx_op_ch_sel(struct adv76xx_state *state) { #define _SEL(a,b,c,d,e,f) { \ - ADV7604_OP_CH_SEL_##a, ADV7604_OP_CH_SEL_##b, ADV7604_OP_CH_SEL_##c, \ - ADV7604_OP_CH_SEL_##d, ADV7604_OP_CH_SEL_##e, ADV7604_OP_CH_SEL_##f } + ADV76XX_OP_CH_SEL_##a, ADV76XX_OP_CH_SEL_##b, ADV76XX_OP_CH_SEL_##c, \ + ADV76XX_OP_CH_SEL_##d, ADV76XX_OP_CH_SEL_##e, ADV76XX_OP_CH_SEL_##f } #define _BUS(x) [ADV7604_BUS_ORDER_##x] static const unsigned int op_ch_sel[6][6] = { @@ -1795,33 +1799,34 @@ static unsigned int adv7604_op_ch_sel(struct adv7604_state *state) return op_ch_sel[state->pdata.bus_order][state->format->op_ch_sel >> 5]; } -static void adv7604_setup_format(struct adv7604_state *state) +static void adv76xx_setup_format(struct adv76xx_state *state) { struct v4l2_subdev *sd = &state->sd; io_write_clr_set(sd, 0x02, 0x02, - state->format->rgb_out ? ADV7604_RGB_OUT : 0); + state->format->rgb_out ? ADV76XX_RGB_OUT : 0); io_write(sd, 0x03, state->format->op_format_sel | state->pdata.op_format_mode_sel); - io_write_clr_set(sd, 0x04, 0xe0, adv7604_op_ch_sel(state)); + io_write_clr_set(sd, 0x04, 0xe0, adv76xx_op_ch_sel(state)); io_write_clr_set(sd, 0x05, 0x01, - state->format->swap_cb_cr ? ADV7604_OP_SWAP_CB_CR : 0); + state->format->swap_cb_cr ? ADV76XX_OP_SWAP_CB_CR : 0); } -static int adv7604_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int adv76xx_get_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); if (format->pad != state->source_pad) return -EINVAL; - adv7604_fill_format(state, &format->format); + adv76xx_fill_format(state, &format->format); if (format->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *fmt; - fmt = v4l2_subdev_get_try_format(fh, format->pad); + fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); format->format.code = fmt->code; } else { format->format.code = state->format->code; @@ -1830,39 +1835,40 @@ static int adv7604_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, return 0; } -static int adv7604_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int adv76xx_set_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { - struct adv7604_state *state = to_state(sd); - const struct adv7604_format_info *info; + struct adv76xx_state *state = to_state(sd); + const struct adv76xx_format_info *info; if (format->pad != state->source_pad) return -EINVAL; - info = adv7604_format_info(state, format->format.code); + info = adv76xx_format_info(state, format->format.code); if (info == NULL) - info = adv7604_format_info(state, MEDIA_BUS_FMT_YUYV8_2X8); + info = adv76xx_format_info(state, MEDIA_BUS_FMT_YUYV8_2X8); - adv7604_fill_format(state, &format->format); + adv76xx_fill_format(state, &format->format); format->format.code = info->code; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *fmt; - fmt = v4l2_subdev_get_try_format(fh, format->pad); + fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); fmt->code = format->format.code; } else { state->format = info; - adv7604_setup_format(state); + adv76xx_setup_format(state); } return 0; } -static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled) +static int adv76xx_isr(struct v4l2_subdev *sd, u32 status, bool *handled) { - struct adv7604_state *state = to_state(sd); - const struct adv7604_chip_info *info = state->info; + struct adv76xx_state *state = to_state(sd); + const struct adv76xx_chip_info *info = state->info; const u8 irq_reg_0x43 = io_read(sd, 0x43); const u8 irq_reg_0x6b = io_read(sd, 0x6b); const u8 irq_reg_0x70 = io_read(sd, 0x70); @@ -1890,7 +1896,7 @@ static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled) "%s: fmt_change = 0x%x, fmt_change_digital = 0x%x\n", __func__, fmt_change, fmt_change_digital); - v4l2_subdev_notify(sd, ADV7604_FMT_CHANGE, NULL); + v4l2_subdev_notify(sd, ADV76XX_FMT_CHANGE, NULL); if (handled) *handled = true; @@ -1909,22 +1915,22 @@ static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled) if (tx_5v) { v4l2_dbg(1, debug, sd, "%s: tx_5v: 0x%x\n", __func__, tx_5v); io_write(sd, 0x71, tx_5v); - adv7604_s_detect_tx_5v_ctrl(sd); + adv76xx_s_detect_tx_5v_ctrl(sd); if (handled) *handled = true; } return 0; } -static int adv7604_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) +static int adv76xx_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) { - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); u8 *data = NULL; memset(edid->reserved, 0, sizeof(edid->reserved)); switch (edid->pad) { - case ADV7604_PAD_HDMI_PORT_A: + case ADV76XX_PAD_HDMI_PORT_A: case ADV7604_PAD_HDMI_PORT_B: case ADV7604_PAD_HDMI_PORT_C: case ADV7604_PAD_HDMI_PORT_D: @@ -1982,10 +1988,10 @@ static int get_edid_spa_location(const u8 *edid) return -1; } -static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) +static int adv76xx_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) { - struct adv7604_state *state = to_state(sd); - const struct adv7604_chip_info *info = state->info; + struct adv76xx_state *state = to_state(sd); + const struct adv76xx_chip_info *info = state->info; int spa_loc; int err; int i; @@ -1999,7 +2005,7 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) if (edid->blocks == 0) { /* Disable hotplug and I2C access to EDID RAM from DDC port */ state->edid.present &= ~(1 << edid->pad); - adv7604_set_hpd(state, state->edid.present); + adv76xx_set_hpd(state, state->edid.present); rep_write_clr_set(sd, info->edid_enable_reg, 0x0f, state->edid.present); /* Fall back to a 16:9 aspect ratio */ @@ -2023,7 +2029,7 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) /* Disable hotplug and I2C access to EDID RAM from DDC port */ cancel_delayed_work_sync(&state->delayed_work_enable_hotplug); - adv7604_set_hpd(state, 0); + adv76xx_set_hpd(state, 0); rep_write_clr_set(sd, info->edid_enable_reg, 0x0f, 0x00); spa_loc = get_edid_spa_location(edid->edid); @@ -2031,7 +2037,7 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) spa_loc = 0xc0; /* Default value [REF_02, p. 116] */ switch (edid->pad) { - case ADV7604_PAD_HDMI_PORT_A: + case ADV76XX_PAD_HDMI_PORT_A: state->spa_port_a[0] = edid->edid[spa_loc]; state->spa_port_a[1] = edid->edid[spa_loc + 1]; break; @@ -2074,7 +2080,7 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) return err; } - /* adv7604 calculates the checksums and enables I2C access to internal + /* adv76xx calculates the checksums and enables I2C access to internal EDID RAM from DDC port. */ rep_write_clr_set(sd, info->edid_enable_reg, 0x0f, state->edid.present); @@ -2138,10 +2144,10 @@ static void print_avi_infoframe(struct v4l2_subdev *sd) buf[8], buf[9], buf[10], buf[11], buf[12], buf[13]); } -static int adv7604_log_status(struct v4l2_subdev *sd) +static int adv76xx_log_status(struct v4l2_subdev *sd) { - struct adv7604_state *state = to_state(sd); - const struct adv7604_chip_info *info = state->info; + struct adv76xx_state *state = to_state(sd); + const struct adv76xx_chip_info *info = state->info; struct v4l2_dv_timings timings; struct stdi_readback stdi; u8 reg_io_0x02 = io_read(sd, 0x02); @@ -2200,7 +2206,7 @@ static int adv7604_log_status(struct v4l2_subdev *sd) v4l2_info(sd, "STDI locked: %s\n", no_lock_stdi(sd) ? "false" : "true"); v4l2_info(sd, "CP locked: %s\n", no_lock_cp(sd) ? "false" : "true"); v4l2_info(sd, "CP free run: %s\n", - (!!(cp_read(sd, 0xff) & 0x10) ? "on" : "off")); + (in_free_run(sd)) ? "on" : "off"); v4l2_info(sd, "Prim-mode = 0x%x, video std = 0x%x, v_freq = 0x%x\n", io_read(sd, 0x01) & 0x0f, io_read(sd, 0x00) & 0x3f, (io_read(sd, 0x01) & 0x70) >> 4); @@ -2213,7 +2219,7 @@ static int adv7604_log_status(struct v4l2_subdev *sd) stdi.lcf, stdi.bl, stdi.lcvs, stdi.interlaced ? "interlaced" : "progressive", stdi.hs_pol, stdi.vs_pol); - if (adv7604_query_dv_timings(sd, &timings)) + if (adv76xx_query_dv_timings(sd, &timings)) v4l2_info(sd, "No video detected\n"); else v4l2_print_dv_timings(sd->name, "Detected format: ", @@ -2235,7 +2241,7 @@ static int adv7604_log_status(struct v4l2_subdev *sd) ((reg_io_0x02 & 0x04) ^ (reg_io_0x02 & 0x01)) ? "enabled" : "disabled"); v4l2_info(sd, "Color space conversion: %s\n", - csc_coeff_sel_rb[cp_read(sd, 0xfc) >> 4]); + csc_coeff_sel_rb[cp_read(sd, info->cp_csc) >> 4]); if (!is_digital_input(sd)) return 0; @@ -2279,47 +2285,47 @@ static int adv7604_log_status(struct v4l2_subdev *sd) /* ----------------------------------------------------------------------- */ -static const struct v4l2_ctrl_ops adv7604_ctrl_ops = { - .s_ctrl = adv7604_s_ctrl, +static const struct v4l2_ctrl_ops adv76xx_ctrl_ops = { + .s_ctrl = adv76xx_s_ctrl, }; -static const struct v4l2_subdev_core_ops adv7604_core_ops = { - .log_status = adv7604_log_status, - .interrupt_service_routine = adv7604_isr, +static const struct v4l2_subdev_core_ops adv76xx_core_ops = { + .log_status = adv76xx_log_status, + .interrupt_service_routine = adv76xx_isr, #ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = adv7604_g_register, - .s_register = adv7604_s_register, + .g_register = adv76xx_g_register, + .s_register = adv76xx_s_register, #endif }; -static const struct v4l2_subdev_video_ops adv7604_video_ops = { - .s_routing = adv7604_s_routing, - .g_input_status = adv7604_g_input_status, - .s_dv_timings = adv7604_s_dv_timings, - .g_dv_timings = adv7604_g_dv_timings, - .query_dv_timings = adv7604_query_dv_timings, +static const struct v4l2_subdev_video_ops adv76xx_video_ops = { + .s_routing = adv76xx_s_routing, + .g_input_status = adv76xx_g_input_status, + .s_dv_timings = adv76xx_s_dv_timings, + .g_dv_timings = adv76xx_g_dv_timings, + .query_dv_timings = adv76xx_query_dv_timings, }; -static const struct v4l2_subdev_pad_ops adv7604_pad_ops = { - .enum_mbus_code = adv7604_enum_mbus_code, - .get_fmt = adv7604_get_format, - .set_fmt = adv7604_set_format, - .get_edid = adv7604_get_edid, - .set_edid = adv7604_set_edid, - .dv_timings_cap = adv7604_dv_timings_cap, - .enum_dv_timings = adv7604_enum_dv_timings, +static const struct v4l2_subdev_pad_ops adv76xx_pad_ops = { + .enum_mbus_code = adv76xx_enum_mbus_code, + .get_fmt = adv76xx_get_format, + .set_fmt = adv76xx_set_format, + .get_edid = adv76xx_get_edid, + .set_edid = adv76xx_set_edid, + .dv_timings_cap = adv76xx_dv_timings_cap, + .enum_dv_timings = adv76xx_enum_dv_timings, }; -static const struct v4l2_subdev_ops adv7604_ops = { - .core = &adv7604_core_ops, - .video = &adv7604_video_ops, - .pad = &adv7604_pad_ops, +static const struct v4l2_subdev_ops adv76xx_ops = { + .core = &adv76xx_core_ops, + .video = &adv76xx_video_ops, + .pad = &adv76xx_pad_ops, }; /* -------------------------- custom ctrls ---------------------------------- */ static const struct v4l2_ctrl_config adv7604_ctrl_analog_sampling_phase = { - .ops = &adv7604_ctrl_ops, + .ops = &adv76xx_ctrl_ops, .id = V4L2_CID_ADV_RX_ANALOG_SAMPLING_PHASE, .name = "Analog Sampling Phase", .type = V4L2_CTRL_TYPE_INTEGER, @@ -2329,8 +2335,8 @@ static const struct v4l2_ctrl_config adv7604_ctrl_analog_sampling_phase = { .def = 0, }; -static const struct v4l2_ctrl_config adv7604_ctrl_free_run_color_manual = { - .ops = &adv7604_ctrl_ops, +static const struct v4l2_ctrl_config adv76xx_ctrl_free_run_color_manual = { + .ops = &adv76xx_ctrl_ops, .id = V4L2_CID_ADV_RX_FREE_RUN_COLOR_MANUAL, .name = "Free Running Color, Manual", .type = V4L2_CTRL_TYPE_BOOLEAN, @@ -2340,8 +2346,8 @@ static const struct v4l2_ctrl_config adv7604_ctrl_free_run_color_manual = { .def = false, }; -static const struct v4l2_ctrl_config adv7604_ctrl_free_run_color = { - .ops = &adv7604_ctrl_ops, +static const struct v4l2_ctrl_config adv76xx_ctrl_free_run_color = { + .ops = &adv76xx_ctrl_ops, .id = V4L2_CID_ADV_RX_FREE_RUN_COLOR, .name = "Free Running Color", .type = V4L2_CTRL_TYPE_INTEGER, @@ -2353,11 +2359,11 @@ static const struct v4l2_ctrl_config adv7604_ctrl_free_run_color = { /* ----------------------------------------------------------------------- */ -static int adv7604_core_init(struct v4l2_subdev *sd) +static int adv76xx_core_init(struct v4l2_subdev *sd) { - struct adv7604_state *state = to_state(sd); - const struct adv7604_chip_info *info = state->info; - struct adv7604_platform_data *pdata = &state->pdata; + struct adv76xx_state *state = to_state(sd); + const struct adv76xx_chip_info *info = state->info; + struct adv76xx_platform_data *pdata = &state->pdata; hdmi_write(sd, 0x48, (pdata->disable_pwrdnb ? 0x80 : 0) | @@ -2385,7 +2391,7 @@ static int adv7604_core_init(struct v4l2_subdev *sd) io_write_clr_set(sd, 0x05, 0x0e, pdata->blank_data << 3 | pdata->insert_av_codes << 2 | pdata->replicate_av_codes << 1); - adv7604_setup_format(state); + adv76xx_setup_format(state); cp_write(sd, 0x69, 0x30); /* Enable CP CSC */ @@ -2415,7 +2421,7 @@ static int adv7604_core_init(struct v4l2_subdev *sd) /* TODO from platform data */ afe_write(sd, 0xb5, 0x01); /* Setting MCLK to 256Fs */ - if (adv7604_has_afe(state)) { + if (adv76xx_has_afe(state)) { afe_write(sd, 0x02, pdata->ain_sel); /* Select analog input muxing mode */ io_write_clr_set(sd, 0x30, 1 << 4, pdata->output_bus_lsb_to_msb << 4); } @@ -2440,7 +2446,7 @@ static void adv7611_setup_irqs(struct v4l2_subdev *sd) io_write(sd, 0x41, 0xd0); /* STDI irq for any change, disable INT2 */ } -static void adv7604_unregister_clients(struct adv7604_state *state) +static void adv76xx_unregister_clients(struct adv76xx_state *state) { unsigned int i; @@ -2450,7 +2456,7 @@ static void adv7604_unregister_clients(struct adv7604_state *state) } } -static struct i2c_client *adv7604_dummy_client(struct v4l2_subdev *sd, +static struct i2c_client *adv76xx_dummy_client(struct v4l2_subdev *sd, u8 addr, u8 io_reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -2460,74 +2466,74 @@ static struct i2c_client *adv7604_dummy_client(struct v4l2_subdev *sd, return i2c_new_dummy(client->adapter, io_read(sd, io_reg) >> 1); } -static const struct adv7604_reg_seq adv7604_recommended_settings_afe[] = { +static const struct adv76xx_reg_seq adv7604_recommended_settings_afe[] = { /* reset ADI recommended settings for HDMI: */ /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x0d), 0x04 }, /* HDMI filter optimization */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x0d), 0x04 }, /* HDMI filter optimization */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x3d), 0x00 }, /* DDC bus active pull-up control */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x3e), 0x74 }, /* TMDS PLL optimization */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x4e), 0x3b }, /* TMDS PLL optimization */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x57), 0x74 }, /* TMDS PLL optimization */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x58), 0x63 }, /* TMDS PLL optimization */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x8d), 0x18 }, /* equaliser */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x8e), 0x34 }, /* equaliser */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x93), 0x88 }, /* equaliser */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x94), 0x2e }, /* equaliser */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x96), 0x00 }, /* enable automatic EQ changing */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x0d), 0x04 }, /* HDMI filter optimization */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x0d), 0x04 }, /* HDMI filter optimization */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x3d), 0x00 }, /* DDC bus active pull-up control */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x3e), 0x74 }, /* TMDS PLL optimization */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x4e), 0x3b }, /* TMDS PLL optimization */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x57), 0x74 }, /* TMDS PLL optimization */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x58), 0x63 }, /* TMDS PLL optimization */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x8d), 0x18 }, /* equaliser */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x8e), 0x34 }, /* equaliser */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x93), 0x88 }, /* equaliser */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x94), 0x2e }, /* equaliser */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x96), 0x00 }, /* enable automatic EQ changing */ /* set ADI recommended settings for digitizer */ /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 17. */ - { ADV7604_REG(ADV7604_PAGE_AFE, 0x12), 0x7b }, /* ADC noise shaping filter controls */ - { ADV7604_REG(ADV7604_PAGE_AFE, 0x0c), 0x1f }, /* CP core gain controls */ - { ADV7604_REG(ADV7604_PAGE_CP, 0x3e), 0x04 }, /* CP core pre-gain control */ - { ADV7604_REG(ADV7604_PAGE_CP, 0xc3), 0x39 }, /* CP coast control. Graphics mode */ - { ADV7604_REG(ADV7604_PAGE_CP, 0x40), 0x5c }, /* CP core pre-gain control. Graphics mode */ + { ADV76XX_REG(ADV76XX_PAGE_AFE, 0x12), 0x7b }, /* ADC noise shaping filter controls */ + { ADV76XX_REG(ADV76XX_PAGE_AFE, 0x0c), 0x1f }, /* CP core gain controls */ + { ADV76XX_REG(ADV76XX_PAGE_CP, 0x3e), 0x04 }, /* CP core pre-gain control */ + { ADV76XX_REG(ADV76XX_PAGE_CP, 0xc3), 0x39 }, /* CP coast control. Graphics mode */ + { ADV76XX_REG(ADV76XX_PAGE_CP, 0x40), 0x5c }, /* CP core pre-gain control. Graphics mode */ - { ADV7604_REG_SEQ_TERM, 0 }, + { ADV76XX_REG_SEQ_TERM, 0 }, }; -static const struct adv7604_reg_seq adv7604_recommended_settings_hdmi[] = { +static const struct adv76xx_reg_seq adv7604_recommended_settings_hdmi[] = { /* set ADI recommended settings for HDMI: */ /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x0d), 0x84 }, /* HDMI filter optimization */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x3d), 0x10 }, /* DDC bus active pull-up control */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x3e), 0x39 }, /* TMDS PLL optimization */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x4e), 0x3b }, /* TMDS PLL optimization */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x57), 0xb6 }, /* TMDS PLL optimization */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x58), 0x03 }, /* TMDS PLL optimization */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x8d), 0x18 }, /* equaliser */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x8e), 0x34 }, /* equaliser */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x93), 0x8b }, /* equaliser */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x94), 0x2d }, /* equaliser */ - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x96), 0x01 }, /* enable automatic EQ changing */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x0d), 0x84 }, /* HDMI filter optimization */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x3d), 0x10 }, /* DDC bus active pull-up control */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x3e), 0x39 }, /* TMDS PLL optimization */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x4e), 0x3b }, /* TMDS PLL optimization */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x57), 0xb6 }, /* TMDS PLL optimization */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x58), 0x03 }, /* TMDS PLL optimization */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x8d), 0x18 }, /* equaliser */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x8e), 0x34 }, /* equaliser */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x93), 0x8b }, /* equaliser */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x94), 0x2d }, /* equaliser */ + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x96), 0x01 }, /* enable automatic EQ changing */ /* reset ADI recommended settings for digitizer */ /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 17. */ - { ADV7604_REG(ADV7604_PAGE_AFE, 0x12), 0xfb }, /* ADC noise shaping filter controls */ - { ADV7604_REG(ADV7604_PAGE_AFE, 0x0c), 0x0d }, /* CP core gain controls */ + { ADV76XX_REG(ADV76XX_PAGE_AFE, 0x12), 0xfb }, /* ADC noise shaping filter controls */ + { ADV76XX_REG(ADV76XX_PAGE_AFE, 0x0c), 0x0d }, /* CP core gain controls */ - { ADV7604_REG_SEQ_TERM, 0 }, + { ADV76XX_REG_SEQ_TERM, 0 }, }; -static const struct adv7604_reg_seq adv7611_recommended_settings_hdmi[] = { +static const struct adv76xx_reg_seq adv7611_recommended_settings_hdmi[] = { /* ADV7611 Register Settings Recommendations Rev 1.5, May 2014 */ - { ADV7604_REG(ADV7604_PAGE_CP, 0x6c), 0x00 }, - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x9b), 0x03 }, - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x6f), 0x08 }, - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x85), 0x1f }, - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x87), 0x70 }, - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x57), 0xda }, - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x58), 0x01 }, - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x03), 0x98 }, - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x4c), 0x44 }, - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x8d), 0x04 }, - { ADV7604_REG(ADV7604_PAGE_HDMI, 0x8e), 0x1e }, - - { ADV7604_REG_SEQ_TERM, 0 }, + { ADV76XX_REG(ADV76XX_PAGE_CP, 0x6c), 0x00 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x9b), 0x03 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x6f), 0x08 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x85), 0x1f }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x87), 0x70 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x57), 0xda }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x58), 0x01 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x03), 0x98 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x4c), 0x44 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x8d), 0x04 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x8e), 0x1e }, + + { ADV76XX_REG_SEQ_TERM, 0 }, }; -static const struct adv7604_chip_info adv7604_chip_info[] = { +static const struct adv76xx_chip_info adv76xx_chip_info[] = { [ADV7604] = { .type = ADV7604, .has_afe = true, @@ -2539,6 +2545,7 @@ static const struct adv7604_chip_info adv7604_chip_info[] = { .tdms_lock_mask = 0xe0, .cable_det_mask = 0x1e, .fmt_change_digital_mask = 0xc1, + .cp_csc = 0xfc, .formats = adv7604_formats, .nformats = ARRAY_SIZE(adv7604_formats), .set_termination = adv7604_set_termination, @@ -2553,18 +2560,18 @@ static const struct adv7604_chip_info adv7604_chip_info[] = { [0] = ARRAY_SIZE(adv7604_recommended_settings_afe), [1] = ARRAY_SIZE(adv7604_recommended_settings_hdmi), }, - .page_mask = BIT(ADV7604_PAGE_IO) | BIT(ADV7604_PAGE_AVLINK) | - BIT(ADV7604_PAGE_CEC) | BIT(ADV7604_PAGE_INFOFRAME) | + .page_mask = BIT(ADV76XX_PAGE_IO) | BIT(ADV7604_PAGE_AVLINK) | + BIT(ADV76XX_PAGE_CEC) | BIT(ADV76XX_PAGE_INFOFRAME) | BIT(ADV7604_PAGE_ESDP) | BIT(ADV7604_PAGE_DPP) | - BIT(ADV7604_PAGE_AFE) | BIT(ADV7604_PAGE_REP) | - BIT(ADV7604_PAGE_EDID) | BIT(ADV7604_PAGE_HDMI) | - BIT(ADV7604_PAGE_TEST) | BIT(ADV7604_PAGE_CP) | + BIT(ADV76XX_PAGE_AFE) | BIT(ADV76XX_PAGE_REP) | + BIT(ADV76XX_PAGE_EDID) | BIT(ADV76XX_PAGE_HDMI) | + BIT(ADV76XX_PAGE_TEST) | BIT(ADV76XX_PAGE_CP) | BIT(ADV7604_PAGE_VDP), }, [ADV7611] = { .type = ADV7611, .has_afe = false, - .max_port = ADV7604_PAD_HDMI_PORT_A, + .max_port = ADV76XX_PAD_HDMI_PORT_A, .num_dv_ports = 1, .edid_enable_reg = 0x74, .edid_status_reg = 0x76, @@ -2572,6 +2579,7 @@ static const struct adv7604_chip_info adv7604_chip_info[] = { .tdms_lock_mask = 0x43, .cable_det_mask = 0x01, .fmt_change_digital_mask = 0x03, + .cp_csc = 0xf4, .formats = adv7611_formats, .nformats = ARRAY_SIZE(adv7611_formats), .set_termination = adv7611_set_termination, @@ -2584,34 +2592,34 @@ static const struct adv7604_chip_info adv7604_chip_info[] = { .num_recommended_settings = { [1] = ARRAY_SIZE(adv7611_recommended_settings_hdmi), }, - .page_mask = BIT(ADV7604_PAGE_IO) | BIT(ADV7604_PAGE_CEC) | - BIT(ADV7604_PAGE_INFOFRAME) | BIT(ADV7604_PAGE_AFE) | - BIT(ADV7604_PAGE_REP) | BIT(ADV7604_PAGE_EDID) | - BIT(ADV7604_PAGE_HDMI) | BIT(ADV7604_PAGE_CP), + .page_mask = BIT(ADV76XX_PAGE_IO) | BIT(ADV76XX_PAGE_CEC) | + BIT(ADV76XX_PAGE_INFOFRAME) | BIT(ADV76XX_PAGE_AFE) | + BIT(ADV76XX_PAGE_REP) | BIT(ADV76XX_PAGE_EDID) | + BIT(ADV76XX_PAGE_HDMI) | BIT(ADV76XX_PAGE_CP), }, }; -static struct i2c_device_id adv7604_i2c_id[] = { - { "adv7604", (kernel_ulong_t)&adv7604_chip_info[ADV7604] }, - { "adv7611", (kernel_ulong_t)&adv7604_chip_info[ADV7611] }, +static struct i2c_device_id adv76xx_i2c_id[] = { + { "adv7604", (kernel_ulong_t)&adv76xx_chip_info[ADV7604] }, + { "adv7611", (kernel_ulong_t)&adv76xx_chip_info[ADV7611] }, { } }; -MODULE_DEVICE_TABLE(i2c, adv7604_i2c_id); +MODULE_DEVICE_TABLE(i2c, adv76xx_i2c_id); -static struct of_device_id adv7604_of_id[] __maybe_unused = { - { .compatible = "adi,adv7611", .data = &adv7604_chip_info[ADV7611] }, +static struct of_device_id adv76xx_of_id[] __maybe_unused = { + { .compatible = "adi,adv7611", .data = &adv76xx_chip_info[ADV7611] }, { } }; -MODULE_DEVICE_TABLE(of, adv7604_of_id); +MODULE_DEVICE_TABLE(of, adv76xx_of_id); -static int adv7604_parse_dt(struct adv7604_state *state) +static int adv76xx_parse_dt(struct adv76xx_state *state) { struct v4l2_of_endpoint bus_cfg; struct device_node *endpoint; struct device_node *np; unsigned int flags; - np = state->i2c_clients[ADV7604_PAGE_IO]->dev.of_node; + np = state->i2c_clients[ADV76XX_PAGE_IO]->dev.of_node; /* Parse the endpoint. */ endpoint = of_graph_get_next_endpoint(np, NULL); @@ -2638,20 +2646,20 @@ static int adv7604_parse_dt(struct adv7604_state *state) } /* Disable the interrupt for now as no DT-based board uses it. */ - state->pdata.int1_config = ADV7604_INT1_CONFIG_DISABLED; + state->pdata.int1_config = ADV76XX_INT1_CONFIG_DISABLED; /* Use the default I2C addresses. */ state->pdata.i2c_addresses[ADV7604_PAGE_AVLINK] = 0x42; - state->pdata.i2c_addresses[ADV7604_PAGE_CEC] = 0x40; - state->pdata.i2c_addresses[ADV7604_PAGE_INFOFRAME] = 0x3e; + state->pdata.i2c_addresses[ADV76XX_PAGE_CEC] = 0x40; + state->pdata.i2c_addresses[ADV76XX_PAGE_INFOFRAME] = 0x3e; state->pdata.i2c_addresses[ADV7604_PAGE_ESDP] = 0x38; state->pdata.i2c_addresses[ADV7604_PAGE_DPP] = 0x3c; - state->pdata.i2c_addresses[ADV7604_PAGE_AFE] = 0x26; - state->pdata.i2c_addresses[ADV7604_PAGE_REP] = 0x32; - state->pdata.i2c_addresses[ADV7604_PAGE_EDID] = 0x36; - state->pdata.i2c_addresses[ADV7604_PAGE_HDMI] = 0x34; - state->pdata.i2c_addresses[ADV7604_PAGE_TEST] = 0x30; - state->pdata.i2c_addresses[ADV7604_PAGE_CP] = 0x22; + state->pdata.i2c_addresses[ADV76XX_PAGE_AFE] = 0x26; + state->pdata.i2c_addresses[ADV76XX_PAGE_REP] = 0x32; + state->pdata.i2c_addresses[ADV76XX_PAGE_EDID] = 0x36; + state->pdata.i2c_addresses[ADV76XX_PAGE_HDMI] = 0x34; + state->pdata.i2c_addresses[ADV76XX_PAGE_TEST] = 0x30; + state->pdata.i2c_addresses[ADV76XX_PAGE_CP] = 0x22; state->pdata.i2c_addresses[ADV7604_PAGE_VDP] = 0x24; /* Hardcode the remaining platform data fields. */ @@ -2666,12 +2674,12 @@ static int adv7604_parse_dt(struct adv7604_state *state) return 0; } -static int adv7604_probe(struct i2c_client *client, +static int adv76xx_probe(struct i2c_client *client, const struct i2c_device_id *id) { static const struct v4l2_dv_timings cea640x480 = V4L2_DV_BT_CEA_640X480P59_94; - struct adv7604_state *state; + struct adv76xx_state *state; struct v4l2_ctrl_handler *hdl; struct v4l2_subdev *sd; unsigned int i; @@ -2681,16 +2689,16 @@ static int adv7604_probe(struct i2c_client *client, /* Check if the adapter supports the needed features */ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -EIO; - v4l_dbg(1, debug, client, "detecting adv7604 client on address 0x%x\n", + v4l_dbg(1, debug, client, "detecting adv76xx client on address 0x%x\n", client->addr << 1); state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL); if (!state) { - v4l_err(client, "Could not allocate adv7604_state memory!\n"); + v4l_err(client, "Could not allocate adv76xx_state memory!\n"); return -ENOMEM; } - state->i2c_clients[ADV7604_PAGE_IO] = client; + state->i2c_clients[ADV76XX_PAGE_IO] = client; /* initialize variables */ state->restart_stdi_once = true; @@ -2699,18 +2707,18 @@ static int adv7604_probe(struct i2c_client *client, if (IS_ENABLED(CONFIG_OF) && client->dev.of_node) { const struct of_device_id *oid; - oid = of_match_node(adv7604_of_id, client->dev.of_node); + oid = of_match_node(adv76xx_of_id, client->dev.of_node); state->info = oid->data; - err = adv7604_parse_dt(state); + err = adv76xx_parse_dt(state); if (err < 0) { v4l_err(client, "DT parsing error\n"); return err; } } else if (client->dev.platform_data) { - struct adv7604_platform_data *pdata = client->dev.platform_data; + struct adv76xx_platform_data *pdata = client->dev.platform_data; - state->info = (const struct adv7604_chip_info *)id->driver_data; + state->info = (const struct adv76xx_chip_info *)id->driver_data; state->pdata = *pdata; } else { v4l_err(client, "No platform data!\n"); @@ -2720,20 +2728,20 @@ static int adv7604_probe(struct i2c_client *client, /* Request GPIOs. */ for (i = 0; i < state->info->num_dv_ports; ++i) { state->hpd_gpio[i] = - devm_gpiod_get_index(&client->dev, "hpd", i); + devm_gpiod_get_index_optional(&client->dev, "hpd", i, + GPIOD_OUT_LOW); if (IS_ERR(state->hpd_gpio[i])) - continue; - - gpiod_direction_output(state->hpd_gpio[i], 0); + return PTR_ERR(state->hpd_gpio[i]); - v4l_info(client, "Handling HPD %u GPIO\n", i); + if (state->hpd_gpio[i]) + v4l_info(client, "Handling HPD %u GPIO\n", i); } state->timings = cea640x480; - state->format = adv7604_format_info(state, MEDIA_BUS_FMT_YUYV8_2X8); + state->format = adv76xx_format_info(state, MEDIA_BUS_FMT_YUYV8_2X8); sd = &state->sd; - v4l2_i2c_subdev_init(sd, client, &adv7604_ops); + v4l2_i2c_subdev_init(sd, client, &adv76xx_ops); snprintf(sd->name, sizeof(sd->name), "%s %d-%04x", id->name, i2c_adapter_id(client->adapter), client->addr); @@ -2763,15 +2771,15 @@ static int adv7604_probe(struct i2c_client *client, /* control handlers */ hdl = &state->hdl; - v4l2_ctrl_handler_init(hdl, adv7604_has_afe(state) ? 9 : 8); + v4l2_ctrl_handler_init(hdl, adv76xx_has_afe(state) ? 9 : 8); - v4l2_ctrl_new_std(hdl, &adv7604_ctrl_ops, + v4l2_ctrl_new_std(hdl, &adv76xx_ctrl_ops, V4L2_CID_BRIGHTNESS, -128, 127, 1, 0); - v4l2_ctrl_new_std(hdl, &adv7604_ctrl_ops, + v4l2_ctrl_new_std(hdl, &adv76xx_ctrl_ops, V4L2_CID_CONTRAST, 0, 255, 1, 128); - v4l2_ctrl_new_std(hdl, &adv7604_ctrl_ops, + v4l2_ctrl_new_std(hdl, &adv76xx_ctrl_ops, V4L2_CID_SATURATION, 0, 255, 1, 128); - v4l2_ctrl_new_std(hdl, &adv7604_ctrl_ops, + v4l2_ctrl_new_std(hdl, &adv76xx_ctrl_ops, V4L2_CID_HUE, 0, 128, 1, 0); /* private controls */ @@ -2779,18 +2787,18 @@ static int adv7604_probe(struct i2c_client *client, V4L2_CID_DV_RX_POWER_PRESENT, 0, (1 << state->info->num_dv_ports) - 1, 0, 0); state->rgb_quantization_range_ctrl = - v4l2_ctrl_new_std_menu(hdl, &adv7604_ctrl_ops, + v4l2_ctrl_new_std_menu(hdl, &adv76xx_ctrl_ops, V4L2_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL, 0, V4L2_DV_RGB_RANGE_AUTO); /* custom controls */ - if (adv7604_has_afe(state)) + if (adv76xx_has_afe(state)) state->analog_sampling_phase_ctrl = v4l2_ctrl_new_custom(hdl, &adv7604_ctrl_analog_sampling_phase, NULL); state->free_run_color_manual_ctrl = - v4l2_ctrl_new_custom(hdl, &adv7604_ctrl_free_run_color_manual, NULL); + v4l2_ctrl_new_custom(hdl, &adv76xx_ctrl_free_run_color_manual, NULL); state->free_run_color_ctrl = - v4l2_ctrl_new_custom(hdl, &adv7604_ctrl_free_run_color, NULL); + v4l2_ctrl_new_custom(hdl, &adv76xx_ctrl_free_run_color, NULL); sd->ctrl_handler = hdl; if (hdl->error) { @@ -2799,22 +2807,22 @@ static int adv7604_probe(struct i2c_client *client, } state->detect_tx_5v_ctrl->is_private = true; state->rgb_quantization_range_ctrl->is_private = true; - if (adv7604_has_afe(state)) + if (adv76xx_has_afe(state)) state->analog_sampling_phase_ctrl->is_private = true; state->free_run_color_manual_ctrl->is_private = true; state->free_run_color_ctrl->is_private = true; - if (adv7604_s_detect_tx_5v_ctrl(sd)) { + if (adv76xx_s_detect_tx_5v_ctrl(sd)) { err = -ENODEV; goto err_hdl; } - for (i = 1; i < ADV7604_PAGE_MAX; ++i) { + for (i = 1; i < ADV76XX_PAGE_MAX; ++i) { if (!(BIT(i) & state->info->page_mask)) continue; state->i2c_clients[i] = - adv7604_dummy_client(sd, state->pdata.i2c_addresses[i], + adv76xx_dummy_client(sd, state->pdata.i2c_addresses[i], 0xf2 + i); if (state->i2c_clients[i] == NULL) { err = -ENOMEM; @@ -2832,7 +2840,7 @@ static int adv7604_probe(struct i2c_client *client, } INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug, - adv7604_delayed_work_enable_hotplug); + adv76xx_delayed_work_enable_hotplug); state->source_pad = state->info->num_dv_ports + (state->info->has_afe ? 2 : 0); @@ -2845,7 +2853,7 @@ static int adv7604_probe(struct i2c_client *client, if (err) goto err_work_queues; - err = adv7604_core_init(sd); + err = adv76xx_core_init(sd); if (err) goto err_entity; v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, @@ -2863,7 +2871,7 @@ err_work_queues: cancel_delayed_work(&state->delayed_work_enable_hotplug); destroy_workqueue(state->work_queues); err_i2c: - adv7604_unregister_clients(state); + adv76xx_unregister_clients(state); err_hdl: v4l2_ctrl_handler_free(hdl); return err; @@ -2871,32 +2879,31 @@ err_hdl: /* ----------------------------------------------------------------------- */ -static int adv7604_remove(struct i2c_client *client) +static int adv76xx_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct adv7604_state *state = to_state(sd); + struct adv76xx_state *state = to_state(sd); cancel_delayed_work(&state->delayed_work_enable_hotplug); destroy_workqueue(state->work_queues); v4l2_async_unregister_subdev(sd); - v4l2_device_unregister_subdev(sd); media_entity_cleanup(&sd->entity); - adv7604_unregister_clients(to_state(sd)); + adv76xx_unregister_clients(to_state(sd)); v4l2_ctrl_handler_free(sd->ctrl_handler); return 0; } /* ----------------------------------------------------------------------- */ -static struct i2c_driver adv7604_driver = { +static struct i2c_driver adv76xx_driver = { .driver = { .owner = THIS_MODULE, .name = "adv7604", - .of_match_table = of_match_ptr(adv7604_of_id), + .of_match_table = of_match_ptr(adv76xx_of_id), }, - .probe = adv7604_probe, - .remove = adv7604_remove, - .id_table = adv7604_i2c_id, + .probe = adv76xx_probe, + .remove = adv76xx_remove, + .id_table = adv76xx_i2c_id, }; -module_i2c_driver(adv7604_driver); +module_i2c_driver(adv76xx_driver); diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 7c215ee142c4..b5a37fe10a6a 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -1119,7 +1119,7 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) /* Receiving DVI-D signal * ADV7842 selects RGB limited range regardless of * input format (CE/IT) in automatic mode */ - if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861) { + if (state->timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) { /* RGB limited range (16-235) */ io_write_and_or(sd, 0x02, 0x0f, 0x00); } else { @@ -1901,7 +1901,8 @@ static int adv7842_g_mbus_fmt(struct v4l2_subdev *sd, return 0; } - if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861) { + fmt->colorspace = V4L2_COLORSPACE_SRGB; + if (state->timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) { fmt->colorspace = (state->timings.bt.height <= 576) ? V4L2_COLORSPACE_SMPTE170M : V4L2_COLORSPACE_REC709; } diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index 573e08826b9b..bd496447749a 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -5137,6 +5137,9 @@ static int cx25840_probe(struct i2c_client *client, int default_volume; u32 id; u16 device_id; +#if defined(CONFIG_MEDIA_CONTROLLER) + int ret; +#endif /* Check if the adapter supports the needed features */ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) @@ -5178,6 +5181,33 @@ static int cx25840_probe(struct i2c_client *client, sd = &state->sd; v4l2_i2c_subdev_init(sd, client, &cx25840_ops); +#if defined(CONFIG_MEDIA_CONTROLLER) + /* + * TODO: add media controller support for analog video inputs like + * composite, svideo, etc. + * A real input pad for this analog demod would be like: + * ___________ + * TUNER --------> | | + * | | + * SVIDEO .......> | cx25840 | + * | | + * COMPOSITE1 ...> |_________| + * + * However, at least for now, there's no much gain on modelling + * those extra inputs. So, let's add it only when needed. + */ + state->pads[CX25840_PAD_INPUT].flags = MEDIA_PAD_FL_SINK; + state->pads[CX25840_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE; + state->pads[CX25840_PAD_VBI_OUT].flags = MEDIA_PAD_FL_SOURCE; + sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_DECODER; + + ret = media_entity_init(&sd->entity, ARRAY_SIZE(state->pads), + state->pads, 0); + if (ret < 0) { + v4l_info(client, "failed to initialize media entity!\n"); + return ret; + } +#endif switch (id) { case CX23885_AV: diff --git a/drivers/media/i2c/cx25840/cx25840-core.h b/drivers/media/i2c/cx25840/cx25840-core.h index 37bc04217c44..fdea48ce0c03 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.h +++ b/drivers/media/i2c/cx25840/cx25840-core.h @@ -41,6 +41,14 @@ enum cx25840_model { CX25837, }; +enum cx25840_media_pads { + CX25840_PAD_INPUT, + CX25840_PAD_VID_OUT, + CX25840_PAD_VBI_OUT, + + CX25840_NUM_PADS +}; + struct cx25840_state { struct i2c_client *c; struct v4l2_subdev sd; @@ -64,6 +72,9 @@ struct cx25840_state { wait_queue_head_t fw_wait; /* wake up when the fw load is finished */ struct work_struct fw_work; /* work entry for fw load */ struct cx25840_ir_state *ir_state; +#if defined(CONFIG_MEDIA_CONTROLLER) + struct media_pad pads[CX25840_NUM_PADS]; +#endif }; static inline struct cx25840_state *to_state(struct v4l2_subdev *sd) diff --git a/drivers/media/i2c/m5mols/m5mols_core.c b/drivers/media/i2c/m5mols/m5mols_core.c index 6ed16e569bbf..6404c0d93e7a 100644 --- a/drivers/media/i2c/m5mols/m5mols_core.c +++ b/drivers/media/i2c/m5mols/m5mols_core.c @@ -531,17 +531,17 @@ static int __find_resolution(struct v4l2_subdev *sd, } static struct v4l2_mbus_framefmt *__find_format(struct m5mols_info *info, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, enum v4l2_subdev_format_whence which, enum m5mols_restype type) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return fh ? v4l2_subdev_get_try_format(fh, 0) : NULL; + return cfg ? v4l2_subdev_get_try_format(&info->sd, cfg, 0) : NULL; return &info->ffmt[type]; } -static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct m5mols_info *info = to_m5mols(sd); @@ -550,7 +550,7 @@ static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, mutex_lock(&info->lock); - format = __find_format(info, fh, fmt->which, info->res_type); + format = __find_format(info, cfg, fmt->which, info->res_type); if (format) fmt->format = *format; else @@ -560,7 +560,7 @@ static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, return ret; } -static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct m5mols_info *info = to_m5mols(sd); @@ -574,7 +574,7 @@ static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, if (ret < 0) return ret; - sfmt = __find_format(info, fh, fmt->which, type); + sfmt = __find_format(info, cfg, fmt->which, type); if (!sfmt) return 0; @@ -640,7 +640,7 @@ static int m5mols_set_frame_desc(struct v4l2_subdev *sd, unsigned int pad, static int m5mols_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (!code || code->index >= SIZE_DEFAULT_FFMT) @@ -895,7 +895,7 @@ static const struct v4l2_subdev_core_ops m5mols_core_ops = { */ static int m5mols_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { - struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0); + struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd, fh->pad, 0); *format = m5mols_default_ffmt[0]; return 0; diff --git a/drivers/media/i2c/mt9m032.c b/drivers/media/i2c/mt9m032.c index 76431223f0ff..c7747bd0cabb 100644 --- a/drivers/media/i2c/mt9m032.c +++ b/drivers/media/i2c/mt9m032.c @@ -317,7 +317,7 @@ static int mt9m032_setup_pll(struct mt9m032 *sensor) */ static int mt9m032_enum_mbus_code(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->index != 0) @@ -328,7 +328,7 @@ static int mt9m032_enum_mbus_code(struct v4l2_subdev *subdev, } static int mt9m032_enum_frame_size(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { if (fse->index != 0 || fse->code != MEDIA_BUS_FMT_Y8_1X8) @@ -345,18 +345,18 @@ static int mt9m032_enum_frame_size(struct v4l2_subdev *subdev, /** * __mt9m032_get_pad_crop() - get crop rect * @sensor: pointer to the sensor struct - * @fh: file handle for getting the try crop rect from + * @cfg: v4l2_subdev_pad_config for getting the try crop rect from * @which: select try or active crop rect * * Returns a pointer the current active or fh relative try crop rect */ static struct v4l2_rect * -__mt9m032_get_pad_crop(struct mt9m032 *sensor, struct v4l2_subdev_fh *fh, +__mt9m032_get_pad_crop(struct mt9m032 *sensor, struct v4l2_subdev_pad_config *cfg, enum v4l2_subdev_format_whence which) { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_crop(fh, 0); + return v4l2_subdev_get_try_crop(&sensor->subdev, cfg, 0); case V4L2_SUBDEV_FORMAT_ACTIVE: return &sensor->crop; default: @@ -367,18 +367,18 @@ __mt9m032_get_pad_crop(struct mt9m032 *sensor, struct v4l2_subdev_fh *fh, /** * __mt9m032_get_pad_format() - get format * @sensor: pointer to the sensor struct - * @fh: file handle for getting the try format from + * @cfg: v4l2_subdev_pad_config for getting the try format from * @which: select try or active format * * Returns a pointer the current active or fh relative try format */ static struct v4l2_mbus_framefmt * -__mt9m032_get_pad_format(struct mt9m032 *sensor, struct v4l2_subdev_fh *fh, +__mt9m032_get_pad_format(struct mt9m032 *sensor, struct v4l2_subdev_pad_config *cfg, enum v4l2_subdev_format_whence which) { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_format(fh, 0); + return v4l2_subdev_get_try_format(&sensor->subdev, cfg, 0); case V4L2_SUBDEV_FORMAT_ACTIVE: return &sensor->format; default: @@ -387,20 +387,20 @@ __mt9m032_get_pad_format(struct mt9m032 *sensor, struct v4l2_subdev_fh *fh, } static int mt9m032_get_pad_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct mt9m032 *sensor = to_mt9m032(subdev); mutex_lock(&sensor->lock); - fmt->format = *__mt9m032_get_pad_format(sensor, fh, fmt->which); + fmt->format = *__mt9m032_get_pad_format(sensor, cfg, fmt->which); mutex_unlock(&sensor->lock); return 0; } static int mt9m032_set_pad_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct mt9m032 *sensor = to_mt9m032(subdev); @@ -414,7 +414,7 @@ static int mt9m032_set_pad_format(struct v4l2_subdev *subdev, } /* Scaling is not supported, the format is thus fixed. */ - fmt->format = *__mt9m032_get_pad_format(sensor, fh, fmt->which); + fmt->format = *__mt9m032_get_pad_format(sensor, cfg, fmt->which); ret = 0; done: @@ -423,7 +423,7 @@ done: } static int mt9m032_get_pad_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct mt9m032 *sensor = to_mt9m032(subdev); @@ -432,14 +432,14 @@ static int mt9m032_get_pad_selection(struct v4l2_subdev *subdev, return -EINVAL; mutex_lock(&sensor->lock); - sel->r = *__mt9m032_get_pad_crop(sensor, fh, sel->which); + sel->r = *__mt9m032_get_pad_crop(sensor, cfg, sel->which); mutex_unlock(&sensor->lock); return 0; } static int mt9m032_set_pad_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct mt9m032 *sensor = to_mt9m032(subdev); @@ -475,13 +475,13 @@ static int mt9m032_set_pad_selection(struct v4l2_subdev *subdev, rect.height = min_t(unsigned int, rect.height, MT9M032_PIXEL_ARRAY_HEIGHT - rect.top); - __crop = __mt9m032_get_pad_crop(sensor, fh, sel->which); + __crop = __mt9m032_get_pad_crop(sensor, cfg, sel->which); if (rect.width != __crop->width || rect.height != __crop->height) { /* Reset the output image size if the crop rectangle size has * been modified. */ - format = __mt9m032_get_pad_format(sensor, fh, sel->which); + format = __mt9m032_get_pad_format(sensor, cfg, sel->which); format->width = rect.width; format->height = rect.height; } diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index e3acae9a2ec3..0db15f528ac1 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -15,12 +15,11 @@ #include <linux/clk.h> #include <linux/delay.h> #include <linux/device.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/log2.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/of_graph.h> #include <linux/pm.h> #include <linux/regulator/consumer.h> @@ -28,6 +27,7 @@ #include <linux/videodev2.h> #include <media/mt9p031.h> +#include <media/v4l2-async.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-subdev.h> @@ -135,7 +135,7 @@ struct mt9p031 { struct aptina_pll pll; unsigned int clk_div; bool use_pll; - int reset; + struct gpio_desc *reset; struct v4l2_ctrl_handler ctrls; struct v4l2_ctrl *blc_auto; @@ -251,7 +251,7 @@ static int mt9p031_clk_setup(struct mt9p031 *mt9p031) div = DIV_ROUND_UP(pdata->ext_freq, pdata->target_freq); div = roundup_pow_of_two(div) / 2; - mt9p031->clk_div = max_t(unsigned int, div, 64); + mt9p031->clk_div = min_t(unsigned int, div, 64); mt9p031->use_pll = false; return 0; @@ -308,9 +308,9 @@ static int mt9p031_power_on(struct mt9p031 *mt9p031) { int ret; - /* Ensure RESET_BAR is low */ - if (gpio_is_valid(mt9p031->reset)) { - gpio_set_value(mt9p031->reset, 0); + /* Ensure RESET_BAR is active */ + if (mt9p031->reset) { + gpiod_set_value(mt9p031->reset, 1); usleep_range(1000, 2000); } @@ -331,8 +331,8 @@ static int mt9p031_power_on(struct mt9p031 *mt9p031) } /* Now RESET_BAR must be high */ - if (gpio_is_valid(mt9p031->reset)) { - gpio_set_value(mt9p031->reset, 1); + if (mt9p031->reset) { + gpiod_set_value(mt9p031->reset, 0); usleep_range(1000, 2000); } @@ -341,8 +341,8 @@ static int mt9p031_power_on(struct mt9p031 *mt9p031) static void mt9p031_power_off(struct mt9p031 *mt9p031) { - if (gpio_is_valid(mt9p031->reset)) { - gpio_set_value(mt9p031->reset, 0); + if (mt9p031->reset) { + gpiod_set_value(mt9p031->reset, 1); usleep_range(1000, 2000); } @@ -474,7 +474,7 @@ static int mt9p031_s_stream(struct v4l2_subdev *subdev, int enable) } static int mt9p031_enum_mbus_code(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { struct mt9p031 *mt9p031 = to_mt9p031(subdev); @@ -487,7 +487,7 @@ static int mt9p031_enum_mbus_code(struct v4l2_subdev *subdev, } static int mt9p031_enum_frame_size(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct mt9p031 *mt9p031 = to_mt9p031(subdev); @@ -505,12 +505,12 @@ static int mt9p031_enum_frame_size(struct v4l2_subdev *subdev, } static struct v4l2_mbus_framefmt * -__mt9p031_get_pad_format(struct mt9p031 *mt9p031, struct v4l2_subdev_fh *fh, +__mt9p031_get_pad_format(struct mt9p031 *mt9p031, struct v4l2_subdev_pad_config *cfg, unsigned int pad, u32 which) { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&mt9p031->subdev, cfg, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &mt9p031->format; default: @@ -519,12 +519,12 @@ __mt9p031_get_pad_format(struct mt9p031 *mt9p031, struct v4l2_subdev_fh *fh, } static struct v4l2_rect * -__mt9p031_get_pad_crop(struct mt9p031 *mt9p031, struct v4l2_subdev_fh *fh, +__mt9p031_get_pad_crop(struct mt9p031 *mt9p031, struct v4l2_subdev_pad_config *cfg, unsigned int pad, u32 which) { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_crop(fh, pad); + return v4l2_subdev_get_try_crop(&mt9p031->subdev, cfg, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &mt9p031->crop; default: @@ -533,18 +533,18 @@ __mt9p031_get_pad_crop(struct mt9p031 *mt9p031, struct v4l2_subdev_fh *fh, } static int mt9p031_get_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct mt9p031 *mt9p031 = to_mt9p031(subdev); - fmt->format = *__mt9p031_get_pad_format(mt9p031, fh, fmt->pad, + fmt->format = *__mt9p031_get_pad_format(mt9p031, cfg, fmt->pad, fmt->which); return 0; } static int mt9p031_set_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { struct mt9p031 *mt9p031 = to_mt9p031(subdev); @@ -555,7 +555,7 @@ static int mt9p031_set_format(struct v4l2_subdev *subdev, unsigned int hratio; unsigned int vratio; - __crop = __mt9p031_get_pad_crop(mt9p031, fh, format->pad, + __crop = __mt9p031_get_pad_crop(mt9p031, cfg, format->pad, format->which); /* Clamp the width and height to avoid dividing by zero. */ @@ -571,7 +571,7 @@ static int mt9p031_set_format(struct v4l2_subdev *subdev, hratio = DIV_ROUND_CLOSEST(__crop->width, width); vratio = DIV_ROUND_CLOSEST(__crop->height, height); - __format = __mt9p031_get_pad_format(mt9p031, fh, format->pad, + __format = __mt9p031_get_pad_format(mt9p031, cfg, format->pad, format->which); __format->width = __crop->width / hratio; __format->height = __crop->height / vratio; @@ -582,7 +582,7 @@ static int mt9p031_set_format(struct v4l2_subdev *subdev, } static int mt9p031_get_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct mt9p031 *mt9p031 = to_mt9p031(subdev); @@ -590,12 +590,12 @@ static int mt9p031_get_selection(struct v4l2_subdev *subdev, if (sel->target != V4L2_SEL_TGT_CROP) return -EINVAL; - sel->r = *__mt9p031_get_pad_crop(mt9p031, fh, sel->pad, sel->which); + sel->r = *__mt9p031_get_pad_crop(mt9p031, cfg, sel->pad, sel->which); return 0; } static int mt9p031_set_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct mt9p031 *mt9p031 = to_mt9p031(subdev); @@ -625,13 +625,13 @@ static int mt9p031_set_selection(struct v4l2_subdev *subdev, rect.height = min_t(unsigned int, rect.height, MT9P031_PIXEL_ARRAY_HEIGHT - rect.top); - __crop = __mt9p031_get_pad_crop(mt9p031, fh, sel->pad, sel->which); + __crop = __mt9p031_get_pad_crop(mt9p031, cfg, sel->pad, sel->which); if (rect.width != __crop->width || rect.height != __crop->height) { /* Reset the output image size if the crop rectangle size has * been modified. */ - __format = __mt9p031_get_pad_format(mt9p031, fh, sel->pad, + __format = __mt9p031_get_pad_format(mt9p031, cfg, sel->pad, sel->which); __format->width = rect.width; __format->height = rect.height; @@ -946,13 +946,13 @@ static int mt9p031_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) struct v4l2_mbus_framefmt *format; struct v4l2_rect *crop; - crop = v4l2_subdev_get_try_crop(fh, 0); + crop = v4l2_subdev_get_try_crop(subdev, fh->pad, 0); crop->left = MT9P031_COLUMN_START_DEF; crop->top = MT9P031_ROW_START_DEF; crop->width = MT9P031_WINDOW_WIDTH_DEF; crop->height = MT9P031_WINDOW_HEIGHT_DEF; - format = v4l2_subdev_get_try_format(fh, 0); + format = v4l2_subdev_get_try_format(subdev, fh->pad, 0); if (mt9p031->model == MT9P031_MODEL_MONOCHROME) format->code = MEDIA_BUS_FMT_Y12_1X12; @@ -1022,7 +1022,6 @@ mt9p031_get_pdata(struct i2c_client *client) if (!pdata) goto done; - pdata->reset = of_get_named_gpio(client->dev.of_node, "reset-gpios", 0); of_property_read_u32(np, "input-clock-frequency", &pdata->ext_freq); of_property_read_u32(np, "pixel-clock-frequency", &pdata->target_freq); @@ -1059,7 +1058,6 @@ static int mt9p031_probe(struct i2c_client *client, mt9p031->output_control = MT9P031_OUTPUT_CONTROL_DEF; mt9p031->mode2 = MT9P031_READ_MODE_2_ROW_BLC; mt9p031->model = did->driver_data; - mt9p031->reset = -1; mt9p031->regulators[0].supply = "vdd"; mt9p031->regulators[1].supply = "vdd_io"; @@ -1071,6 +1069,8 @@ static int mt9p031_probe(struct i2c_client *client, return ret; } + mutex_init(&mt9p031->power_lock); + v4l2_ctrl_handler_init(&mt9p031->ctrls, ARRAY_SIZE(mt9p031_ctrls) + 6); v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops, @@ -1108,7 +1108,6 @@ static int mt9p031_probe(struct i2c_client *client, mt9p031->blc_offset = v4l2_ctrl_find(&mt9p031->ctrls, V4L2_CID_BLC_DIGITAL_OFFSET); - mutex_init(&mt9p031->power_lock); v4l2_i2c_subdev_init(&mt9p031->subdev, client, &mt9p031_subdev_ops); mt9p031->subdev.internal_ops = &mt9p031_subdev_internal_ops; @@ -1134,21 +1133,20 @@ static int mt9p031_probe(struct i2c_client *client, mt9p031->format.field = V4L2_FIELD_NONE; mt9p031->format.colorspace = V4L2_COLORSPACE_SRGB; - if (gpio_is_valid(pdata->reset)) { - ret = devm_gpio_request_one(&client->dev, pdata->reset, - GPIOF_OUT_INIT_LOW, "mt9p031_rst"); - if (ret < 0) - goto done; - - mt9p031->reset = pdata->reset; - } + mt9p031->reset = devm_gpiod_get_optional(&client->dev, "reset", + GPIOD_OUT_HIGH); ret = mt9p031_clk_setup(mt9p031); + if (ret) + goto done; + + ret = v4l2_async_register_subdev(&mt9p031->subdev); done: if (ret < 0) { v4l2_ctrl_handler_free(&mt9p031->ctrls); media_entity_cleanup(&mt9p031->subdev.entity); + mutex_destroy(&mt9p031->power_lock); } return ret; @@ -1160,8 +1158,9 @@ static int mt9p031_remove(struct i2c_client *client) struct mt9p031 *mt9p031 = to_mt9p031(subdev); v4l2_ctrl_handler_free(&mt9p031->ctrls); - v4l2_device_unregister_subdev(subdev); + v4l2_async_unregister_subdev(subdev); media_entity_cleanup(&subdev->entity); + mutex_destroy(&mt9p031->power_lock); return 0; } diff --git a/drivers/media/i2c/mt9t001.c b/drivers/media/i2c/mt9t001.c index f6ca636b538d..8ae99f7f254c 100644 --- a/drivers/media/i2c/mt9t001.c +++ b/drivers/media/i2c/mt9t001.c @@ -244,12 +244,12 @@ static int __mt9t001_set_power(struct mt9t001 *mt9t001, bool on) */ static struct v4l2_mbus_framefmt * -__mt9t001_get_pad_format(struct mt9t001 *mt9t001, struct v4l2_subdev_fh *fh, +__mt9t001_get_pad_format(struct mt9t001 *mt9t001, struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&mt9t001->subdev, cfg, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &mt9t001->format; default: @@ -258,12 +258,12 @@ __mt9t001_get_pad_format(struct mt9t001 *mt9t001, struct v4l2_subdev_fh *fh, } static struct v4l2_rect * -__mt9t001_get_pad_crop(struct mt9t001 *mt9t001, struct v4l2_subdev_fh *fh, +__mt9t001_get_pad_crop(struct mt9t001 *mt9t001, struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_crop(fh, pad); + return v4l2_subdev_get_try_crop(&mt9t001->subdev, cfg, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &mt9t001->crop; default: @@ -327,7 +327,7 @@ static int mt9t001_s_stream(struct v4l2_subdev *subdev, int enable) } static int mt9t001_enum_mbus_code(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->index > 0) @@ -338,7 +338,7 @@ static int mt9t001_enum_mbus_code(struct v4l2_subdev *subdev, } static int mt9t001_enum_frame_size(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { if (fse->index >= 8 || fse->code != MEDIA_BUS_FMT_SGRBG10_1X10) @@ -353,18 +353,18 @@ static int mt9t001_enum_frame_size(struct v4l2_subdev *subdev, } static int mt9t001_get_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { struct mt9t001 *mt9t001 = to_mt9t001(subdev); - format->format = *__mt9t001_get_pad_format(mt9t001, fh, format->pad, + format->format = *__mt9t001_get_pad_format(mt9t001, cfg, format->pad, format->which); return 0; } static int mt9t001_set_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { struct mt9t001 *mt9t001 = to_mt9t001(subdev); @@ -375,7 +375,7 @@ static int mt9t001_set_format(struct v4l2_subdev *subdev, unsigned int hratio; unsigned int vratio; - __crop = __mt9t001_get_pad_crop(mt9t001, fh, format->pad, + __crop = __mt9t001_get_pad_crop(mt9t001, cfg, format->pad, format->which); /* Clamp the width and height to avoid dividing by zero. */ @@ -391,7 +391,7 @@ static int mt9t001_set_format(struct v4l2_subdev *subdev, hratio = DIV_ROUND_CLOSEST(__crop->width, width); vratio = DIV_ROUND_CLOSEST(__crop->height, height); - __format = __mt9t001_get_pad_format(mt9t001, fh, format->pad, + __format = __mt9t001_get_pad_format(mt9t001, cfg, format->pad, format->which); __format->width = __crop->width / hratio; __format->height = __crop->height / vratio; @@ -402,7 +402,7 @@ static int mt9t001_set_format(struct v4l2_subdev *subdev, } static int mt9t001_get_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct mt9t001 *mt9t001 = to_mt9t001(subdev); @@ -410,12 +410,12 @@ static int mt9t001_get_selection(struct v4l2_subdev *subdev, if (sel->target != V4L2_SEL_TGT_CROP) return -EINVAL; - sel->r = *__mt9t001_get_pad_crop(mt9t001, fh, sel->pad, sel->which); + sel->r = *__mt9t001_get_pad_crop(mt9t001, cfg, sel->pad, sel->which); return 0; } static int mt9t001_set_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct mt9t001 *mt9t001 = to_mt9t001(subdev); @@ -447,13 +447,13 @@ static int mt9t001_set_selection(struct v4l2_subdev *subdev, rect.height = min_t(unsigned int, rect.height, MT9T001_PIXEL_ARRAY_HEIGHT - rect.top); - __crop = __mt9t001_get_pad_crop(mt9t001, fh, sel->pad, sel->which); + __crop = __mt9t001_get_pad_crop(mt9t001, cfg, sel->pad, sel->which); if (rect.width != __crop->width || rect.height != __crop->height) { /* Reset the output image size if the crop rectangle size has * been modified. */ - __format = __mt9t001_get_pad_format(mt9t001, fh, sel->pad, + __format = __mt9t001_get_pad_format(mt9t001, cfg, sel->pad, sel->which); __format->width = rect.width; __format->height = rect.height; @@ -790,13 +790,13 @@ static int mt9t001_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) struct v4l2_mbus_framefmt *format; struct v4l2_rect *crop; - crop = v4l2_subdev_get_try_crop(fh, 0); + crop = v4l2_subdev_get_try_crop(subdev, fh->pad, 0); crop->left = MT9T001_COLUMN_START_DEF; crop->top = MT9T001_ROW_START_DEF; crop->width = MT9T001_WINDOW_WIDTH_DEF + 1; crop->height = MT9T001_WINDOW_HEIGHT_DEF + 1; - format = v4l2_subdev_get_try_format(fh, 0); + format = v4l2_subdev_get_try_format(subdev, fh->pad, 0); format->code = MEDIA_BUS_FMT_SGRBG10_1X10; format->width = MT9T001_WINDOW_WIDTH_DEF + 1; format->height = MT9T001_WINDOW_HEIGHT_DEF + 1; diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c index bd3f979a4d49..977f4006edbd 100644 --- a/drivers/media/i2c/mt9v032.c +++ b/drivers/media/i2c/mt9v032.c @@ -17,6 +17,8 @@ #include <linux/i2c.h> #include <linux/log2.h> #include <linux/mutex.h> +#include <linux/of.h> +#include <linux/of_gpio.h> #include <linux/regmap.h> #include <linux/slab.h> #include <linux/videodev2.h> @@ -26,6 +28,7 @@ #include <media/mt9v032.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> +#include <media/v4l2-of.h> #include <media/v4l2-subdev.h> /* The first four rows are black rows. The active area spans 753x481 pixels. */ @@ -371,12 +374,12 @@ static int __mt9v032_set_power(struct mt9v032 *mt9v032, bool on) */ static struct v4l2_mbus_framefmt * -__mt9v032_get_pad_format(struct mt9v032 *mt9v032, struct v4l2_subdev_fh *fh, +__mt9v032_get_pad_format(struct mt9v032 *mt9v032, struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&mt9v032->subdev, cfg, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &mt9v032->format; default: @@ -385,12 +388,12 @@ __mt9v032_get_pad_format(struct mt9v032 *mt9v032, struct v4l2_subdev_fh *fh, } static struct v4l2_rect * -__mt9v032_get_pad_crop(struct mt9v032 *mt9v032, struct v4l2_subdev_fh *fh, +__mt9v032_get_pad_crop(struct mt9v032 *mt9v032, struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_crop(fh, pad); + return v4l2_subdev_get_try_crop(&mt9v032->subdev, cfg, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &mt9v032->crop; default: @@ -448,7 +451,7 @@ static int mt9v032_s_stream(struct v4l2_subdev *subdev, int enable) } static int mt9v032_enum_mbus_code(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->index > 0) @@ -459,7 +462,7 @@ static int mt9v032_enum_mbus_code(struct v4l2_subdev *subdev, } static int mt9v032_enum_frame_size(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { if (fse->index >= 3 || fse->code != MEDIA_BUS_FMT_SGRBG10_1X10) @@ -474,12 +477,12 @@ static int mt9v032_enum_frame_size(struct v4l2_subdev *subdev, } static int mt9v032_get_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { struct mt9v032 *mt9v032 = to_mt9v032(subdev); - format->format = *__mt9v032_get_pad_format(mt9v032, fh, format->pad, + format->format = *__mt9v032_get_pad_format(mt9v032, cfg, format->pad, format->which); return 0; } @@ -509,7 +512,7 @@ static unsigned int mt9v032_calc_ratio(unsigned int input, unsigned int output) } static int mt9v032_set_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { struct mt9v032 *mt9v032 = to_mt9v032(subdev); @@ -520,7 +523,7 @@ static int mt9v032_set_format(struct v4l2_subdev *subdev, unsigned int hratio; unsigned int vratio; - __crop = __mt9v032_get_pad_crop(mt9v032, fh, format->pad, + __crop = __mt9v032_get_pad_crop(mt9v032, cfg, format->pad, format->which); /* Clamp the width and height to avoid dividing by zero. */ @@ -536,7 +539,7 @@ static int mt9v032_set_format(struct v4l2_subdev *subdev, hratio = mt9v032_calc_ratio(__crop->width, width); vratio = mt9v032_calc_ratio(__crop->height, height); - __format = __mt9v032_get_pad_format(mt9v032, fh, format->pad, + __format = __mt9v032_get_pad_format(mt9v032, cfg, format->pad, format->which); __format->width = __crop->width / hratio; __format->height = __crop->height / vratio; @@ -553,7 +556,7 @@ static int mt9v032_set_format(struct v4l2_subdev *subdev, } static int mt9v032_get_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct mt9v032 *mt9v032 = to_mt9v032(subdev); @@ -561,12 +564,12 @@ static int mt9v032_get_selection(struct v4l2_subdev *subdev, if (sel->target != V4L2_SEL_TGT_CROP) return -EINVAL; - sel->r = *__mt9v032_get_pad_crop(mt9v032, fh, sel->pad, sel->which); + sel->r = *__mt9v032_get_pad_crop(mt9v032, cfg, sel->pad, sel->which); return 0; } static int mt9v032_set_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct mt9v032 *mt9v032 = to_mt9v032(subdev); @@ -598,13 +601,13 @@ static int mt9v032_set_selection(struct v4l2_subdev *subdev, rect.height = min_t(unsigned int, rect.height, MT9V032_PIXEL_ARRAY_HEIGHT - rect.top); - __crop = __mt9v032_get_pad_crop(mt9v032, fh, sel->pad, sel->which); + __crop = __mt9v032_get_pad_crop(mt9v032, cfg, sel->pad, sel->which); if (rect.width != __crop->width || rect.height != __crop->height) { /* Reset the output image size if the crop rectangle size has * been modified. */ - __format = __mt9v032_get_pad_format(mt9v032, fh, sel->pad, + __format = __mt9v032_get_pad_format(mt9v032, cfg, sel->pad, sel->which); __format->width = rect.width; __format->height = rect.height; @@ -810,13 +813,13 @@ static int mt9v032_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) struct v4l2_mbus_framefmt *format; struct v4l2_rect *crop; - crop = v4l2_subdev_get_try_crop(fh, 0); + crop = v4l2_subdev_get_try_crop(subdev, fh->pad, 0); crop->left = MT9V032_COLUMN_START_DEF; crop->top = MT9V032_ROW_START_DEF; crop->width = MT9V032_WINDOW_WIDTH_DEF; crop->height = MT9V032_WINDOW_HEIGHT_DEF; - format = v4l2_subdev_get_try_format(fh, 0); + format = v4l2_subdev_get_try_format(subdev, fh->pad, 0); if (mt9v032->model->color) format->code = MEDIA_BUS_FMT_SGRBG10_1X10; @@ -876,10 +879,58 @@ static const struct regmap_config mt9v032_regmap_config = { * Driver initialization and probing */ +static struct mt9v032_platform_data * +mt9v032_get_pdata(struct i2c_client *client) +{ + struct mt9v032_platform_data *pdata; + struct v4l2_of_endpoint endpoint; + struct device_node *np; + struct property *prop; + + if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node) + return client->dev.platform_data; + + np = of_graph_get_next_endpoint(client->dev.of_node, NULL); + if (!np) + return NULL; + + if (v4l2_of_parse_endpoint(np, &endpoint) < 0) + goto done; + + pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + goto done; + + prop = of_find_property(np, "link-frequencies", NULL); + if (prop) { + u64 *link_freqs; + size_t size = prop->length / sizeof(*link_freqs); + + link_freqs = devm_kcalloc(&client->dev, size, + sizeof(*link_freqs), GFP_KERNEL); + if (!link_freqs) + goto done; + + if (of_property_read_u64_array(np, "link-frequencies", + link_freqs, size) < 0) + goto done; + + pdata->link_freqs = link_freqs; + pdata->link_def_freq = link_freqs[0]; + } + + pdata->clk_pol = !!(endpoint.bus.parallel.flags & + V4L2_MBUS_PCLK_SAMPLE_RISING); + +done: + of_node_put(np); + return pdata; +} + static int mt9v032_probe(struct i2c_client *client, const struct i2c_device_id *did) { - struct mt9v032_platform_data *pdata = client->dev.platform_data; + struct mt9v032_platform_data *pdata = mt9v032_get_pdata(client); struct mt9v032 *mt9v032; unsigned int i; int ret; @@ -961,9 +1012,12 @@ static int mt9v032_probe(struct i2c_client *client, mt9v032->subdev.ctrl_handler = &mt9v032->ctrls; - if (mt9v032->ctrls.error) - printk(KERN_INFO "%s: control initialization error %d\n", - __func__, mt9v032->ctrls.error); + if (mt9v032->ctrls.error) { + dev_err(&client->dev, "control initialization error %d\n", + mt9v032->ctrls.error); + ret = mt9v032->ctrls.error; + goto err; + } mt9v032->crop.left = MT9V032_COLUMN_START_DEF; mt9v032->crop.top = MT9V032_ROW_START_DEF; @@ -1016,7 +1070,6 @@ static int mt9v032_remove(struct i2c_client *client) v4l2_async_unregister_subdev(subdev); v4l2_ctrl_handler_free(&mt9v032->ctrls); - v4l2_device_unregister_subdev(subdev); media_entity_cleanup(&subdev->entity); return 0; @@ -1035,9 +1088,25 @@ static const struct i2c_device_id mt9v032_id[] = { }; MODULE_DEVICE_TABLE(i2c, mt9v032_id); +#if IS_ENABLED(CONFIG_OF) +static const struct of_device_id mt9v032_of_match[] = { + { .compatible = "aptina,mt9v022" }, + { .compatible = "aptina,mt9v022m" }, + { .compatible = "aptina,mt9v024" }, + { .compatible = "aptina,mt9v024m" }, + { .compatible = "aptina,mt9v032" }, + { .compatible = "aptina,mt9v032m" }, + { .compatible = "aptina,mt9v034" }, + { .compatible = "aptina,mt9v034m" }, + { /* Sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mt9v032_of_match); +#endif + static struct i2c_driver mt9v032_driver = { .driver = { .name = "mt9v032", + .of_match_table = of_match_ptr(mt9v032_of_match), }, .probe = mt9v032_probe, .remove = mt9v032_remove, diff --git a/drivers/media/i2c/noon010pc30.c b/drivers/media/i2c/noon010pc30.c index 00c7b26f4823..f197b6cbd407 100644 --- a/drivers/media/i2c/noon010pc30.c +++ b/drivers/media/i2c/noon010pc30.c @@ -492,7 +492,7 @@ unlock: } static int noon010_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->index >= ARRAY_SIZE(noon010_formats)) @@ -502,15 +502,16 @@ static int noon010_enum_mbus_code(struct v4l2_subdev *sd, return 0; } -static int noon010_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int noon010_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct noon010_info *info = to_noon010(sd); struct v4l2_mbus_framefmt *mf; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - if (fh) { - mf = v4l2_subdev_get_try_format(fh, 0); + if (cfg) { + mf = v4l2_subdev_get_try_format(sd, cfg, 0); fmt->format = *mf; } return 0; @@ -542,7 +543,7 @@ static const struct noon010_format *noon010_try_fmt(struct v4l2_subdev *sd, return &noon010_formats[i]; } -static int noon010_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int noon010_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct noon010_info *info = to_noon010(sd); @@ -557,8 +558,8 @@ static int noon010_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, fmt->format.field = V4L2_FIELD_NONE; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - if (fh) { - mf = v4l2_subdev_get_try_format(fh, 0); + if (cfg) { + mf = v4l2_subdev_get_try_format(sd, cfg, 0); *mf = fmt->format; } return 0; @@ -640,7 +641,7 @@ static int noon010_log_status(struct v4l2_subdev *sd) static int noon010_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { - struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(fh, 0); + struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(sd, fh->pad, 0); mf->width = noon010_sizes[0].width; mf->height = noon010_sizes[0].height; diff --git a/drivers/media/i2c/ov2659.c b/drivers/media/i2c/ov2659.c new file mode 100644 index 000000000000..edebd114279d --- /dev/null +++ b/drivers/media/i2c/ov2659.c @@ -0,0 +1,1509 @@ +/* + * Omnivision OV2659 CMOS Image Sensor driver + * + * Copyright (C) 2015 Texas Instruments, Inc. + * + * Benoit Parrot <bparrot@ti.com> + * Lad, Prabhakar <prabhakar.csengg@gmail.com> + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/media.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_graph.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <linux/videodev2.h> + +#include <media/media-entity.h> +#include <media/ov2659.h> +#include <media/v4l2-common.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-event.h> +#include <media/v4l2-image-sizes.h> +#include <media/v4l2-mediabus.h> +#include <media/v4l2-of.h> +#include <media/v4l2-subdev.h> + +#define DRIVER_NAME "ov2659" + +/* + * OV2659 register definitions + */ +#define REG_SOFTWARE_STANDBY 0x0100 +#define REG_SOFTWARE_RESET 0x0103 +#define REG_IO_CTRL00 0x3000 +#define REG_IO_CTRL01 0x3001 +#define REG_IO_CTRL02 0x3002 +#define REG_OUTPUT_VALUE00 0x3008 +#define REG_OUTPUT_VALUE01 0x3009 +#define REG_OUTPUT_VALUE02 0x300d +#define REG_OUTPUT_SELECT00 0x300e +#define REG_OUTPUT_SELECT01 0x300f +#define REG_OUTPUT_SELECT02 0x3010 +#define REG_OUTPUT_DRIVE 0x3011 +#define REG_INPUT_READOUT00 0x302d +#define REG_INPUT_READOUT01 0x302e +#define REG_INPUT_READOUT02 0x302f + +#define REG_SC_PLL_CTRL0 0x3003 +#define REG_SC_PLL_CTRL1 0x3004 +#define REG_SC_PLL_CTRL2 0x3005 +#define REG_SC_PLL_CTRL3 0x3006 +#define REG_SC_CHIP_ID_H 0x300a +#define REG_SC_CHIP_ID_L 0x300b +#define REG_SC_PWC 0x3014 +#define REG_SC_CLKRST0 0x301a +#define REG_SC_CLKRST1 0x301b +#define REG_SC_CLKRST2 0x301c +#define REG_SC_CLKRST3 0x301d +#define REG_SC_SUB_ID 0x302a +#define REG_SC_SCCB_ID 0x302b + +#define REG_GROUP_ADDRESS_00 0x3200 +#define REG_GROUP_ADDRESS_01 0x3201 +#define REG_GROUP_ADDRESS_02 0x3202 +#define REG_GROUP_ADDRESS_03 0x3203 +#define REG_GROUP_ACCESS 0x3208 + +#define REG_AWB_R_GAIN_H 0x3400 +#define REG_AWB_R_GAIN_L 0x3401 +#define REG_AWB_G_GAIN_H 0x3402 +#define REG_AWB_G_GAIN_L 0x3403 +#define REG_AWB_B_GAIN_H 0x3404 +#define REG_AWB_B_GAIN_L 0x3405 +#define REG_AWB_MANUAL_CONTROL 0x3406 + +#define REG_TIMING_HS_H 0x3800 +#define REG_TIMING_HS_L 0x3801 +#define REG_TIMING_VS_H 0x3802 +#define REG_TIMING_VS_L 0x3803 +#define REG_TIMING_HW_H 0x3804 +#define REG_TIMING_HW_L 0x3805 +#define REG_TIMING_VH_H 0x3806 +#define REG_TIMING_VH_L 0x3807 +#define REG_TIMING_DVPHO_H 0x3808 +#define REG_TIMING_DVPHO_L 0x3809 +#define REG_TIMING_DVPVO_H 0x380a +#define REG_TIMING_DVPVO_L 0x380b +#define REG_TIMING_HTS_H 0x380c +#define REG_TIMING_HTS_L 0x380d +#define REG_TIMING_VTS_H 0x380e +#define REG_TIMING_VTS_L 0x380f +#define REG_TIMING_HOFFS_H 0x3810 +#define REG_TIMING_HOFFS_L 0x3811 +#define REG_TIMING_VOFFS_H 0x3812 +#define REG_TIMING_VOFFS_L 0x3813 +#define REG_TIMING_XINC 0x3814 +#define REG_TIMING_YINC 0x3815 +#define REG_TIMING_VERT_FORMAT 0x3820 +#define REG_TIMING_HORIZ_FORMAT 0x3821 + +#define REG_FORMAT_CTRL00 0x4300 + +#define REG_VFIFO_READ_START_H 0x4608 +#define REG_VFIFO_READ_START_L 0x4609 + +#define REG_DVP_CTRL02 0x4708 + +#define REG_ISP_CTRL00 0x5000 +#define REG_ISP_CTRL01 0x5001 +#define REG_ISP_CTRL02 0x5002 + +#define REG_LENC_RED_X0_H 0x500c +#define REG_LENC_RED_X0_L 0x500d +#define REG_LENC_RED_Y0_H 0x500e +#define REG_LENC_RED_Y0_L 0x500f +#define REG_LENC_RED_A1 0x5010 +#define REG_LENC_RED_B1 0x5011 +#define REG_LENC_RED_A2_B2 0x5012 +#define REG_LENC_GREEN_X0_H 0x5013 +#define REG_LENC_GREEN_X0_L 0x5014 +#define REG_LENC_GREEN_Y0_H 0x5015 +#define REG_LENC_GREEN_Y0_L 0x5016 +#define REG_LENC_GREEN_A1 0x5017 +#define REG_LENC_GREEN_B1 0x5018 +#define REG_LENC_GREEN_A2_B2 0x5019 +#define REG_LENC_BLUE_X0_H 0x501a +#define REG_LENC_BLUE_X0_L 0x501b +#define REG_LENC_BLUE_Y0_H 0x501c +#define REG_LENC_BLUE_Y0_L 0x501d +#define REG_LENC_BLUE_A1 0x501e +#define REG_LENC_BLUE_B1 0x501f +#define REG_LENC_BLUE_A2_B2 0x5020 + +#define REG_AWB_CTRL00 0x5035 +#define REG_AWB_CTRL01 0x5036 +#define REG_AWB_CTRL02 0x5037 +#define REG_AWB_CTRL03 0x5038 +#define REG_AWB_CTRL04 0x5039 +#define REG_AWB_LOCAL_LIMIT 0x503a +#define REG_AWB_CTRL12 0x5049 +#define REG_AWB_CTRL13 0x504a +#define REG_AWB_CTRL14 0x504b + +#define REG_SHARPENMT_THRESH1 0x5064 +#define REG_SHARPENMT_THRESH2 0x5065 +#define REG_SHARPENMT_OFFSET1 0x5066 +#define REG_SHARPENMT_OFFSET2 0x5067 +#define REG_DENOISE_THRESH1 0x5068 +#define REG_DENOISE_THRESH2 0x5069 +#define REG_DENOISE_OFFSET1 0x506a +#define REG_DENOISE_OFFSET2 0x506b +#define REG_SHARPEN_THRESH1 0x506c +#define REG_SHARPEN_THRESH2 0x506d +#define REG_CIP_CTRL00 0x506e +#define REG_CIP_CTRL01 0x506f + +#define REG_CMX_SIGN 0x5079 +#define REG_CMX_MISC_CTRL 0x507a + +#define REG_PRE_ISP_CTRL00 0x50a0 +#define TEST_PATTERN_ENABLE BIT(7) +#define VERTICAL_COLOR_BAR_MASK 0x53 + +#define REG_NULL 0x0000 /* Array end token */ + +#define OV265X_ID(_msb, _lsb) ((_msb) << 8 | (_lsb)) +#define OV2659_ID 0x2656 + +struct sensor_register { + u16 addr; + u8 value; +}; + +struct ov2659_framesize { + u16 width; + u16 height; + u16 max_exp_lines; + const struct sensor_register *regs; +}; + +struct ov2659_pll_ctrl { + u8 ctrl1; + u8 ctrl2; + u8 ctrl3; +}; + +struct ov2659_pixfmt { + u32 code; + /* Output format Register Value (REG_FORMAT_CTRL00) */ + struct sensor_register *format_ctrl_regs; +}; + +struct pll_ctrl_reg { + unsigned int div; + unsigned char reg; +}; + +struct ov2659 { + struct v4l2_subdev sd; + struct media_pad pad; + struct v4l2_mbus_framefmt format; + unsigned int xvclk_frequency; + const struct ov2659_platform_data *pdata; + struct mutex lock; + struct i2c_client *client; + struct v4l2_ctrl_handler ctrls; + struct v4l2_ctrl *link_frequency; + const struct ov2659_framesize *frame_size; + struct sensor_register *format_ctrl_regs; + struct ov2659_pll_ctrl pll; + int streaming; +}; + +static const struct sensor_register ov2659_init_regs[] = { + { REG_IO_CTRL00, 0x03 }, + { REG_IO_CTRL01, 0xff }, + { REG_IO_CTRL02, 0xe0 }, + { 0x3633, 0x3d }, + { 0x3620, 0x02 }, + { 0x3631, 0x11 }, + { 0x3612, 0x04 }, + { 0x3630, 0x20 }, + { 0x4702, 0x02 }, + { 0x370c, 0x34 }, + { REG_TIMING_HS_H, 0x00 }, + { REG_TIMING_HS_L, 0x00 }, + { REG_TIMING_VS_H, 0x00 }, + { REG_TIMING_VS_L, 0x00 }, + { REG_TIMING_HW_H, 0x06 }, + { REG_TIMING_HW_L, 0x5f }, + { REG_TIMING_VH_H, 0x04 }, + { REG_TIMING_VH_L, 0xb7 }, + { REG_TIMING_DVPHO_H, 0x03 }, + { REG_TIMING_DVPHO_L, 0x20 }, + { REG_TIMING_DVPVO_H, 0x02 }, + { REG_TIMING_DVPVO_L, 0x58 }, + { REG_TIMING_HTS_H, 0x05 }, + { REG_TIMING_HTS_L, 0x14 }, + { REG_TIMING_VTS_H, 0x02 }, + { REG_TIMING_VTS_L, 0x68 }, + { REG_TIMING_HOFFS_L, 0x08 }, + { REG_TIMING_VOFFS_L, 0x02 }, + { REG_TIMING_XINC, 0x31 }, + { REG_TIMING_YINC, 0x31 }, + { 0x3a02, 0x02 }, + { 0x3a03, 0x68 }, + { 0x3a08, 0x00 }, + { 0x3a09, 0x5c }, + { 0x3a0a, 0x00 }, + { 0x3a0b, 0x4d }, + { 0x3a0d, 0x08 }, + { 0x3a0e, 0x06 }, + { 0x3a14, 0x02 }, + { 0x3a15, 0x28 }, + { REG_DVP_CTRL02, 0x01 }, + { 0x3623, 0x00 }, + { 0x3634, 0x76 }, + { 0x3701, 0x44 }, + { 0x3702, 0x18 }, + { 0x3703, 0x24 }, + { 0x3704, 0x24 }, + { 0x3705, 0x0c }, + { REG_TIMING_VERT_FORMAT, 0x81 }, + { REG_TIMING_HORIZ_FORMAT, 0x01 }, + { 0x370a, 0x52 }, + { REG_VFIFO_READ_START_H, 0x00 }, + { REG_VFIFO_READ_START_L, 0x80 }, + { REG_FORMAT_CTRL00, 0x30 }, + { 0x5086, 0x02 }, + { REG_ISP_CTRL00, 0xfb }, + { REG_ISP_CTRL01, 0x1f }, + { REG_ISP_CTRL02, 0x00 }, + { 0x5025, 0x0e }, + { 0x5026, 0x18 }, + { 0x5027, 0x34 }, + { 0x5028, 0x4c }, + { 0x5029, 0x62 }, + { 0x502a, 0x74 }, + { 0x502b, 0x85 }, + { 0x502c, 0x92 }, + { 0x502d, 0x9e }, + { 0x502e, 0xb2 }, + { 0x502f, 0xc0 }, + { 0x5030, 0xcc }, + { 0x5031, 0xe0 }, + { 0x5032, 0xee }, + { 0x5033, 0xf6 }, + { 0x5034, 0x11 }, + { 0x5070, 0x1c }, + { 0x5071, 0x5b }, + { 0x5072, 0x05 }, + { 0x5073, 0x20 }, + { 0x5074, 0x94 }, + { 0x5075, 0xb4 }, + { 0x5076, 0xb4 }, + { 0x5077, 0xaf }, + { 0x5078, 0x05 }, + { REG_CMX_SIGN, 0x98 }, + { REG_CMX_MISC_CTRL, 0x21 }, + { REG_AWB_CTRL00, 0x6a }, + { REG_AWB_CTRL01, 0x11 }, + { REG_AWB_CTRL02, 0x92 }, + { REG_AWB_CTRL03, 0x21 }, + { REG_AWB_CTRL04, 0xe1 }, + { REG_AWB_LOCAL_LIMIT, 0x01 }, + { 0x503c, 0x05 }, + { 0x503d, 0x08 }, + { 0x503e, 0x08 }, + { 0x503f, 0x64 }, + { 0x5040, 0x58 }, + { 0x5041, 0x2a }, + { 0x5042, 0xc5 }, + { 0x5043, 0x2e }, + { 0x5044, 0x3a }, + { 0x5045, 0x3c }, + { 0x5046, 0x44 }, + { 0x5047, 0xf8 }, + { 0x5048, 0x08 }, + { REG_AWB_CTRL12, 0x70 }, + { REG_AWB_CTRL13, 0xf0 }, + { REG_AWB_CTRL14, 0xf0 }, + { REG_LENC_RED_X0_H, 0x03 }, + { REG_LENC_RED_X0_L, 0x20 }, + { REG_LENC_RED_Y0_H, 0x02 }, + { REG_LENC_RED_Y0_L, 0x5c }, + { REG_LENC_RED_A1, 0x48 }, + { REG_LENC_RED_B1, 0x00 }, + { REG_LENC_RED_A2_B2, 0x66 }, + { REG_LENC_GREEN_X0_H, 0x03 }, + { REG_LENC_GREEN_X0_L, 0x30 }, + { REG_LENC_GREEN_Y0_H, 0x02 }, + { REG_LENC_GREEN_Y0_L, 0x7c }, + { REG_LENC_GREEN_A1, 0x40 }, + { REG_LENC_GREEN_B1, 0x00 }, + { REG_LENC_GREEN_A2_B2, 0x66 }, + { REG_LENC_BLUE_X0_H, 0x03 }, + { REG_LENC_BLUE_X0_L, 0x10 }, + { REG_LENC_BLUE_Y0_H, 0x02 }, + { REG_LENC_BLUE_Y0_L, 0x7c }, + { REG_LENC_BLUE_A1, 0x3a }, + { REG_LENC_BLUE_B1, 0x00 }, + { REG_LENC_BLUE_A2_B2, 0x66 }, + { REG_CIP_CTRL00, 0x44 }, + { REG_SHARPENMT_THRESH1, 0x08 }, + { REG_SHARPENMT_THRESH2, 0x10 }, + { REG_SHARPENMT_OFFSET1, 0x12 }, + { REG_SHARPENMT_OFFSET2, 0x02 }, + { REG_SHARPEN_THRESH1, 0x08 }, + { REG_SHARPEN_THRESH2, 0x10 }, + { REG_CIP_CTRL01, 0xa6 }, + { REG_DENOISE_THRESH1, 0x08 }, + { REG_DENOISE_THRESH2, 0x10 }, + { REG_DENOISE_OFFSET1, 0x04 }, + { REG_DENOISE_OFFSET2, 0x12 }, + { 0x507e, 0x40 }, + { 0x507f, 0x20 }, + { 0x507b, 0x02 }, + { REG_CMX_MISC_CTRL, 0x01 }, + { 0x5084, 0x0c }, + { 0x5085, 0x3e }, + { 0x5005, 0x80 }, + { 0x3a0f, 0x30 }, + { 0x3a10, 0x28 }, + { 0x3a1b, 0x32 }, + { 0x3a1e, 0x26 }, + { 0x3a11, 0x60 }, + { 0x3a1f, 0x14 }, + { 0x5060, 0x69 }, + { 0x5061, 0x7d }, + { 0x5062, 0x7d }, + { 0x5063, 0x69 }, + { REG_NULL, 0x00 }, +}; + +/* 1280X720 720p */ +static struct sensor_register ov2659_720p[] = { + { REG_TIMING_HS_H, 0x00 }, + { REG_TIMING_HS_L, 0xa0 }, + { REG_TIMING_VS_H, 0x00 }, + { REG_TIMING_VS_L, 0xf0 }, + { REG_TIMING_HW_H, 0x05 }, + { REG_TIMING_HW_L, 0xbf }, + { REG_TIMING_VH_H, 0x03 }, + { REG_TIMING_VH_L, 0xcb }, + { REG_TIMING_DVPHO_H, 0x05 }, + { REG_TIMING_DVPHO_L, 0x00 }, + { REG_TIMING_DVPVO_H, 0x02 }, + { REG_TIMING_DVPVO_L, 0xd0 }, + { REG_TIMING_HTS_H, 0x06 }, + { REG_TIMING_HTS_L, 0x4c }, + { REG_TIMING_VTS_H, 0x02 }, + { REG_TIMING_VTS_L, 0xe8 }, + { REG_TIMING_HOFFS_L, 0x10 }, + { REG_TIMING_VOFFS_L, 0x06 }, + { REG_TIMING_XINC, 0x11 }, + { REG_TIMING_YINC, 0x11 }, + { REG_TIMING_VERT_FORMAT, 0x80 }, + { REG_TIMING_HORIZ_FORMAT, 0x00 }, + { 0x3a03, 0xe8 }, + { 0x3a09, 0x6f }, + { 0x3a0b, 0x5d }, + { 0x3a15, 0x9a }, + { REG_NULL, 0x00 }, +}; + +/* 1600X1200 UXGA */ +static struct sensor_register ov2659_uxga[] = { + { REG_TIMING_HS_H, 0x00 }, + { REG_TIMING_HS_L, 0x00 }, + { REG_TIMING_VS_H, 0x00 }, + { REG_TIMING_VS_L, 0x00 }, + { REG_TIMING_HW_H, 0x06 }, + { REG_TIMING_HW_L, 0x5f }, + { REG_TIMING_VH_H, 0x04 }, + { REG_TIMING_VH_L, 0xbb }, + { REG_TIMING_DVPHO_H, 0x06 }, + { REG_TIMING_DVPHO_L, 0x40 }, + { REG_TIMING_DVPVO_H, 0x04 }, + { REG_TIMING_DVPVO_L, 0xb0 }, + { REG_TIMING_HTS_H, 0x07 }, + { REG_TIMING_HTS_L, 0x9f }, + { REG_TIMING_VTS_H, 0x04 }, + { REG_TIMING_VTS_L, 0xd0 }, + { REG_TIMING_HOFFS_L, 0x10 }, + { REG_TIMING_VOFFS_L, 0x06 }, + { REG_TIMING_XINC, 0x11 }, + { REG_TIMING_YINC, 0x11 }, + { 0x3a02, 0x04 }, + { 0x3a03, 0xd0 }, + { 0x3a08, 0x00 }, + { 0x3a09, 0xb8 }, + { 0x3a0a, 0x00 }, + { 0x3a0b, 0x9a }, + { 0x3a0d, 0x08 }, + { 0x3a0e, 0x06 }, + { 0x3a14, 0x04 }, + { 0x3a15, 0x50 }, + { 0x3623, 0x00 }, + { 0x3634, 0x44 }, + { 0x3701, 0x44 }, + { 0x3702, 0x30 }, + { 0x3703, 0x48 }, + { 0x3704, 0x48 }, + { 0x3705, 0x18 }, + { REG_TIMING_VERT_FORMAT, 0x80 }, + { REG_TIMING_HORIZ_FORMAT, 0x00 }, + { 0x370a, 0x12 }, + { REG_VFIFO_READ_START_H, 0x00 }, + { REG_VFIFO_READ_START_L, 0x80 }, + { REG_ISP_CTRL02, 0x00 }, + { REG_NULL, 0x00 }, +}; + +/* 1280X1024 SXGA */ +static struct sensor_register ov2659_sxga[] = { + { REG_TIMING_HS_H, 0x00 }, + { REG_TIMING_HS_L, 0x00 }, + { REG_TIMING_VS_H, 0x00 }, + { REG_TIMING_VS_L, 0x00 }, + { REG_TIMING_HW_H, 0x06 }, + { REG_TIMING_HW_L, 0x5f }, + { REG_TIMING_VH_H, 0x04 }, + { REG_TIMING_VH_L, 0xb7 }, + { REG_TIMING_DVPHO_H, 0x05 }, + { REG_TIMING_DVPHO_L, 0x00 }, + { REG_TIMING_DVPVO_H, 0x04 }, + { REG_TIMING_DVPVO_L, 0x00 }, + { REG_TIMING_HTS_H, 0x07 }, + { REG_TIMING_HTS_L, 0x9c }, + { REG_TIMING_VTS_H, 0x04 }, + { REG_TIMING_VTS_L, 0xd0 }, + { REG_TIMING_HOFFS_L, 0x10 }, + { REG_TIMING_VOFFS_L, 0x06 }, + { REG_TIMING_XINC, 0x11 }, + { REG_TIMING_YINC, 0x11 }, + { 0x3a02, 0x02 }, + { 0x3a03, 0x68 }, + { 0x3a08, 0x00 }, + { 0x3a09, 0x5c }, + { 0x3a0a, 0x00 }, + { 0x3a0b, 0x4d }, + { 0x3a0d, 0x08 }, + { 0x3a0e, 0x06 }, + { 0x3a14, 0x02 }, + { 0x3a15, 0x28 }, + { 0x3623, 0x00 }, + { 0x3634, 0x76 }, + { 0x3701, 0x44 }, + { 0x3702, 0x18 }, + { 0x3703, 0x24 }, + { 0x3704, 0x24 }, + { 0x3705, 0x0c }, + { REG_TIMING_VERT_FORMAT, 0x80 }, + { REG_TIMING_HORIZ_FORMAT, 0x00 }, + { 0x370a, 0x52 }, + { REG_VFIFO_READ_START_H, 0x00 }, + { REG_VFIFO_READ_START_L, 0x80 }, + { REG_ISP_CTRL02, 0x00 }, + { REG_NULL, 0x00 }, +}; + +/* 1024X768 SXGA */ +static struct sensor_register ov2659_xga[] = { + { REG_TIMING_HS_H, 0x00 }, + { REG_TIMING_HS_L, 0x00 }, + { REG_TIMING_VS_H, 0x00 }, + { REG_TIMING_VS_L, 0x00 }, + { REG_TIMING_HW_H, 0x06 }, + { REG_TIMING_HW_L, 0x5f }, + { REG_TIMING_VH_H, 0x04 }, + { REG_TIMING_VH_L, 0xb7 }, + { REG_TIMING_DVPHO_H, 0x04 }, + { REG_TIMING_DVPHO_L, 0x00 }, + { REG_TIMING_DVPVO_H, 0x03 }, + { REG_TIMING_DVPVO_L, 0x00 }, + { REG_TIMING_HTS_H, 0x07 }, + { REG_TIMING_HTS_L, 0x9c }, + { REG_TIMING_VTS_H, 0x04 }, + { REG_TIMING_VTS_L, 0xd0 }, + { REG_TIMING_HOFFS_L, 0x10 }, + { REG_TIMING_VOFFS_L, 0x06 }, + { REG_TIMING_XINC, 0x11 }, + { REG_TIMING_YINC, 0x11 }, + { 0x3a02, 0x02 }, + { 0x3a03, 0x68 }, + { 0x3a08, 0x00 }, + { 0x3a09, 0x5c }, + { 0x3a0a, 0x00 }, + { 0x3a0b, 0x4d }, + { 0x3a0d, 0x08 }, + { 0x3a0e, 0x06 }, + { 0x3a14, 0x02 }, + { 0x3a15, 0x28 }, + { 0x3623, 0x00 }, + { 0x3634, 0x76 }, + { 0x3701, 0x44 }, + { 0x3702, 0x18 }, + { 0x3703, 0x24 }, + { 0x3704, 0x24 }, + { 0x3705, 0x0c }, + { REG_TIMING_VERT_FORMAT, 0x80 }, + { REG_TIMING_HORIZ_FORMAT, 0x00 }, + { 0x370a, 0x52 }, + { REG_VFIFO_READ_START_H, 0x00 }, + { REG_VFIFO_READ_START_L, 0x80 }, + { REG_ISP_CTRL02, 0x00 }, + { REG_NULL, 0x00 }, +}; + +/* 800X600 SVGA */ +static struct sensor_register ov2659_svga[] = { + { REG_TIMING_HS_H, 0x00 }, + { REG_TIMING_HS_L, 0x00 }, + { REG_TIMING_VS_H, 0x00 }, + { REG_TIMING_VS_L, 0x00 }, + { REG_TIMING_HW_H, 0x06 }, + { REG_TIMING_HW_L, 0x5f }, + { REG_TIMING_VH_H, 0x04 }, + { REG_TIMING_VH_L, 0xb7 }, + { REG_TIMING_DVPHO_H, 0x03 }, + { REG_TIMING_DVPHO_L, 0x20 }, + { REG_TIMING_DVPVO_H, 0x02 }, + { REG_TIMING_DVPVO_L, 0x58 }, + { REG_TIMING_HTS_H, 0x05 }, + { REG_TIMING_HTS_L, 0x14 }, + { REG_TIMING_VTS_H, 0x02 }, + { REG_TIMING_VTS_L, 0x68 }, + { REG_TIMING_HOFFS_L, 0x08 }, + { REG_TIMING_VOFFS_L, 0x02 }, + { REG_TIMING_XINC, 0x31 }, + { REG_TIMING_YINC, 0x31 }, + { 0x3a02, 0x02 }, + { 0x3a03, 0x68 }, + { 0x3a08, 0x00 }, + { 0x3a09, 0x5c }, + { 0x3a0a, 0x00 }, + { 0x3a0b, 0x4d }, + { 0x3a0d, 0x08 }, + { 0x3a0e, 0x06 }, + { 0x3a14, 0x02 }, + { 0x3a15, 0x28 }, + { 0x3623, 0x00 }, + { 0x3634, 0x76 }, + { 0x3701, 0x44 }, + { 0x3702, 0x18 }, + { 0x3703, 0x24 }, + { 0x3704, 0x24 }, + { 0x3705, 0x0c }, + { REG_TIMING_VERT_FORMAT, 0x81 }, + { REG_TIMING_HORIZ_FORMAT, 0x01 }, + { 0x370a, 0x52 }, + { REG_VFIFO_READ_START_H, 0x00 }, + { REG_VFIFO_READ_START_L, 0x80 }, + { REG_ISP_CTRL02, 0x00 }, + { REG_NULL, 0x00 }, +}; + +/* 640X480 VGA */ +static struct sensor_register ov2659_vga[] = { + { REG_TIMING_HS_H, 0x00 }, + { REG_TIMING_HS_L, 0x00 }, + { REG_TIMING_VS_H, 0x00 }, + { REG_TIMING_VS_L, 0x00 }, + { REG_TIMING_HW_H, 0x06 }, + { REG_TIMING_HW_L, 0x5f }, + { REG_TIMING_VH_H, 0x04 }, + { REG_TIMING_VH_L, 0xb7 }, + { REG_TIMING_DVPHO_H, 0x02 }, + { REG_TIMING_DVPHO_L, 0x80 }, + { REG_TIMING_DVPVO_H, 0x01 }, + { REG_TIMING_DVPVO_L, 0xe0 }, + { REG_TIMING_HTS_H, 0x05 }, + { REG_TIMING_HTS_L, 0x14 }, + { REG_TIMING_VTS_H, 0x02 }, + { REG_TIMING_VTS_L, 0x68 }, + { REG_TIMING_HOFFS_L, 0x08 }, + { REG_TIMING_VOFFS_L, 0x02 }, + { REG_TIMING_XINC, 0x31 }, + { REG_TIMING_YINC, 0x31 }, + { 0x3a02, 0x02 }, + { 0x3a03, 0x68 }, + { 0x3a08, 0x00 }, + { 0x3a09, 0x5c }, + { 0x3a0a, 0x00 }, + { 0x3a0b, 0x4d }, + { 0x3a0d, 0x08 }, + { 0x3a0e, 0x06 }, + { 0x3a14, 0x02 }, + { 0x3a15, 0x28 }, + { 0x3623, 0x00 }, + { 0x3634, 0x76 }, + { 0x3701, 0x44 }, + { 0x3702, 0x18 }, + { 0x3703, 0x24 }, + { 0x3704, 0x24 }, + { 0x3705, 0x0c }, + { REG_TIMING_VERT_FORMAT, 0x81 }, + { REG_TIMING_HORIZ_FORMAT, 0x01 }, + { 0x370a, 0x52 }, + { REG_VFIFO_READ_START_H, 0x00 }, + { REG_VFIFO_READ_START_L, 0x80 }, + { REG_ISP_CTRL02, 0x10 }, + { REG_NULL, 0x00 }, +}; + +/* 320X240 QVGA */ +static struct sensor_register ov2659_qvga[] = { + { REG_TIMING_HS_H, 0x00 }, + { REG_TIMING_HS_L, 0x00 }, + { REG_TIMING_VS_H, 0x00 }, + { REG_TIMING_VS_L, 0x00 }, + { REG_TIMING_HW_H, 0x06 }, + { REG_TIMING_HW_L, 0x5f }, + { REG_TIMING_VH_H, 0x04 }, + { REG_TIMING_VH_L, 0xb7 }, + { REG_TIMING_DVPHO_H, 0x01 }, + { REG_TIMING_DVPHO_L, 0x40 }, + { REG_TIMING_DVPVO_H, 0x00 }, + { REG_TIMING_DVPVO_L, 0xf0 }, + { REG_TIMING_HTS_H, 0x05 }, + { REG_TIMING_HTS_L, 0x14 }, + { REG_TIMING_VTS_H, 0x02 }, + { REG_TIMING_VTS_L, 0x68 }, + { REG_TIMING_HOFFS_L, 0x08 }, + { REG_TIMING_VOFFS_L, 0x02 }, + { REG_TIMING_XINC, 0x31 }, + { REG_TIMING_YINC, 0x31 }, + { 0x3a02, 0x02 }, + { 0x3a03, 0x68 }, + { 0x3a08, 0x00 }, + { 0x3a09, 0x5c }, + { 0x3a0a, 0x00 }, + { 0x3a0b, 0x4d }, + { 0x3a0d, 0x08 }, + { 0x3a0e, 0x06 }, + { 0x3a14, 0x02 }, + { 0x3a15, 0x28 }, + { 0x3623, 0x00 }, + { 0x3634, 0x76 }, + { 0x3701, 0x44 }, + { 0x3702, 0x18 }, + { 0x3703, 0x24 }, + { 0x3704, 0x24 }, + { 0x3705, 0x0c }, + { REG_TIMING_VERT_FORMAT, 0x81 }, + { REG_TIMING_HORIZ_FORMAT, 0x01 }, + { 0x370a, 0x52 }, + { REG_VFIFO_READ_START_H, 0x00 }, + { REG_VFIFO_READ_START_L, 0x80 }, + { REG_ISP_CTRL02, 0x10 }, + { REG_NULL, 0x00 }, +}; + +static const struct pll_ctrl_reg ctrl3[] = { + { 1, 0x00 }, + { 2, 0x02 }, + { 3, 0x03 }, + { 4, 0x06 }, + { 6, 0x0d }, + { 8, 0x0e }, + { 12, 0x0f }, + { 16, 0x12 }, + { 24, 0x13 }, + { 32, 0x16 }, + { 48, 0x1b }, + { 64, 0x1e }, + { 96, 0x1f }, + { 0, 0x00 }, +}; + +static const struct pll_ctrl_reg ctrl1[] = { + { 2, 0x10 }, + { 4, 0x20 }, + { 6, 0x30 }, + { 8, 0x40 }, + { 10, 0x50 }, + { 12, 0x60 }, + { 14, 0x70 }, + { 16, 0x80 }, + { 18, 0x90 }, + { 20, 0xa0 }, + { 22, 0xb0 }, + { 24, 0xc0 }, + { 26, 0xd0 }, + { 28, 0xe0 }, + { 30, 0xf0 }, + { 0, 0x00 }, +}; + +static const struct ov2659_framesize ov2659_framesizes[] = { + { /* QVGA */ + .width = 320, + .height = 240, + .regs = ov2659_qvga, + .max_exp_lines = 248, + }, { /* VGA */ + .width = 640, + .height = 480, + .regs = ov2659_vga, + .max_exp_lines = 498, + }, { /* SVGA */ + .width = 800, + .height = 600, + .regs = ov2659_svga, + .max_exp_lines = 498, + }, { /* XGA */ + .width = 1024, + .height = 768, + .regs = ov2659_xga, + .max_exp_lines = 498, + }, { /* 720P */ + .width = 1280, + .height = 720, + .regs = ov2659_720p, + .max_exp_lines = 498, + }, { /* SXGA */ + .width = 1280, + .height = 1024, + .regs = ov2659_sxga, + .max_exp_lines = 1048, + }, { /* UXGA */ + .width = 1600, + .height = 1200, + .regs = ov2659_uxga, + .max_exp_lines = 498, + }, +}; + +/* YUV422 YUYV*/ +static struct sensor_register ov2659_format_yuyv[] = { + { REG_FORMAT_CTRL00, 0x30 }, + { REG_NULL, 0x0 }, +}; + +/* YUV422 UYVY */ +static struct sensor_register ov2659_format_uyvy[] = { + { REG_FORMAT_CTRL00, 0x32 }, + { REG_NULL, 0x0 }, +}; + +/* Raw Bayer BGGR */ +static struct sensor_register ov2659_format_bggr[] = { + { REG_FORMAT_CTRL00, 0x00 }, + { REG_NULL, 0x0 }, +}; + +/* RGB565 */ +static struct sensor_register ov2659_format_rgb565[] = { + { REG_FORMAT_CTRL00, 0x60 }, + { REG_NULL, 0x0 }, +}; + +static const struct ov2659_pixfmt ov2659_formats[] = { + { + .code = MEDIA_BUS_FMT_YUYV8_2X8, + .format_ctrl_regs = ov2659_format_yuyv, + }, { + .code = MEDIA_BUS_FMT_UYVY8_2X8, + .format_ctrl_regs = ov2659_format_uyvy, + }, { + .code = MEDIA_BUS_FMT_RGB565_2X8_BE, + .format_ctrl_regs = ov2659_format_rgb565, + }, { + .code = MEDIA_BUS_FMT_SBGGR8_1X8, + .format_ctrl_regs = ov2659_format_bggr, + }, +}; + +static inline struct ov2659 *to_ov2659(struct v4l2_subdev *sd) +{ + return container_of(sd, struct ov2659, sd); +} + +/* sensor register write */ +static int ov2659_write(struct i2c_client *client, u16 reg, u8 val) +{ + struct i2c_msg msg; + u8 buf[3]; + int ret; + + buf[0] = reg >> 8; + buf[1] = reg & 0xFF; + buf[2] = val; + + msg.addr = client->addr; + msg.flags = client->flags; + msg.buf = buf; + msg.len = sizeof(buf); + + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret >= 0) + return 0; + + dev_dbg(&client->dev, + "ov2659 write reg(0x%x val:0x%x) failed !\n", reg, val); + + return ret; +} + +/* sensor register read */ +static int ov2659_read(struct i2c_client *client, u16 reg, u8 *val) +{ + struct i2c_msg msg[2]; + u8 buf[2]; + int ret; + + buf[0] = reg >> 8; + buf[1] = reg & 0xFF; + + msg[0].addr = client->addr; + msg[0].flags = client->flags; + msg[0].buf = buf; + msg[0].len = sizeof(buf); + + msg[1].addr = client->addr; + msg[1].flags = client->flags | I2C_M_RD; + msg[1].buf = buf; + msg[1].len = 1; + + ret = i2c_transfer(client->adapter, msg, 2); + if (ret >= 0) { + *val = buf[0]; + return 0; + } + + dev_dbg(&client->dev, + "ov2659 read reg(0x%x val:0x%x) failed !\n", reg, *val); + + return ret; +} + +static int ov2659_write_array(struct i2c_client *client, + const struct sensor_register *regs) +{ + int i, ret = 0; + + for (i = 0; ret == 0 && regs[i].addr; i++) + ret = ov2659_write(client, regs[i].addr, regs[i].value); + + return ret; +} + +static void ov2659_pll_calc_params(struct ov2659 *ov2659) +{ + const struct ov2659_platform_data *pdata = ov2659->pdata; + u8 ctrl1_reg = 0, ctrl2_reg = 0, ctrl3_reg = 0; + struct i2c_client *client = ov2659->client; + unsigned int desired = pdata->link_frequency; + u32 s_prediv = 1, s_postdiv = 1, s_mult = 1; + u32 prediv, postdiv, mult; + u32 bestdelta = -1; + u32 delta, actual; + int i, j; + + for (i = 0; ctrl1[i].div != 0; i++) { + postdiv = ctrl1[i].div; + for (j = 0; ctrl3[j].div != 0; j++) { + prediv = ctrl3[j].div; + for (mult = 1; mult <= 63; mult++) { + actual = ov2659->xvclk_frequency; + actual *= mult; + actual /= prediv; + actual /= postdiv; + delta = actual - desired; + delta = abs(delta); + + if ((delta < bestdelta) || (bestdelta == -1)) { + bestdelta = delta; + s_mult = mult; + s_prediv = prediv; + s_postdiv = postdiv; + ctrl1_reg = ctrl1[i].reg; + ctrl2_reg = mult; + ctrl3_reg = ctrl3[j].reg; + } + } + } + } + + ov2659->pll.ctrl1 = ctrl1_reg; + ov2659->pll.ctrl2 = ctrl2_reg; + ov2659->pll.ctrl3 = ctrl3_reg; + + dev_dbg(&client->dev, + "Actual reg config: ctrl1_reg: %02x ctrl2_reg: %02x ctrl3_reg: %02x\n", + ctrl1_reg, ctrl2_reg, ctrl3_reg); +} + +static int ov2659_set_pixel_clock(struct ov2659 *ov2659) +{ + struct i2c_client *client = ov2659->client; + struct sensor_register pll_regs[] = { + {REG_SC_PLL_CTRL1, ov2659->pll.ctrl1}, + {REG_SC_PLL_CTRL2, ov2659->pll.ctrl2}, + {REG_SC_PLL_CTRL3, ov2659->pll.ctrl3}, + {REG_NULL, 0x00}, + }; + + dev_dbg(&client->dev, "%s\n", __func__); + + return ov2659_write_array(client, pll_regs); +}; + +static void ov2659_get_default_format(struct v4l2_mbus_framefmt *format) +{ + format->width = ov2659_framesizes[2].width; + format->height = ov2659_framesizes[2].height; + format->colorspace = V4L2_COLORSPACE_SRGB; + format->code = ov2659_formats[0].code; + format->field = V4L2_FIELD_NONE; +} + +static void ov2659_set_streaming(struct ov2659 *ov2659, int on) +{ + struct i2c_client *client = ov2659->client; + int ret; + + on = !!on; + + dev_dbg(&client->dev, "%s: on: %d\n", __func__, on); + + ret = ov2659_write(client, REG_SOFTWARE_STANDBY, on); + if (ret) + dev_err(&client->dev, "ov2659 soft standby failed\n"); +} + +static int ov2659_init(struct v4l2_subdev *sd, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return ov2659_write_array(client, ov2659_init_regs); +} + +/* + * V4L2 subdev video and pad level operations + */ + +static int ov2659_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + dev_dbg(&client->dev, "%s:\n", __func__); + + if (code->index >= ARRAY_SIZE(ov2659_formats)) + return -EINVAL; + + code->code = ov2659_formats[code->index].code; + + return 0; +} + +static int ov2659_enum_frame_sizes(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int i = ARRAY_SIZE(ov2659_formats); + + dev_dbg(&client->dev, "%s:\n", __func__); + + if (fse->index >= ARRAY_SIZE(ov2659_framesizes)) + return -EINVAL; + + while (--i) + if (fse->code == ov2659_formats[i].code) + break; + + fse->code = ov2659_formats[i].code; + + fse->min_width = ov2659_framesizes[fse->index].width; + fse->max_width = fse->min_width; + fse->max_height = ov2659_framesizes[fse->index].height; + fse->min_height = fse->max_height; + + return 0; +} + +static int ov2659_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov2659 *ov2659 = to_ov2659(sd); + struct v4l2_mbus_framefmt *mf; + + dev_dbg(&client->dev, "ov2659_get_fmt\n"); + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + mf = v4l2_subdev_get_try_format(sd, cfg, 0); + mutex_lock(&ov2659->lock); + fmt->format = *mf; + mutex_unlock(&ov2659->lock); + return 0; + } + + mutex_lock(&ov2659->lock); + fmt->format = ov2659->format; + mutex_unlock(&ov2659->lock); + + dev_dbg(&client->dev, "ov2659_get_fmt: %x %dx%d\n", + ov2659->format.code, ov2659->format.width, + ov2659->format.height); + + return 0; +} + +static void __ov2659_try_frame_size(struct v4l2_mbus_framefmt *mf, + const struct ov2659_framesize **size) +{ + const struct ov2659_framesize *fsize = &ov2659_framesizes[0]; + const struct ov2659_framesize *match = NULL; + int i = ARRAY_SIZE(ov2659_framesizes); + unsigned int min_err = UINT_MAX; + + while (i--) { + int err = abs(fsize->width - mf->width) + + abs(fsize->height - mf->height); + if ((err < min_err) && (fsize->regs[0].addr)) { + min_err = err; + match = fsize; + } + fsize++; + } + + if (!match) + match = &ov2659_framesizes[2]; + + mf->width = match->width; + mf->height = match->height; + + if (size) + *size = match; +} + +static int ov2659_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + unsigned int index = ARRAY_SIZE(ov2659_formats); + struct v4l2_mbus_framefmt *mf = &fmt->format; + const struct ov2659_framesize *size = NULL; + struct ov2659 *ov2659 = to_ov2659(sd); + int ret = 0; + + dev_dbg(&client->dev, "ov2659_set_fmt\n"); + + __ov2659_try_frame_size(mf, &size); + + while (--index >= 0) + if (ov2659_formats[index].code == mf->code) + break; + + if (index < 0) + return -EINVAL; + + mf->colorspace = V4L2_COLORSPACE_SRGB; + mf->code = ov2659_formats[index].code; + mf->field = V4L2_FIELD_NONE; + + mutex_lock(&ov2659->lock); + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); + *mf = fmt->format; + } else { + s64 val; + + if (ov2659->streaming) { + mutex_unlock(&ov2659->lock); + return -EBUSY; + } + + ov2659->frame_size = size; + ov2659->format = fmt->format; + ov2659->format_ctrl_regs = + ov2659_formats[index].format_ctrl_regs; + + if (ov2659->format.code != MEDIA_BUS_FMT_SBGGR8_1X8) + val = ov2659->pdata->link_frequency / 2; + else + val = ov2659->pdata->link_frequency; + + ret = v4l2_ctrl_s_ctrl_int64(ov2659->link_frequency, val); + if (ret < 0) + dev_warn(&client->dev, + "failed to set link_frequency rate (%d)\n", + ret); + } + + mutex_unlock(&ov2659->lock); + return ret; +} + +static int ov2659_set_frame_size(struct ov2659 *ov2659) +{ + struct i2c_client *client = ov2659->client; + + dev_dbg(&client->dev, "%s\n", __func__); + + return ov2659_write_array(ov2659->client, ov2659->frame_size->regs); +} + +static int ov2659_set_format(struct ov2659 *ov2659) +{ + struct i2c_client *client = ov2659->client; + + dev_dbg(&client->dev, "%s\n", __func__); + + return ov2659_write_array(ov2659->client, ov2659->format_ctrl_regs); +} + +static int ov2659_s_stream(struct v4l2_subdev *sd, int on) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov2659 *ov2659 = to_ov2659(sd); + int ret = 0; + + dev_dbg(&client->dev, "%s: on: %d\n", __func__, on); + + mutex_lock(&ov2659->lock); + + on = !!on; + + if (ov2659->streaming == on) + goto unlock; + + if (!on) { + /* Stop Streaming Sequence */ + ov2659_set_streaming(ov2659, 0); + ov2659->streaming = on; + goto unlock; + } + + ov2659_set_pixel_clock(ov2659); + ov2659_set_frame_size(ov2659); + ov2659_set_format(ov2659); + ov2659_set_streaming(ov2659, 1); + ov2659->streaming = on; + +unlock: + mutex_unlock(&ov2659->lock); + return ret; +} + +static int ov2659_set_test_pattern(struct ov2659 *ov2659, int value) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov2659->sd); + int ret; + u8 val; + + ret = ov2659_read(client, REG_PRE_ISP_CTRL00, &val); + if (ret < 0) + return ret; + + switch (value) { + case 0: + val &= ~TEST_PATTERN_ENABLE; + break; + case 1: + val &= VERTICAL_COLOR_BAR_MASK; + val |= TEST_PATTERN_ENABLE; + break; + } + + return ov2659_write(client, REG_PRE_ISP_CTRL00, val); +} + +static int ov2659_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov2659 *ov2659 = + container_of(ctrl->handler, struct ov2659, ctrls); + + switch (ctrl->id) { + case V4L2_CID_TEST_PATTERN: + return ov2659_set_test_pattern(ov2659, ctrl->val); + } + + return 0; +} + +static struct v4l2_ctrl_ops ov2659_ctrl_ops = { + .s_ctrl = ov2659_s_ctrl, +}; + +static const char * const ov2659_test_pattern_menu[] = { + "Disabled", + "Vertical Color Bars", +}; + +/* ----------------------------------------------------------------------------- + * V4L2 subdev internal operations + */ + +static int ov2659_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format = + v4l2_subdev_get_try_format(sd, fh->pad, 0); + + dev_dbg(&client->dev, "%s:\n", __func__); + + ov2659_get_default_format(format); + + return 0; +} + +static const struct v4l2_subdev_core_ops ov2659_subdev_core_ops = { + .log_status = v4l2_ctrl_subdev_log_status, + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, +}; + +static const struct v4l2_subdev_video_ops ov2659_subdev_video_ops = { + .s_stream = ov2659_s_stream, +}; + +static const struct v4l2_subdev_pad_ops ov2659_subdev_pad_ops = { + .enum_mbus_code = ov2659_enum_mbus_code, + .enum_frame_size = ov2659_enum_frame_sizes, + .get_fmt = ov2659_get_fmt, + .set_fmt = ov2659_set_fmt, +}; + +static const struct v4l2_subdev_ops ov2659_subdev_ops = { + .core = &ov2659_subdev_core_ops, + .video = &ov2659_subdev_video_ops, + .pad = &ov2659_subdev_pad_ops, +}; + +static const struct v4l2_subdev_internal_ops ov2659_subdev_internal_ops = { + .open = ov2659_open, +}; + +static int ov2659_detect(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + u8 pid, ver; + int ret; + + dev_dbg(&client->dev, "%s:\n", __func__); + + ret = ov2659_write(client, REG_SOFTWARE_RESET, 0x01); + if (ret != 0) { + dev_err(&client->dev, "Sensor soft reset failed\n"); + return -ENODEV; + } + usleep_range(1000, 2000); + + ret = ov2659_init(sd, 0); + if (ret < 0) + return ret; + + /* Check sensor revision */ + ret = ov2659_read(client, REG_SC_CHIP_ID_H, &pid); + if (!ret) + ret = ov2659_read(client, REG_SC_CHIP_ID_L, &ver); + + if (!ret) { + unsigned short id; + + id = OV265X_ID(pid, ver); + if (id != OV2659_ID) + dev_err(&client->dev, + "Sensor detection failed (%04X, %d)\n", + id, ret); + else + dev_info(&client->dev, "Found OV%04X sensor\n", id); + } + + return ret; +} + +static struct ov2659_platform_data * +ov2659_get_pdata(struct i2c_client *client) +{ + struct ov2659_platform_data *pdata; + struct device_node *endpoint; + int ret; + + if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node) + return client->dev.platform_data; + + endpoint = of_graph_get_next_endpoint(client->dev.of_node, NULL); + if (!endpoint) + return NULL; + + pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + goto done; + + ret = of_property_read_u64(endpoint, "link-frequencies", + &pdata->link_frequency); + if (ret) { + dev_err(&client->dev, "link-frequencies property not found\n"); + pdata = NULL; + } + +done: + of_node_put(endpoint); + return pdata; +} + +static int ov2659_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + const struct ov2659_platform_data *pdata = ov2659_get_pdata(client); + struct v4l2_subdev *sd; + struct ov2659 *ov2659; + struct clk *clk; + int ret; + + if (!pdata) { + dev_err(&client->dev, "platform data not specified\n"); + return -EINVAL; + } + + ov2659 = devm_kzalloc(&client->dev, sizeof(*ov2659), GFP_KERNEL); + if (!ov2659) + return -ENOMEM; + + ov2659->pdata = pdata; + ov2659->client = client; + + clk = devm_clk_get(&client->dev, "xvclk"); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + ov2659->xvclk_frequency = clk_get_rate(clk); + if (ov2659->xvclk_frequency < 6000000 || + ov2659->xvclk_frequency > 27000000) + return -EINVAL; + + v4l2_ctrl_handler_init(&ov2659->ctrls, 2); + ov2659->link_frequency = + v4l2_ctrl_new_std(&ov2659->ctrls, &ov2659_ctrl_ops, + V4L2_CID_PIXEL_RATE, + pdata->link_frequency / 2, + pdata->link_frequency, 1, + pdata->link_frequency); + v4l2_ctrl_new_std_menu_items(&ov2659->ctrls, &ov2659_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov2659_test_pattern_menu) - 1, + 0, 0, ov2659_test_pattern_menu); + ov2659->sd.ctrl_handler = &ov2659->ctrls; + + if (ov2659->ctrls.error) { + dev_err(&client->dev, "%s: control initialization error %d\n", + __func__, ov2659->ctrls.error); + return ov2659->ctrls.error; + } + + sd = &ov2659->sd; + client->flags |= I2C_CLIENT_SCCB; + v4l2_i2c_subdev_init(sd, client, &ov2659_subdev_ops); + + sd->internal_ops = &ov2659_subdev_internal_ops; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | + V4L2_SUBDEV_FL_HAS_EVENTS; + +#if defined(CONFIG_MEDIA_CONTROLLER) + ov2659->pad.flags = MEDIA_PAD_FL_SOURCE; + sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; + ret = media_entity_init(&sd->entity, 1, &ov2659->pad, 0); + if (ret < 0) { + v4l2_ctrl_handler_free(&ov2659->ctrls); + return ret; + } +#endif + + mutex_init(&ov2659->lock); + + ov2659_get_default_format(&ov2659->format); + ov2659->frame_size = &ov2659_framesizes[2]; + ov2659->format_ctrl_regs = ov2659_formats[0].format_ctrl_regs; + + ret = ov2659_detect(sd); + if (ret < 0) + goto error; + + /* Calculate the PLL register value needed */ + ov2659_pll_calc_params(ov2659); + + ret = v4l2_async_register_subdev(&ov2659->sd); + if (ret) + goto error; + + dev_info(&client->dev, "%s sensor driver registered !!\n", sd->name); + + return 0; + +error: + v4l2_ctrl_handler_free(&ov2659->ctrls); +#if defined(CONFIG_MEDIA_CONTROLLER) + media_entity_cleanup(&sd->entity); +#endif + mutex_destroy(&ov2659->lock); + return ret; +} + +static int ov2659_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov2659 *ov2659 = to_ov2659(sd); + + v4l2_ctrl_handler_free(&ov2659->ctrls); + v4l2_async_unregister_subdev(sd); +#if defined(CONFIG_MEDIA_CONTROLLER) + media_entity_cleanup(&sd->entity); +#endif + mutex_destroy(&ov2659->lock); + + return 0; +} + +static const struct i2c_device_id ov2659_id[] = { + { "ov2659", 0 }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(i2c, ov2659_id); + +#if IS_ENABLED(CONFIG_OF) +static const struct of_device_id ov2659_of_match[] = { + { .compatible = "ovti,ov2659", }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, ov2659_of_match); +#endif + +static struct i2c_driver ov2659_i2c_driver = { + .driver = { + .name = DRIVER_NAME, + .of_match_table = of_match_ptr(ov2659_of_match), + }, + .probe = ov2659_probe, + .remove = ov2659_remove, + .id_table = ov2659_id, +}; + +module_i2c_driver(ov2659_i2c_driver); + +MODULE_AUTHOR("Benoit Parrot <bparrot@ti.com>"); +MODULE_DESCRIPTION("OV2659 CMOS Image Sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index 957927f7a353..b9847527eb5a 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -1069,29 +1069,35 @@ static int ov7670_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) static int ov7670_frame_rates[] = { 30, 15, 10, 5, 1 }; -static int ov7670_enum_frameintervals(struct v4l2_subdev *sd, - struct v4l2_frmivalenum *interval) +static int ov7670_enum_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_interval_enum *fie) { - if (interval->index >= ARRAY_SIZE(ov7670_frame_rates)) + if (fie->pad) return -EINVAL; - interval->type = V4L2_FRMIVAL_TYPE_DISCRETE; - interval->discrete.numerator = 1; - interval->discrete.denominator = ov7670_frame_rates[interval->index]; + if (fie->index >= ARRAY_SIZE(ov7670_frame_rates)) + return -EINVAL; + fie->interval.numerator = 1; + fie->interval.denominator = ov7670_frame_rates[fie->index]; return 0; } /* * Frame size enumeration */ -static int ov7670_enum_framesizes(struct v4l2_subdev *sd, - struct v4l2_frmsizeenum *fsize) +static int ov7670_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) { struct ov7670_info *info = to_state(sd); int i; int num_valid = -1; - __u32 index = fsize->index; + __u32 index = fse->index; unsigned int n_win_sizes = info->devtype->n_win_sizes; + if (fse->pad) + return -EINVAL; + /* * If a minimum width/height was requested, filter out the capture * windows that fall outside that. @@ -1103,9 +1109,8 @@ static int ov7670_enum_framesizes(struct v4l2_subdev *sd, if (info->min_height && win->height < info->min_height) continue; if (index == ++num_valid) { - fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; - fsize->discrete.width = win->width; - fsize->discrete.height = win->height; + fse->min_width = fse->max_width = win->width; + fse->min_height = fse->max_height = win->height; return 0; } } @@ -1485,13 +1490,17 @@ static const struct v4l2_subdev_video_ops ov7670_video_ops = { .s_mbus_fmt = ov7670_s_mbus_fmt, .s_parm = ov7670_s_parm, .g_parm = ov7670_g_parm, - .enum_frameintervals = ov7670_enum_frameintervals, - .enum_framesizes = ov7670_enum_framesizes, +}; + +static const struct v4l2_subdev_pad_ops ov7670_pad_ops = { + .enum_frame_interval = ov7670_enum_frame_interval, + .enum_frame_size = ov7670_enum_frame_size, }; static const struct v4l2_subdev_ops ov7670_ops = { .core = &ov7670_core_ops, .video = &ov7670_video_ops, + .pad = &ov7670_pad_ops, }; /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c index 2246bd5436ad..2bc473385c91 100644 --- a/drivers/media/i2c/ov9650.c +++ b/drivers/media/i2c/ov9650.c @@ -1067,7 +1067,7 @@ static void ov965x_get_default_format(struct v4l2_mbus_framefmt *mf) } static int ov965x_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->index >= ARRAY_SIZE(ov965x_formats)) @@ -1078,7 +1078,7 @@ static int ov965x_enum_mbus_code(struct v4l2_subdev *sd, } static int ov965x_enum_frame_sizes(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { int i = ARRAY_SIZE(ov965x_formats); @@ -1164,14 +1164,14 @@ static int ov965x_s_frame_interval(struct v4l2_subdev *sd, return ret; } -static int ov965x_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int ov965x_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct ov965x *ov965x = to_ov965x(sd); struct v4l2_mbus_framefmt *mf; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(fh, 0); + mf = v4l2_subdev_get_try_format(sd, cfg, 0); fmt->format = *mf; return 0; } @@ -1208,7 +1208,7 @@ static void __ov965x_try_frame_size(struct v4l2_mbus_framefmt *mf, *size = match; } -static int ov965x_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int ov965x_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { unsigned int index = ARRAY_SIZE(ov965x_formats); @@ -1230,8 +1230,8 @@ static int ov965x_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, mutex_lock(&ov965x->lock); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - if (fh != NULL) { - mf = v4l2_subdev_get_try_format(fh, fmt->pad); + if (cfg != NULL) { + mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); *mf = fmt->format; } } else { @@ -1361,7 +1361,7 @@ static int ov965x_s_stream(struct v4l2_subdev *sd, int on) */ static int ov965x_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { - struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(fh, 0); + struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(sd, fh->pad, 0); ov965x_get_default_format(mf); return 0; diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c index ee0f57e01b56..08b234bd2962 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c @@ -824,10 +824,11 @@ static const struct s5c73m3_frame_size *s5c73m3_find_frame_size( } static void s5c73m3_oif_try_format(struct s5c73m3 *state, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt, const struct s5c73m3_frame_size **fs) { + struct v4l2_subdev *sd = &state->sensor_sd; u32 code; switch (fmt->pad) { @@ -850,7 +851,7 @@ static void s5c73m3_oif_try_format(struct s5c73m3 *state, *fs = state->oif_pix_size[RES_ISP]; else *fs = s5c73m3_find_frame_size( - v4l2_subdev_get_try_format(fh, + v4l2_subdev_get_try_format(sd, cfg, OIF_ISP_PAD), RES_ISP); break; @@ -860,7 +861,7 @@ static void s5c73m3_oif_try_format(struct s5c73m3 *state, } static void s5c73m3_try_format(struct s5c73m3 *state, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt, const struct s5c73m3_frame_size **fs) { @@ -952,7 +953,7 @@ static int s5c73m3_oif_s_frame_interval(struct v4l2_subdev *sd, } static int s5c73m3_oif_enum_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_interval_enum *fie) { struct s5c73m3 *state = oif_sd_to_s5c73m3(sd); @@ -990,7 +991,7 @@ static int s5c73m3_oif_get_pad_code(int pad, int index) } static int s5c73m3_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct s5c73m3 *state = sensor_sd_to_s5c73m3(sd); @@ -998,7 +999,7 @@ static int s5c73m3_get_fmt(struct v4l2_subdev *sd, u32 code; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - fmt->format = *v4l2_subdev_get_try_format(fh, fmt->pad); + fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad); return 0; } @@ -1024,7 +1025,7 @@ static int s5c73m3_get_fmt(struct v4l2_subdev *sd, } static int s5c73m3_oif_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct s5c73m3 *state = oif_sd_to_s5c73m3(sd); @@ -1032,7 +1033,7 @@ static int s5c73m3_oif_get_fmt(struct v4l2_subdev *sd, u32 code; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - fmt->format = *v4l2_subdev_get_try_format(fh, fmt->pad); + fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad); return 0; } @@ -1062,7 +1063,7 @@ static int s5c73m3_oif_get_fmt(struct v4l2_subdev *sd, } static int s5c73m3_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { const struct s5c73m3_frame_size *frame_size = NULL; @@ -1072,10 +1073,10 @@ static int s5c73m3_set_fmt(struct v4l2_subdev *sd, mutex_lock(&state->lock); - s5c73m3_try_format(state, fh, fmt, &frame_size); + s5c73m3_try_format(state, cfg, fmt, &frame_size); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(fh, fmt->pad); + mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); *mf = fmt->format; } else { switch (fmt->pad) { @@ -1101,7 +1102,7 @@ static int s5c73m3_set_fmt(struct v4l2_subdev *sd, } static int s5c73m3_oif_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { const struct s5c73m3_frame_size *frame_size = NULL; @@ -1111,13 +1112,13 @@ static int s5c73m3_oif_set_fmt(struct v4l2_subdev *sd, mutex_lock(&state->lock); - s5c73m3_oif_try_format(state, fh, fmt, &frame_size); + s5c73m3_oif_try_format(state, cfg, fmt, &frame_size); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(fh, fmt->pad); + mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); *mf = fmt->format; if (fmt->pad == OIF_ISP_PAD) { - mf = v4l2_subdev_get_try_format(fh, OIF_SOURCE_PAD); + mf = v4l2_subdev_get_try_format(sd, cfg, OIF_SOURCE_PAD); mf->width = fmt->format.width; mf->height = fmt->format.height; } @@ -1189,7 +1190,7 @@ static int s5c73m3_oif_set_frame_desc(struct v4l2_subdev *sd, unsigned int pad, } static int s5c73m3_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { static const int codes[] = { @@ -1205,7 +1206,7 @@ static int s5c73m3_enum_mbus_code(struct v4l2_subdev *sd, } static int s5c73m3_oif_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { int ret; @@ -1220,7 +1221,7 @@ static int s5c73m3_oif_enum_mbus_code(struct v4l2_subdev *sd, } static int s5c73m3_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { int idx; @@ -1247,9 +1248,10 @@ static int s5c73m3_enum_frame_size(struct v4l2_subdev *sd, } static int s5c73m3_oif_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { + struct s5c73m3 *state = oif_sd_to_s5c73m3(sd); int idx; if (fse->pad == OIF_SOURCE_PAD) { @@ -1259,11 +1261,25 @@ static int s5c73m3_oif_enum_frame_size(struct v4l2_subdev *sd, switch (fse->code) { case S5C73M3_JPEG_FMT: case S5C73M3_ISP_FMT: { - struct v4l2_mbus_framefmt *mf = - v4l2_subdev_get_try_format(fh, OIF_ISP_PAD); + unsigned w, h; + + if (fse->which == V4L2_SUBDEV_FORMAT_TRY) { + struct v4l2_mbus_framefmt *mf; + + mf = v4l2_subdev_get_try_format(sd, cfg, + OIF_ISP_PAD); + + w = mf->width; + h = mf->height; + } else { + const struct s5c73m3_frame_size *fs; - fse->max_width = fse->min_width = mf->width; - fse->max_height = fse->min_height = mf->height; + fs = state->oif_pix_size[RES_ISP]; + w = fs->width; + h = fs->height; + } + fse->max_width = fse->min_width = w; + fse->max_height = fse->min_height = h; return 0; } default: @@ -1306,11 +1322,11 @@ static int s5c73m3_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct v4l2_mbus_framefmt *mf; - mf = v4l2_subdev_get_try_format(fh, S5C73M3_ISP_PAD); + mf = v4l2_subdev_get_try_format(sd, fh->pad, S5C73M3_ISP_PAD); s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1], S5C73M3_ISP_FMT); - mf = v4l2_subdev_get_try_format(fh, S5C73M3_JPEG_PAD); + mf = v4l2_subdev_get_try_format(sd, fh->pad, S5C73M3_JPEG_PAD); s5c73m3_fill_mbus_fmt(mf, &s5c73m3_jpeg_resolutions[1], S5C73M3_JPEG_FMT); @@ -1321,15 +1337,15 @@ static int s5c73m3_oif_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct v4l2_mbus_framefmt *mf; - mf = v4l2_subdev_get_try_format(fh, OIF_ISP_PAD); + mf = v4l2_subdev_get_try_format(sd, fh->pad, OIF_ISP_PAD); s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1], S5C73M3_ISP_FMT); - mf = v4l2_subdev_get_try_format(fh, OIF_JPEG_PAD); + mf = v4l2_subdev_get_try_format(sd, fh->pad, OIF_JPEG_PAD); s5c73m3_fill_mbus_fmt(mf, &s5c73m3_jpeg_resolutions[1], S5C73M3_JPEG_FMT); - mf = v4l2_subdev_get_try_format(fh, OIF_SOURCE_PAD); + mf = v4l2_subdev_get_try_format(sd, fh->pad, OIF_SOURCE_PAD); s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1], S5C73M3_ISP_FMT); return 0; diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-spi.c b/drivers/media/i2c/s5c73m3/s5c73m3-spi.c index f60b265b4da1..63eb19093381 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-spi.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-spi.c @@ -52,7 +52,7 @@ static int spi_xmit(struct spi_device *spi_dev, void *addr, const int len, xfer.rx_buf = addr; if (spi_dev == NULL) { - dev_err(&spi_dev->dev, "SPI device is uninitialized\n"); + pr_err("SPI device is uninitialized\n"); return -ENODEV; } diff --git a/drivers/media/i2c/s5k4ecgx.c b/drivers/media/i2c/s5k4ecgx.c index 70071314789e..97084237275d 100644 --- a/drivers/media/i2c/s5k4ecgx.c +++ b/drivers/media/i2c/s5k4ecgx.c @@ -531,7 +531,7 @@ static int s5k4ecgx_try_frame_size(struct v4l2_mbus_framefmt *mf, } static int s5k4ecgx_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->index >= ARRAY_SIZE(s5k4ecgx_formats)) @@ -541,15 +541,15 @@ static int s5k4ecgx_enum_mbus_code(struct v4l2_subdev *sd, return 0; } -static int s5k4ecgx_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int s5k4ecgx_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct s5k4ecgx *priv = to_s5k4ecgx(sd); struct v4l2_mbus_framefmt *mf; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - if (fh) { - mf = v4l2_subdev_get_try_format(fh, 0); + if (cfg) { + mf = v4l2_subdev_get_try_format(sd, cfg, 0); fmt->format = *mf; } return 0; @@ -581,7 +581,7 @@ static const struct s5k4ecgx_pixfmt *s5k4ecgx_try_fmt(struct v4l2_subdev *sd, return &s5k4ecgx_formats[i]; } -static int s5k4ecgx_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int s5k4ecgx_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct s5k4ecgx *priv = to_s5k4ecgx(sd); @@ -596,8 +596,8 @@ static int s5k4ecgx_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, fmt->format.field = V4L2_FIELD_NONE; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - if (fh) { - mf = v4l2_subdev_get_try_format(fh, 0); + if (cfg) { + mf = v4l2_subdev_get_try_format(sd, cfg, 0); *mf = fmt->format; } return 0; @@ -692,7 +692,7 @@ static int s5k4ecgx_registered(struct v4l2_subdev *sd) */ static int s5k4ecgx_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { - struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(fh, 0); + struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(sd, fh->pad, 0); mf->width = s5k4ecgx_prev_sizes[0].size.width; mf->height = s5k4ecgx_prev_sizes[0].size.height; diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c index a3d7d0391302..297ef04e146a 100644 --- a/drivers/media/i2c/s5k5baf.c +++ b/drivers/media/i2c/s5k5baf.c @@ -374,6 +374,8 @@ static int s5k5baf_fw_parse(struct device *dev, struct s5k5baf_fw **fw, count -= S5K5BAG_FW_TAG_LEN; d = devm_kzalloc(dev, count * sizeof(u16), GFP_KERNEL); + if (!d) + return -ENOMEM; for (i = 0; i < count; ++i) d[i] = le16_to_cpu(data[i]); @@ -1182,7 +1184,7 @@ static int s5k5baf_s_frame_interval(struct v4l2_subdev *sd, * V4L2 subdev pad level and video operations */ static int s5k5baf_enum_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_interval_enum *fie) { if (fie->index > S5K5BAF_MAX_FR_TIME - S5K5BAF_MIN_FR_TIME || @@ -1201,7 +1203,7 @@ static int s5k5baf_enum_frame_interval(struct v4l2_subdev *sd, } static int s5k5baf_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->pad == PAD_CIS) { @@ -1219,7 +1221,7 @@ static int s5k5baf_enum_mbus_code(struct v4l2_subdev *sd, } static int s5k5baf_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { int i; @@ -1276,7 +1278,7 @@ static int s5k5baf_try_isp_format(struct v4l2_mbus_framefmt *mf) return pixfmt; } -static int s5k5baf_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int s5k5baf_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct s5k5baf *state = to_s5k5baf(sd); @@ -1284,7 +1286,7 @@ static int s5k5baf_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, struct v4l2_mbus_framefmt *mf; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(fh, fmt->pad); + mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); fmt->format = *mf; return 0; } @@ -1306,7 +1308,7 @@ static int s5k5baf_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, return 0; } -static int s5k5baf_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int s5k5baf_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct v4l2_mbus_framefmt *mf = &fmt->format; @@ -1317,7 +1319,7 @@ static int s5k5baf_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, mf->field = V4L2_FIELD_NONE; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_try_format(fh, fmt->pad) = *mf; + *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = *mf; return 0; } @@ -1369,7 +1371,7 @@ static int s5k5baf_is_bound_target(u32 target) } static int s5k5baf_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { static enum selection_rect rtype; @@ -1389,9 +1391,9 @@ static int s5k5baf_get_selection(struct v4l2_subdev *sd, if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { if (rtype == R_COMPOSE) - sel->r = *v4l2_subdev_get_try_compose(fh, sel->pad); + sel->r = *v4l2_subdev_get_try_compose(sd, cfg, sel->pad); else - sel->r = *v4l2_subdev_get_try_crop(fh, sel->pad); + sel->r = *v4l2_subdev_get_try_crop(sd, cfg, sel->pad); return 0; } @@ -1460,7 +1462,7 @@ static bool s5k5baf_cmp_rect(const struct v4l2_rect *r1, } static int s5k5baf_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { static enum selection_rect rtype; @@ -1481,9 +1483,9 @@ static int s5k5baf_set_selection(struct v4l2_subdev *sd, if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { rects = (struct v4l2_rect * []) { &s5k5baf_cis_rect, - v4l2_subdev_get_try_crop(fh, PAD_CIS), - v4l2_subdev_get_try_compose(fh, PAD_CIS), - v4l2_subdev_get_try_crop(fh, PAD_OUT) + v4l2_subdev_get_try_crop(sd, cfg, PAD_CIS), + v4l2_subdev_get_try_compose(sd, cfg, PAD_CIS), + v4l2_subdev_get_try_crop(sd, cfg, PAD_OUT) }; s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r); return 0; @@ -1701,22 +1703,22 @@ static int s5k5baf_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct v4l2_mbus_framefmt *mf; - mf = v4l2_subdev_get_try_format(fh, PAD_CIS); + mf = v4l2_subdev_get_try_format(sd, fh->pad, PAD_CIS); s5k5baf_try_cis_format(mf); if (s5k5baf_is_cis_subdev(sd)) return 0; - mf = v4l2_subdev_get_try_format(fh, PAD_OUT); + mf = v4l2_subdev_get_try_format(sd, fh->pad, PAD_OUT); mf->colorspace = s5k5baf_formats[0].colorspace; mf->code = s5k5baf_formats[0].code; mf->width = s5k5baf_cis_rect.width; mf->height = s5k5baf_cis_rect.height; mf->field = V4L2_FIELD_NONE; - *v4l2_subdev_get_try_crop(fh, PAD_CIS) = s5k5baf_cis_rect; - *v4l2_subdev_get_try_compose(fh, PAD_CIS) = s5k5baf_cis_rect; - *v4l2_subdev_get_try_crop(fh, PAD_OUT) = s5k5baf_cis_rect; + *v4l2_subdev_get_try_crop(sd, fh->pad, PAD_CIS) = s5k5baf_cis_rect; + *v4l2_subdev_get_try_compose(sd, fh->pad, PAD_CIS) = s5k5baf_cis_rect; + *v4l2_subdev_get_try_crop(sd, fh->pad, PAD_OUT) = s5k5baf_cis_rect; return 0; } diff --git a/drivers/media/i2c/s5k6a3.c b/drivers/media/i2c/s5k6a3.c index 91b841a1b850..bc389d5e42ae 100644 --- a/drivers/media/i2c/s5k6a3.c +++ b/drivers/media/i2c/s5k6a3.c @@ -99,7 +99,7 @@ static const struct v4l2_mbus_framefmt *find_sensor_format( } static int s5k6a3_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->index >= ARRAY_SIZE(s5k6a3_formats)) @@ -123,17 +123,17 @@ static void s5k6a3_try_format(struct v4l2_mbus_framefmt *mf) } static struct v4l2_mbus_framefmt *__s5k6a3_get_format( - struct s5k6a3 *sensor, struct v4l2_subdev_fh *fh, + struct s5k6a3 *sensor, struct v4l2_subdev_pad_config *cfg, u32 pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return fh ? v4l2_subdev_get_try_format(fh, pad) : NULL; + return cfg ? v4l2_subdev_get_try_format(&sensor->subdev, cfg, pad) : NULL; return &sensor->format; } static int s5k6a3_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct s5k6a3 *sensor = sd_to_s5k6a3(sd); @@ -141,7 +141,7 @@ static int s5k6a3_set_fmt(struct v4l2_subdev *sd, s5k6a3_try_format(&fmt->format); - mf = __s5k6a3_get_format(sensor, fh, fmt->pad, fmt->which); + mf = __s5k6a3_get_format(sensor, cfg, fmt->pad, fmt->which); if (mf) { mutex_lock(&sensor->lock); if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) @@ -152,13 +152,13 @@ static int s5k6a3_set_fmt(struct v4l2_subdev *sd, } static int s5k6a3_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_format *fmt) + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) { struct s5k6a3 *sensor = sd_to_s5k6a3(sd); struct v4l2_mbus_framefmt *mf; - mf = __s5k6a3_get_format(sensor, fh, fmt->pad, fmt->which); + mf = __s5k6a3_get_format(sensor, cfg, fmt->pad, fmt->which); mutex_lock(&sensor->lock); fmt->format = *mf; @@ -174,7 +174,7 @@ static struct v4l2_subdev_pad_ops s5k6a3_pad_ops = { static int s5k6a3_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { - struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0); + struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd, fh->pad, 0); *format = s5k6a3_formats[0]; format->width = S5K6A3_DEFAULT_WIDTH; diff --git a/drivers/media/i2c/s5k6aa.c b/drivers/media/i2c/s5k6aa.c index b1c583239dab..de803a11efb4 100644 --- a/drivers/media/i2c/s5k6aa.c +++ b/drivers/media/i2c/s5k6aa.c @@ -996,7 +996,7 @@ static int s5k6aa_s_frame_interval(struct v4l2_subdev *sd, * V4L2 subdev pad level and video operations */ static int s5k6aa_enum_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_interval_enum *fie) { struct s5k6aa *s5k6aa = to_s5k6aa(sd); @@ -1023,7 +1023,7 @@ static int s5k6aa_enum_frame_interval(struct v4l2_subdev *sd, } static int s5k6aa_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->index >= ARRAY_SIZE(s5k6aa_formats)) @@ -1034,7 +1034,7 @@ static int s5k6aa_enum_mbus_code(struct v4l2_subdev *sd, } static int s5k6aa_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { int i = ARRAY_SIZE(s5k6aa_formats); @@ -1056,14 +1056,14 @@ static int s5k6aa_enum_frame_size(struct v4l2_subdev *sd, } static struct v4l2_rect * -__s5k6aa_get_crop_rect(struct s5k6aa *s5k6aa, struct v4l2_subdev_fh *fh, +__s5k6aa_get_crop_rect(struct s5k6aa *s5k6aa, struct v4l2_subdev_pad_config *cfg, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_ACTIVE) return &s5k6aa->ccd_rect; WARN_ON(which != V4L2_SUBDEV_FORMAT_TRY); - return v4l2_subdev_get_try_crop(fh, 0); + return v4l2_subdev_get_try_crop(&s5k6aa->sd, cfg, 0); } static void s5k6aa_try_format(struct s5k6aa *s5k6aa, @@ -1087,7 +1087,7 @@ static void s5k6aa_try_format(struct s5k6aa *s5k6aa, mf->field = V4L2_FIELD_NONE; } -static int s5k6aa_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int s5k6aa_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct s5k6aa *s5k6aa = to_s5k6aa(sd); @@ -1096,7 +1096,7 @@ static int s5k6aa_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, memset(fmt->reserved, 0, sizeof(fmt->reserved)); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(fh, 0); + mf = v4l2_subdev_get_try_format(sd, cfg, 0); fmt->format = *mf; return 0; } @@ -1108,7 +1108,7 @@ static int s5k6aa_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, return 0; } -static int s5k6aa_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int s5k6aa_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct s5k6aa *s5k6aa = to_s5k6aa(sd); @@ -1121,8 +1121,8 @@ static int s5k6aa_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, s5k6aa_try_format(s5k6aa, &fmt->format); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(fh, fmt->pad); - crop = v4l2_subdev_get_try_crop(fh, 0); + mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); + crop = v4l2_subdev_get_try_crop(sd, cfg, 0); } else { if (s5k6aa->streaming) { ret = -EBUSY; @@ -1162,7 +1162,7 @@ static int s5k6aa_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, } static int s5k6aa_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct s5k6aa *s5k6aa = to_s5k6aa(sd); @@ -1174,7 +1174,7 @@ static int s5k6aa_get_selection(struct v4l2_subdev *sd, memset(sel->reserved, 0, sizeof(sel->reserved)); mutex_lock(&s5k6aa->lock); - rect = __s5k6aa_get_crop_rect(s5k6aa, fh, sel->which); + rect = __s5k6aa_get_crop_rect(s5k6aa, cfg, sel->which); sel->r = *rect; mutex_unlock(&s5k6aa->lock); @@ -1185,7 +1185,7 @@ static int s5k6aa_get_selection(struct v4l2_subdev *sd, } static int s5k6aa_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct s5k6aa *s5k6aa = to_s5k6aa(sd); @@ -1197,13 +1197,13 @@ static int s5k6aa_set_selection(struct v4l2_subdev *sd, return -EINVAL; mutex_lock(&s5k6aa->lock); - crop_r = __s5k6aa_get_crop_rect(s5k6aa, fh, sel->which); + crop_r = __s5k6aa_get_crop_rect(s5k6aa, cfg, sel->which); if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { mf = &s5k6aa->preset->mbus_fmt; s5k6aa->apply_crop = 1; } else { - mf = v4l2_subdev_get_try_format(fh, 0); + mf = v4l2_subdev_get_try_format(sd, cfg, 0); } v4l_bound_align_image(&sel->r.width, mf->width, S5K6AA_WIN_WIDTH_MAX, 1, @@ -1424,8 +1424,8 @@ static int s5k6aa_initialize_ctrls(struct s5k6aa *s5k6aa) */ static int s5k6aa_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { - struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0); - struct v4l2_rect *crop = v4l2_subdev_get_try_crop(fh, 0); + struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd, fh->pad, 0); + struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, fh->pad, 0); format->colorspace = s5k6aa_formats[0].colorspace; format->code = s5k6aa_formats[0].code; diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index d47eff5d3101..557f25def3a0 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -344,7 +344,7 @@ static const struct smiapp_csi_data_format smiapp_csi_data_formats[] = { { MEDIA_BUS_FMT_SGBRG8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_GBRG, }, }; -const char *pixel_order_str[] = { "GRBG", "RGGB", "BGGR", "GBRG" }; +static const char *pixel_order_str[] = { "GRBG", "RGGB", "BGGR", "GBRG" }; #define to_csi_format_idx(fmt) (((unsigned long)(fmt) \ - (unsigned long)smiapp_csi_data_formats) \ @@ -1557,7 +1557,7 @@ static int smiapp_set_stream(struct v4l2_subdev *subdev, int enable) } static int smiapp_enum_mbus_code(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { struct i2c_client *client = v4l2_get_subdevdata(subdev); @@ -1611,13 +1611,13 @@ static u32 __smiapp_get_mbus_code(struct v4l2_subdev *subdev, } static int __smiapp_get_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct smiapp_subdev *ssd = to_smiapp_subdev(subdev); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - fmt->format = *v4l2_subdev_get_try_format(fh, fmt->pad); + fmt->format = *v4l2_subdev_get_try_format(subdev, cfg, fmt->pad); } else { struct v4l2_rect *r; @@ -1636,21 +1636,21 @@ static int __smiapp_get_format(struct v4l2_subdev *subdev, } static int smiapp_get_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); int rval; mutex_lock(&sensor->mutex); - rval = __smiapp_get_format(subdev, fh, fmt); + rval = __smiapp_get_format(subdev, cfg, fmt); mutex_unlock(&sensor->mutex); return rval; } static void smiapp_get_crop_compose(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_rect **crops, struct v4l2_rect **comps, int which) { @@ -1666,12 +1666,12 @@ static void smiapp_get_crop_compose(struct v4l2_subdev *subdev, } else { if (crops) { for (i = 0; i < subdev->entity.num_pads; i++) { - crops[i] = v4l2_subdev_get_try_crop(fh, i); + crops[i] = v4l2_subdev_get_try_crop(subdev, cfg, i); BUG_ON(!crops[i]); } } if (comps) { - *comps = v4l2_subdev_get_try_compose(fh, + *comps = v4l2_subdev_get_try_compose(subdev, cfg, SMIAPP_PAD_SINK); BUG_ON(!*comps); } @@ -1680,14 +1680,14 @@ static void smiapp_get_crop_compose(struct v4l2_subdev *subdev, /* Changes require propagation only on sink pad. */ static void smiapp_propagate(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, int which, + struct v4l2_subdev_pad_config *cfg, int which, int target) { struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); struct smiapp_subdev *ssd = to_smiapp_subdev(subdev); struct v4l2_rect *comp, *crops[SMIAPP_PADS]; - smiapp_get_crop_compose(subdev, fh, crops, &comp, which); + smiapp_get_crop_compose(subdev, cfg, crops, &comp, which); switch (target) { case V4L2_SEL_TGT_CROP: @@ -1730,7 +1730,7 @@ static const struct smiapp_csi_data_format } static int smiapp_set_format_source(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); @@ -1741,7 +1741,7 @@ static int smiapp_set_format_source(struct v4l2_subdev *subdev, unsigned int i; int rval; - rval = __smiapp_get_format(subdev, fh, fmt); + rval = __smiapp_get_format(subdev, cfg, fmt); if (rval) return rval; @@ -1783,7 +1783,7 @@ static int smiapp_set_format_source(struct v4l2_subdev *subdev, } static int smiapp_set_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); @@ -1795,7 +1795,7 @@ static int smiapp_set_format(struct v4l2_subdev *subdev, if (fmt->pad == ssd->source_pad) { int rval; - rval = smiapp_set_format_source(subdev, fh, fmt); + rval = smiapp_set_format_source(subdev, cfg, fmt); mutex_unlock(&sensor->mutex); @@ -1817,7 +1817,7 @@ static int smiapp_set_format(struct v4l2_subdev *subdev, sensor->limits[SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE], sensor->limits[SMIAPP_LIMIT_MAX_Y_OUTPUT_SIZE]); - smiapp_get_crop_compose(subdev, fh, crops, NULL, fmt->which); + smiapp_get_crop_compose(subdev, cfg, crops, NULL, fmt->which); crops[ssd->sink_pad]->left = 0; crops[ssd->sink_pad]->top = 0; @@ -1825,7 +1825,7 @@ static int smiapp_set_format(struct v4l2_subdev *subdev, crops[ssd->sink_pad]->height = fmt->format.height; if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) ssd->sink_fmt = *crops[ssd->sink_pad]; - smiapp_propagate(subdev, fh, fmt->which, + smiapp_propagate(subdev, cfg, fmt->which, V4L2_SEL_TGT_CROP); mutex_unlock(&sensor->mutex); @@ -1878,7 +1878,7 @@ static int scaling_goodness(struct v4l2_subdev *subdev, int w, int ask_w, } static void smiapp_set_compose_binner(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel, struct v4l2_rect **crops, struct v4l2_rect *comp) @@ -1926,7 +1926,7 @@ static void smiapp_set_compose_binner(struct v4l2_subdev *subdev, * result. */ static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel, struct v4l2_rect **crops, struct v4l2_rect *comp) @@ -2042,25 +2042,25 @@ static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev, } /* We're only called on source pads. This function sets scaling. */ static int smiapp_set_compose(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); struct smiapp_subdev *ssd = to_smiapp_subdev(subdev); struct v4l2_rect *comp, *crops[SMIAPP_PADS]; - smiapp_get_crop_compose(subdev, fh, crops, &comp, sel->which); + smiapp_get_crop_compose(subdev, cfg, crops, &comp, sel->which); sel->r.top = 0; sel->r.left = 0; if (ssd == sensor->binner) - smiapp_set_compose_binner(subdev, fh, sel, crops, comp); + smiapp_set_compose_binner(subdev, cfg, sel, crops, comp); else - smiapp_set_compose_scaler(subdev, fh, sel, crops, comp); + smiapp_set_compose_scaler(subdev, cfg, sel, crops, comp); *comp = sel->r; - smiapp_propagate(subdev, fh, sel->which, + smiapp_propagate(subdev, cfg, sel->which, V4L2_SEL_TGT_COMPOSE); if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) @@ -2113,7 +2113,7 @@ static int __smiapp_sel_supported(struct v4l2_subdev *subdev, } static int smiapp_set_crop(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); @@ -2121,7 +2121,7 @@ static int smiapp_set_crop(struct v4l2_subdev *subdev, struct v4l2_rect *src_size, *crops[SMIAPP_PADS]; struct v4l2_rect _r; - smiapp_get_crop_compose(subdev, fh, crops, NULL, sel->which); + smiapp_get_crop_compose(subdev, cfg, crops, NULL, sel->which); if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { if (sel->pad == ssd->sink_pad) @@ -2132,15 +2132,15 @@ static int smiapp_set_crop(struct v4l2_subdev *subdev, if (sel->pad == ssd->sink_pad) { _r.left = 0; _r.top = 0; - _r.width = v4l2_subdev_get_try_format(fh, sel->pad) + _r.width = v4l2_subdev_get_try_format(subdev, cfg, sel->pad) ->width; - _r.height = v4l2_subdev_get_try_format(fh, sel->pad) + _r.height = v4l2_subdev_get_try_format(subdev, cfg, sel->pad) ->height; src_size = &_r; } else { src_size = v4l2_subdev_get_try_compose( - fh, ssd->sink_pad); + subdev, cfg, ssd->sink_pad); } } @@ -2158,14 +2158,14 @@ static int smiapp_set_crop(struct v4l2_subdev *subdev, *crops[sel->pad] = sel->r; if (ssd != sensor->pixel_array && sel->pad == SMIAPP_PAD_SINK) - smiapp_propagate(subdev, fh, sel->which, + smiapp_propagate(subdev, cfg, sel->which, V4L2_SEL_TGT_CROP); return 0; } static int __smiapp_get_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); @@ -2178,13 +2178,13 @@ static int __smiapp_get_selection(struct v4l2_subdev *subdev, if (ret) return ret; - smiapp_get_crop_compose(subdev, fh, crops, &comp, sel->which); + smiapp_get_crop_compose(subdev, cfg, crops, &comp, sel->which); if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { sink_fmt = ssd->sink_fmt; } else { struct v4l2_mbus_framefmt *fmt = - v4l2_subdev_get_try_format(fh, ssd->sink_pad); + v4l2_subdev_get_try_format(subdev, cfg, ssd->sink_pad); sink_fmt.left = 0; sink_fmt.top = 0; @@ -2220,20 +2220,20 @@ static int __smiapp_get_selection(struct v4l2_subdev *subdev, } static int smiapp_get_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); int rval; mutex_lock(&sensor->mutex); - rval = __smiapp_get_selection(subdev, fh, sel); + rval = __smiapp_get_selection(subdev, cfg, sel); mutex_unlock(&sensor->mutex); return rval; } static int smiapp_set_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); @@ -2259,10 +2259,10 @@ static int smiapp_set_selection(struct v4l2_subdev *subdev, switch (sel->target) { case V4L2_SEL_TGT_CROP: - ret = smiapp_set_crop(subdev, fh, sel); + ret = smiapp_set_crop(subdev, cfg, sel); break; case V4L2_SEL_TGT_COMPOSE: - ret = smiapp_set_compose(subdev, fh, sel); + ret = smiapp_set_compose(subdev, cfg, sel); break; default: ret = -EINVAL; @@ -2841,8 +2841,8 @@ static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) for (i = 0; i < ssd->npads; i++) { struct v4l2_mbus_framefmt *try_fmt = - v4l2_subdev_get_try_format(fh, i); - struct v4l2_rect *try_crop = v4l2_subdev_get_try_crop(fh, i); + v4l2_subdev_get_try_format(sd, fh->pad, i); + struct v4l2_rect *try_crop = v4l2_subdev_get_try_crop(sd, fh->pad, i); struct v4l2_rect *try_comp; try_fmt->width = sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1; @@ -2858,7 +2858,7 @@ static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) if (ssd != sensor->pixel_array) continue; - try_comp = v4l2_subdev_get_try_compose(fh, i); + try_comp = v4l2_subdev_get_try_compose(sd, fh->pad, i); *try_comp = *try_crop; } @@ -2977,12 +2977,7 @@ static struct smiapp_platform_data *smiapp_get_pdata(struct device *dev) struct smiapp_platform_data *pdata; struct v4l2_of_endpoint bus_cfg; struct device_node *ep; - struct property *prop; - __be32 *val; uint32_t asize; -#ifdef CONFIG_OF - unsigned int i; -#endif int rval; if (!dev->of_node) @@ -2993,10 +2988,8 @@ static struct smiapp_platform_data *smiapp_get_pdata(struct device *dev) return NULL; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) { - rval = -ENOMEM; + if (!pdata) goto out_err; - } v4l2_of_parse_endpoint(ep, &bus_cfg); @@ -3006,7 +2999,6 @@ static struct smiapp_platform_data *smiapp_get_pdata(struct device *dev) break; /* FIXME: add CCP2 support. */ default: - rval = -EINVAL; goto out_err; } @@ -3030,8 +3022,7 @@ static struct smiapp_platform_data *smiapp_get_pdata(struct device *dev) dev_dbg(dev, "reset %d, nvm %d, clk %d, csi %d\n", pdata->xshutdown, pdata->nvm_size, pdata->ext_clk, pdata->csi_signalling_mode); - rval = of_get_property( - dev->of_node, "link-frequencies", &asize) ? 0 : -ENOENT; + rval = of_get_property(ep, "link-frequencies", &asize) ? 0 : -ENOENT; if (rval) { dev_warn(dev, "can't get link-frequencies array size\n"); goto out_err; @@ -3044,25 +3035,12 @@ static struct smiapp_platform_data *smiapp_get_pdata(struct device *dev) } asize /= sizeof(*pdata->op_sys_clock); - /* - * Read a 64-bit array --- this will be replaced with a - * of_property_read_u64_array() once it's merged. - */ - prop = of_find_property(dev->of_node, "link-frequencies", NULL); - if (!prop) - goto out_err; - if (!prop->value) - goto out_err; - if (asize * sizeof(*pdata->op_sys_clock) > prop->length) - goto out_err; - val = prop->value; - if (IS_ERR(val)) + rval = of_property_read_u64_array( + ep, "link-frequencies", pdata->op_sys_clock, asize); + if (rval) { + dev_warn(dev, "can't get link-frequencies\n"); goto out_err; - -#ifdef CONFIG_OF - for (i = 0; i < asize; i++) - pdata->op_sys_clock[i] = of_read_number(val + i * 2, 2); -#endif + } for (; asize > 0; asize--) dev_dbg(dev, "freq %d: %lld\n", asize - 1, diff --git a/drivers/media/i2c/soc_camera/mt9m111.c b/drivers/media/i2c/soc_camera/mt9m111.c index 5992ea93257a..441e0fda24fe 100644 --- a/drivers/media/i2c/soc_camera/mt9m111.c +++ b/drivers/media/i2c/soc_camera/mt9m111.c @@ -1016,7 +1016,6 @@ static int mt9m111_remove(struct i2c_client *client) v4l2_async_unregister_subdev(&mt9m111->subdev); v4l2_clk_put(mt9m111->clk); - v4l2_device_unregister_subdev(&mt9m111->subdev); v4l2_ctrl_handler_free(&mt9m111->hdl); return 0; diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c index 1fdce2f6f880..e3c907a97765 100644 --- a/drivers/media/i2c/soc_camera/ov2640.c +++ b/drivers/media/i2c/soc_camera/ov2640.c @@ -18,6 +18,9 @@ #include <linux/i2c.h> #include <linux/slab.h> #include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/gpio/consumer.h> +#include <linux/of_gpio.h> #include <linux/v4l2-mediabus.h> #include <linux/videodev2.h> @@ -283,6 +286,10 @@ struct ov2640_priv { u32 cfmt_code; struct v4l2_clk *clk; const struct ov2640_win_size *win; + + struct soc_camera_subdev_desc ssdd_dt; + struct gpio_desc *resetb_gpio; + struct gpio_desc *pwdn_gpio; }; /* @@ -1038,6 +1045,63 @@ static struct v4l2_subdev_ops ov2640_subdev_ops = { .video = &ov2640_subdev_video_ops, }; +/* OF probe functions */ +static int ov2640_hw_power(struct device *dev, int on) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ov2640_priv *priv = to_ov2640(client); + + dev_dbg(&client->dev, "%s: %s the camera\n", + __func__, on ? "ENABLE" : "DISABLE"); + + if (priv->pwdn_gpio) + gpiod_direction_output(priv->pwdn_gpio, !on); + + return 0; +} + +static int ov2640_hw_reset(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ov2640_priv *priv = to_ov2640(client); + + if (priv->resetb_gpio) { + /* Active the resetb pin to perform a reset pulse */ + gpiod_direction_output(priv->resetb_gpio, 1); + usleep_range(3000, 5000); + gpiod_direction_output(priv->resetb_gpio, 0); + } + + return 0; +} + +static int ov2640_probe_dt(struct i2c_client *client, + struct ov2640_priv *priv) +{ + /* Request the reset GPIO deasserted */ + priv->resetb_gpio = devm_gpiod_get_optional(&client->dev, "resetb", + GPIOD_OUT_LOW); + if (!priv->resetb_gpio) + dev_dbg(&client->dev, "resetb gpio is not assigned!\n"); + else if (IS_ERR(priv->resetb_gpio)) + return PTR_ERR(priv->resetb_gpio); + + /* Request the power down GPIO asserted */ + priv->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "pwdn", + GPIOD_OUT_HIGH); + if (!priv->pwdn_gpio) + dev_dbg(&client->dev, "pwdn gpio is not assigned!\n"); + else if (IS_ERR(priv->pwdn_gpio)) + return PTR_ERR(priv->pwdn_gpio); + + /* Initialize the soc_camera_subdev_desc */ + priv->ssdd_dt.power = ov2640_hw_power; + priv->ssdd_dt.reset = ov2640_hw_reset; + client->dev.platform_data = &priv->ssdd_dt; + + return 0; +} + /* * i2c_driver functions */ @@ -1049,12 +1113,6 @@ static int ov2640_probe(struct i2c_client *client, struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); int ret; - if (!ssdd) { - dev_err(&adapter->dev, - "OV2640: Missing platform_data for driver\n"); - return -EINVAL; - } - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { dev_err(&adapter->dev, "OV2640: I2C-Adapter doesn't support SMBUS\n"); @@ -1068,6 +1126,22 @@ static int ov2640_probe(struct i2c_client *client, return -ENOMEM; } + priv->clk = v4l2_clk_get(&client->dev, "xvclk"); + if (IS_ERR(priv->clk)) + return -EPROBE_DEFER; + + if (!ssdd && !client->dev.of_node) { + dev_err(&client->dev, "Missing platform_data for driver\n"); + ret = -EINVAL; + goto err_clk; + } + + if (!ssdd) { + ret = ov2640_probe_dt(client, priv); + if (ret) + goto err_clk; + } + v4l2_i2c_subdev_init(&priv->subdev, client, &ov2640_subdev_ops); v4l2_ctrl_handler_init(&priv->hdl, 2); v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops, @@ -1075,24 +1149,27 @@ static int ov2640_probe(struct i2c_client *client, v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0); priv->subdev.ctrl_handler = &priv->hdl; - if (priv->hdl.error) - return priv->hdl.error; - - priv->clk = v4l2_clk_get(&client->dev, "mclk"); - if (IS_ERR(priv->clk)) { - ret = PTR_ERR(priv->clk); - goto eclkget; + if (priv->hdl.error) { + ret = priv->hdl.error; + goto err_clk; } ret = ov2640_video_probe(client); - if (ret) { - v4l2_clk_put(priv->clk); -eclkget: - v4l2_ctrl_handler_free(&priv->hdl); - } else { - dev_info(&adapter->dev, "OV2640 Probed\n"); - } + if (ret < 0) + goto err_videoprobe; + + ret = v4l2_async_register_subdev(&priv->subdev); + if (ret < 0) + goto err_videoprobe; + + dev_info(&adapter->dev, "OV2640 Probed\n"); + return 0; + +err_videoprobe: + v4l2_ctrl_handler_free(&priv->hdl); +err_clk: + v4l2_clk_put(priv->clk); return ret; } @@ -1100,6 +1177,7 @@ static int ov2640_remove(struct i2c_client *client) { struct ov2640_priv *priv = to_ov2640(client); + v4l2_async_unregister_subdev(&priv->subdev); v4l2_clk_put(priv->clk); v4l2_device_unregister_subdev(&priv->subdev); v4l2_ctrl_handler_free(&priv->hdl); @@ -1112,9 +1190,16 @@ static const struct i2c_device_id ov2640_id[] = { }; MODULE_DEVICE_TABLE(i2c, ov2640_id); +static const struct of_device_id ov2640_of_match[] = { + {.compatible = "ovti,ov2640", }, + {}, +}; +MODULE_DEVICE_TABLE(of, ov2640_of_match); + static struct i2c_driver ov2640_i2c_driver = { .driver = { .name = "ov2640", + .of_match_table = of_match_ptr(ov2640_of_match), }, .probe = ov2640_probe, .remove = ov2640_remove, diff --git a/drivers/media/i2c/ths7303.c b/drivers/media/i2c/ths7303.c index ed9ae8875348..9f7fdb6b61ca 100644 --- a/drivers/media/i2c/ths7303.c +++ b/drivers/media/i2c/ths7303.c @@ -52,10 +52,6 @@ MODULE_DESCRIPTION("TI THS7303 video amplifier driver"); MODULE_AUTHOR("Chaithrika U S"); MODULE_LICENSE("GPL"); -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Debug level 0-1"); - static inline struct ths7303_state *to_state(struct v4l2_subdev *sd) { return container_of(sd, struct ths7303_state, sd); diff --git a/drivers/media/i2c/ths8200.c b/drivers/media/i2c/ths8200.c index 4ebd329d7b42..73fc42bc2de6 100644 --- a/drivers/media/i2c/ths8200.c +++ b/drivers/media/i2c/ths8200.c @@ -479,7 +479,6 @@ static int ths8200_remove(struct i2c_client *client) ths8200_s_power(sd, false); v4l2_async_unregister_subdev(&decoder->sd); - v4l2_device_unregister_subdev(sd); return 0; } diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index 204204259ac6..1c6bc306ecdc 100644 --- a/drivers/media/i2c/tvp514x.c +++ b/drivers/media/i2c/tvp514x.c @@ -923,13 +923,13 @@ static const struct v4l2_ctrl_ops tvp514x_ctrl_ops = { /** * tvp514x_enum_mbus_code() - V4L2 decoder interface handler for enum_mbus_code * @sd: pointer to standard V4L2 sub-device structure - * @fh: file handle + * @cfg: pad configuration * @code: pointer to v4l2_subdev_mbus_code_enum structure * * Enumertaes mbus codes supported */ static int tvp514x_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { u32 pad = code->pad; @@ -950,13 +950,13 @@ static int tvp514x_enum_mbus_code(struct v4l2_subdev *sd, /** * tvp514x_get_pad_format() - V4L2 decoder interface handler for get pad format * @sd: pointer to standard V4L2 sub-device structure - * @fh: file handle + * @cfg: pad configuration * @format: pointer to v4l2_subdev_format structure * * Retrieves pad format which is active or tried based on requirement */ static int tvp514x_get_pad_format(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { struct tvp514x_decoder *decoder = to_decoder(sd); @@ -979,13 +979,13 @@ static int tvp514x_get_pad_format(struct v4l2_subdev *sd, /** * tvp514x_set_pad_format() - V4L2 decoder interface handler for set pad format * @sd: pointer to standard V4L2 sub-device structure - * @fh: file handle + * @cfg: pad configuration * @format: pointer to v4l2_subdev_format structure * * Set pad format for the output pad */ static int tvp514x_set_pad_format(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct tvp514x_decoder *decoder = to_decoder(sd); @@ -1209,7 +1209,6 @@ static int tvp514x_remove(struct i2c_client *client) struct tvp514x_decoder *decoder = to_decoder(sd); v4l2_async_unregister_subdev(&decoder->sd); - v4l2_device_unregister_subdev(sd); #if defined(CONFIG_MEDIA_CONTROLLER) media_entity_cleanup(&decoder->sd.entity); #endif diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c index fe4870e22cfe..787cdfb08749 100644 --- a/drivers/media/i2c/tvp7002.c +++ b/drivers/media/i2c/tvp7002.c @@ -846,13 +846,13 @@ static const struct v4l2_ctrl_ops tvp7002_ctrl_ops = { /* * tvp7002_enum_mbus_code() - Enum supported digital video format on pad * @sd: pointer to standard V4L2 sub-device structure - * @fh: file handle for the subdev + * @cfg: pad configuration * @code: pointer to subdev enum mbus code struct * * Enumerate supported digital video formats for pad. */ static int -tvp7002_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +tvp7002_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { /* Check requested format index is within range */ @@ -867,13 +867,13 @@ tvp7002_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * tvp7002_get_pad_format() - get video format on pad * @sd: pointer to standard V4L2 sub-device structure - * @fh: file handle for the subdev + * @cfg: pad configuration * @fmt: pointer to subdev format struct * * get video format for pad. */ static int -tvp7002_get_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +tvp7002_get_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct tvp7002 *tvp7002 = to_tvp7002(sd); @@ -890,16 +890,16 @@ tvp7002_get_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * tvp7002_set_pad_format() - set video format on pad * @sd: pointer to standard V4L2 sub-device structure - * @fh: file handle for the subdev + * @cfg: pad configuration * @fmt: pointer to subdev format struct * * set video format for pad. */ static int -tvp7002_set_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +tvp7002_set_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { - return tvp7002_get_pad_format(sd, fh, fmt); + return tvp7002_get_pad_format(sd, cfg, fmt); } /* V4L2 core operation handlers */ @@ -1116,7 +1116,6 @@ static int tvp7002_remove(struct i2c_client *c) #if defined(CONFIG_MEDIA_CONTROLLER) media_entity_cleanup(&device->sd.entity); #endif - v4l2_device_unregister_subdev(sd); v4l2_ctrl_handler_free(&device->hdl); return 0; } diff --git a/drivers/media/mmc/siano/smssdio.c b/drivers/media/mmc/siano/smssdio.c index 912c2814c6cf..fee2d710bbf8 100644 --- a/drivers/media/mmc/siano/smssdio.c +++ b/drivers/media/mmc/siano/smssdio.c @@ -32,6 +32,8 @@ * Fix stop command */ +#include "smscoreapi.h" + #include <linux/moduleparam.h> #include <linux/slab.h> #include <linux/firmware.h> @@ -41,7 +43,6 @@ #include <linux/mmc/sdio_ids.h> #include <linux/module.h> -#include "smscoreapi.h" #include "sms-cards.h" #include "smsendian.h" @@ -141,14 +142,14 @@ static void smssdio_interrupt(struct sdio_func *func) */ (void)sdio_readb(func, SMSSDIO_INT, &ret); if (ret) { - sms_err("Unable to read interrupt register!\n"); + pr_err("Unable to read interrupt register!\n"); return; } if (smsdev->split_cb == NULL) { cb = smscore_getbuffer(smsdev->coredev); if (!cb) { - sms_err("Unable to allocate data buffer!\n"); + pr_err("Unable to allocate data buffer!\n"); return; } @@ -157,7 +158,7 @@ static void smssdio_interrupt(struct sdio_func *func) SMSSDIO_DATA, SMSSDIO_BLOCK_SIZE); if (ret) { - sms_err("Error %d reading initial block!\n", ret); + pr_err("Error %d reading initial block!\n", ret); return; } @@ -198,7 +199,7 @@ static void smssdio_interrupt(struct sdio_func *func) size); if (ret && ret != -EINVAL) { smscore_putbuffer(smsdev->coredev, cb); - sms_err("Error %d reading data from card!\n", ret); + pr_err("Error %d reading data from card!\n", ret); return; } @@ -216,8 +217,8 @@ static void smssdio_interrupt(struct sdio_func *func) smsdev->func->cur_blksize); if (ret) { smscore_putbuffer(smsdev->coredev, cb); - sms_err("Error %d reading " - "data from card!\n", ret); + pr_err("Error %d reading data from card!\n", + ret); return; } @@ -278,7 +279,7 @@ static int smssdio_probe(struct sdio_func *func, goto free; } - ret = smscore_register_device(¶ms, &smsdev->coredev); + ret = smscore_register_device(¶ms, &smsdev->coredev, NULL); if (ret < 0) goto free; diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 4ec2a3c3f23c..bc12060e0882 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -2474,7 +2474,7 @@ static int bttv_querycap(struct file *file, void *priv, return -EINVAL; strlcpy(cap->driver, "bttv", sizeof(cap->driver)); - strlcpy(cap->card, btv->video_dev->name, sizeof(cap->card)); + strlcpy(cap->card, btv->video_dev.name, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", pci_name(btv->c.pci)); cap->capabilities = @@ -2484,9 +2484,9 @@ static int bttv_querycap(struct file *file, void *priv, V4L2_CAP_DEVICE_CAPS; if (no_overlay <= 0) cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY; - if (btv->vbi_dev) + if (video_is_registered(&btv->vbi_dev)) cap->capabilities |= V4L2_CAP_VBI_CAPTURE; - if (btv->radio_dev) + if (video_is_registered(&btv->radio_dev)) cap->capabilities |= V4L2_CAP_RADIO; /* @@ -3905,18 +3905,14 @@ static irqreturn_t bttv_irq(int irq, void *dev_id) /* ----------------------------------------------------------------------- */ /* initialization */ -static struct video_device *vdev_init(struct bttv *btv, - const struct video_device *template, - const char *type_name) +static void vdev_init(struct bttv *btv, + struct video_device *vfd, + const struct video_device *template, + const char *type_name) { - struct video_device *vfd; - - vfd = video_device_alloc(); - if (NULL == vfd) - return NULL; *vfd = *template; vfd->v4l2_dev = &btv->c.v4l2_dev; - vfd->release = video_device_release; + vfd->release = video_device_release_empty; video_set_drvdata(vfd, btv); snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)", btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "", @@ -3927,32 +3923,13 @@ static struct video_device *vdev_init(struct bttv *btv, v4l2_disable_ioctl(vfd, VIDIOC_G_TUNER); v4l2_disable_ioctl(vfd, VIDIOC_S_TUNER); } - return vfd; } static void bttv_unregister_video(struct bttv *btv) { - if (btv->video_dev) { - if (video_is_registered(btv->video_dev)) - video_unregister_device(btv->video_dev); - else - video_device_release(btv->video_dev); - btv->video_dev = NULL; - } - if (btv->vbi_dev) { - if (video_is_registered(btv->vbi_dev)) - video_unregister_device(btv->vbi_dev); - else - video_device_release(btv->vbi_dev); - btv->vbi_dev = NULL; - } - if (btv->radio_dev) { - if (video_is_registered(btv->radio_dev)) - video_unregister_device(btv->radio_dev); - else - video_device_release(btv->radio_dev); - btv->radio_dev = NULL; - } + video_unregister_device(&btv->video_dev); + video_unregister_device(&btv->vbi_dev); + video_unregister_device(&btv->radio_dev); } /* register video4linux devices */ @@ -3962,44 +3939,38 @@ static int bttv_register_video(struct bttv *btv) pr_notice("Overlay support disabled\n"); /* video */ - btv->video_dev = vdev_init(btv, &bttv_video_template, "video"); + vdev_init(btv, &btv->video_dev, &bttv_video_template, "video"); - if (NULL == btv->video_dev) - goto err; - if (video_register_device(btv->video_dev, VFL_TYPE_GRABBER, + if (video_register_device(&btv->video_dev, VFL_TYPE_GRABBER, video_nr[btv->c.nr]) < 0) goto err; pr_info("%d: registered device %s\n", - btv->c.nr, video_device_node_name(btv->video_dev)); - if (device_create_file(&btv->video_dev->dev, + btv->c.nr, video_device_node_name(&btv->video_dev)); + if (device_create_file(&btv->video_dev.dev, &dev_attr_card)<0) { pr_err("%d: device_create_file 'card' failed\n", btv->c.nr); goto err; } /* vbi */ - btv->vbi_dev = vdev_init(btv, &bttv_video_template, "vbi"); + vdev_init(btv, &btv->vbi_dev, &bttv_video_template, "vbi"); - if (NULL == btv->vbi_dev) - goto err; - if (video_register_device(btv->vbi_dev, VFL_TYPE_VBI, + if (video_register_device(&btv->vbi_dev, VFL_TYPE_VBI, vbi_nr[btv->c.nr]) < 0) goto err; pr_info("%d: registered device %s\n", - btv->c.nr, video_device_node_name(btv->vbi_dev)); + btv->c.nr, video_device_node_name(&btv->vbi_dev)); if (!btv->has_radio) return 0; /* radio */ - btv->radio_dev = vdev_init(btv, &radio_template, "radio"); - if (NULL == btv->radio_dev) - goto err; - btv->radio_dev->ctrl_handler = &btv->radio_ctrl_handler; - if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO, + vdev_init(btv, &btv->radio_dev, &radio_template, "radio"); + btv->radio_dev.ctrl_handler = &btv->radio_ctrl_handler; + if (video_register_device(&btv->radio_dev, VFL_TYPE_RADIO, radio_nr[btv->c.nr]) < 0) goto err; pr_info("%d: registered device %s\n", - btv->c.nr, video_device_node_name(btv->radio_dev)); + btv->c.nr, video_device_node_name(&btv->radio_dev)); /* all done */ return 0; diff --git a/drivers/media/pci/bt8xx/bttvp.h b/drivers/media/pci/bt8xx/bttvp.h index bc048c586b1f..a444cfb35c0b 100644 --- a/drivers/media/pci/bt8xx/bttvp.h +++ b/drivers/media/pci/bt8xx/bttvp.h @@ -404,9 +404,9 @@ struct bttv { struct v4l2_subdev *sd_tda7432; /* video4linux (1) */ - struct video_device *video_dev; - struct video_device *radio_dev; - struct video_device *vbi_dev; + struct video_device video_dev; + struct video_device radio_dev; + struct video_device vbi_dev; /* controls */ struct v4l2_ctrl_handler ctrl_handler; diff --git a/drivers/media/pci/cx18/cx18-alsa-main.c b/drivers/media/pci/cx18/cx18-alsa-main.c index ea272bcb38df..0b0e8015ad34 100644 --- a/drivers/media/pci/cx18/cx18-alsa-main.c +++ b/drivers/media/pci/cx18/cx18-alsa-main.c @@ -216,7 +216,7 @@ static int cx18_alsa_load(struct cx18 *cx) } s = &cx->streams[CX18_ENC_STREAM_TYPE_PCM]; - if (s->video_dev == NULL) { + if (s->video_dev.v4l2_dev == NULL) { CX18_DEBUG_ALSA_INFO("%s: PCM stream for card is disabled - " "skipping\n", __func__); return 0; diff --git a/drivers/media/pci/cx18/cx18-driver.h b/drivers/media/pci/cx18/cx18-driver.h index 207d6e82403b..b15beed2dc14 100644 --- a/drivers/media/pci/cx18/cx18-driver.h +++ b/drivers/media/pci/cx18/cx18-driver.h @@ -373,7 +373,7 @@ struct cx18_in_work_order { struct cx18_stream { /* These first five fields are always set, even if the stream is not actually created. */ - struct video_device *video_dev; /* NULL when stream not created */ + struct video_device video_dev; /* v4l2_dev is NULL when stream not created */ struct cx18_dvb *dvb; /* DVB / Digital Transport */ struct cx18 *cx; /* for ease of use */ const char *name; /* name of the stream */ @@ -409,6 +409,7 @@ struct cx18_stream { /* Videobuf for YUV video */ u32 pixelformat; u32 vb_bytes_per_frame; + u32 vb_bytes_per_line; struct list_head vb_capture; /* video capture queue */ spinlock_t vb_lock; struct timer_list vb_timeout; diff --git a/drivers/media/pci/cx18/cx18-fileops.c b/drivers/media/pci/cx18/cx18-fileops.c index 76a3b4ac541e..df837408efd5 100644 --- a/drivers/media/pci/cx18/cx18-fileops.c +++ b/drivers/media/pci/cx18/cx18-fileops.c @@ -34,6 +34,7 @@ #include "cx18-controls.h" #include "cx18-ioctl.h" #include "cx18-cards.h" +#include <media/v4l2-event.h> /* This function tries to claim the stream for a specific file descriptor. If no one else is using this stream then the stream is claimed and @@ -609,13 +610,16 @@ ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count, unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait) { + unsigned long req_events = poll_requested_events(wait); struct cx18_open_id *id = file2id(filp); struct cx18 *cx = id->cx; struct cx18_stream *s = &cx->streams[id->type]; int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags); + unsigned res = 0; /* Start a capture if there is none */ - if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags)) { + if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags) && + (req_events & (POLLIN | POLLRDNORM))) { int rc; mutex_lock(&cx->serialize_lock); @@ -632,21 +636,26 @@ unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait) if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) && (id->type == CX18_ENC_STREAM_TYPE_YUV)) { int videobuf_poll = videobuf_poll_stream(filp, &s->vbuf_q, wait); + + if (v4l2_event_pending(&id->fh)) + res |= POLLPRI; if (eof && videobuf_poll == POLLERR) - return POLLHUP; - else - return videobuf_poll; + return res | POLLHUP; + return res | videobuf_poll; } /* add stream's waitq to the poll list */ CX18_DEBUG_HI_FILE("Encoder poll\n"); - poll_wait(filp, &s->waitq, wait); + if (v4l2_event_pending(&id->fh)) + res |= POLLPRI; + else + poll_wait(filp, &s->waitq, wait); if (atomic_read(&s->q_full.depth)) - return POLLIN | POLLRDNORM; + return res | POLLIN | POLLRDNORM; if (eof) - return POLLHUP; - return 0; + return res | POLLHUP; + return res; } int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma) @@ -797,7 +806,7 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp) CX18_DEBUG_WARN("nomem on v4l2 open\n"); return -ENOMEM; } - v4l2_fh_init(&item->fh, s->video_dev); + v4l2_fh_init(&item->fh, &s->video_dev); item->cx = cx; item->type = s->type; diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c index b8e4b68a9196..79aee30d5fd8 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.c +++ b/drivers/media/pci/cx18/cx18-ioctl.c @@ -39,6 +39,7 @@ #include "cx18-cards.h" #include "cx18-av-core.h" #include <media/tveeprom.h> +#include <media/v4l2-event.h> u16 cx18_service2vbi(int type) { @@ -159,7 +160,7 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh, if (id->type == CX18_ENC_STREAM_TYPE_YUV) { pixfmt->pixelformat = s->pixelformat; pixfmt->sizeimage = s->vb_bytes_per_frame; - pixfmt->bytesperline = 720; + pixfmt->bytesperline = s->vb_bytes_per_line; } else { pixfmt->pixelformat = V4L2_PIX_FMT_MPEG; pixfmt->sizeimage = 128 * 1024; @@ -287,10 +288,13 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh, s->pixelformat = fmt->fmt.pix.pixelformat; /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2))) UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */ - if (s->pixelformat == V4L2_PIX_FMT_HM12) + if (s->pixelformat == V4L2_PIX_FMT_HM12) { s->vb_bytes_per_frame = h * 720 * 3 / 2; - else + s->vb_bytes_per_line = 720; /* First plane */ + } else { s->vb_bytes_per_frame = h * 720 * 2; + s->vb_bytes_per_line = 1440; /* Packed */ + } mbus_fmt.width = cx->cxhdl.width = w; mbus_fmt.height = cx->cxhdl.height = h; @@ -447,34 +451,29 @@ static int cx18_cropcap(struct file *file, void *fh, if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - cropcap->bounds.top = cropcap->bounds.left = 0; - cropcap->bounds.width = 720; - cropcap->bounds.height = cx->is_50hz ? 576 : 480; cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10; cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11; - cropcap->defrect = cropcap->bounds; return 0; } -static int cx18_s_crop(struct file *file, void *fh, const struct v4l2_crop *crop) -{ - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - CX18_DEBUG_WARN("VIDIOC_S_CROP not implemented\n"); - return -EINVAL; -} - -static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop) +static int cx18_g_selection(struct file *file, void *fh, + struct v4l2_selection *sel) { struct cx18 *cx = fh2id(fh)->cx; - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - CX18_DEBUG_WARN("VIDIOC_G_CROP not implemented\n"); - return -EINVAL; + switch (sel->target) { + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_DEFAULT: + sel->r.top = sel->r.left = 0; + sel->r.width = 720; + sel->r.height = cx->is_50hz ? 576 : 480; + break; + default: + return -EINVAL; + } + return 0; } static int cx18_enum_fmt_vid_cap(struct file *file, void *fh, @@ -510,6 +509,9 @@ int cx18_s_input(struct file *file, void *fh, unsigned int inp) { struct cx18_open_id *id = fh2id(fh); struct cx18 *cx = id->cx; + v4l2_std_id std = V4L2_STD_ALL; + const struct cx18_card_video_input *card_input = + cx->card->video_inputs + inp; if (inp >= cx->nof_inputs) return -EINVAL; @@ -525,6 +527,11 @@ int cx18_s_input(struct file *file, void *fh, unsigned int inp) cx->active_input = inp; /* Set the audio input to whatever is appropriate for the input type. */ cx->audio_input = cx->card->video_inputs[inp].audio_index; + if (card_input->video_type == V4L2_INPUT_TYPE_TUNER) + std = cx->tuner_std; + cx->streams[CX18_ENC_STREAM_TYPE_MPG].video_dev.tvnorms = std; + cx->streams[CX18_ENC_STREAM_TYPE_YUV].video_dev.tvnorms = std; + cx->streams[CX18_ENC_STREAM_TYPE_VBI].video_dev.tvnorms = std; /* prevent others from messing with the streams until we're finished changing inputs. */ @@ -1036,7 +1043,7 @@ static int cx18_log_status(struct file *file, void *fh) for (i = 0; i < CX18_MAX_STREAMS; i++) { struct cx18_stream *s = &cx->streams[i]; - if (s->video_dev == NULL || s->buffers == 0) + if (s->video_dev.v4l2_dev == NULL || s->buffers == 0) continue; CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", s->name, s->s_flags, @@ -1078,8 +1085,7 @@ static const struct v4l2_ioctl_ops cx18_ioctl_ops = { .vidioc_enumaudio = cx18_enumaudio, .vidioc_enum_input = cx18_enum_input, .vidioc_cropcap = cx18_cropcap, - .vidioc_s_crop = cx18_s_crop, - .vidioc_g_crop = cx18_g_crop, + .vidioc_g_selection = cx18_g_selection, .vidioc_g_input = cx18_g_input, .vidioc_s_input = cx18_s_input, .vidioc_g_frequency = cx18_g_frequency, @@ -1114,6 +1120,8 @@ static const struct v4l2_ioctl_ops cx18_ioctl_ops = { .vidioc_querybuf = cx18_querybuf, .vidioc_qbuf = cx18_qbuf, .vidioc_dqbuf = cx18_dqbuf, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; void cx18_set_funcs(struct video_device *vdev) diff --git a/drivers/media/pci/cx18/cx18-streams.c b/drivers/media/pci/cx18/cx18-streams.c index 369445fcf3e5..c82d25d53341 100644 --- a/drivers/media/pci/cx18/cx18-streams.c +++ b/drivers/media/pci/cx18/cx18-streams.c @@ -254,11 +254,8 @@ static struct videobuf_queue_ops cx18_videobuf_qops = { static void cx18_stream_init(struct cx18 *cx, int type) { struct cx18_stream *s = &cx->streams[type]; - struct video_device *video_dev = s->video_dev; - /* we need to keep video_dev, so restore it afterwards */ memset(s, 0, sizeof(*s)); - s->video_dev = video_dev; /* initialize cx18_stream fields */ s->dvb = NULL; @@ -307,6 +304,7 @@ static void cx18_stream_init(struct cx18 *cx, int type) /* Assume the previous pixel default */ s->pixelformat = V4L2_PIX_FMT_HM12; s->vb_bytes_per_frame = cx->cxhdl.height * 720 * 3 / 2; + s->vb_bytes_per_line = 720; } } @@ -319,12 +317,12 @@ static int cx18_prep_dev(struct cx18 *cx, int type) /* * These five fields are always initialized. - * For analog capture related streams, if video_dev == NULL then the + * For analog capture related streams, if video_dev.v4l2_dev == NULL then the * stream is not in use. * For the TS stream, if dvb == NULL then the stream is not in use. * In those cases no other fields but these four can be used. */ - s->video_dev = NULL; + s->video_dev.v4l2_dev = NULL; s->dvb = NULL; s->cx = cx; s->type = type; @@ -367,24 +365,20 @@ static int cx18_prep_dev(struct cx18 *cx, int type) if (num_offset == -1) return 0; - /* allocate and initialize the v4l2 video device structure */ - s->video_dev = video_device_alloc(); - if (s->video_dev == NULL) { - CX18_ERR("Couldn't allocate v4l2 video_device for %s\n", - s->name); - return -ENOMEM; - } - - snprintf(s->video_dev->name, sizeof(s->video_dev->name), "%s %s", + /* initialize the v4l2 video device structure */ + snprintf(s->video_dev.name, sizeof(s->video_dev.name), "%s %s", cx->v4l2_dev.name, s->name); - s->video_dev->num = num; - s->video_dev->v4l2_dev = &cx->v4l2_dev; - s->video_dev->fops = &cx18_v4l2_enc_fops; - s->video_dev->release = video_device_release; - s->video_dev->tvnorms = V4L2_STD_ALL; - s->video_dev->lock = &cx->serialize_lock; - cx18_set_funcs(s->video_dev); + s->video_dev.num = num; + s->video_dev.v4l2_dev = &cx->v4l2_dev; + s->video_dev.fops = &cx18_v4l2_enc_fops; + s->video_dev.release = video_device_release_empty; + if (cx->card->video_inputs->video_type == CX18_CARD_INPUT_VID_TUNER) + s->video_dev.tvnorms = cx->tuner_std; + else + s->video_dev.tvnorms = V4L2_STD_ALL; + s->video_dev.lock = &cx->serialize_lock; + cx18_set_funcs(&s->video_dev); return 0; } @@ -428,31 +422,30 @@ static int cx18_reg_dev(struct cx18 *cx, int type) } } - if (s->video_dev == NULL) + if (s->video_dev.v4l2_dev == NULL) return 0; - num = s->video_dev->num; + num = s->video_dev.num; /* card number + user defined offset + device offset */ if (type != CX18_ENC_STREAM_TYPE_MPG) { struct cx18_stream *s_mpg = &cx->streams[CX18_ENC_STREAM_TYPE_MPG]; - if (s_mpg->video_dev) - num = s_mpg->video_dev->num + if (s_mpg->video_dev.v4l2_dev) + num = s_mpg->video_dev.num + cx18_stream_info[type].num_offset; } - video_set_drvdata(s->video_dev, s); + video_set_drvdata(&s->video_dev, s); /* Register device. First try the desired minor, then any free one. */ - ret = video_register_device_no_warn(s->video_dev, vfl_type, num); + ret = video_register_device_no_warn(&s->video_dev, vfl_type, num); if (ret < 0) { CX18_ERR("Couldn't register v4l2 device for %s (device node number %d)\n", s->name, num); - video_device_release(s->video_dev); - s->video_dev = NULL; + s->video_dev.v4l2_dev = NULL; return ret; } - name = video_device_node_name(s->video_dev); + name = video_device_node_name(&s->video_dev); switch (vfl_type) { case VFL_TYPE_GRABBER: @@ -542,10 +535,9 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister) } /* If struct video_device exists, can have buffers allocated */ - vdev = cx->streams[type].video_dev; + vdev = &cx->streams[type].video_dev; - cx->streams[type].video_dev = NULL; - if (vdev == NULL) + if (vdev->v4l2_dev == NULL) continue; if (type == CX18_ENC_STREAM_TYPE_YUV) @@ -553,11 +545,7 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister) cx18_stream_free(&cx->streams[type]); - /* Unregister or release device */ - if (unregister) - video_unregister_device(vdev); - else - video_device_release(vdev); + video_unregister_device(vdev); } } @@ -1042,7 +1030,7 @@ u32 cx18_find_handle(struct cx18 *cx) for (i = 0; i < CX18_MAX_STREAMS; i++) { struct cx18_stream *s = &cx->streams[i]; - if (s->video_dev && (s->handle != CX18_INVALID_TASK_HANDLE)) + if (s->video_dev.v4l2_dev && (s->handle != CX18_INVALID_TASK_HANDLE)) return s->handle; } return CX18_INVALID_TASK_HANDLE; diff --git a/drivers/media/pci/cx18/cx18-streams.h b/drivers/media/pci/cx18/cx18-streams.h index 713b0e61536d..27f8af9b11cd 100644 --- a/drivers/media/pci/cx18/cx18-streams.h +++ b/drivers/media/pci/cx18/cx18-streams.h @@ -33,7 +33,7 @@ void cx18_stream_rotate_idx_mdls(struct cx18 *cx); static inline bool cx18_stream_enabled(struct cx18_stream *s) { - return s->video_dev || + return s->video_dev.v4l2_dev || (s->dvb && s->dvb->enabled) || (s->type == CX18_ENC_STREAM_TYPE_IDX && s->cx->stream_buffers[CX18_ENC_STREAM_TYPE_IDX] != 0); diff --git a/drivers/media/pci/cx23885/Kconfig b/drivers/media/pci/cx23885/Kconfig index 74d774e5227b..2e1b88ccdbf2 100644 --- a/drivers/media/pci/cx23885/Kconfig +++ b/drivers/media/pci/cx23885/Kconfig @@ -40,7 +40,6 @@ config VIDEO_CX23885 select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_M88RS6000T if MEDIA_SUBDRV_AUTOSELECT select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT ---help--- diff --git a/drivers/media/pci/cx23885/altera-ci.c b/drivers/media/pci/cx23885/altera-ci.c index 2bbbf545b042..0a91df2c9f08 100644 --- a/drivers/media/pci/cx23885/altera-ci.c +++ b/drivers/media/pci/cx23885/altera-ci.c @@ -483,7 +483,6 @@ static void altera_hw_filt_release(void *main_dev, int filt_nr) } } -EXPORT_SYMBOL(altera_hw_filt_release); void altera_ci_release(void *dev, int ci_nr) { @@ -598,7 +597,6 @@ static int altera_pid_feed_control(void *demux_dev, int filt_nr, return 0; } -EXPORT_SYMBOL(altera_pid_feed_control); static int altera_ci_start_feed(struct dvb_demux_feed *feed, int num) { @@ -699,7 +697,6 @@ err: return ret; } -EXPORT_SYMBOL(altera_hw_filt_init); int altera_ci_init(struct altera_ci_config *config, int ci_nr) { diff --git a/drivers/media/pci/cx23885/altera-ci.h b/drivers/media/pci/cx23885/altera-ci.h index 5028f0cf83f4..6c511723fd1b 100644 --- a/drivers/media/pci/cx23885/altera-ci.h +++ b/drivers/media/pci/cx23885/altera-ci.h @@ -39,7 +39,7 @@ struct altera_ci_config { int (*fpga_rw) (void *dev, int ad_rg, int val, int rw); }; -#if IS_ENABLED(CONFIG_MEDIA_ALTERA_CI) +#if IS_REACHABLE(CONFIG_MEDIA_ALTERA_CI) extern int altera_ci_init(struct altera_ci_config *config, int ci_nr); extern void altera_ci_release(void *dev, int ci_nr); diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index 1ad49946d7fa..7aee76af7a85 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -825,6 +825,7 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) int i; spin_lock_init(&dev->pci_irqmask_lock); + spin_lock_init(&dev->slock); mutex_init(&dev->lock); mutex_init(&dev->gpio_lock); diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index 45fbe1e4d2d0..745caabe3397 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -73,7 +73,6 @@ #include "si2157.h" #include "sp2.h" #include "m88ds3103.h" -#include "m88ts2022.h" #include "m88rs6000t.h" static unsigned int debug; @@ -1187,7 +1186,7 @@ static int dvb_register(struct cx23885_tsport *port) struct vb2_dvb_frontend *fe0, *fe1 = NULL; struct si2168_config si2168_config; struct si2157_config si2157_config; - struct m88ts2022_config m88ts2022_config; + struct ts2020_config ts2020_config; struct i2c_board_info info; struct i2c_adapter *adapter; struct i2c_client *client_demod = NULL, *client_tuner = NULL; @@ -1856,13 +1855,12 @@ static int dvb_register(struct cx23885_tsport *port) break; /* attach tuner */ - memset(&m88ts2022_config, 0, sizeof(m88ts2022_config)); - m88ts2022_config.fe = fe0->dvb.frontend; - m88ts2022_config.clock = 27000000; + memset(&ts2020_config, 0, sizeof(ts2020_config)); + ts2020_config.fe = fe0->dvb.frontend; memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE); + strlcpy(info.type, "ts2020", I2C_NAME_SIZE); info.addr = 0x60; - info.platform_data = &m88ts2022_config; + info.platform_data = &ts2020_config; request_module(info.type); client_tuner = i2c_new_device(adapter, &info); if (client_tuner == NULL || @@ -1986,13 +1984,12 @@ static int dvb_register(struct cx23885_tsport *port) break; /* attach tuner */ - memset(&m88ts2022_config, 0, sizeof(m88ts2022_config)); - m88ts2022_config.fe = fe0->dvb.frontend; - m88ts2022_config.clock = 27000000; + memset(&ts2020_config, 0, sizeof(ts2020_config)); + ts2020_config.fe = fe0->dvb.frontend; memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE); + strlcpy(info.type, "ts2020", I2C_NAME_SIZE); info.addr = 0x60; - info.platform_data = &m88ts2022_config; + info.platform_data = &ts2020_config; request_module(info.type); client_tuner = i2c_new_device(adapter, &info); if (client_tuner == NULL || client_tuner->dev.driver == NULL) @@ -2032,13 +2029,12 @@ static int dvb_register(struct cx23885_tsport *port) break; /* attach tuner */ - memset(&m88ts2022_config, 0, sizeof(m88ts2022_config)); - m88ts2022_config.fe = fe0->dvb.frontend; - m88ts2022_config.clock = 27000000; + memset(&ts2020_config, 0, sizeof(ts2020_config)); + ts2020_config.fe = fe0->dvb.frontend; memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE); + strlcpy(info.type, "ts2020", I2C_NAME_SIZE); info.addr = 0x60; - info.platform_data = &m88ts2022_config; + info.platform_data = &ts2020_config; request_module(info.type); client_tuner = i2c_new_device(adapter, &info); if (client_tuner == NULL || client_tuner->dev.driver == NULL) diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 5e93c682a3f5..2232b389c441 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -1137,7 +1137,6 @@ int cx23885_video_register(struct cx23885_dev *dev) int err; dprintk(1, "%s()\n", __func__); - spin_lock_init(&dev->slock); /* Initialize VBI template */ cx23885_vbi_template = cx23885_video_template; diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c index b6be46e94289..24216efa56e7 100644 --- a/drivers/media/pci/cx88/cx88-blackbird.c +++ b/drivers/media/pci/cx88/cx88-blackbird.c @@ -1102,32 +1102,26 @@ static int cx8802_blackbird_advise_release(struct cx8802_driver *drv) static void blackbird_unregister_video(struct cx8802_dev *dev) { - if (dev->mpeg_dev) { - if (video_is_registered(dev->mpeg_dev)) - video_unregister_device(dev->mpeg_dev); - else - video_device_release(dev->mpeg_dev); - dev->mpeg_dev = NULL; - } + video_unregister_device(&dev->mpeg_dev); } static int blackbird_register_video(struct cx8802_dev *dev) { int err; - dev->mpeg_dev = cx88_vdev_init(dev->core, dev->pci, - &cx8802_mpeg_template, "mpeg"); - dev->mpeg_dev->ctrl_handler = &dev->cxhdl.hdl; - video_set_drvdata(dev->mpeg_dev, dev); - dev->mpeg_dev->queue = &dev->vb2_mpegq; - err = video_register_device(dev->mpeg_dev, VFL_TYPE_GRABBER, -1); + cx88_vdev_init(dev->core, dev->pci, &dev->mpeg_dev, + &cx8802_mpeg_template, "mpeg"); + dev->mpeg_dev.ctrl_handler = &dev->cxhdl.hdl; + video_set_drvdata(&dev->mpeg_dev, dev); + dev->mpeg_dev.queue = &dev->vb2_mpegq; + err = video_register_device(&dev->mpeg_dev, VFL_TYPE_GRABBER, -1); if (err < 0) { printk(KERN_INFO "%s/2: can't register mpeg device\n", dev->core->name); return err; } printk(KERN_INFO "%s/2: registered device %s [mpeg]\n", - dev->core->name, video_device_node_name(dev->mpeg_dev)); + dev->core->name, video_device_node_name(&dev->mpeg_dev)); return 0; } diff --git a/drivers/media/pci/cx88/cx88-core.c b/drivers/media/pci/cx88/cx88-core.c index c38d5a12e277..3501be9f19d8 100644 --- a/drivers/media/pci/cx88/cx88-core.c +++ b/drivers/media/pci/cx88/cx88-core.c @@ -985,17 +985,14 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm) /* ------------------------------------------------------------------ */ -struct video_device *cx88_vdev_init(struct cx88_core *core, - struct pci_dev *pci, - const struct video_device *template_, - const char *type) +void cx88_vdev_init(struct cx88_core *core, + struct pci_dev *pci, + struct video_device *vfd, + const struct video_device *template_, + const char *type) { - struct video_device *vfd; - - vfd = video_device_alloc(); - if (NULL == vfd) - return NULL; *vfd = *template_; + /* * The dev pointer of v4l2_device is NULL, instead we set the * video_device dev_parent pointer to the correct PCI bus device. @@ -1004,11 +1001,10 @@ struct video_device *cx88_vdev_init(struct cx88_core *core, */ vfd->v4l2_dev = &core->v4l2_dev; vfd->dev_parent = &pci->dev; - vfd->release = video_device_release; + vfd->release = video_device_release_empty; vfd->lock = &core->lock; snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", core->name, type, core->board.name); - return vfd; } struct cx88_core* cx88_core_get(struct pci_dev *pci) diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c index a369b0840acf..98344540c51f 100644 --- a/drivers/media/pci/cx88/cx88-mpeg.c +++ b/drivers/media/pci/cx88/cx88-mpeg.c @@ -732,7 +732,7 @@ static int cx8802_probe(struct pci_dev *pci_dev, dev->alloc_ctx = vb2_dma_sg_init_ctx(&pci_dev->dev); if (IS_ERR(dev->alloc_ctx)) { err = PTR_ERR(dev->alloc_ctx); - goto fail_core; + goto fail_dev; } dev->core = core; @@ -754,6 +754,7 @@ static int cx8802_probe(struct pci_dev *pci_dev, fail_free: vb2_dma_sg_cleanup_ctx(dev->alloc_ctx); + fail_dev: kfree(dev); fail_core: core->dvbdev = NULL; diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index 860c98fc72c7..c9decd80bf61 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -1274,27 +1274,9 @@ static const struct v4l2_ctrl_ops cx8800_ctrl_aud_ops = { static void cx8800_unregister_video(struct cx8800_dev *dev) { - if (dev->radio_dev) { - if (video_is_registered(dev->radio_dev)) - video_unregister_device(dev->radio_dev); - else - video_device_release(dev->radio_dev); - dev->radio_dev = NULL; - } - if (dev->vbi_dev) { - if (video_is_registered(dev->vbi_dev)) - video_unregister_device(dev->vbi_dev); - else - video_device_release(dev->vbi_dev); - dev->vbi_dev = NULL; - } - if (dev->video_dev) { - if (video_is_registered(dev->video_dev)) - video_unregister_device(dev->video_dev); - else - video_device_release(dev->video_dev); - dev->video_dev = NULL; - } + video_unregister_device(&dev->radio_dev); + video_unregister_device(&dev->vbi_dev); + video_unregister_device(&dev->video_dev); } static int cx8800_initdev(struct pci_dev *pci_dev, @@ -1485,12 +1467,12 @@ static int cx8800_initdev(struct pci_dev *pci_dev, goto fail_unreg; /* register v4l devices */ - dev->video_dev = cx88_vdev_init(core,dev->pci, - &cx8800_video_template,"video"); - video_set_drvdata(dev->video_dev, dev); - dev->video_dev->ctrl_handler = &core->video_hdl; - dev->video_dev->queue = &dev->vb2_vidq; - err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER, + cx88_vdev_init(core, dev->pci, &dev->video_dev, + &cx8800_video_template, "video"); + video_set_drvdata(&dev->video_dev, dev); + dev->video_dev.ctrl_handler = &core->video_hdl; + dev->video_dev.queue = &dev->vb2_vidq; + err = video_register_device(&dev->video_dev, VFL_TYPE_GRABBER, video_nr[core->nr]); if (err < 0) { printk(KERN_ERR "%s/0: can't register video device\n", @@ -1498,12 +1480,13 @@ static int cx8800_initdev(struct pci_dev *pci_dev, goto fail_unreg; } printk(KERN_INFO "%s/0: registered device %s [v4l2]\n", - core->name, video_device_node_name(dev->video_dev)); + core->name, video_device_node_name(&dev->video_dev)); - dev->vbi_dev = cx88_vdev_init(core,dev->pci,&cx8800_vbi_template,"vbi"); - video_set_drvdata(dev->vbi_dev, dev); - dev->vbi_dev->queue = &dev->vb2_vbiq; - err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI, + cx88_vdev_init(core, dev->pci, &dev->vbi_dev, + &cx8800_vbi_template, "vbi"); + video_set_drvdata(&dev->vbi_dev, dev); + dev->vbi_dev.queue = &dev->vb2_vbiq; + err = video_register_device(&dev->vbi_dev, VFL_TYPE_VBI, vbi_nr[core->nr]); if (err < 0) { printk(KERN_ERR "%s/0: can't register vbi device\n", @@ -1511,14 +1494,14 @@ static int cx8800_initdev(struct pci_dev *pci_dev, goto fail_unreg; } printk(KERN_INFO "%s/0: registered device %s\n", - core->name, video_device_node_name(dev->vbi_dev)); + core->name, video_device_node_name(&dev->vbi_dev)); if (core->board.radio.type == CX88_RADIO) { - dev->radio_dev = cx88_vdev_init(core,dev->pci, - &cx8800_radio_template,"radio"); - video_set_drvdata(dev->radio_dev, dev); - dev->radio_dev->ctrl_handler = &core->audio_hdl; - err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO, + cx88_vdev_init(core, dev->pci, &dev->radio_dev, + &cx8800_radio_template, "radio"); + video_set_drvdata(&dev->radio_dev, dev); + dev->radio_dev.ctrl_handler = &core->audio_hdl; + err = video_register_device(&dev->radio_dev, VFL_TYPE_RADIO, radio_nr[core->nr]); if (err < 0) { printk(KERN_ERR "%s/0: can't register radio device\n", @@ -1526,7 +1509,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev, goto fail_unreg; } printk(KERN_INFO "%s/0: registered device %s\n", - core->name, video_device_node_name(dev->radio_dev)); + core->name, video_device_node_name(&dev->radio_dev)); } /* start tvaudio thread */ diff --git a/drivers/media/pci/cx88/cx88.h b/drivers/media/pci/cx88/cx88.h index 7748ca9abb09..b9fe1ac24803 100644 --- a/drivers/media/pci/cx88/cx88.h +++ b/drivers/media/pci/cx88/cx88.h @@ -478,9 +478,9 @@ struct cx8800_dev { /* various device info */ unsigned int resources; - struct video_device *video_dev; - struct video_device *vbi_dev; - struct video_device *radio_dev; + struct video_device video_dev; + struct video_device vbi_dev; + struct video_device radio_dev; /* pci i/o */ struct pci_dev *pci; @@ -563,7 +563,7 @@ struct cx8802_dev { /* for blackbird only */ struct list_head devlist; #if IS_ENABLED(CONFIG_VIDEO_CX88_BLACKBIRD) - struct video_device *mpeg_dev; + struct video_device mpeg_dev; u32 mailbox; /* mpeg params */ @@ -647,10 +647,11 @@ extern int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int height, enum v4l2_field field); extern int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm); -extern struct video_device *cx88_vdev_init(struct cx88_core *core, - struct pci_dev *pci, - const struct video_device *template_, - const char *type); +extern void cx88_vdev_init(struct cx88_core *core, + struct pci_dev *pci, + struct video_device *vfd, + const struct video_device *template_, + const char *type); extern struct cx88_core *cx88_core_get(struct pci_dev *pci); extern void cx88_core_put(struct cx88_core *core, struct pci_dev *pci); diff --git a/drivers/media/pci/ivtv/ivtv-alsa-main.c b/drivers/media/pci/ivtv/ivtv-alsa-main.c index 39b52929755a..41fa21534edf 100644 --- a/drivers/media/pci/ivtv/ivtv-alsa-main.c +++ b/drivers/media/pci/ivtv/ivtv-alsa-main.c @@ -224,7 +224,7 @@ static int ivtv_alsa_load(struct ivtv *itv) } s = &itv->streams[IVTV_ENC_STREAM_TYPE_PCM]; - if (s->vdev == NULL) { + if (s->vdev.v4l2_dev == NULL) { IVTV_DEBUG_ALSA_INFO("%s: PCM stream for card is disabled - " "skipping\n", __func__); return 0; diff --git a/drivers/media/pci/ivtv/ivtv-alsa-pcm.c b/drivers/media/pci/ivtv/ivtv-alsa-pcm.c index 7bf9cbca4fa6..f198b9826ed8 100644 --- a/drivers/media/pci/ivtv/ivtv-alsa-pcm.c +++ b/drivers/media/pci/ivtv/ivtv-alsa-pcm.c @@ -167,7 +167,7 @@ static int snd_ivtv_pcm_capture_open(struct snd_pcm_substream *substream) s = &itv->streams[IVTV_ENC_STREAM_TYPE_PCM]; - v4l2_fh_init(&item.fh, s->vdev); + v4l2_fh_init(&item.fh, &s->vdev); item.itv = itv; item.type = s->type; diff --git a/drivers/media/pci/ivtv/ivtv-driver.c b/drivers/media/pci/ivtv/ivtv-driver.c index 802642d26643..c2e60b4f292d 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.c +++ b/drivers/media/pci/ivtv/ivtv-driver.c @@ -1284,7 +1284,7 @@ static int ivtv_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) return 0; free_streams: - ivtv_streams_cleanup(itv, 1); + ivtv_streams_cleanup(itv); free_irq: free_irq(itv->pdev->irq, (void *)itv); free_i2c: @@ -1444,7 +1444,7 @@ static void ivtv_remove(struct pci_dev *pdev) flush_kthread_worker(&itv->irq_worker); kthread_stop(itv->irq_worker_task); - ivtv_streams_cleanup(itv, 1); + ivtv_streams_cleanup(itv); ivtv_udma_free(itv); v4l2_ctrl_handler_free(&itv->cxhdl.hdl); diff --git a/drivers/media/pci/ivtv/ivtv-driver.h b/drivers/media/pci/ivtv/ivtv-driver.h index bc309f42c8ed..e8b6c7ad2ba9 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.h +++ b/drivers/media/pci/ivtv/ivtv-driver.h @@ -327,7 +327,7 @@ struct ivtv; /* forward reference */ struct ivtv_stream { /* These first four fields are always set, even if the stream is not actually created. */ - struct video_device *vdev; /* NULL when stream not created */ + struct video_device vdev; /* vdev.v4l2_dev is NULL if there is no device */ struct ivtv *itv; /* for ease of use */ const char *name; /* name of the stream */ int type; /* stream type */ diff --git a/drivers/media/pci/ivtv/ivtv-fileops.c b/drivers/media/pci/ivtv/ivtv-fileops.c index e5ff6277ca85..605d280d8a5f 100644 --- a/drivers/media/pci/ivtv/ivtv-fileops.c +++ b/drivers/media/pci/ivtv/ivtv-fileops.c @@ -995,7 +995,7 @@ static int ivtv_open(struct file *filp) IVTV_DEBUG_WARN("nomem on v4l2 open\n"); return -ENOMEM; } - v4l2_fh_init(&item->fh, s->vdev); + v4l2_fh_init(&item->fh, &s->vdev); item->itv = itv; item->type = s->type; diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c index 4d8ee18c3feb..6fe6c4a0e858 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.c +++ b/drivers/media/pci/ivtv/ivtv-ioctl.c @@ -448,9 +448,12 @@ static int ivtv_g_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *f static int ivtv_g_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt) { struct ivtv *itv = fh2id(fh)->itv; + struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; struct v4l2_window *winfmt = &fmt->fmt.win; - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + if (!(s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + return -EINVAL; + if (!itv->osd_video_pbase) return -EINVAL; winfmt->chromakey = itv->osd_chroma_key; winfmt->global_alpha = itv->osd_global_alpha; @@ -555,10 +558,13 @@ static int ivtv_try_fmt_vid_out(struct file *file, void *fh, struct v4l2_format static int ivtv_try_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt) { struct ivtv *itv = fh2id(fh)->itv; + struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; u32 chromakey = fmt->fmt.win.chromakey; u8 global_alpha = fmt->fmt.win.global_alpha; - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + if (!(s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + return -EINVAL; + if (!itv->osd_video_pbase) return -EINVAL; ivtv_g_fmt_vid_out_overlay(file, fh, fmt); fmt->fmt.win.chromakey = chromakey; @@ -741,6 +747,11 @@ static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vc snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->pdev)); vcap->capabilities = itv->v4l2_cap | V4L2_CAP_DEVICE_CAPS; vcap->device_caps = s->caps; + if ((s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY) && + !itv->osd_video_pbase) { + vcap->capabilities &= ~V4L2_CAP_VIDEO_OUTPUT_OVERLAY; + vcap->device_caps &= ~V4L2_CAP_VIDEO_OUTPUT_OVERLAY; + } return 0; } @@ -816,80 +827,103 @@ static int ivtv_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropca { struct ivtv_open_id *id = fh2id(fh); struct ivtv *itv = id->itv; - struct yuv_playback_info *yi = &itv->yuv_info; - int streamtype; - - streamtype = id->type; - if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) - return -EINVAL; - cropcap->bounds.top = cropcap->bounds.left = 0; - cropcap->bounds.width = 720; if (cropcap->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - cropcap->bounds.height = itv->is_50hz ? 576 : 480; cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10; cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11; - } else if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { - if (yi->track_osd) { - cropcap->bounds.width = yi->osd_full_w; - cropcap->bounds.height = yi->osd_full_h; - } else { - cropcap->bounds.width = 720; - cropcap->bounds.height = - itv->is_out_50hz ? 576 : 480; - } + } else if (cropcap->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10; cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11; } else { - cropcap->bounds.height = itv->is_out_50hz ? 576 : 480; - cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10; - cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11; + return -EINVAL; } - cropcap->defrect = cropcap->bounds; return 0; } -static int ivtv_s_crop(struct file *file, void *fh, const struct v4l2_crop *crop) +static int ivtv_s_selection(struct file *file, void *fh, + struct v4l2_selection *sel) { struct ivtv_open_id *id = fh2id(fh); struct ivtv *itv = id->itv; struct yuv_playback_info *yi = &itv->yuv_info; - int streamtype; + struct v4l2_rect r = { 0, 0, 720, 0 }; + int streamtype = id->type; - streamtype = id->type; + if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || + !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return -EINVAL; - if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && - (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { - if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { - yi->main_rect = crop->c; - return 0; - } else { - if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, - crop->c.width, crop->c.height, crop->c.left, crop->c.top)) { - itv->main_rect = crop->c; - return 0; - } - } + if (sel->target != V4L2_SEL_TGT_COMPOSE) return -EINVAL; + + + if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || + !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return -EINVAL; + + r.height = itv->is_out_50hz ? 576 : 480; + if (streamtype == IVTV_DEC_STREAM_TYPE_YUV && yi->track_osd) { + r.width = yi->osd_full_w; + r.height = yi->osd_full_h; + } + sel->r.width = clamp(sel->r.width, 16U, r.width); + sel->r.height = clamp(sel->r.height, 16U, r.height); + sel->r.left = clamp_t(unsigned, sel->r.left, 0, r.width - sel->r.width); + sel->r.top = clamp_t(unsigned, sel->r.top, 0, r.height - sel->r.height); + + if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { + yi->main_rect = sel->r; + return 0; + } + if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, + sel->r.width, sel->r.height, sel->r.left, sel->r.top)) { + itv->main_rect = sel->r; + return 0; } return -EINVAL; } -static int ivtv_g_crop(struct file *file, void *fh, struct v4l2_crop *crop) +static int ivtv_g_selection(struct file *file, void *fh, + struct v4l2_selection *sel) { struct ivtv_open_id *id = fh2id(fh); struct ivtv *itv = id->itv; struct yuv_playback_info *yi = &itv->yuv_info; - int streamtype; + struct v4l2_rect r = { 0, 0, 720, 0 }; + int streamtype = id->type; + + if (sel->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + switch (sel->target) { + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r.top = sel->r.left = 0; + sel->r.width = 720; + sel->r.height = itv->is_50hz ? 576 : 480; + return 0; + default: + return -EINVAL; + } + } - streamtype = id->type; + if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || + !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) + return -EINVAL; - if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && - (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { + switch (sel->target) { + case V4L2_SEL_TGT_COMPOSE: if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) - crop->c = yi->main_rect; + sel->r = yi->main_rect; else - crop->c = itv->main_rect; + sel->r = itv->main_rect; + return 0; + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + r.height = itv->is_out_50hz ? 576 : 480; + if (streamtype == IVTV_DEC_STREAM_TYPE_YUV && yi->track_osd) { + r.width = yi->osd_full_w; + r.height = yi->osd_full_h; + } + sel->r = r; return 0; } return -EINVAL; @@ -987,7 +1021,7 @@ int ivtv_s_input(struct file *file, void *fh, unsigned int inp) else std = V4L2_STD_ALL; for (i = 0; i <= IVTV_ENC_STREAM_TYPE_VBI; i++) - itv->streams[i].vdev->tvnorms = std; + itv->streams[i].vdev.tvnorms = std; /* prevent others from messing with the streams until we're finished changing inputs. */ @@ -1038,7 +1072,7 @@ static int ivtv_g_frequency(struct file *file, void *fh, struct v4l2_frequency * struct ivtv *itv = fh2id(fh)->itv; struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; - if (s->vdev->vfl_dir) + if (s->vdev.vfl_dir) return -ENOTTY; if (vf->tuner != 0) return -EINVAL; @@ -1052,7 +1086,7 @@ int ivtv_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *v struct ivtv *itv = fh2id(fh)->itv; struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; - if (s->vdev->vfl_dir) + if (s->vdev.vfl_dir) return -ENOTTY; if (vf->tuner != 0) return -EINVAL; @@ -1340,6 +1374,7 @@ static int ivtv_try_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder static int ivtv_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) { struct ivtv *itv = fh2id(fh)->itv; + struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; u32 data[CX2341X_MBOX_MAX_DATA]; struct yuv_playback_info *yi = &itv->yuv_info; @@ -1363,10 +1398,10 @@ static int ivtv_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) 0, }; - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) - return -EINVAL; + if (!(s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + return -ENOTTY; if (!itv->osd_video_pbase) - return -EINVAL; + return -ENOTTY; fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY | V4L2_FBUF_CAP_GLOBAL_ALPHA; @@ -1427,12 +1462,13 @@ static int ivtv_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffe { struct ivtv_open_id *id = fh2id(fh); struct ivtv *itv = id->itv; + struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; struct yuv_playback_info *yi = &itv->yuv_info; - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) - return -EINVAL; + if (!(s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + return -ENOTTY; if (!itv->osd_video_pbase) - return -EINVAL; + return -ENOTTY; itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0; itv->osd_local_alpha_state = @@ -1447,9 +1483,12 @@ static int ivtv_overlay(struct file *file, void *fh, unsigned int on) { struct ivtv_open_id *id = fh2id(fh); struct ivtv *itv = id->itv; + struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; - if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) - return -EINVAL; + if (!(s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) + return -ENOTTY; + if (!itv->osd_video_pbase) + return -ENOTTY; ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, on != 0); @@ -1547,7 +1586,7 @@ static int ivtv_log_status(struct file *file, void *fh) for (i = 0; i < IVTV_MAX_STREAMS; i++) { struct ivtv_stream *s = &itv->streams[i]; - if (s->vdev == NULL || s->buffers == 0) + if (s->vdev.v4l2_dev == NULL || s->buffers == 0) continue; IVTV_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", s->name, s->s_flags, (s->buffers - s->q_free.buffers) * 100 / s->buffers, @@ -1837,8 +1876,8 @@ static const struct v4l2_ioctl_ops ivtv_ioctl_ops = { .vidioc_enum_output = ivtv_enum_output, .vidioc_enumaudout = ivtv_enumaudout, .vidioc_cropcap = ivtv_cropcap, - .vidioc_s_crop = ivtv_s_crop, - .vidioc_g_crop = ivtv_g_crop, + .vidioc_s_selection = ivtv_s_selection, + .vidioc_g_selection = ivtv_g_selection, .vidioc_g_input = ivtv_g_input, .vidioc_s_input = ivtv_s_input, .vidioc_g_output = ivtv_g_output, diff --git a/drivers/media/pci/ivtv/ivtv-irq.c b/drivers/media/pci/ivtv/ivtv-irq.c index e7d701777e53..36ca2d67c812 100644 --- a/drivers/media/pci/ivtv/ivtv-irq.c +++ b/drivers/media/pci/ivtv/ivtv-irq.c @@ -75,7 +75,7 @@ static void ivtv_pio_work_handler(struct ivtv *itv) IVTV_DEBUG_HI_DMA("ivtv_pio_work_handler\n"); if (itv->cur_pio_stream < 0 || itv->cur_pio_stream >= IVTV_MAX_STREAMS || - s->vdev == NULL || !ivtv_use_pio(s)) { + s->vdev.v4l2_dev == NULL || !ivtv_use_pio(s)) { itv->cur_pio_stream = -1; /* trigger PIO complete user interrupt */ write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44); @@ -132,7 +132,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA int rc; /* sanity checks */ - if (s->vdev == NULL) { + if (s->vdev.v4l2_dev == NULL) { IVTV_DEBUG_WARN("Stream %s not started\n", s->name); return -1; } @@ -890,8 +890,8 @@ static void ivtv_irq_vsync(struct ivtv *itv) if (s) wake_up(&s->waitq); } - if (s && s->vdev) - v4l2_event_queue(s->vdev, frame ? &evtop : &evbottom); + if (s && s->vdev.v4l2_dev) + v4l2_event_queue(&s->vdev, frame ? &evtop : &evbottom); wake_up(&itv->vsync_waitq); /* Send VBI to saa7127 */ diff --git a/drivers/media/pci/ivtv/ivtv-streams.c b/drivers/media/pci/ivtv/ivtv-streams.c index f0a1cc472313..d27c6df97566 100644 --- a/drivers/media/pci/ivtv/ivtv-streams.c +++ b/drivers/media/pci/ivtv/ivtv-streams.c @@ -130,7 +130,8 @@ static struct { "decoder MPG", VFL_TYPE_GRABBER, IVTV_V4L2_DEC_MPG_OFFSET, PCI_DMA_TODEVICE, 0, - V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, + V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | + V4L2_CAP_VIDEO_OUTPUT_OVERLAY, &ivtv_v4l2_dec_fops }, { /* IVTV_DEC_STREAM_TYPE_VBI */ @@ -151,7 +152,8 @@ static struct { "decoder YUV", VFL_TYPE_GRABBER, IVTV_V4L2_DEC_YUV_OFFSET, PCI_DMA_TODEVICE, 0, - V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, + V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | + V4L2_CAP_VIDEO_OUTPUT_OVERLAY, &ivtv_v4l2_dec_fops } }; @@ -159,11 +161,9 @@ static struct { static void ivtv_stream_init(struct ivtv *itv, int type) { struct ivtv_stream *s = &itv->streams[type]; - struct video_device *vdev = s->vdev; /* we need to keep vdev, so restore it afterwards */ memset(s, 0, sizeof(*s)); - s->vdev = vdev; /* initialize ivtv_stream fields */ s->itv = itv; @@ -194,10 +194,10 @@ static int ivtv_prep_dev(struct ivtv *itv, int type) int num_offset = ivtv_stream_info[type].num_offset; int num = itv->instance + ivtv_first_minor + num_offset; - /* These four fields are always initialized. If vdev == NULL, then + /* These four fields are always initialized. If vdev.v4l2_dev == NULL, then this stream is not in use. In that case no other fields but these four can be used. */ - s->vdev = NULL; + s->vdev.v4l2_dev = NULL; s->itv = itv; s->type = type; s->name = ivtv_stream_info[type].name; @@ -218,40 +218,33 @@ static int ivtv_prep_dev(struct ivtv *itv, int type) ivtv_stream_init(itv, type); - /* allocate and initialize the v4l2 video device structure */ - s->vdev = video_device_alloc(); - if (s->vdev == NULL) { - IVTV_ERR("Couldn't allocate v4l2 video_device for %s\n", s->name); - return -ENOMEM; - } - - snprintf(s->vdev->name, sizeof(s->vdev->name), "%s %s", + snprintf(s->vdev.name, sizeof(s->vdev.name), "%s %s", itv->v4l2_dev.name, s->name); - s->vdev->num = num; - s->vdev->v4l2_dev = &itv->v4l2_dev; + s->vdev.num = num; + s->vdev.v4l2_dev = &itv->v4l2_dev; if (ivtv_stream_info[type].v4l2_caps & (V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_SLICED_VBI_OUTPUT)) - s->vdev->vfl_dir = VFL_DIR_TX; - s->vdev->fops = ivtv_stream_info[type].fops; - s->vdev->ctrl_handler = itv->v4l2_dev.ctrl_handler; - s->vdev->release = video_device_release; - s->vdev->tvnorms = V4L2_STD_ALL; - s->vdev->lock = &itv->serialize_lock; + s->vdev.vfl_dir = VFL_DIR_TX; + s->vdev.fops = ivtv_stream_info[type].fops; + s->vdev.ctrl_handler = itv->v4l2_dev.ctrl_handler; + s->vdev.release = video_device_release_empty; + s->vdev.tvnorms = V4L2_STD_ALL; + s->vdev.lock = &itv->serialize_lock; if (s->type == IVTV_DEC_STREAM_TYPE_VBI) { - v4l2_disable_ioctl(s->vdev, VIDIOC_S_AUDIO); - v4l2_disable_ioctl(s->vdev, VIDIOC_G_AUDIO); - v4l2_disable_ioctl(s->vdev, VIDIOC_ENUMAUDIO); - v4l2_disable_ioctl(s->vdev, VIDIOC_ENUMINPUT); - v4l2_disable_ioctl(s->vdev, VIDIOC_S_INPUT); - v4l2_disable_ioctl(s->vdev, VIDIOC_G_INPUT); - v4l2_disable_ioctl(s->vdev, VIDIOC_S_FREQUENCY); - v4l2_disable_ioctl(s->vdev, VIDIOC_G_FREQUENCY); - v4l2_disable_ioctl(s->vdev, VIDIOC_S_TUNER); - v4l2_disable_ioctl(s->vdev, VIDIOC_G_TUNER); - v4l2_disable_ioctl(s->vdev, VIDIOC_S_STD); + v4l2_disable_ioctl(&s->vdev, VIDIOC_S_AUDIO); + v4l2_disable_ioctl(&s->vdev, VIDIOC_G_AUDIO); + v4l2_disable_ioctl(&s->vdev, VIDIOC_ENUMAUDIO); + v4l2_disable_ioctl(&s->vdev, VIDIOC_ENUMINPUT); + v4l2_disable_ioctl(&s->vdev, VIDIOC_S_INPUT); + v4l2_disable_ioctl(&s->vdev, VIDIOC_G_INPUT); + v4l2_disable_ioctl(&s->vdev, VIDIOC_S_FREQUENCY); + v4l2_disable_ioctl(&s->vdev, VIDIOC_G_FREQUENCY); + v4l2_disable_ioctl(&s->vdev, VIDIOC_S_TUNER); + v4l2_disable_ioctl(&s->vdev, VIDIOC_G_TUNER); + v4l2_disable_ioctl(&s->vdev, VIDIOC_S_STD); } - ivtv_set_funcs(s->vdev); + ivtv_set_funcs(&s->vdev); return 0; } @@ -266,7 +259,7 @@ int ivtv_streams_setup(struct ivtv *itv) if (ivtv_prep_dev(itv, type)) break; - if (itv->streams[type].vdev == NULL) + if (itv->streams[type].vdev.v4l2_dev == NULL) continue; /* Allocate Stream */ @@ -277,7 +270,7 @@ int ivtv_streams_setup(struct ivtv *itv) return 0; /* One or more streams could not be initialized. Clean 'em all up. */ - ivtv_streams_cleanup(itv, 0); + ivtv_streams_cleanup(itv); return -ENOMEM; } @@ -288,28 +281,26 @@ static int ivtv_reg_dev(struct ivtv *itv, int type) const char *name; int num; - if (s->vdev == NULL) + if (s->vdev.v4l2_dev == NULL) return 0; - num = s->vdev->num; + num = s->vdev.num; /* card number + user defined offset + device offset */ if (type != IVTV_ENC_STREAM_TYPE_MPG) { struct ivtv_stream *s_mpg = &itv->streams[IVTV_ENC_STREAM_TYPE_MPG]; - if (s_mpg->vdev) - num = s_mpg->vdev->num + ivtv_stream_info[type].num_offset; + if (s_mpg->vdev.v4l2_dev) + num = s_mpg->vdev.num + ivtv_stream_info[type].num_offset; } - video_set_drvdata(s->vdev, s); + video_set_drvdata(&s->vdev, s); /* Register device. First try the desired minor, then any free one. */ - if (video_register_device_no_warn(s->vdev, vfl_type, num)) { + if (video_register_device_no_warn(&s->vdev, vfl_type, num)) { IVTV_ERR("Couldn't register v4l2 device for %s (device node number %d)\n", s->name, num); - video_device_release(s->vdev); - s->vdev = NULL; return -ENOMEM; } - name = video_device_node_name(s->vdev); + name = video_device_node_name(&s->vdev); switch (vfl_type) { case VFL_TYPE_GRABBER: @@ -346,29 +337,25 @@ int ivtv_streams_register(struct ivtv *itv) return 0; /* One or more streams could not be initialized. Clean 'em all up. */ - ivtv_streams_cleanup(itv, 1); + ivtv_streams_cleanup(itv); return -ENOMEM; } /* Unregister v4l2 devices */ -void ivtv_streams_cleanup(struct ivtv *itv, int unregister) +void ivtv_streams_cleanup(struct ivtv *itv) { int type; /* Teardown all streams */ for (type = 0; type < IVTV_MAX_STREAMS; type++) { - struct video_device *vdev = itv->streams[type].vdev; + struct video_device *vdev = &itv->streams[type].vdev; - itv->streams[type].vdev = NULL; - if (vdev == NULL) + if (vdev->v4l2_dev == NULL) continue; + video_unregister_device(vdev); ivtv_stream_free(&itv->streams[type]); - /* Unregister or release device */ - if (unregister) - video_unregister_device(vdev); - else - video_device_release(vdev); + itv->streams[type].vdev.v4l2_dev = NULL; } } @@ -492,7 +479,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) int captype = 0, subtype = 0; int enable_passthrough = 0; - if (s->vdev == NULL) + if (s->vdev.v4l2_dev == NULL) return -EINVAL; IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name); @@ -661,7 +648,7 @@ static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s) u16 width; u16 height; - if (s->vdev == NULL) + if (s->vdev.v4l2_dev == NULL) return -EINVAL; IVTV_DEBUG_INFO("Setting some initial decoder settings\n"); @@ -723,7 +710,7 @@ int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset) struct ivtv *itv = s->itv; int rc; - if (s->vdev == NULL) + if (s->vdev.v4l2_dev == NULL) return -EINVAL; if (test_and_set_bit(IVTV_F_S_STREAMING, &s->s_flags)) @@ -778,7 +765,7 @@ void ivtv_stop_all_captures(struct ivtv *itv) for (i = IVTV_MAX_STREAMS - 1; i >= 0; i--) { struct ivtv_stream *s = &itv->streams[i]; - if (s->vdev == NULL) + if (s->vdev.v4l2_dev == NULL) continue; if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) { ivtv_stop_v4l2_encode_stream(s, 0); @@ -793,7 +780,7 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) int cap_type; int stopmode; - if (s->vdev == NULL) + if (s->vdev.v4l2_dev == NULL) return -EINVAL; /* This function assumes that you are allowed to stop the capture @@ -917,7 +904,7 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts) }; struct ivtv *itv = s->itv; - if (s->vdev == NULL) + if (s->vdev.v4l2_dev == NULL) return -EINVAL; if (s->type != IVTV_DEC_STREAM_TYPE_YUV && s->type != IVTV_DEC_STREAM_TYPE_MPG) @@ -969,7 +956,7 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts) set_bit(IVTV_F_I_EV_DEC_STOPPED, &itv->i_flags); wake_up(&itv->event_waitq); - v4l2_event_queue(s->vdev, &ev); + v4l2_event_queue(&s->vdev, &ev); /* wake up wait queues */ wake_up(&s->waitq); @@ -982,7 +969,7 @@ int ivtv_passthrough_mode(struct ivtv *itv, int enable) struct ivtv_stream *yuv_stream = &itv->streams[IVTV_ENC_STREAM_TYPE_YUV]; struct ivtv_stream *dec_stream = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV]; - if (yuv_stream->vdev == NULL || dec_stream->vdev == NULL) + if (yuv_stream->vdev.v4l2_dev == NULL || dec_stream->vdev.v4l2_dev == NULL) return -EINVAL; IVTV_DEBUG_INFO("ivtv ioctl: Select passthrough mode\n"); diff --git a/drivers/media/pci/ivtv/ivtv-streams.h b/drivers/media/pci/ivtv/ivtv-streams.h index a653a5136417..3d76a415fbd8 100644 --- a/drivers/media/pci/ivtv/ivtv-streams.h +++ b/drivers/media/pci/ivtv/ivtv-streams.h @@ -23,7 +23,7 @@ int ivtv_streams_setup(struct ivtv *itv); int ivtv_streams_register(struct ivtv *itv); -void ivtv_streams_cleanup(struct ivtv *itv, int unregister); +void ivtv_streams_cleanup(struct ivtv *itv); /* Capture related */ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s); diff --git a/drivers/media/pci/meye/meye.c b/drivers/media/pci/meye/meye.c index 9d9f90cb7740..ba887e8e1b17 100644 --- a/drivers/media/pci/meye/meye.c +++ b/drivers/media/pci/meye/meye.c @@ -1546,7 +1546,7 @@ static struct video_device meye_template = { .name = "meye", .fops = &meye_fops, .ioctl_ops = &meye_ioctl_ops, - .release = video_device_release, + .release = video_device_release_empty, }; static const struct v4l2_ctrl_ops meye_ctrl_ops = { @@ -1623,7 +1623,7 @@ static int meye_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) if (meye.mchip_dev != NULL) { printk(KERN_ERR "meye: only one device allowed!\n"); - goto outnotdev; + return ret; } ret = v4l2_device_register(&pcidev->dev, v4l2_dev); @@ -1633,11 +1633,6 @@ static int meye_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) } ret = -ENOMEM; meye.mchip_dev = pcidev; - meye.vdev = video_device_alloc(); - if (!meye.vdev) { - v4l2_err(v4l2_dev, "video_device_alloc() failed!\n"); - goto outnotdev; - } meye.grab_temp = vmalloc(MCHIP_NB_PAGES_MJPEG * PAGE_SIZE); if (!meye.grab_temp) { @@ -1658,8 +1653,8 @@ static int meye_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) goto outkfifoalloc2; } - memcpy(meye.vdev, &meye_template, sizeof(meye_template)); - meye.vdev->v4l2_dev = &meye.v4l2_dev; + meye.vdev = meye_template; + meye.vdev.v4l2_dev = &meye.v4l2_dev; ret = -EIO; if ((ret = sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 1))) { @@ -1743,9 +1738,9 @@ static int meye_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) } v4l2_ctrl_handler_setup(&meye.hdl); - meye.vdev->ctrl_handler = &meye.hdl; + meye.vdev.ctrl_handler = &meye.hdl; - if (video_register_device(meye.vdev, VFL_TYPE_GRABBER, + if (video_register_device(&meye.vdev, VFL_TYPE_GRABBER, video_nr) < 0) { v4l2_err(v4l2_dev, "video_register_device failed\n"); goto outvideoreg; @@ -1777,14 +1772,12 @@ outkfifoalloc2: outkfifoalloc1: vfree(meye.grab_temp); outvmalloc: - video_device_release(meye.vdev); -outnotdev: return ret; } static void meye_remove(struct pci_dev *pcidev) { - video_unregister_device(meye.vdev); + video_unregister_device(&meye.vdev); mchip_hic_stop(); diff --git a/drivers/media/pci/meye/meye.h b/drivers/media/pci/meye/meye.h index 6fed9274cfa5..751be5e533c7 100644 --- a/drivers/media/pci/meye/meye.h +++ b/drivers/media/pci/meye/meye.h @@ -311,7 +311,7 @@ struct meye { struct kfifo doneq; /* queue for grabbed buffers */ spinlock_t doneq_lock; /* lock protecting the queue */ wait_queue_head_t proc_list; /* wait queue */ - struct video_device *vdev; /* video device parameters */ + struct video_device vdev; /* video device parameters */ u16 brightness; u16 hue; u16 contrast; diff --git a/drivers/media/pci/saa7146/hexium_gemini.c b/drivers/media/pci/saa7146/hexium_gemini.c index 366434f5647e..03cbcd2095c6 100644 --- a/drivers/media/pci/saa7146/hexium_gemini.c +++ b/drivers/media/pci/saa7146/hexium_gemini.c @@ -66,7 +66,7 @@ struct hexium { int type; - struct video_device *video_dev; + struct video_device video_dev; struct i2c_adapter i2c_adapter; int cur_input; /* current input */ diff --git a/drivers/media/pci/saa7146/hexium_orion.c b/drivers/media/pci/saa7146/hexium_orion.c index a1eb26d11070..15f0d66ff78a 100644 --- a/drivers/media/pci/saa7146/hexium_orion.c +++ b/drivers/media/pci/saa7146/hexium_orion.c @@ -63,7 +63,7 @@ struct hexium_data struct hexium { int type; - struct video_device *video_dev; + struct video_device video_dev; struct i2c_adapter i2c_adapter; int cur_input; /* current input */ diff --git a/drivers/media/pci/saa7146/mxb.c b/drivers/media/pci/saa7146/mxb.c index c4c8fce8f2b4..0ca1e07ae783 100644 --- a/drivers/media/pci/saa7146/mxb.c +++ b/drivers/media/pci/saa7146/mxb.c @@ -151,8 +151,8 @@ static struct mxb_routing TEA6420_line[MXB_AUDIOS + 1][2] = { struct mxb { - struct video_device *video_dev; - struct video_device *vbi_dev; + struct video_device video_dev; + struct video_device vbi_dev; struct i2c_adapter i2c_adapter; diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c index 4b0bec3766ed..9cf3c6cba498 100644 --- a/drivers/media/pci/saa7164/saa7164-core.c +++ b/drivers/media/pci/saa7164/saa7164-core.c @@ -1436,11 +1436,11 @@ static void saa7164_finidev(struct pci_dev *pci_dev) saa7164_i2c_unregister(&dev->i2c_bus[1]); saa7164_i2c_unregister(&dev->i2c_bus[2]); - pci_disable_device(pci_dev); - /* unregister stuff */ free_irq(pci_dev->irq, dev); + pci_disable_device(pci_dev); + mutex_lock(&devlist); list_del(&dev->devlist); mutex_unlock(&devlist); diff --git a/drivers/media/pci/smipcie/Kconfig b/drivers/media/pci/smipcie/Kconfig index c8de53f5ea28..21a1583dbd8f 100644 --- a/drivers/media/pci/smipcie/Kconfig +++ b/drivers/media/pci/smipcie/Kconfig @@ -4,7 +4,7 @@ config DVB_SMIPCIE select I2C_ALGOBIT select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TS2020 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_M88RS6000T if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT help diff --git a/drivers/media/pci/smipcie/smipcie.c b/drivers/media/pci/smipcie/smipcie.c index 36c8ed77309c..411592524c63 100644 --- a/drivers/media/pci/smipcie/smipcie.c +++ b/drivers/media/pci/smipcie/smipcie.c @@ -16,7 +16,7 @@ #include "smipcie.h" #include "m88ds3103.h" -#include "m88ts2022.h" +#include "ts2020.h" #include "m88rs6000t.h" #include "si2168.h" #include "si2157.h" @@ -532,9 +532,7 @@ static int smi_dvbsky_m88ds3103_fe_attach(struct smi_port *port) struct i2c_adapter *tuner_i2c_adapter; struct i2c_client *tuner_client; struct i2c_board_info tuner_info; - struct m88ts2022_config m88ts2022_config = { - .clock = 27000000, - }; + struct ts2020_config ts2020_config = {}; memset(&tuner_info, 0, sizeof(struct i2c_board_info)); i2c = (port->idx == 0) ? &dev->i2c_bus[0] : &dev->i2c_bus[1]; @@ -546,10 +544,10 @@ static int smi_dvbsky_m88ds3103_fe_attach(struct smi_port *port) return ret; } /* attach tuner */ - m88ts2022_config.fe = port->fe; - strlcpy(tuner_info.type, "m88ts2022", I2C_NAME_SIZE); + ts2020_config.fe = port->fe; + strlcpy(tuner_info.type, "ts2020", I2C_NAME_SIZE); tuner_info.addr = 0x60; - tuner_info.platform_data = &m88ts2022_config; + tuner_info.platform_data = &ts2020_config; tuner_client = smi_add_i2c_client(tuner_i2c_adapter, &tuner_info); if (!tuner_client) { ret = -ENODEV; diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c index 22450f583da1..d384a6b0b09f 100644 --- a/drivers/media/pci/sta2x11/sta2x11_vip.c +++ b/drivers/media/pci/sta2x11/sta2x11_vip.c @@ -127,7 +127,7 @@ static inline struct vip_buffer *to_vip_buffer(struct vb2_buffer *vb2) */ struct sta2x11_vip { struct v4l2_device v4l2_dev; - struct video_device *video_dev; + struct video_device video_dev; struct pci_dev *pdev; struct i2c_adapter *adapter; unsigned int register_save_area[IRQ_COUNT + SAVE_COUNT + AUX_COUNT]; @@ -763,7 +763,7 @@ static const struct v4l2_ioctl_ops vip_ioctl_ops = { static struct video_device video_dev_template = { .name = KBUILD_MODNAME, - .release = video_device_release, + .release = video_device_release_empty, .fops = &vip_fops, .ioctl_ops = &vip_ioctl_ops, .tvnorms = V4L2_STD_ALL, @@ -1082,19 +1082,13 @@ static int sta2x11_vip_init_one(struct pci_dev *pdev, goto release_buf; } - /* Alloc, initialize and register video device */ - vip->video_dev = video_device_alloc(); - if (!vip->video_dev) { - ret = -ENOMEM; - goto release_irq; - } + /* Initialize and register video device */ + vip->video_dev = video_dev_template; + vip->video_dev.v4l2_dev = &vip->v4l2_dev; + vip->video_dev.queue = &vip->vb_vidq; + video_set_drvdata(&vip->video_dev, vip); - vip->video_dev = &video_dev_template; - vip->video_dev->v4l2_dev = &vip->v4l2_dev; - vip->video_dev->queue = &vip->vb_vidq; - video_set_drvdata(vip->video_dev, vip); - - ret = video_register_device(vip->video_dev, VFL_TYPE_GRABBER, -1); + ret = video_register_device(&vip->video_dev, VFL_TYPE_GRABBER, -1); if (ret) goto vrelease; @@ -1124,13 +1118,9 @@ static int sta2x11_vip_init_one(struct pci_dev *pdev, return 0; vunreg: - video_set_drvdata(vip->video_dev, NULL); + video_set_drvdata(&vip->video_dev, NULL); vrelease: - if (video_is_registered(vip->video_dev)) - video_unregister_device(vip->video_dev); - else - video_device_release(vip->video_dev); -release_irq: + video_unregister_device(&vip->video_dev); free_irq(pdev->irq, vip); release_buf: sta2x11_vip_release_buffer(vip); @@ -1175,9 +1165,8 @@ static void sta2x11_vip_remove_one(struct pci_dev *pdev) sta2x11_vip_clear_register(vip); - video_set_drvdata(vip->video_dev, NULL); - video_unregister_device(vip->video_dev); - /*do not call video_device_release() here, is already done */ + video_set_drvdata(&vip->video_dev, NULL); + video_unregister_device(&vip->video_dev); free_irq(pdev->irq, vip); pci_disable_msi(pdev); vb2_queue_release(&vip->vb_vidq); diff --git a/drivers/media/pci/ttpci/av7110.h b/drivers/media/pci/ttpci/av7110.h index ef3d9606b269..835635b0c712 100644 --- a/drivers/media/pci/ttpci/av7110.h +++ b/drivers/media/pci/ttpci/av7110.h @@ -102,8 +102,8 @@ struct av7110 { struct dvb_device dvb_dev; struct dvb_net dvb_net; - struct video_device *v4l_dev; - struct video_device *vbi_dev; + struct video_device v4l_dev; + struct video_device vbi_dev; struct saa7146_dev *dev; diff --git a/drivers/media/pci/ttpci/budget-av.c b/drivers/media/pci/ttpci/budget-av.c index 0ba3875af22e..54c9910256f8 100644 --- a/drivers/media/pci/ttpci/budget-av.c +++ b/drivers/media/pci/ttpci/budget-av.c @@ -68,7 +68,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); struct budget_av { struct budget budget; - struct video_device *vd; + struct video_device vd; int cur_input; int has_saa7113; struct tasklet_struct ciintf_irq_tasklet; diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index d9b872b9285a..421f53188c6c 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -56,7 +56,7 @@ config VIDEO_VIU config VIDEO_TIMBERDALE tristate "Support for timberdale Video In/LogiWIN" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API + depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && HAS_DMA depends on (MFD_TIMBERDALE && TIMB_DMA) || COMPILE_TEST select VIDEO_ADV7180 select VIDEOBUF_DMA_CONTIG @@ -90,6 +90,7 @@ config VIDEO_OMAP3 select ARM_DMA_USE_IOMMU select OMAP_IOMMU select VIDEOBUF2_DMA_CONTIG + select MFD_SYSCON ---help--- Driver for an OMAP 3 camera controller. @@ -117,6 +118,7 @@ source "drivers/media/platform/soc_camera/Kconfig" source "drivers/media/platform/exynos4-is/Kconfig" source "drivers/media/platform/s5p-tv/Kconfig" source "drivers/media/platform/am437x/Kconfig" +source "drivers/media/platform/xilinx/Kconfig" endif # V4L_PLATFORM_DRIVERS diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 3ec154742083..8f855616c237 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -48,4 +48,6 @@ obj-y += omap/ obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x/ +obj-$(CONFIG_VIDEO_XILINX) += xilinx/ + ccflags-y += -I$(srctree)/drivers/media/i2c diff --git a/drivers/media/platform/am437x/Kconfig b/drivers/media/platform/am437x/Kconfig index 7b023a76e32e..42d9c186710a 100644 --- a/drivers/media/platform/am437x/Kconfig +++ b/drivers/media/platform/am437x/Kconfig @@ -1,6 +1,6 @@ config VIDEO_AM437X_VPFE tristate "TI AM437x VPFE video capture driver" - depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA depends on SOC_AM43XX || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG help diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c index 56a5cb0d2152..4899924ea926 100644 --- a/drivers/media/platform/am437x/am437x-vpfe.c +++ b/drivers/media/platform/am437x/am437x-vpfe.c @@ -1645,6 +1645,7 @@ static int vpfe_enum_size(struct file *file, void *priv, fse.index = fsize->index; fse.pad = 0; fse.code = mbus.code; + fse.which = V4L2_SUBDEV_FORMAT_ACTIVE; ret = v4l2_subdev_call(sdinfo->sd, pad, enum_frame_size, NULL, &fse); if (ret) return -EINVAL; @@ -1700,11 +1701,16 @@ static int vpfe_get_app_input_index(struct vpfe_device *vpfe, { struct vpfe_config *cfg = vpfe->cfg; struct vpfe_subdev_info *sdinfo; + struct i2c_client *client; + struct i2c_client *curr_client; int i, j = 0; + curr_client = v4l2_get_subdevdata(vpfe->current_subdev->sd); for (i = 0; i < ARRAY_SIZE(vpfe->cfg->asd); i++) { sdinfo = &cfg->sub_devs[i]; - if (!strcmp(sdinfo->name, vpfe->current_subdev->name)) { + client = v4l2_get_subdevdata(sdinfo->sd); + if (client->addr == curr_client->addr && + client->adapter->nr == client->adapter->nr) { if (vpfe->current_input >= 1) return -1; *app_input_index = j + vpfe->current_input; @@ -2296,20 +2302,10 @@ vpfe_async_bound(struct v4l2_async_notifier *notifier, vpfe_dbg(1, vpfe, "vpfe_async_bound\n"); for (i = 0; i < ARRAY_SIZE(vpfe->cfg->asd); i++) { - sdinfo = &vpfe->cfg->sub_devs[i]; - - if (!strcmp(sdinfo->name, subdev->name)) { + if (vpfe->cfg->asd[i]->match.of.node == asd[i].match.of.node) { + sdinfo = &vpfe->cfg->sub_devs[i]; vpfe->sd[i] = subdev; - vpfe_info(vpfe, - "v4l2 sub device %s registered\n", - subdev->name); - vpfe->sd[i]->grp_id = - sdinfo->grp_id; - /* update tvnorms from the sub devices */ - for (j = 0; j < 1; j++) - vpfe->video_dev->tvnorms |= - sdinfo->inputs[j].std; - + vpfe->sd[i]->grp_id = sdinfo->grp_id; found = true; break; } @@ -2320,6 +2316,8 @@ vpfe_async_bound(struct v4l2_async_notifier *notifier, return -EINVAL; } + vpfe->video_dev.tvnorms |= sdinfo->inputs[0].std; + /* setup the supported formats & indexes */ for (j = 0, i = 0; ; ++j) { struct vpfe_fmt *fmt; @@ -2327,6 +2325,7 @@ vpfe_async_bound(struct v4l2_async_notifier *notifier, memset(&mbus_code, 0, sizeof(mbus_code)); mbus_code.index = j; + mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE; ret = v4l2_subdev_call(subdev, pad, enum_mbus_code, NULL, &mbus_code); if (ret) @@ -2390,9 +2389,9 @@ static int vpfe_probe_complete(struct vpfe_device *vpfe) INIT_LIST_HEAD(&vpfe->dma_queue); - vdev = vpfe->video_dev; + vdev = &vpfe->video_dev; strlcpy(vdev->name, VPFE_MODULE_NAME, sizeof(vdev->name)); - vdev->release = video_device_release; + vdev->release = video_device_release_empty; vdev->fops = &vpfe_fops; vdev->ioctl_ops = &vpfe_ioctl_ops; vdev->v4l2_dev = &vpfe->v4l2_dev; @@ -2400,7 +2399,7 @@ static int vpfe_probe_complete(struct vpfe_device *vpfe) vdev->queue = q; vdev->lock = &vpfe->lock; video_set_drvdata(vdev, vpfe); - err = video_register_device(vpfe->video_dev, VFL_TYPE_GRABBER, -1); + err = video_register_device(&vpfe->video_dev, VFL_TYPE_GRABBER, -1); if (err) { vpfe_err(vpfe, "Unable to register video device.\n"); @@ -2425,7 +2424,7 @@ static int vpfe_async_complete(struct v4l2_async_notifier *notifier) static struct vpfe_config * vpfe_get_pdata(struct platform_device *pdev) { - struct device_node *endpoint = NULL, *rem = NULL; + struct device_node *endpoint = NULL; struct v4l2_of_endpoint bus_cfg; struct vpfe_subdev_info *sdinfo; struct vpfe_config *pdata; @@ -2443,6 +2442,8 @@ vpfe_get_pdata(struct platform_device *pdev) return NULL; for (i = 0; ; i++) { + struct device_node *rem; + endpoint = of_graph_get_next_endpoint(pdev->dev.of_node, endpoint); if (!endpoint) @@ -2497,11 +2498,15 @@ vpfe_get_pdata(struct platform_device *pdev) goto done; } - strncpy(sdinfo->name, rem->name, sizeof(sdinfo->name)); - pdata->asd[i] = devm_kzalloc(&pdev->dev, sizeof(struct v4l2_async_subdev), GFP_KERNEL); + if (!pdata->asd[i]) { + of_node_put(rem); + pdata = NULL; + goto done; + } + pdata->asd[i]->match_type = V4L2_ASYNC_MATCH_OF; pdata->asd[i]->match.of.node = rem; of_node_put(endpoint); @@ -2513,7 +2518,6 @@ vpfe_get_pdata(struct platform_device *pdev) done: of_node_put(endpoint); - of_node_put(rem); return NULL; } @@ -2561,17 +2565,11 @@ static int vpfe_probe(struct platform_device *pdev) return -EINVAL; } - vpfe->video_dev = video_device_alloc(); - if (!vpfe->video_dev) { - dev_err(&pdev->dev, "Unable to allocate video device\n"); - return -ENOMEM; - } - ret = v4l2_device_register(&pdev->dev, &vpfe->v4l2_dev); if (ret) { vpfe_err(vpfe, "Unable to register v4l2 device.\n"); - goto probe_out_video_release; + return ret; } /* set the driver data in platform device */ @@ -2609,9 +2607,6 @@ static int vpfe_probe(struct platform_device *pdev) probe_out_v4l2_unregister: v4l2_device_unregister(&vpfe->v4l2_dev); -probe_out_video_release: - if (!video_is_registered(vpfe->video_dev)) - video_device_release(vpfe->video_dev); return ret; } @@ -2628,7 +2623,7 @@ static int vpfe_remove(struct platform_device *pdev) v4l2_async_notifier_unregister(&vpfe->notifier); v4l2_device_unregister(&vpfe->v4l2_dev); - video_unregister_device(vpfe->video_dev); + video_unregister_device(&vpfe->video_dev); return 0; } diff --git a/drivers/media/platform/am437x/am437x-vpfe.h b/drivers/media/platform/am437x/am437x-vpfe.h index 0f557352313d..5bfb35649a39 100644 --- a/drivers/media/platform/am437x/am437x-vpfe.h +++ b/drivers/media/platform/am437x/am437x-vpfe.h @@ -83,7 +83,6 @@ struct vpfe_route { }; struct vpfe_subdev_info { - char name[32]; /* Sub device group id */ int grp_id; /* inputs available at the sub device */ @@ -223,7 +222,7 @@ struct vpfe_ccdc { struct vpfe_device { /* V4l2 specific parameters */ /* Identifies video device for this channel */ - struct video_device *video_dev; + struct video_device video_dev; /* sub devices */ struct v4l2_subdev **sd; /* vpfe cfg */ diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c index 8f6698668ecf..6a437f86dcdc 100644 --- a/drivers/media/platform/blackfin/bfin_capture.c +++ b/drivers/media/platform/blackfin/bfin_capture.c @@ -44,7 +44,6 @@ #include <media/blackfin/ppi.h> #define CAPTURE_DRV_NAME "bfin_capture" -#define BCAP_MIN_NUM_BUF 2 struct bcap_format { char *desc; @@ -65,7 +64,7 @@ struct bcap_device { /* v4l2 control handler */ struct v4l2_ctrl_handler ctrl_handler; /* device node data */ - struct video_device *video_dev; + struct video_device video_dev; /* sub device instance */ struct v4l2_subdev *sd; /* capture config */ @@ -104,12 +103,8 @@ struct bcap_device { struct completion comp; /* prepare to stop */ bool stop; -}; - -struct bcap_fh { - struct v4l2_fh fh; - /* indicates whether this file handle is doing IO */ - bool io_allowed; + /* vb2 buffer sequence counter */ + unsigned sequence; }; static const struct bcap_format bcap_formats[] = { @@ -201,90 +196,6 @@ static void bcap_free_sensor_formats(struct bcap_device *bcap_dev) bcap_dev->sensor_formats = NULL; } -static int bcap_open(struct file *file) -{ - struct bcap_device *bcap_dev = video_drvdata(file); - struct video_device *vfd = bcap_dev->video_dev; - struct bcap_fh *bcap_fh; - - if (!bcap_dev->sd) { - v4l2_err(&bcap_dev->v4l2_dev, "No sub device registered\n"); - return -ENODEV; - } - - bcap_fh = kzalloc(sizeof(*bcap_fh), GFP_KERNEL); - if (!bcap_fh) { - v4l2_err(&bcap_dev->v4l2_dev, - "unable to allocate memory for file handle object\n"); - return -ENOMEM; - } - - v4l2_fh_init(&bcap_fh->fh, vfd); - - /* store pointer to v4l2_fh in private_data member of file */ - file->private_data = &bcap_fh->fh; - v4l2_fh_add(&bcap_fh->fh); - bcap_fh->io_allowed = false; - return 0; -} - -static int bcap_release(struct file *file) -{ - struct bcap_device *bcap_dev = video_drvdata(file); - struct v4l2_fh *fh = file->private_data; - struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh); - - /* if this instance is doing IO */ - if (bcap_fh->io_allowed) - vb2_queue_release(&bcap_dev->buffer_queue); - - file->private_data = NULL; - v4l2_fh_del(&bcap_fh->fh); - v4l2_fh_exit(&bcap_fh->fh); - kfree(bcap_fh); - return 0; -} - -static int bcap_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct bcap_device *bcap_dev = video_drvdata(file); - int ret; - - if (mutex_lock_interruptible(&bcap_dev->mutex)) - return -ERESTARTSYS; - ret = vb2_mmap(&bcap_dev->buffer_queue, vma); - mutex_unlock(&bcap_dev->mutex); - return ret; -} - -#ifndef CONFIG_MMU -static unsigned long bcap_get_unmapped_area(struct file *file, - unsigned long addr, - unsigned long len, - unsigned long pgoff, - unsigned long flags) -{ - struct bcap_device *bcap_dev = video_drvdata(file); - - return vb2_get_unmapped_area(&bcap_dev->buffer_queue, - addr, - len, - pgoff, - flags); -} -#endif - -static unsigned int bcap_poll(struct file *file, poll_table *wait) -{ - struct bcap_device *bcap_dev = video_drvdata(file); - unsigned int res; - - mutex_lock(&bcap_dev->mutex); - res = vb2_poll(&bcap_dev->buffer_queue, file, wait); - mutex_unlock(&bcap_dev->mutex); - return res; -} - static int bcap_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, unsigned int *nbuffers, unsigned int *nplanes, @@ -292,37 +203,32 @@ static int bcap_queue_setup(struct vb2_queue *vq, { struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); - if (*nbuffers < BCAP_MIN_NUM_BUF) - *nbuffers = BCAP_MIN_NUM_BUF; + if (fmt && fmt->fmt.pix.sizeimage < bcap_dev->fmt.sizeimage) + return -EINVAL; + + if (vq->num_buffers + *nbuffers < 2) + *nbuffers = 2; *nplanes = 1; - sizes[0] = bcap_dev->fmt.sizeimage; + sizes[0] = fmt ? fmt->fmt.pix.sizeimage : bcap_dev->fmt.sizeimage; alloc_ctxs[0] = bcap_dev->alloc_ctx; return 0; } -static int bcap_buffer_init(struct vb2_buffer *vb) -{ - struct bcap_buffer *buf = to_bcap_vb(vb); - - INIT_LIST_HEAD(&buf->list); - return 0; -} - static int bcap_buffer_prepare(struct vb2_buffer *vb) { struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue); - struct bcap_buffer *buf = to_bcap_vb(vb); - unsigned long size; + unsigned long size = bcap_dev->fmt.sizeimage; - size = bcap_dev->fmt.sizeimage; if (vb2_plane_size(vb, 0) < size) { v4l2_err(&bcap_dev->v4l2_dev, "buffer too small (%lu < %lu)\n", vb2_plane_size(vb, 0), size); return -EINVAL; } - vb2_set_plane_payload(&buf->vb, 0, size); + vb2_set_plane_payload(vb, 0, size); + + vb->v4l2_buf.field = bcap_dev->fmt.field; return 0; } @@ -353,14 +259,16 @@ static int bcap_start_streaming(struct vb2_queue *vq, unsigned int count) { struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); struct ppi_if *ppi = bcap_dev->ppi; + struct bcap_buffer *buf, *tmp; struct ppi_params params; + dma_addr_t addr; int ret; /* enable streamon on the sub device */ ret = v4l2_subdev_call(bcap_dev->sd, video, s_stream, 1); if (ret && (ret != -ENOIOCTLCMD)) { v4l2_err(&bcap_dev->v4l2_dev, "stream on failed in subdev\n"); - return ret; + goto err; } /* set ppi params */ @@ -399,7 +307,7 @@ static int bcap_start_streaming(struct vb2_queue *vq, unsigned int count) if (ret < 0) { v4l2_err(&bcap_dev->v4l2_dev, "Error in setting ppi params\n"); - return ret; + goto err; } /* attach ppi DMA irq handler */ @@ -407,12 +315,34 @@ static int bcap_start_streaming(struct vb2_queue *vq, unsigned int count) if (ret < 0) { v4l2_err(&bcap_dev->v4l2_dev, "Error in attaching interrupt handler\n"); - return ret; + goto err; } + bcap_dev->sequence = 0; + reinit_completion(&bcap_dev->comp); bcap_dev->stop = false; + + /* get the next frame from the dma queue */ + bcap_dev->cur_frm = list_entry(bcap_dev->dma_queue.next, + struct bcap_buffer, list); + /* remove buffer from the dma queue */ + list_del_init(&bcap_dev->cur_frm->list); + addr = vb2_dma_contig_plane_dma_addr(&bcap_dev->cur_frm->vb, 0); + /* update DMA address */ + ppi->ops->update_addr(ppi, (unsigned long)addr); + /* enable ppi */ + ppi->ops->start(ppi); + return 0; + +err: + list_for_each_entry_safe(buf, tmp, &bcap_dev->dma_queue, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED); + } + + return ret; } static void bcap_stop_streaming(struct vb2_queue *vq) @@ -431,6 +361,9 @@ static void bcap_stop_streaming(struct vb2_queue *vq) "stream off failed in subdev\n"); /* release all active buffers */ + if (bcap_dev->cur_frm) + vb2_buffer_done(&bcap_dev->cur_frm->vb, VB2_BUF_STATE_ERROR); + while (!list_empty(&bcap_dev->dma_queue)) { bcap_dev->cur_frm = list_entry(bcap_dev->dma_queue.next, struct bcap_buffer, list); @@ -441,7 +374,6 @@ static void bcap_stop_streaming(struct vb2_queue *vq) static struct vb2_ops bcap_video_qops = { .queue_setup = bcap_queue_setup, - .buf_init = bcap_buffer_init, .buf_prepare = bcap_buffer_prepare, .buf_cleanup = bcap_buffer_cleanup, .buf_queue = bcap_buffer_queue, @@ -451,57 +383,6 @@ static struct vb2_ops bcap_video_qops = { .stop_streaming = bcap_stop_streaming, }; -static int bcap_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *req_buf) -{ - struct bcap_device *bcap_dev = video_drvdata(file); - struct vb2_queue *vq = &bcap_dev->buffer_queue; - struct v4l2_fh *fh = file->private_data; - struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh); - - if (vb2_is_busy(vq)) - return -EBUSY; - - bcap_fh->io_allowed = true; - - return vb2_reqbufs(vq, req_buf); -} - -static int bcap_querybuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct bcap_device *bcap_dev = video_drvdata(file); - - return vb2_querybuf(&bcap_dev->buffer_queue, buf); -} - -static int bcap_qbuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct bcap_device *bcap_dev = video_drvdata(file); - struct v4l2_fh *fh = file->private_data; - struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh); - - if (!bcap_fh->io_allowed) - return -EBUSY; - - return vb2_qbuf(&bcap_dev->buffer_queue, buf); -} - -static int bcap_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct bcap_device *bcap_dev = video_drvdata(file); - struct v4l2_fh *fh = file->private_data; - struct bcap_fh *bcap_fh = container_of(fh, struct bcap_fh, fh); - - if (!bcap_fh->io_allowed) - return -EBUSY; - - return vb2_dqbuf(&bcap_dev->buffer_queue, - buf, file->f_flags & O_NONBLOCK); -} - static irqreturn_t bcap_isr(int irq, void *dev_id) { struct ppi_if *ppi = dev_id; @@ -517,6 +398,7 @@ static irqreturn_t bcap_isr(int irq, void *dev_id) vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); ppi->err = false; } else { + vb->v4l2_buf.sequence = bcap_dev->sequence++; vb2_buffer_done(vb, VB2_BUF_STATE_DONE); } bcap_dev->cur_frm = list_entry(bcap_dev->dma_queue.next, @@ -543,62 +425,14 @@ static irqreturn_t bcap_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static int bcap_streamon(struct file *file, void *priv, - enum v4l2_buf_type buf_type) -{ - struct bcap_device *bcap_dev = video_drvdata(file); - struct bcap_fh *fh = file->private_data; - struct ppi_if *ppi = bcap_dev->ppi; - dma_addr_t addr; - int ret; - - if (!fh->io_allowed) - return -EBUSY; - - /* call streamon to start streaming in videobuf */ - ret = vb2_streamon(&bcap_dev->buffer_queue, buf_type); - if (ret) - return ret; - - /* if dma queue is empty, return error */ - if (list_empty(&bcap_dev->dma_queue)) { - v4l2_err(&bcap_dev->v4l2_dev, "dma queue is empty\n"); - ret = -EINVAL; - goto err; - } - - /* get the next frame from the dma queue */ - bcap_dev->cur_frm = list_entry(bcap_dev->dma_queue.next, - struct bcap_buffer, list); - /* remove buffer from the dma queue */ - list_del_init(&bcap_dev->cur_frm->list); - addr = vb2_dma_contig_plane_dma_addr(&bcap_dev->cur_frm->vb, 0); - /* update DMA address */ - ppi->ops->update_addr(ppi, (unsigned long)addr); - /* enable ppi */ - ppi->ops->start(ppi); - - return 0; -err: - vb2_streamoff(&bcap_dev->buffer_queue, buf_type); - return ret; -} - -static int bcap_streamoff(struct file *file, void *priv, - enum v4l2_buf_type buf_type) -{ - struct bcap_device *bcap_dev = video_drvdata(file); - struct bcap_fh *fh = file->private_data; - - if (!fh->io_allowed) - return -EBUSY; - - return vb2_streamoff(&bcap_dev->buffer_queue, buf_type); -} - static int bcap_querystd(struct file *file, void *priv, v4l2_std_id *std) { struct bcap_device *bcap_dev = video_drvdata(file); + struct v4l2_input input; + + input = bcap_dev->cfg->inputs[bcap_dev->cur_input]; + if (!(input.capabilities & V4L2_IN_CAP_STD)) + return -ENODATA; return v4l2_subdev_call(bcap_dev->sd, video, querystd, std); } @@ -606,6 +440,11 @@ static int bcap_querystd(struct file *file, void *priv, v4l2_std_id *std) static int bcap_g_std(struct file *file, void *priv, v4l2_std_id *std) { struct bcap_device *bcap_dev = video_drvdata(file); + struct v4l2_input input; + + input = bcap_dev->cfg->inputs[bcap_dev->cur_input]; + if (!(input.capabilities & V4L2_IN_CAP_STD)) + return -ENODATA; *std = bcap_dev->std; return 0; @@ -614,8 +453,13 @@ static int bcap_g_std(struct file *file, void *priv, v4l2_std_id *std) static int bcap_s_std(struct file *file, void *priv, v4l2_std_id std) { struct bcap_device *bcap_dev = video_drvdata(file); + struct v4l2_input input; int ret; + input = bcap_dev->cfg->inputs[bcap_dev->cur_input]; + if (!(input.capabilities & V4L2_IN_CAP_STD)) + return -ENODATA; + if (vb2_is_busy(&bcap_dev->buffer_queue)) return -EBUSY; @@ -631,6 +475,11 @@ static int bcap_enum_dv_timings(struct file *file, void *priv, struct v4l2_enum_dv_timings *timings) { struct bcap_device *bcap_dev = video_drvdata(file); + struct v4l2_input input; + + input = bcap_dev->cfg->inputs[bcap_dev->cur_input]; + if (!(input.capabilities & V4L2_IN_CAP_DV_TIMINGS)) + return -ENODATA; timings->pad = 0; @@ -642,6 +491,11 @@ static int bcap_query_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct bcap_device *bcap_dev = video_drvdata(file); + struct v4l2_input input; + + input = bcap_dev->cfg->inputs[bcap_dev->cur_input]; + if (!(input.capabilities & V4L2_IN_CAP_DV_TIMINGS)) + return -ENODATA; return v4l2_subdev_call(bcap_dev->sd, video, query_dv_timings, timings); @@ -651,6 +505,11 @@ static int bcap_g_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct bcap_device *bcap_dev = video_drvdata(file); + struct v4l2_input input; + + input = bcap_dev->cfg->inputs[bcap_dev->cur_input]; + if (!(input.capabilities & V4L2_IN_CAP_DV_TIMINGS)) + return -ENODATA; *timings = bcap_dev->dv_timings; return 0; @@ -660,7 +519,13 @@ static int bcap_s_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct bcap_device *bcap_dev = video_drvdata(file); + struct v4l2_input input; int ret; + + input = bcap_dev->cfg->inputs[bcap_dev->cur_input]; + if (!(input.capabilities & V4L2_IN_CAP_DV_TIMINGS)) + return -ENODATA; + if (vb2_is_busy(&bcap_dev->buffer_queue)) return -EBUSY; @@ -881,12 +746,14 @@ static const struct v4l2_ioctl_ops bcap_ioctl_ops = { .vidioc_g_dv_timings = bcap_g_dv_timings, .vidioc_query_dv_timings = bcap_query_dv_timings, .vidioc_enum_dv_timings = bcap_enum_dv_timings, - .vidioc_reqbufs = bcap_reqbufs, - .vidioc_querybuf = bcap_querybuf, - .vidioc_qbuf = bcap_qbuf, - .vidioc_dqbuf = bcap_dqbuf, - .vidioc_streamon = bcap_streamon, - .vidioc_streamoff = bcap_streamoff, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, .vidioc_g_parm = bcap_g_parm, .vidioc_s_parm = bcap_s_parm, .vidioc_log_status = bcap_log_status, @@ -894,14 +761,14 @@ static const struct v4l2_ioctl_ops bcap_ioctl_ops = { static struct v4l2_file_operations bcap_fops = { .owner = THIS_MODULE, - .open = bcap_open, - .release = bcap_release, + .open = v4l2_fh_open, + .release = vb2_fop_release, .unlocked_ioctl = video_ioctl2, - .mmap = bcap_mmap, + .mmap = vb2_fop_mmap, #ifndef CONFIG_MMU - .get_unmapped_area = bcap_get_unmapped_area, + .get_unmapped_area = vb2_fop_get_unmapped_area, #endif - .poll = bcap_poll + .poll = vb2_fop_poll }; static int bcap_probe(struct platform_device *pdev) @@ -942,27 +809,20 @@ static int bcap_probe(struct platform_device *pdev) goto err_free_ppi; } - vfd = video_device_alloc(); - if (!vfd) { - ret = -ENOMEM; - v4l2_err(pdev->dev.driver, "Unable to alloc video device\n"); - goto err_cleanup_ctx; - } - + vfd = &bcap_dev->video_dev; /* initialize field of video device */ - vfd->release = video_device_release; + vfd->release = video_device_release_empty; vfd->fops = &bcap_fops; vfd->ioctl_ops = &bcap_ioctl_ops; vfd->tvnorms = 0; vfd->v4l2_dev = &bcap_dev->v4l2_dev; strncpy(vfd->name, CAPTURE_DRV_NAME, sizeof(vfd->name)); - bcap_dev->video_dev = vfd; ret = v4l2_device_register(&pdev->dev, &bcap_dev->v4l2_dev); if (ret) { v4l2_err(pdev->dev.driver, "Unable to register v4l2 device\n"); - goto err_release_vdev; + goto err_cleanup_ctx; } v4l2_info(&bcap_dev->v4l2_dev, "v4l2 device registered\n"); @@ -978,13 +838,14 @@ static int bcap_probe(struct platform_device *pdev) /* initialize queue */ q = &bcap_dev->buffer_queue; q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - q->io_modes = VB2_MMAP; + q->io_modes = VB2_MMAP | VB2_DMABUF; q->drv_priv = bcap_dev; q->buf_struct_size = sizeof(struct bcap_buffer); q->ops = &bcap_video_qops; q->mem_ops = &vb2_dma_contig_memops; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; q->lock = &bcap_dev->mutex; + q->min_buffers_needed = 1; ret = vb2_queue_init(q); if (ret) @@ -997,15 +858,16 @@ static int bcap_probe(struct platform_device *pdev) INIT_LIST_HEAD(&bcap_dev->dma_queue); vfd->lock = &bcap_dev->mutex; + vfd->queue = q; /* register video device */ - ret = video_register_device(bcap_dev->video_dev, VFL_TYPE_GRABBER, -1); + ret = video_register_device(&bcap_dev->video_dev, VFL_TYPE_GRABBER, -1); if (ret) { v4l2_err(&bcap_dev->v4l2_dev, "Unable to register video device\n"); goto err_free_handler; } - video_set_drvdata(bcap_dev->video_dev, bcap_dev); + video_set_drvdata(&bcap_dev->video_dev, bcap_dev); v4l2_info(&bcap_dev->v4l2_dev, "video device registered as: %s\n", video_device_node_name(vfd)); @@ -1083,15 +945,11 @@ static int bcap_probe(struct platform_device *pdev) } return 0; err_unreg_vdev: - video_unregister_device(bcap_dev->video_dev); - bcap_dev->video_dev = NULL; + video_unregister_device(&bcap_dev->video_dev); err_free_handler: v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler); err_unreg_v4l2: v4l2_device_unregister(&bcap_dev->v4l2_dev); -err_release_vdev: - if (bcap_dev->video_dev) - video_device_release(bcap_dev->video_dev); err_cleanup_ctx: vb2_dma_contig_cleanup_ctx(bcap_dev->alloc_ctx); err_free_ppi: @@ -1108,7 +966,7 @@ static int bcap_remove(struct platform_device *pdev) struct bcap_device, v4l2_dev); bcap_free_sensor_formats(bcap_dev); - video_unregister_device(bcap_dev->video_dev); + video_unregister_device(&bcap_dev->video_dev); v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler); v4l2_device_unregister(v4l2_dev); vb2_dma_contig_cleanup_ctx(bcap_dev->alloc_ctx); diff --git a/drivers/media/platform/coda/Makefile b/drivers/media/platform/coda/Makefile index 25ce15561695..834e504bf085 100644 --- a/drivers/media/platform/coda/Makefile +++ b/drivers/media/platform/coda/Makefile @@ -1,3 +1,5 @@ +ccflags-y += -I$(src) + coda-objs := coda-common.o coda-bit.o coda-h264.o coda-jpeg.o obj-$(CONFIG_VIDEO_CODA) += coda.o diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 856b542b35b9..d0430071d2ee 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -15,6 +15,7 @@ #include <linux/clk.h> #include <linux/irqreturn.h> #include <linux/kernel.h> +#include <linux/log2.h> #include <linux/platform_device.h> #include <linux/reset.h> #include <linux/slab.h> @@ -29,13 +30,18 @@ #include <media/videobuf2-vmalloc.h> #include "coda.h" +#define CREATE_TRACE_POINTS +#include "trace.h" +#define CODA_PARA_BUF_SIZE (10 * 1024) #define CODA7_PS_BUF_SIZE 0x28000 #define CODA9_PS_SAVE_SIZE (512 * 1024) #define CODA_DEFAULT_GAMMA 4096 #define CODA9_DEFAULT_GAMMA 24576 /* 0.75 * 32768 */ +static void coda_free_bitstream_buffer(struct coda_ctx *ctx); + static inline int coda_is_initialized(struct coda_dev *dev) { return coda_read(dev, CODA_REG_BIT_CUR_PC) != 0; @@ -84,15 +90,21 @@ static void coda_command_async(struct coda_ctx *ctx, int cmd) coda_write(dev, ctx->params.codec_mode, CODA_REG_BIT_RUN_COD_STD); coda_write(dev, ctx->params.codec_mode_aux, CODA7_REG_BIT_RUN_AUX_STD); + trace_coda_bit_run(ctx, cmd); + coda_write(dev, cmd, CODA_REG_BIT_RUN_COMMAND); } static int coda_command_sync(struct coda_ctx *ctx, int cmd) { struct coda_dev *dev = ctx->dev; + int ret; coda_command_async(ctx, cmd); - return coda_wait_timeout(dev); + ret = coda_wait_timeout(dev); + trace_coda_bit_done(ctx); + + return ret; } int coda_hw_reset(struct coda_ctx *ctx) @@ -177,10 +189,6 @@ static int coda_bitstream_queue(struct coda_ctx *ctx, if (n < src_size) return -ENOSPC; - dma_sync_single_for_device(&ctx->dev->plat_dev->dev, - ctx->bitstream.paddr, ctx->bitstream.size, - DMA_TO_DEVICE); - src_buf->v4l2_buf.sequence = ctx->qsequence++; return 0; @@ -214,7 +222,7 @@ static bool coda_bitstream_try_queue(struct coda_ctx *ctx, return true; } -void coda_fill_bitstream(struct coda_ctx *ctx) +void coda_fill_bitstream(struct coda_ctx *ctx, bool streaming) { struct vb2_buffer *src_buf; struct coda_buffer_meta *meta; @@ -235,9 +243,12 @@ void coda_fill_bitstream(struct coda_ctx *ctx) if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG && !coda_jpeg_check_buffer(ctx, src_buf)) { v4l2_err(&ctx->dev->v4l2_dev, - "dropping invalid JPEG frame\n"); + "dropping invalid JPEG frame %d\n", + ctx->qsequence); src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); + v4l2_m2m_buf_done(src_buf, streaming ? + VB2_BUF_STATE_ERROR : + VB2_BUF_STATE_QUEUED); continue; } @@ -262,6 +273,8 @@ void coda_fill_bitstream(struct coda_ctx *ctx) ctx->bitstream_fifo.kfifo.mask; list_add_tail(&meta->list, &ctx->buffer_meta_list); + + trace_coda_bit_queue(ctx, src_buf, meta); } v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); @@ -297,6 +310,14 @@ static void coda_parabuf_write(struct coda_ctx *ctx, int index, u32 value) p[index ^ 1] = value; } +static inline int coda_alloc_context_buf(struct coda_ctx *ctx, + struct coda_aux_buf *buf, size_t size, + const char *name) +{ + return coda_alloc_aux_buf(ctx->dev, buf, size, name, ctx->debugfs_entry); +} + + static void coda_free_framebuffers(struct coda_ctx *ctx) { int i; @@ -377,6 +398,7 @@ static void coda_free_context_buffers(struct coda_ctx *ctx) coda_free_aux_buf(dev, &ctx->psbuf); if (dev->devtype->product != CODA_DX6) coda_free_aux_buf(dev, &ctx->workbuf); + coda_free_aux_buf(dev, &ctx->parabuf); } static int coda_alloc_context_buffers(struct coda_ctx *ctx, @@ -386,57 +408,42 @@ static int coda_alloc_context_buffers(struct coda_ctx *ctx, size_t size; int ret; + if (!ctx->parabuf.vaddr) { + ret = coda_alloc_context_buf(ctx, &ctx->parabuf, + CODA_PARA_BUF_SIZE, "parabuf"); + if (ret < 0) + return ret; + } + if (dev->devtype->product == CODA_DX6) return 0; - if (ctx->psbuf.vaddr) { - v4l2_err(&dev->v4l2_dev, "psmembuf still allocated\n"); - return -EBUSY; - } - if (ctx->slicebuf.vaddr) { - v4l2_err(&dev->v4l2_dev, "slicebuf still allocated\n"); - return -EBUSY; - } - if (ctx->workbuf.vaddr) { - v4l2_err(&dev->v4l2_dev, "context buffer still allocated\n"); - ret = -EBUSY; - return -ENOMEM; - } - - if (q_data->fourcc == V4L2_PIX_FMT_H264) { + if (!ctx->slicebuf.vaddr && q_data->fourcc == V4L2_PIX_FMT_H264) { /* worst case slice size */ size = (DIV_ROUND_UP(q_data->width, 16) * DIV_ROUND_UP(q_data->height, 16)) * 3200 / 8 + 512; ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size, "slicebuf"); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, - "failed to allocate %d byte slice buffer", - ctx->slicebuf.size); - return ret; - } + if (ret < 0) + goto err; } - if (dev->devtype->product == CODA_7541) { + if (!ctx->psbuf.vaddr && dev->devtype->product == CODA_7541) { ret = coda_alloc_context_buf(ctx, &ctx->psbuf, CODA7_PS_BUF_SIZE, "psbuf"); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, - "failed to allocate psmem buffer"); + if (ret < 0) goto err; - } } - size = dev->devtype->workbuf_size; - if (dev->devtype->product == CODA_960 && - q_data->fourcc == V4L2_PIX_FMT_H264) - size += CODA9_PS_SAVE_SIZE; - ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size, "workbuf"); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, - "failed to allocate %d byte context buffer", - ctx->workbuf.size); - goto err; + if (!ctx->workbuf.vaddr) { + size = dev->devtype->workbuf_size; + if (dev->devtype->product == CODA_960 && + q_data->fourcc == V4L2_PIX_FMT_H264) + size += CODA9_PS_SAVE_SIZE; + ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size, + "workbuf"); + if (ret < 0) + goto err; } return 0; @@ -709,6 +716,27 @@ err_clk_per: * Encoder context operations */ +static int coda_encoder_reqbufs(struct coda_ctx *ctx, + struct v4l2_requestbuffers *rb) +{ + struct coda_q_data *q_data_src; + int ret; + + if (rb->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return 0; + + if (rb->count) { + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + ret = coda_alloc_context_buffers(ctx, q_data_src); + if (ret < 0) + return ret; + } else { + coda_free_context_buffers(ctx); + } + + return 0; +} + static int coda_start_encoding(struct coda_ctx *ctx) { struct coda_dev *dev = ctx->dev; @@ -725,11 +753,6 @@ static int coda_start_encoding(struct coda_ctx *ctx) q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); dst_fourcc = q_data_dst->fourcc; - /* Allocate per-instance buffers */ - ret = coda_alloc_context_buffers(ctx, q_data_src); - if (ret < 0) - return ret; - buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); bitstream_buf = vb2_dma_contig_plane_dma_addr(buf, 0); bitstream_size = q_data_dst->sizeimage; @@ -1227,6 +1250,8 @@ static int coda_prepare_encode(struct coda_ctx *ctx) coda_write(dev, ctx->iram_info.axi_sram_use, CODA7_REG_BIT_AXI_SRAM_USE); + trace_coda_enc_pic_run(ctx, src_buf); + coda_command_async(ctx, CODA_COMMAND_PIC_RUN); return 0; @@ -1241,6 +1266,8 @@ static void coda_finish_encode(struct coda_ctx *ctx) src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + trace_coda_enc_pic_done(ctx, dst_buf); + /* Get results from the coda */ start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START); wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); @@ -1311,7 +1338,6 @@ static void coda_seq_end_work(struct work_struct *work) ctx->bitstream.vaddr, ctx->bitstream.size); coda_free_framebuffers(ctx); - coda_free_context_buffers(ctx); mutex_unlock(&dev->coda_mutex); mutex_unlock(&ctx->buffer_mutex); @@ -1322,11 +1348,13 @@ static void coda_bit_release(struct coda_ctx *ctx) mutex_lock(&ctx->buffer_mutex); coda_free_framebuffers(ctx); coda_free_context_buffers(ctx); + coda_free_bitstream_buffer(ctx); mutex_unlock(&ctx->buffer_mutex); } const struct coda_context_ops coda_bit_encode_ops = { .queue_init = coda_encoder_queue_init, + .reqbufs = coda_encoder_reqbufs, .start_streaming = coda_start_encoding, .prepare_run = coda_prepare_encode, .finish_run = coda_finish_encode, @@ -1338,6 +1366,65 @@ const struct coda_context_ops coda_bit_encode_ops = { * Decoder context operations */ +static int coda_alloc_bitstream_buffer(struct coda_ctx *ctx, + struct coda_q_data *q_data) +{ + if (ctx->bitstream.vaddr) + return 0; + + ctx->bitstream.size = roundup_pow_of_two(q_data->sizeimage * 2); + ctx->bitstream.vaddr = dma_alloc_writecombine( + &ctx->dev->plat_dev->dev, ctx->bitstream.size, + &ctx->bitstream.paddr, GFP_KERNEL); + if (!ctx->bitstream.vaddr) { + v4l2_err(&ctx->dev->v4l2_dev, + "failed to allocate bitstream ringbuffer"); + return -ENOMEM; + } + kfifo_init(&ctx->bitstream_fifo, + ctx->bitstream.vaddr, ctx->bitstream.size); + + return 0; +} + +static void coda_free_bitstream_buffer(struct coda_ctx *ctx) +{ + if (ctx->bitstream.vaddr == NULL) + return; + + dma_free_writecombine(&ctx->dev->plat_dev->dev, ctx->bitstream.size, + ctx->bitstream.vaddr, ctx->bitstream.paddr); + ctx->bitstream.vaddr = NULL; + kfifo_init(&ctx->bitstream_fifo, NULL, 0); +} + +static int coda_decoder_reqbufs(struct coda_ctx *ctx, + struct v4l2_requestbuffers *rb) +{ + struct coda_q_data *q_data_src; + int ret; + + if (rb->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return 0; + + if (rb->count) { + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + ret = coda_alloc_context_buffers(ctx, q_data_src); + if (ret < 0) + return ret; + ret = coda_alloc_bitstream_buffer(ctx, q_data_src); + if (ret < 0) { + coda_free_context_buffers(ctx); + return ret; + } + } else { + coda_free_bitstream_buffer(ctx); + coda_free_context_buffers(ctx); + } + + return 0; +} + static int __coda_start_decoding(struct coda_ctx *ctx) { struct coda_q_data *q_data_src, *q_data_dst; @@ -1356,11 +1443,6 @@ static int __coda_start_decoding(struct coda_ctx *ctx) src_fourcc = q_data_src->fourcc; dst_fourcc = q_data_dst->fourcc; - /* Allocate per-instance buffers */ - ret = coda_alloc_context_buffers(ctx, q_data_src); - if (ret < 0) - return ret; - coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); /* Update coda bitstream read and write pointers from kfifo */ @@ -1579,7 +1661,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx) /* Try to copy source buffer contents into the bitstream ringbuffer */ mutex_lock(&ctx->bitstream_mutex); - coda_fill_bitstream(ctx); + coda_fill_bitstream(ctx, true); mutex_unlock(&ctx->bitstream_mutex); if (coda_get_bitstream_payload(ctx) < 512 && @@ -1675,6 +1757,8 @@ static int coda_prepare_decode(struct coda_ctx *ctx) /* Clear decode success flag */ coda_write(dev, 0, CODA_RET_DEC_PIC_SUCCESS); + trace_coda_dec_pic_run(ctx, meta); + coda_command_async(ctx, CODA_COMMAND_PIC_RUN); return 0; @@ -1704,7 +1788,7 @@ static void coda_finish_decode(struct coda_ctx *ctx) * by up to 512 bytes */ if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) { - if (coda_get_bitstream_payload(ctx) >= CODA_MAX_FRAME_SIZE - 512) + if (coda_get_bitstream_payload(ctx) >= ctx->bitstream.size - 512) kfifo_init(&ctx->bitstream_fifo, ctx->bitstream.vaddr, ctx->bitstream.size); } @@ -1835,6 +1919,8 @@ static void coda_finish_decode(struct coda_ctx *ctx) } mutex_unlock(&ctx->bitstream_mutex); + trace_coda_dec_pic_done(ctx, &ctx->frame_metas[decoded_idx]); + val = coda_read(dev, CODA_RET_DEC_PIC_TYPE) & 0x7; if (val == 0) ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_KEYFRAME; @@ -1874,6 +1960,8 @@ static void coda_finish_decode(struct coda_ctx *ctx) dst_buf->v4l2_buf.timecode = meta->timecode; dst_buf->v4l2_buf.timestamp = meta->timestamp; + trace_coda_dec_rot_done(ctx, meta, dst_buf); + switch (q_data_dst->fourcc) { case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: @@ -1906,6 +1994,7 @@ static void coda_finish_decode(struct coda_ctx *ctx) const struct coda_context_ops coda_bit_decode_ops = { .queue_init = coda_decoder_queue_init, + .reqbufs = coda_decoder_reqbufs, .start_streaming = coda_start_decoding, .prepare_run = coda_prepare_decode, .finish_run = coda_finish_decode, @@ -1931,6 +2020,8 @@ irqreturn_t coda_irq_handler(int irq, void *data) return IRQ_HANDLED; } + trace_coda_bit_done(ctx); + if (ctx->aborting) { v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "task has been aborted\n"); diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 6f32e6d6b156..8e6fe0200117 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -46,7 +46,6 @@ #define CODADX6_MAX_INSTANCES 4 #define CODA_MAX_FORMATS 4 -#define CODA_PARA_BUF_SIZE (10 * 1024) #define CODA_ISRAM_SIZE (2048 * 2) #define MIN_W 176 @@ -696,6 +695,26 @@ static int coda_s_fmt_vid_out(struct file *file, void *priv, return coda_s_fmt(ctx, &f_cap); } +static int coda_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *rb) +{ + struct coda_ctx *ctx = fh_to_ctx(priv); + int ret; + + ret = v4l2_m2m_reqbufs(file, ctx->fh.m2m_ctx, rb); + if (ret) + return ret; + + /* + * Allow to allocate instance specific per-context buffers, such as + * bitstream ringbuffer, slice buffer, work buffer, etc. if needed. + */ + if (rb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && ctx->ops->reqbufs) + return ctx->ops->reqbufs(ctx, rb); + + return 0; +} + static int coda_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { @@ -841,7 +860,7 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = { .vidioc_try_fmt_vid_out = coda_try_fmt_vid_out, .vidioc_s_fmt_vid_out = coda_s_fmt_vid_out, - .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_reqbufs = coda_reqbufs, .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, .vidioc_qbuf = coda_qbuf, @@ -1173,7 +1192,7 @@ static void coda_buf_queue(struct vb2_buffer *vb) mutex_lock(&ctx->bitstream_mutex); v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb); if (vb2_is_streaming(vb->vb2_queue)) - coda_fill_bitstream(ctx); + coda_fill_bitstream(ctx, true); mutex_unlock(&ctx->bitstream_mutex); } else { v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb); @@ -1215,8 +1234,9 @@ void coda_free_aux_buf(struct coda_dev *dev, buf->vaddr, buf->paddr); buf->vaddr = NULL; buf->size = 0; + debugfs_remove(buf->dentry); + buf->dentry = NULL; } - debugfs_remove(buf->dentry); } static int coda_start_streaming(struct vb2_queue *q, unsigned int count) @@ -1232,9 +1252,9 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) if (q_data_src->fourcc == V4L2_PIX_FMT_H264 || (q_data_src->fourcc == V4L2_PIX_FMT_JPEG && ctx->dev->devtype->product == CODA_7541)) { - /* copy the buffers that where queued before streamon */ + /* copy the buffers that were queued before streamon */ mutex_lock(&ctx->bitstream_mutex); - coda_fill_bitstream(ctx); + coda_fill_bitstream(ctx, false); mutex_unlock(&ctx->bitstream_mutex); if (coda_get_bitstream_payload(ctx) < 512) { @@ -1262,12 +1282,23 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) if (!(ctx->streamon_out & ctx->streamon_cap)) return 0; + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + if ((q_data_src->width != q_data_dst->width && + round_up(q_data_src->width, 16) != q_data_dst->width) || + (q_data_src->height != q_data_dst->height && + round_up(q_data_src->height, 16) != q_data_dst->height)) { + v4l2_err(v4l2_dev, "can't convert %dx%d to %dx%d\n", + q_data_src->width, q_data_src->height, + q_data_dst->width, q_data_dst->height); + ret = -EINVAL; + goto err; + } + /* Allow BIT decoder device_run with no new buffers queued */ if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) v4l2_m2m_set_src_buffered(ctx->fh.m2m_ctx, true); ctx->gopcounter = ctx->params.gop_size - 1; - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); ctx->codec = coda_find_codec(ctx->dev, q_data_src->fourcc, q_data_dst->fourcc); @@ -1308,6 +1339,9 @@ static void coda_stop_streaming(struct vb2_queue *q) struct coda_ctx *ctx = vb2_get_drv_priv(q); struct coda_dev *dev = ctx->dev; struct vb2_buffer *buf; + bool stop; + + stop = ctx->streamon_out && ctx->streamon_cap; if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { v4l2_dbg(1, coda_debug, &dev->v4l2_dev, @@ -1332,7 +1366,7 @@ static void coda_stop_streaming(struct vb2_queue *q) v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); } - if (!ctx->streamon_out && !ctx->streamon_cap) { + if (stop) { struct coda_buffer_meta *meta; if (ctx->ops->seq_end_work) { @@ -1457,7 +1491,7 @@ static const struct v4l2_ctrl_ops coda_ctrl_ops = { static void coda_encode_ctrls(struct coda_ctx *ctx) { v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, - V4L2_CID_MPEG_VIDEO_BITRATE, 0, 32767000, 1, 0); + V4L2_CID_MPEG_VIDEO_BITRATE, 0, 32767000, 1000, 0); v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 60, 1, 16); v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, @@ -1541,6 +1575,13 @@ static int coda_queue_init(struct coda_ctx *ctx, struct vb2_queue *vq) vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; vq->lock = &ctx->dev->dev_mutex; + /* One way to indicate end-of-stream for coda is to set the + * bytesused == 0. However by default videobuf2 handles bytesused + * equal to 0 as a special case and changes its value to the size + * of the buffer. Set the allow_zero_bytesused flag, so + * that videobuf2 will keep the value of bytesused intact. + */ + vq->allow_zero_bytesused = 1; return vb2_queue_init(vq); } @@ -1621,6 +1662,11 @@ static int coda_open(struct file *file) set_bit(idx, &dev->instance_mask); name = kasprintf(GFP_KERNEL, "context%d", idx); + if (!name) { + ret = -ENOMEM; + goto err_coda_name_init; + } + ctx->debugfs_entry = debugfs_create_dir(name, dev->debugfs_root); kfree(name); @@ -1682,28 +1728,6 @@ static int coda_open(struct file *file) ctx->fh.ctrl_handler = &ctx->ctrls; - if (ctx->use_bit) { - ret = coda_alloc_context_buf(ctx, &ctx->parabuf, - CODA_PARA_BUF_SIZE, "parabuf"); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to allocate parabuf"); - goto err_dma_alloc; - } - } - if (ctx->use_bit && ctx->inst_type == CODA_INST_DECODER) { - ctx->bitstream.size = CODA_MAX_FRAME_SIZE; - ctx->bitstream.vaddr = dma_alloc_writecombine( - &dev->plat_dev->dev, ctx->bitstream.size, - &ctx->bitstream.paddr, GFP_KERNEL); - if (!ctx->bitstream.vaddr) { - v4l2_err(&dev->v4l2_dev, - "failed to allocate bitstream ringbuffer"); - ret = -ENOMEM; - goto err_dma_writecombine; - } - } - kfifo_init(&ctx->bitstream_fifo, - ctx->bitstream.vaddr, ctx->bitstream.size); mutex_init(&ctx->bitstream_mutex); mutex_init(&ctx->buffer_mutex); INIT_LIST_HEAD(&ctx->buffer_meta_list); @@ -1717,12 +1741,6 @@ static int coda_open(struct file *file) return 0; -err_dma_writecombine: - if (ctx->dev->devtype->product == CODA_DX6) - coda_free_aux_buf(dev, &ctx->workbuf); - coda_free_aux_buf(dev, &ctx->parabuf); -err_dma_alloc: - v4l2_ctrl_handler_free(&ctx->ctrls); err_ctrls_setup: v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); err_ctx_init: @@ -1735,6 +1753,7 @@ err_pm_get: v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); clear_bit(ctx->idx, &dev->instance_mask); +err_coda_name_init: err_coda_max: kfree(ctx); return ret; @@ -1764,14 +1783,9 @@ static int coda_release(struct file *file) list_del(&ctx->list); coda_unlock(ctx); - if (ctx->bitstream.vaddr) { - dma_free_writecombine(&dev->plat_dev->dev, ctx->bitstream.size, - ctx->bitstream.vaddr, ctx->bitstream.paddr); - } if (ctx->dev->devtype->product == CODA_DX6) coda_free_aux_buf(dev, &ctx->workbuf); - coda_free_aux_buf(dev, &ctx->parabuf); v4l2_ctrl_handler_free(&ctx->ctrls); clk_disable_unprepare(dev->clk_ahb); clk_disable_unprepare(dev->clk_per); @@ -1901,8 +1915,7 @@ static int coda_register_device(struct coda_dev *dev, int i) if (i >= dev->devtype->num_vdevs) return -EINVAL; - snprintf(vfd->name, sizeof(vfd->name), "%s", - dev->devtype->vdevs[i]->name); + strlcpy(vfd->name, dev->devtype->vdevs[i]->name, sizeof(vfd->name)); vfd->fops = &coda_fops; vfd->ioctl_ops = &coda_ioctl_ops; vfd->release = video_device_release_empty, @@ -1933,10 +1946,8 @@ static void coda_fw_callback(const struct firmware *fw, void *context) /* allocate auxiliary per-device code buffer for the BIT processor */ ret = coda_alloc_aux_buf(dev, &dev->codebuf, fw->size, "codebuf", dev->debugfs_root); - if (ret < 0) { - dev_err(&pdev->dev, "failed to allocate code buffer\n"); + if (ret < 0) goto put_pm; - } /* Copy the whole firmware image to the code buffer */ memcpy(dev->codebuf.vaddr, fw->data, fw->size); @@ -2174,20 +2185,16 @@ static int coda_probe(struct platform_device *pdev) ret = coda_alloc_aux_buf(dev, &dev->workbuf, dev->devtype->workbuf_size, "workbuf", dev->debugfs_root); - if (ret < 0) { - dev_err(&pdev->dev, "failed to allocate work buffer\n"); + if (ret < 0) goto err_v4l2_register; - } } if (dev->devtype->tempbuf_size) { ret = coda_alloc_aux_buf(dev, &dev->tempbuf, dev->devtype->tempbuf_size, "tempbuf", dev->debugfs_root); - if (ret < 0) { - dev_err(&pdev->dev, "failed to allocate temp buffer\n"); + if (ret < 0) goto err_v4l2_register; - } } dev->iram.size = dev->devtype->iram_size; diff --git a/drivers/media/platform/coda/coda-jpeg.c b/drivers/media/platform/coda/coda-jpeg.c index 8fa3e353f9e2..11e734bc2cbd 100644 --- a/drivers/media/platform/coda/coda-jpeg.c +++ b/drivers/media/platform/coda/coda-jpeg.c @@ -13,6 +13,7 @@ #include <linux/swab.h> #include "coda.h" +#include "trace.h" #define SOI_MARKER 0xffd8 #define EOI_MARKER 0xffd9 diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index 0c35cd5032ff..6a5c8f6c688e 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -12,6 +12,9 @@ * (at your option) any later version. */ +#ifndef __CODA_H__ +#define __CODA_H__ + #include <linux/debugfs.h> #include <linux/irqreturn.h> #include <linux/mutex.h> @@ -26,7 +29,6 @@ #include "coda_regs.h" #define CODA_MAX_FRAMEBUFFERS 8 -#define CODA_MAX_FRAME_SIZE 0x100000 #define FMO_SLICE_SAVE_BUF_SIZE (32) enum { @@ -178,6 +180,7 @@ struct coda_ctx; struct coda_context_ops { int (*queue_init)(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq); + int (*reqbufs)(struct coda_ctx *ctx, struct v4l2_requestbuffers *rb); int (*start_streaming)(struct coda_ctx *ctx); int (*prepare_run)(struct coda_ctx *ctx); void (*finish_run)(struct coda_ctx *ctx); @@ -249,13 +252,6 @@ int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf, size_t size, const char *name, struct dentry *parent); void coda_free_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf); -static inline int coda_alloc_context_buf(struct coda_ctx *ctx, - struct coda_aux_buf *buf, size_t size, - const char *name) -{ - return coda_alloc_aux_buf(ctx->dev, buf, size, name, ctx->debugfs_entry); -} - int coda_encoder_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq); int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq, @@ -263,7 +259,7 @@ int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq, int coda_hw_reset(struct coda_ctx *ctx); -void coda_fill_bitstream(struct coda_ctx *ctx); +void coda_fill_bitstream(struct coda_ctx *ctx, bool streaming); void coda_set_gdi_regs(struct coda_ctx *ctx); @@ -284,7 +280,7 @@ const char *coda_product_name(int product); int coda_check_firmware(struct coda_dev *dev); -static inline int coda_get_bitstream_payload(struct coda_ctx *ctx) +static inline unsigned int coda_get_bitstream_payload(struct coda_ctx *ctx) { return kfifo_len(&ctx->bitstream_fifo); } @@ -301,3 +297,5 @@ extern const struct coda_context_ops coda_bit_encode_ops; extern const struct coda_context_ops coda_bit_decode_ops; irqreturn_t coda_irq_handler(int irq, void *data); + +#endif /* __CODA_H__ */ diff --git a/drivers/media/platform/coda/trace.h b/drivers/media/platform/coda/trace.h new file mode 100644 index 000000000000..d1d06cbd1f6a --- /dev/null +++ b/drivers/media/platform/coda/trace.h @@ -0,0 +1,203 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM coda + +#if !defined(__CODA_TRACE_H__) || defined(TRACE_HEADER_MULTI_READ) +#define __CODA_TRACE_H__ + +#include <linux/tracepoint.h> +#include <media/videobuf2-core.h> + +#include "coda.h" + +#define TRACE_SYSTEM_STRING __stringify(TRACE_SYSTEM) + +TRACE_EVENT(coda_bit_run, + TP_PROTO(struct coda_ctx *ctx, int cmd), + + TP_ARGS(ctx, cmd), + + TP_STRUCT__entry( + __field(int, minor) + __field(int, ctx) + __field(int, cmd) + ), + + TP_fast_assign( + __entry->minor = ctx->fh.vdev->minor; + __entry->ctx = ctx->idx; + __entry->cmd = cmd; + ), + + TP_printk("minor = %d, ctx = %d, cmd = %d", + __entry->minor, __entry->ctx, __entry->cmd) +); + +TRACE_EVENT(coda_bit_done, + TP_PROTO(struct coda_ctx *ctx), + + TP_ARGS(ctx), + + TP_STRUCT__entry( + __field(int, minor) + __field(int, ctx) + ), + + TP_fast_assign( + __entry->minor = ctx->fh.vdev->minor; + __entry->ctx = ctx->idx; + ), + + TP_printk("minor = %d, ctx = %d", __entry->minor, __entry->ctx) +); + +TRACE_EVENT(coda_enc_pic_run, + TP_PROTO(struct coda_ctx *ctx, struct vb2_buffer *buf), + + TP_ARGS(ctx, buf), + + TP_STRUCT__entry( + __field(int, minor) + __field(int, index) + __field(int, ctx) + ), + + TP_fast_assign( + __entry->minor = ctx->fh.vdev->minor; + __entry->index = buf->v4l2_buf.index; + __entry->ctx = ctx->idx; + ), + + TP_printk("minor = %d, index = %d, ctx = %d", + __entry->minor, __entry->index, __entry->ctx) +); + +TRACE_EVENT(coda_enc_pic_done, + TP_PROTO(struct coda_ctx *ctx, struct vb2_buffer *buf), + + TP_ARGS(ctx, buf), + + TP_STRUCT__entry( + __field(int, minor) + __field(int, index) + __field(int, ctx) + ), + + TP_fast_assign( + __entry->minor = ctx->fh.vdev->minor; + __entry->index = buf->v4l2_buf.index; + __entry->ctx = ctx->idx; + ), + + TP_printk("minor = %d, index = %d, ctx = %d", + __entry->minor, __entry->index, __entry->ctx) +); + +TRACE_EVENT(coda_bit_queue, + TP_PROTO(struct coda_ctx *ctx, struct vb2_buffer *buf, + struct coda_buffer_meta *meta), + + TP_ARGS(ctx, buf, meta), + + TP_STRUCT__entry( + __field(int, minor) + __field(int, index) + __field(int, start) + __field(int, end) + __field(int, ctx) + ), + + TP_fast_assign( + __entry->minor = ctx->fh.vdev->minor; + __entry->index = buf->v4l2_buf.index; + __entry->start = meta->start; + __entry->end = meta->end; + __entry->ctx = ctx->idx; + ), + + TP_printk("minor = %d, index = %d, start = 0x%x, end = 0x%x, ctx = %d", + __entry->minor, __entry->index, __entry->start, __entry->end, + __entry->ctx) +); + +TRACE_EVENT(coda_dec_pic_run, + TP_PROTO(struct coda_ctx *ctx, struct coda_buffer_meta *meta), + + TP_ARGS(ctx, meta), + + TP_STRUCT__entry( + __field(int, minor) + __field(int, start) + __field(int, end) + __field(int, ctx) + ), + + TP_fast_assign( + __entry->minor = ctx->fh.vdev->minor; + __entry->start = meta ? meta->start : 0; + __entry->end = meta ? meta->end : 0; + __entry->ctx = ctx->idx; + ), + + TP_printk("minor = %d, start = 0x%x, end = 0x%x, ctx = %d", + __entry->minor, __entry->start, __entry->end, __entry->ctx) +); + +TRACE_EVENT(coda_dec_pic_done, + TP_PROTO(struct coda_ctx *ctx, struct coda_buffer_meta *meta), + + TP_ARGS(ctx, meta), + + TP_STRUCT__entry( + __field(int, minor) + __field(int, start) + __field(int, end) + __field(int, ctx) + ), + + TP_fast_assign( + __entry->minor = ctx->fh.vdev->minor; + __entry->start = meta->start; + __entry->end = meta->end; + __entry->ctx = ctx->idx; + ), + + TP_printk("minor = %d, start = 0x%x, end = 0x%x, ctx = %d", + __entry->minor, __entry->start, __entry->end, __entry->ctx) +); + +TRACE_EVENT(coda_dec_rot_done, + TP_PROTO(struct coda_ctx *ctx, struct coda_buffer_meta *meta, + struct vb2_buffer *buf), + + TP_ARGS(ctx, meta, buf), + + TP_STRUCT__entry( + __field(int, minor) + __field(int, start) + __field(int, end) + __field(int, index) + __field(int, ctx) + ), + + TP_fast_assign( + __entry->minor = ctx->fh.vdev->minor; + __entry->start = meta->start; + __entry->end = meta->end; + __entry->index = buf->v4l2_buf.index; + __entry->ctx = ctx->idx; + ), + + TP_printk("minor = %d, start = 0x%x, end = 0x%x, index = %d, ctx = %d", + __entry->minor, __entry->start, __entry->end, __entry->index, + __entry->ctx) +); + +#endif /* __CODA_TRACE_H__ */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE trace + +/* This part must be outside protection */ +#include <trace/define_trace.h> diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index b41bf7e822c8..ccfcf3f528d3 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -1871,16 +1871,9 @@ static int vpfe_probe(struct platform_device *pdev) goto probe_free_ccdc_cfg_mem; } - /* Allocate memory for video device */ - vfd = video_device_alloc(); - if (NULL == vfd) { - ret = -ENOMEM; - v4l2_err(pdev->dev.driver, "Unable to alloc video device\n"); - goto probe_out_release_irq; - } - + vfd = &vpfe_dev->video_dev; /* Initialize field of video device */ - vfd->release = video_device_release; + vfd->release = video_device_release_empty; vfd->fops = &vpfe_fops; vfd->ioctl_ops = &vpfe_ioctl_ops; vfd->tvnorms = 0; @@ -1891,14 +1884,12 @@ static int vpfe_probe(struct platform_device *pdev) (VPFE_CAPTURE_VERSION_CODE >> 16) & 0xff, (VPFE_CAPTURE_VERSION_CODE >> 8) & 0xff, (VPFE_CAPTURE_VERSION_CODE) & 0xff); - /* Set video_dev to the video device */ - vpfe_dev->video_dev = vfd; ret = v4l2_device_register(&pdev->dev, &vpfe_dev->v4l2_dev); if (ret) { v4l2_err(pdev->dev.driver, "Unable to register v4l2 device.\n"); - goto probe_out_video_release; + goto probe_out_release_irq; } v4l2_info(&vpfe_dev->v4l2_dev, "v4l2 device registered\n"); spin_lock_init(&vpfe_dev->irqlock); @@ -1914,7 +1905,7 @@ static int vpfe_probe(struct platform_device *pdev) v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "video_dev=%p\n", &vpfe_dev->video_dev); vpfe_dev->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - ret = video_register_device(vpfe_dev->video_dev, + ret = video_register_device(&vpfe_dev->video_dev, VFL_TYPE_GRABBER, -1); if (ret) { @@ -1927,7 +1918,7 @@ static int vpfe_probe(struct platform_device *pdev) /* set the driver data in platform device */ platform_set_drvdata(pdev, vpfe_dev); /* set driver private data */ - video_set_drvdata(vpfe_dev->video_dev, vpfe_dev); + video_set_drvdata(&vpfe_dev->video_dev, vpfe_dev); i2c_adap = i2c_get_adapter(vpfe_cfg->i2c_adapter_id); num_subdevs = vpfe_cfg->num_subdevs; vpfe_dev->sd = kmalloc(sizeof(struct v4l2_subdev *) * num_subdevs, @@ -1979,12 +1970,9 @@ static int vpfe_probe(struct platform_device *pdev) probe_sd_out: kfree(vpfe_dev->sd); probe_out_video_unregister: - video_unregister_device(vpfe_dev->video_dev); + video_unregister_device(&vpfe_dev->video_dev); probe_out_v4l2_unregister: v4l2_device_unregister(&vpfe_dev->v4l2_dev); -probe_out_video_release: - if (!video_is_registered(vpfe_dev->video_dev)) - video_device_release(vpfe_dev->video_dev); probe_out_release_irq: free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); probe_free_ccdc_cfg_mem: @@ -2007,7 +1995,7 @@ static int vpfe_remove(struct platform_device *pdev) free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); kfree(vpfe_dev->sd); v4l2_device_unregister(&vpfe_dev->v4l2_dev); - video_unregister_device(vpfe_dev->video_dev); + video_unregister_device(&vpfe_dev->video_dev); kfree(vpfe_dev); kfree(ccdc_cfg); return 0; diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index fa0a51521772..a5f548138b91 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -712,7 +712,7 @@ static int vpif_set_input( ch->vpifparams.iface = chan_cfg->vpif_if; /* update tvnorms from the sub device input info */ - ch->video_dev->tvnorms = chan_cfg->inputs[index].input.std; + ch->video_dev.tvnorms = chan_cfg->inputs[index].input.std; return 0; } @@ -1337,7 +1337,7 @@ static int vpif_probe_complete(void) struct video_device *vdev; struct channel_obj *ch; struct vb2_queue *q; - int i, j, err, k; + int j, err, k; for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) { ch = vpif_obj.dev[j]; @@ -1384,16 +1384,16 @@ static int vpif_probe_complete(void) INIT_LIST_HEAD(&common->dma_queue); /* Initialize the video_device structure */ - vdev = ch->video_dev; + vdev = &ch->video_dev; strlcpy(vdev->name, VPIF_DRIVER_NAME, sizeof(vdev->name)); - vdev->release = video_device_release; + vdev->release = video_device_release_empty; vdev->fops = &vpif_fops; vdev->ioctl_ops = &vpif_ioctl_ops; vdev->v4l2_dev = &vpif_obj.v4l2_dev; vdev->vfl_dir = VFL_DIR_RX; vdev->queue = q; vdev->lock = &common->lock; - video_set_drvdata(ch->video_dev, ch); + video_set_drvdata(&ch->video_dev, ch); err = video_register_device(vdev, VFL_TYPE_GRABBER, (j ? 1 : 0)); if (err) @@ -1410,14 +1410,9 @@ probe_out: common = &ch->common[k]; vb2_dma_contig_cleanup_ctx(common->alloc_ctx); /* Unregister video device */ - video_unregister_device(ch->video_dev); + video_unregister_device(&ch->video_dev); } kfree(vpif_obj.sd); - for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { - ch = vpif_obj.dev[i]; - /* Note: does nothing if ch->video_dev == NULL */ - video_device_release(ch->video_dev); - } v4l2_device_unregister(&vpif_obj.v4l2_dev); return err; @@ -1438,13 +1433,11 @@ static int vpif_async_complete(struct v4l2_async_notifier *notifier) static __init int vpif_probe(struct platform_device *pdev) { struct vpif_subdev_info *subdevdata; - int i, j, err; - int res_idx = 0; struct i2c_adapter *i2c_adap; - struct channel_obj *ch; - struct video_device *vfd; struct resource *res; int subdev_count; + int res_idx = 0; + int i, err; vpif_dev = &pdev->dev; @@ -1472,24 +1465,6 @@ static __init int vpif_probe(struct platform_device *pdev) res_idx++; } - for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { - /* Get the pointer to the channel object */ - ch = vpif_obj.dev[i]; - /* Allocate memory for video device */ - vfd = video_device_alloc(); - if (NULL == vfd) { - for (j = 0; j < i; j++) { - ch = vpif_obj.dev[j]; - video_device_release(ch->video_dev); - } - err = -ENOMEM; - goto vpif_unregister; - } - - /* Set video_dev to the video device */ - ch->video_dev = vfd; - } - vpif_obj.config = pdev->dev.platform_data; subdev_count = vpif_obj.config->subdev_count; @@ -1498,7 +1473,7 @@ static __init int vpif_probe(struct platform_device *pdev) if (vpif_obj.sd == NULL) { vpif_err("unable to allocate memory for subdevice pointers\n"); err = -ENOMEM; - goto vpif_sd_error; + goto vpif_unregister; } if (!vpif_obj.config->asd_sizes) { @@ -1541,13 +1516,6 @@ static __init int vpif_probe(struct platform_device *pdev) probe_subdev_out: /* free sub devices memory */ kfree(vpif_obj.sd); - -vpif_sd_error: - for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { - ch = vpif_obj.dev[i]; - /* Note: does nothing if ch->video_dev == NULL */ - video_device_release(ch->video_dev); - } vpif_unregister: v4l2_device_unregister(&vpif_obj.v4l2_dev); @@ -1576,7 +1544,7 @@ static int vpif_remove(struct platform_device *device) common = &ch->common[VPIF_VIDEO_INDEX]; vb2_dma_contig_cleanup_ctx(common->alloc_ctx); /* Unregister video device */ - video_unregister_device(ch->video_dev); + video_unregister_device(&ch->video_dev); kfree(vpif_obj.dev[i]); } return 0; diff --git a/drivers/media/platform/davinci/vpif_capture.h b/drivers/media/platform/davinci/vpif_capture.h index f65d28d38e66..8b8a663f6b22 100644 --- a/drivers/media/platform/davinci/vpif_capture.h +++ b/drivers/media/platform/davinci/vpif_capture.h @@ -92,7 +92,7 @@ struct common_obj { struct channel_obj { /* Identifies video device for this channel */ - struct video_device *video_dev; + struct video_device video_dev; /* Indicates id of the field which is being displayed */ u32 field_id; /* flag to indicate whether decoder is initialized */ diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index 839c24de1fd8..682e5d578bf7 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -829,7 +829,7 @@ static int vpif_set_output(struct vpif_display_config *vpif_cfg, ch->sd = sd; if (chan_cfg->outputs != NULL) /* update tvnorms from the sub device output info */ - ch->video_dev->tvnorms = chan_cfg->outputs[index].output.std; + ch->video_dev.tvnorms = chan_cfg->outputs[index].output.std; return 0; } @@ -1204,16 +1204,16 @@ static int vpif_probe_complete(void) ch, &ch->video_dev); /* Initialize the video_device structure */ - vdev = ch->video_dev; + vdev = &ch->video_dev; strlcpy(vdev->name, VPIF_DRIVER_NAME, sizeof(vdev->name)); - vdev->release = video_device_release; + vdev->release = video_device_release_empty; vdev->fops = &vpif_fops; vdev->ioctl_ops = &vpif_ioctl_ops; vdev->v4l2_dev = &vpif_obj.v4l2_dev; vdev->vfl_dir = VFL_DIR_TX; vdev->queue = q; vdev->lock = &common->lock; - video_set_drvdata(ch->video_dev, ch); + video_set_drvdata(&ch->video_dev, ch); err = video_register_device(vdev, VFL_TYPE_GRABBER, (j ? 3 : 2)); if (err < 0) @@ -1227,9 +1227,7 @@ probe_out: ch = vpif_obj.dev[k]; common = &ch->common[k]; vb2_dma_contig_cleanup_ctx(common->alloc_ctx); - video_unregister_device(ch->video_dev); - video_device_release(ch->video_dev); - ch->video_dev = NULL; + video_unregister_device(&ch->video_dev); } return err; } @@ -1246,13 +1244,11 @@ static int vpif_async_complete(struct v4l2_async_notifier *notifier) static __init int vpif_probe(struct platform_device *pdev) { struct vpif_subdev_info *subdevdata; - int i, j = 0, err = 0; - int res_idx = 0; struct i2c_adapter *i2c_adap; - struct channel_obj *ch; - struct video_device *vfd; struct resource *res; int subdev_count; + int res_idx = 0; + int i, err; vpif_dev = &pdev->dev; err = initialize_vpif(); @@ -1281,25 +1277,6 @@ static __init int vpif_probe(struct platform_device *pdev) res_idx++; } - for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { - /* Get the pointer to the channel object */ - ch = vpif_obj.dev[i]; - - /* Allocate memory for video device */ - vfd = video_device_alloc(); - if (vfd == NULL) { - for (j = 0; j < i; j++) { - ch = vpif_obj.dev[j]; - video_device_release(ch->video_dev); - } - err = -ENOMEM; - goto vpif_unregister; - } - - /* Set video_dev to the video device */ - ch->video_dev = vfd; - } - vpif_obj.config = pdev->dev.platform_data; subdev_count = vpif_obj.config->subdev_count; subdevdata = vpif_obj.config->subdevinfo; @@ -1308,7 +1285,7 @@ static __init int vpif_probe(struct platform_device *pdev) if (vpif_obj.sd == NULL) { vpif_err("unable to allocate memory for subdevice pointers\n"); err = -ENOMEM; - goto vpif_sd_error; + goto vpif_unregister; } if (!vpif_obj.config->asd_sizes) { @@ -1348,12 +1325,6 @@ static __init int vpif_probe(struct platform_device *pdev) probe_subdev_out: kfree(vpif_obj.sd); -vpif_sd_error: - for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { - ch = vpif_obj.dev[i]; - /* Note: does nothing if ch->video_dev == NULL */ - video_device_release(ch->video_dev); - } vpif_unregister: v4l2_device_unregister(&vpif_obj.v4l2_dev); @@ -1379,9 +1350,7 @@ static int vpif_remove(struct platform_device *device) common = &ch->common[VPIF_VIDEO_INDEX]; vb2_dma_contig_cleanup_ctx(common->alloc_ctx); /* Unregister video device */ - video_unregister_device(ch->video_dev); - - ch->video_dev = NULL; + video_unregister_device(&ch->video_dev); kfree(vpif_obj.dev[i]); } diff --git a/drivers/media/platform/davinci/vpif_display.h b/drivers/media/platform/davinci/vpif_display.h index 7b21a7607674..849e0e385f18 100644 --- a/drivers/media/platform/davinci/vpif_display.h +++ b/drivers/media/platform/davinci/vpif_display.h @@ -100,7 +100,7 @@ struct common_obj { struct channel_obj { /* V4l2 specific parameters */ - struct video_device *video_dev; /* Identifies video device for + struct video_device video_dev; /* Identifies video device for * this channel */ u32 field_id; /* Indicates id of the field * which is being displayed */ diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index 8a2fd8c33d42..cfebf292e15a 100644 --- a/drivers/media/platform/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/exynos4-is/fimc-capture.c @@ -1482,7 +1482,7 @@ void fimc_sensor_notify(struct v4l2_subdev *sd, unsigned int notification, } static int fimc_subdev_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { struct fimc_fmt *fmt; @@ -1495,7 +1495,7 @@ static int fimc_subdev_enum_mbus_code(struct v4l2_subdev *sd, } static int fimc_subdev_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct fimc_dev *fimc = v4l2_get_subdevdata(sd); @@ -1504,7 +1504,7 @@ static int fimc_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(fh, fmt->pad); + mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); fmt->format = *mf; return 0; } @@ -1536,7 +1536,7 @@ static int fimc_subdev_get_fmt(struct v4l2_subdev *sd, } static int fimc_subdev_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct fimc_dev *fimc = v4l2_get_subdevdata(sd); @@ -1559,7 +1559,7 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd, mf->colorspace = V4L2_COLORSPACE_JPEG; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(fh, fmt->pad); + mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); *mf = fmt->format; return 0; } @@ -1602,7 +1602,7 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd, } static int fimc_subdev_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct fimc_dev *fimc = v4l2_get_subdevdata(sd); @@ -1628,10 +1628,10 @@ static int fimc_subdev_get_selection(struct v4l2_subdev *sd, return 0; case V4L2_SEL_TGT_CROP: - try_sel = v4l2_subdev_get_try_crop(fh, sel->pad); + try_sel = v4l2_subdev_get_try_crop(sd, cfg, sel->pad); break; case V4L2_SEL_TGT_COMPOSE: - try_sel = v4l2_subdev_get_try_compose(fh, sel->pad); + try_sel = v4l2_subdev_get_try_compose(sd, cfg, sel->pad); f = &ctx->d_frame; break; default: @@ -1657,7 +1657,7 @@ static int fimc_subdev_get_selection(struct v4l2_subdev *sd, } static int fimc_subdev_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct fimc_dev *fimc = v4l2_get_subdevdata(sd); @@ -1675,10 +1675,10 @@ static int fimc_subdev_set_selection(struct v4l2_subdev *sd, switch (sel->target) { case V4L2_SEL_TGT_CROP: - try_sel = v4l2_subdev_get_try_crop(fh, sel->pad); + try_sel = v4l2_subdev_get_try_crop(sd, cfg, sel->pad); break; case V4L2_SEL_TGT_COMPOSE: - try_sel = v4l2_subdev_get_try_compose(fh, sel->pad); + try_sel = v4l2_subdev_get_try_compose(sd, cfg, sel->pad); f = &ctx->d_frame; break; default: diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c index 60c744915549..5d78f5716f3b 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp.c +++ b/drivers/media/platform/exynos4-is/fimc-isp.c @@ -112,7 +112,7 @@ static const struct media_entity_operations fimc_is_subdev_media_ops = { }; static int fimc_is_subdev_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { const struct fimc_fmt *fmt; @@ -125,14 +125,14 @@ static int fimc_is_subdev_enum_mbus_code(struct v4l2_subdev *sd, } static int fimc_isp_subdev_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct fimc_isp *isp = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *mf = &fmt->format; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - *mf = *v4l2_subdev_get_try_format(fh, fmt->pad); + *mf = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad); return 0; } @@ -162,7 +162,7 @@ static int fimc_isp_subdev_get_fmt(struct v4l2_subdev *sd, } static void __isp_subdev_try_format(struct fimc_isp *isp, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct v4l2_mbus_framefmt *mf = &fmt->format; @@ -178,7 +178,7 @@ static void __isp_subdev_try_format(struct fimc_isp *isp, mf->code = MEDIA_BUS_FMT_SGRBG10_1X10; } else { if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) - format = v4l2_subdev_get_try_format(fh, + format = v4l2_subdev_get_try_format(&isp->subdev, cfg, FIMC_ISP_SD_PAD_SINK); else format = &isp->sink_fmt; @@ -197,7 +197,7 @@ static void __isp_subdev_try_format(struct fimc_isp *isp, } static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct fimc_isp *isp = v4l2_get_subdevdata(sd); @@ -209,10 +209,10 @@ static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd, __func__, fmt->pad, mf->code, mf->width, mf->height); mutex_lock(&isp->subdev_lock); - __isp_subdev_try_format(isp, fh, fmt); + __isp_subdev_try_format(isp, cfg, fmt); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(fh, fmt->pad); + mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); *mf = fmt->format; /* Propagate format to the source pads */ @@ -223,8 +223,8 @@ static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd, for (pad = FIMC_ISP_SD_PAD_SRC_FIFO; pad < FIMC_ISP_SD_PADS_NUM; pad++) { format.pad = pad; - __isp_subdev_try_format(isp, fh, &format); - mf = v4l2_subdev_get_try_format(fh, pad); + __isp_subdev_try_format(isp, cfg, &format); + mf = v4l2_subdev_get_try_format(sd, cfg, pad); *mf = format.format; } } @@ -236,7 +236,7 @@ static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd, isp->sink_fmt = *mf; format.pad = FIMC_ISP_SD_PAD_SRC_DMA; - __isp_subdev_try_format(isp, fh, &format); + __isp_subdev_try_format(isp, cfg, &format); isp->src_fmt = format.format; __is_set_frame_size(is, &isp->src_fmt); @@ -369,7 +369,7 @@ static int fimc_isp_subdev_open(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt fmt; struct v4l2_mbus_framefmt *format; - format = v4l2_subdev_get_try_format(fh, FIMC_ISP_SD_PAD_SINK); + format = v4l2_subdev_get_try_format(sd, fh->pad, FIMC_ISP_SD_PAD_SINK); fmt.colorspace = V4L2_COLORSPACE_SRGB; fmt.code = fimc_isp_formats[0].mbus_code; @@ -378,12 +378,12 @@ static int fimc_isp_subdev_open(struct v4l2_subdev *sd, fmt.field = V4L2_FIELD_NONE; *format = fmt; - format = v4l2_subdev_get_try_format(fh, FIMC_ISP_SD_PAD_SRC_FIFO); + format = v4l2_subdev_get_try_format(sd, fh->pad, FIMC_ISP_SD_PAD_SRC_FIFO); fmt.width = DEFAULT_PREVIEW_STILL_WIDTH; fmt.height = DEFAULT_PREVIEW_STILL_HEIGHT; *format = fmt; - format = v4l2_subdev_get_try_format(fh, FIMC_ISP_SD_PAD_SRC_DMA); + format = v4l2_subdev_get_try_format(sd, fh->pad, FIMC_ISP_SD_PAD_SRC_DMA); *format = fmt; return 0; diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index 2510f189e242..ca6261a86a5f 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -568,7 +568,7 @@ static const struct v4l2_file_operations fimc_lite_fops = { */ static const struct fimc_fmt *fimc_lite_subdev_try_fmt(struct fimc_lite *fimc, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { struct flite_drvdata *dd = fimc->dd; @@ -592,13 +592,13 @@ static const struct fimc_fmt *fimc_lite_subdev_try_fmt(struct fimc_lite *fimc, struct v4l2_rect *rect; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - sink_fmt = v4l2_subdev_get_try_format(fh, + sink_fmt = v4l2_subdev_get_try_format(&fimc->subdev, cfg, FLITE_SD_PAD_SINK); mf->code = sink_fmt->code; mf->colorspace = sink_fmt->colorspace; - rect = v4l2_subdev_get_try_crop(fh, + rect = v4l2_subdev_get_try_crop(&fimc->subdev, cfg, FLITE_SD_PAD_SINK); } else { mf->code = sink->fmt->mbus_code; @@ -1047,7 +1047,7 @@ static const struct media_entity_operations fimc_lite_subdev_media_ops = { }; static int fimc_lite_subdev_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { const struct fimc_fmt *fmt; @@ -1060,16 +1060,17 @@ static int fimc_lite_subdev_enum_mbus_code(struct v4l2_subdev *sd, } static struct v4l2_mbus_framefmt *__fimc_lite_subdev_get_try_fmt( - struct v4l2_subdev_fh *fh, unsigned int pad) + struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, unsigned int pad) { if (pad != FLITE_SD_PAD_SINK) pad = FLITE_SD_PAD_SOURCE_DMA; - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(sd, cfg, pad); } static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct fimc_lite *fimc = v4l2_get_subdevdata(sd); @@ -1077,7 +1078,7 @@ static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd, struct flite_frame *f = &fimc->inp_frame; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = __fimc_lite_subdev_get_try_fmt(fh, fmt->pad); + mf = __fimc_lite_subdev_get_try_fmt(sd, cfg, fmt->pad); fmt->format = *mf; return 0; } @@ -1100,7 +1101,7 @@ static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd, } static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct fimc_lite *fimc = v4l2_get_subdevdata(sd); @@ -1122,17 +1123,17 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd, return -EBUSY; } - ffmt = fimc_lite_subdev_try_fmt(fimc, fh, fmt); + ffmt = fimc_lite_subdev_try_fmt(fimc, cfg, fmt); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *src_fmt; - mf = __fimc_lite_subdev_get_try_fmt(fh, fmt->pad); + mf = __fimc_lite_subdev_get_try_fmt(sd, cfg, fmt->pad); *mf = fmt->format; if (fmt->pad == FLITE_SD_PAD_SINK) { unsigned int pad = FLITE_SD_PAD_SOURCE_DMA; - src_fmt = __fimc_lite_subdev_get_try_fmt(fh, pad); + src_fmt = __fimc_lite_subdev_get_try_fmt(sd, cfg, pad); *src_fmt = *mf; } @@ -1160,7 +1161,7 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd, } static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct fimc_lite *fimc = v4l2_get_subdevdata(sd); @@ -1172,7 +1173,7 @@ static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd, return -EINVAL; if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { - sel->r = *v4l2_subdev_get_try_crop(fh, sel->pad); + sel->r = *v4l2_subdev_get_try_crop(sd, cfg, sel->pad); return 0; } @@ -1195,7 +1196,7 @@ static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd, } static int fimc_lite_subdev_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct fimc_lite *fimc = v4l2_get_subdevdata(sd); @@ -1209,7 +1210,7 @@ static int fimc_lite_subdev_set_selection(struct v4l2_subdev *sd, fimc_lite_try_crop(fimc, &sel->r); if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_try_crop(fh, sel->pad) = sel->r; + *v4l2_subdev_get_try_crop(sd, cfg, sel->pad) = sel->r; } else { unsigned long flags; spin_lock_irqsave(&fimc->slock, flags); diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c index 2504aa89a6f4..d74e1bec3d86 100644 --- a/drivers/media/platform/exynos4-is/mipi-csis.c +++ b/drivers/media/platform/exynos4-is/mipi-csis.c @@ -540,7 +540,7 @@ unlock: } static int s5pcsis_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->index >= ARRAY_SIZE(s5pcsis_formats)) @@ -568,23 +568,23 @@ static struct csis_pix_format const *s5pcsis_try_format( } static struct v4l2_mbus_framefmt *__s5pcsis_get_format( - struct csis_state *state, struct v4l2_subdev_fh *fh, + struct csis_state *state, struct v4l2_subdev_pad_config *cfg, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return fh ? v4l2_subdev_get_try_format(fh, 0) : NULL; + return cfg ? v4l2_subdev_get_try_format(&state->sd, cfg, 0) : NULL; return &state->format; } -static int s5pcsis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int s5pcsis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct csis_state *state = sd_to_csis_state(sd); struct csis_pix_format const *csis_fmt; struct v4l2_mbus_framefmt *mf; - mf = __s5pcsis_get_format(state, fh, fmt->which); + mf = __s5pcsis_get_format(state, cfg, fmt->which); if (fmt->pad == CSIS_PAD_SOURCE) { if (mf) { @@ -605,13 +605,13 @@ static int s5pcsis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, return 0; } -static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct csis_state *state = sd_to_csis_state(sd); struct v4l2_mbus_framefmt *mf; - mf = __s5pcsis_get_format(state, fh, fmt->which); + mf = __s5pcsis_get_format(state, cfg, fmt->which); if (!mf) return -EINVAL; @@ -651,7 +651,7 @@ static int s5pcsis_log_status(struct v4l2_subdev *sd) static int s5pcsis_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { - struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0); + struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(sd, fh->pad, 0); format->colorspace = V4L2_COLORSPACE_JPEG; format->code = s5pcsis_formats[0].code; diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c index b70c1aecca37..92d954973ccf 100644 --- a/drivers/media/platform/m2m-deinterlace.c +++ b/drivers/media/platform/m2m-deinterlace.c @@ -127,7 +127,7 @@ static struct deinterlace_fmt *find_format(struct v4l2_format *f) struct deinterlace_dev { struct v4l2_device v4l2_dev; - struct video_device *vfd; + struct video_device vfd; atomic_t busy; struct mutex dev_mutex; @@ -983,7 +983,7 @@ static struct video_device deinterlace_videodev = { .fops = &deinterlace_fops, .ioctl_ops = &deinterlace_ioctl_ops, .minor = -1, - .release = video_device_release, + .release = video_device_release_empty, .vfl_dir = VFL_DIR_M2M, }; @@ -1026,13 +1026,7 @@ static int deinterlace_probe(struct platform_device *pdev) atomic_set(&pcdev->busy, 0); mutex_init(&pcdev->dev_mutex); - vfd = video_device_alloc(); - if (!vfd) { - v4l2_err(&pcdev->v4l2_dev, "Failed to allocate video device\n"); - ret = -ENOMEM; - goto unreg_dev; - } - + vfd = &pcdev->vfd; *vfd = deinterlace_videodev; vfd->lock = &pcdev->dev_mutex; vfd->v4l2_dev = &pcdev->v4l2_dev; @@ -1040,12 +1034,11 @@ static int deinterlace_probe(struct platform_device *pdev) ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); if (ret) { v4l2_err(&pcdev->v4l2_dev, "Failed to register video device\n"); - goto rel_vdev; + goto unreg_dev; } video_set_drvdata(vfd, pcdev); snprintf(vfd->name, sizeof(vfd->name), "%s", deinterlace_videodev.name); - pcdev->vfd = vfd; v4l2_info(&pcdev->v4l2_dev, MEM2MEM_TEST_MODULE_NAME " Device registered as /dev/video%d\n", vfd->num); @@ -1069,11 +1062,9 @@ static int deinterlace_probe(struct platform_device *pdev) v4l2_m2m_release(pcdev->m2m_dev); err_m2m: - video_unregister_device(pcdev->vfd); + video_unregister_device(&pcdev->vfd); err_ctx: vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); -rel_vdev: - video_device_release(vfd); unreg_dev: v4l2_device_unregister(&pcdev->v4l2_dev); rel_dma: @@ -1088,7 +1079,7 @@ static int deinterlace_remove(struct platform_device *pdev) v4l2_info(&pcdev->v4l2_dev, "Removing " MEM2MEM_TEST_MODULE_NAME); v4l2_m2m_release(pcdev->m2m_dev); - video_unregister_device(pcdev->vfd); + video_unregister_device(&pcdev->vfd); v4l2_device_unregister(&pcdev->v4l2_dev); vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); dma_release_channel(pcdev->dma_chan); diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index dd5b1415f974..9c64b5d01c6a 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -1568,24 +1568,64 @@ static int mcam_vidioc_enum_framesizes(struct file *filp, void *priv, struct v4l2_frmsizeenum *sizes) { struct mcam_camera *cam = priv; + struct mcam_format_struct *f; + struct v4l2_subdev_frame_size_enum fse = { + .index = sizes->index, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; int ret; + f = mcam_find_format(sizes->pixel_format); + if (f->pixelformat != sizes->pixel_format) + return -EINVAL; + fse.code = f->mbus_code; mutex_lock(&cam->s_mutex); - ret = sensor_call(cam, video, enum_framesizes, sizes); + ret = sensor_call(cam, pad, enum_frame_size, NULL, &fse); mutex_unlock(&cam->s_mutex); - return ret; + if (ret) + return ret; + if (fse.min_width == fse.max_width && + fse.min_height == fse.max_height) { + sizes->type = V4L2_FRMSIZE_TYPE_DISCRETE; + sizes->discrete.width = fse.min_width; + sizes->discrete.height = fse.min_height; + return 0; + } + sizes->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; + sizes->stepwise.min_width = fse.min_width; + sizes->stepwise.max_width = fse.max_width; + sizes->stepwise.min_height = fse.min_height; + sizes->stepwise.max_height = fse.max_height; + sizes->stepwise.step_width = 1; + sizes->stepwise.step_height = 1; + return 0; } static int mcam_vidioc_enum_frameintervals(struct file *filp, void *priv, struct v4l2_frmivalenum *interval) { struct mcam_camera *cam = priv; + struct mcam_format_struct *f; + struct v4l2_subdev_frame_interval_enum fie = { + .index = interval->index, + .width = interval->width, + .height = interval->height, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; int ret; + f = mcam_find_format(interval->pixel_format); + if (f->pixelformat != interval->pixel_format) + return -EINVAL; + fie.code = f->mbus_code; mutex_lock(&cam->s_mutex); - ret = sensor_call(cam, video, enum_frameintervals, interval); + ret = sensor_call(cam, pad, enum_frame_interval, NULL, &fie); mutex_unlock(&cam->s_mutex); - return ret; + if (ret) + return ret; + interval->type = V4L2_FRMIVAL_TYPE_DISCRETE; + interval->discrete = fie.interval; + return 0; } #ifdef CONFIG_VIDEO_ADV_DEBUG diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c index ba2d8f973d58..17b189a81ec5 100644 --- a/drivers/media/platform/omap/omap_vout.c +++ b/drivers/media/platform/omap/omap_vout.c @@ -1978,7 +1978,7 @@ static int __init omap_vout_setup_video_bufs(struct platform_device *pdev, vout->cropped_offset = 0; if (ovid->rotation_type == VOUT_ROT_VRFB) { - int static_vrfb_allocation = (vid_num == 0) ? + bool static_vrfb_allocation = (vid_num == 0) ? vid1_static_vrfb_alloc : vid2_static_vrfb_alloc; ret = omap_vout_setup_vrfb_bufs(pdev, vid_num, static_vrfb_allocation); diff --git a/drivers/media/platform/omap/omap_vout_vrfb.c b/drivers/media/platform/omap/omap_vout_vrfb.c index aa39306afc73..c6e252760c62 100644 --- a/drivers/media/platform/omap/omap_vout_vrfb.c +++ b/drivers/media/platform/omap/omap_vout_vrfb.c @@ -21,6 +21,7 @@ #include "omap_voutdef.h" #include "omap_voutlib.h" +#include "omap_vout_vrfb.h" #define OMAP_DMA_NO_DEVICE 0 diff --git a/drivers/media/platform/omap/omap_vout_vrfb.h b/drivers/media/platform/omap/omap_vout_vrfb.h index 4c2314839b48..c976975024df 100644 --- a/drivers/media/platform/omap/omap_vout_vrfb.h +++ b/drivers/media/platform/omap/omap_vout_vrfb.h @@ -15,7 +15,7 @@ #ifdef CONFIG_VIDEO_OMAP2_VOUT_VRFB void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout); int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num, - u32 static_vrfb_allocation); + bool static_vrfb_allocation); void omap_vout_release_vrfb(struct omap_vout_device *vout); int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout, unsigned int *count, unsigned int startindex); @@ -25,7 +25,7 @@ void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout); #else static inline void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout) { }; static inline int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num, - u32 static_vrfb_allocation) + bool static_vrfb_allocation) { return 0; }; static inline void omap_vout_release_vrfb(struct omap_vout_device *vout) { }; static inline int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout, diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index deca80903c3a..18d0a871747f 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -51,6 +51,7 @@ #include <linux/dma-mapping.h> #include <linux/i2c.h> #include <linux/interrupt.h> +#include <linux/mfd/syscon.h> #include <linux/module.h> #include <linux/omap-iommu.h> #include <linux/platform_device.h> @@ -63,6 +64,7 @@ #include <media/v4l2-common.h> #include <media/v4l2-device.h> +#include <media/v4l2-of.h> #include "isp.h" #include "ispreg.h" @@ -85,35 +87,45 @@ static void isp_restore_ctx(struct isp_device *isp); static const struct isp_res_mapping isp_res_maps[] = { { .isp_rev = ISP_REVISION_2_0, - .map = 1 << OMAP3_ISP_IOMEM_MAIN | - 1 << OMAP3_ISP_IOMEM_CCP2 | - 1 << OMAP3_ISP_IOMEM_CCDC | - 1 << OMAP3_ISP_IOMEM_HIST | - 1 << OMAP3_ISP_IOMEM_H3A | - 1 << OMAP3_ISP_IOMEM_PREV | - 1 << OMAP3_ISP_IOMEM_RESZ | - 1 << OMAP3_ISP_IOMEM_SBL | - 1 << OMAP3_ISP_IOMEM_CSI2A_REGS1 | - 1 << OMAP3_ISP_IOMEM_CSIPHY2 | - 1 << OMAP3_ISP_IOMEM_343X_CONTROL_CSIRXFE, + .offset = { + /* first MMIO area */ + 0x0000, /* base, len 0x0070 */ + 0x0400, /* ccp2, len 0x01f0 */ + 0x0600, /* ccdc, len 0x00a8 */ + 0x0a00, /* hist, len 0x0048 */ + 0x0c00, /* h3a, len 0x0060 */ + 0x0e00, /* preview, len 0x00a0 */ + 0x1000, /* resizer, len 0x00ac */ + 0x1200, /* sbl, len 0x00fc */ + /* second MMIO area */ + 0x0000, /* csi2a, len 0x0170 */ + 0x0170, /* csiphy2, len 0x000c */ + }, + .syscon_offset = 0xdc, + .phy_type = ISP_PHY_TYPE_3430, }, { .isp_rev = ISP_REVISION_15_0, - .map = 1 << OMAP3_ISP_IOMEM_MAIN | - 1 << OMAP3_ISP_IOMEM_CCP2 | - 1 << OMAP3_ISP_IOMEM_CCDC | - 1 << OMAP3_ISP_IOMEM_HIST | - 1 << OMAP3_ISP_IOMEM_H3A | - 1 << OMAP3_ISP_IOMEM_PREV | - 1 << OMAP3_ISP_IOMEM_RESZ | - 1 << OMAP3_ISP_IOMEM_SBL | - 1 << OMAP3_ISP_IOMEM_CSI2A_REGS1 | - 1 << OMAP3_ISP_IOMEM_CSIPHY2 | - 1 << OMAP3_ISP_IOMEM_CSI2A_REGS2 | - 1 << OMAP3_ISP_IOMEM_CSI2C_REGS1 | - 1 << OMAP3_ISP_IOMEM_CSIPHY1 | - 1 << OMAP3_ISP_IOMEM_CSI2C_REGS2 | - 1 << OMAP3_ISP_IOMEM_3630_CONTROL_CAMERA_PHY_CTRL, + .offset = { + /* first MMIO area */ + 0x0000, /* base, len 0x0070 */ + 0x0400, /* ccp2, len 0x01f0 */ + 0x0600, /* ccdc, len 0x00a8 */ + 0x0a00, /* hist, len 0x0048 */ + 0x0c00, /* h3a, len 0x0060 */ + 0x0e00, /* preview, len 0x00a0 */ + 0x1000, /* resizer, len 0x00ac */ + 0x1200, /* sbl, len 0x00fc */ + /* second MMIO area */ + 0x0000, /* csi2a, len 0x0170 (1st area) */ + 0x0170, /* csiphy2, len 0x000c */ + 0x01c0, /* csi2a, len 0x0040 (2nd area) */ + 0x0400, /* csi2c, len 0x0170 (1st area) */ + 0x0570, /* csiphy1, len 0x000c */ + 0x05c0, /* csi2c, len 0x0040 (2nd area) */ + }, + .syscon_offset = 0x2f0, + .phy_type = ISP_PHY_TYPE_3630, }, }; @@ -279,9 +291,20 @@ static const struct clk_init_data isp_xclk_init_data = { .num_parents = 1, }; +static struct clk *isp_xclk_src_get(struct of_phandle_args *clkspec, void *data) +{ + unsigned int idx = clkspec->args[0]; + struct isp_device *isp = data; + + if (idx >= ARRAY_SIZE(isp->xclks)) + return ERR_PTR(-ENOENT); + + return isp->xclks[idx].clk; +} + static int isp_xclk_init(struct isp_device *isp) { - struct isp_platform_data *pdata = isp->pdata; + struct device_node *np = isp->dev->of_node; struct clk_init_data init; unsigned int i; @@ -311,37 +334,27 @@ static int isp_xclk_init(struct isp_device *isp) xclk->clk = clk_register(NULL, &xclk->hw); if (IS_ERR(xclk->clk)) return PTR_ERR(xclk->clk); - - if (pdata->xclks[i].con_id == NULL && - pdata->xclks[i].dev_id == NULL) - continue; - - xclk->lookup = kzalloc(sizeof(*xclk->lookup), GFP_KERNEL); - if (xclk->lookup == NULL) - return -ENOMEM; - - xclk->lookup->con_id = pdata->xclks[i].con_id; - xclk->lookup->dev_id = pdata->xclks[i].dev_id; - xclk->lookup->clk = xclk->clk; - - clkdev_add(xclk->lookup); } + if (np) + of_clk_add_provider(np, isp_xclk_src_get, isp); + return 0; } static void isp_xclk_cleanup(struct isp_device *isp) { + struct device_node *np = isp->dev->of_node; unsigned int i; + if (np) + of_clk_del_provider(np); + for (i = 0; i < ARRAY_SIZE(isp->xclks); ++i) { struct isp_xclk *xclk = &isp->xclks[i]; if (!IS_ERR(xclk->clk)) clk_unregister(xclk->clk); - - if (xclk->lookup) - clkdev_drop(xclk->lookup); } } @@ -422,7 +435,7 @@ static void isp_core_init(struct isp_device *isp, int idle) */ void omap3isp_configure_bridge(struct isp_device *isp, enum ccdc_input_entity input, - const struct isp_parallel_platform_data *pdata, + const struct isp_parallel_cfg *parcfg, unsigned int shift, unsigned int bridge) { u32 ispctrl_val; @@ -437,8 +450,8 @@ void omap3isp_configure_bridge(struct isp_device *isp, switch (input) { case CCDC_INPUT_PARALLEL: ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_PARALLEL; - ispctrl_val |= pdata->clk_pol << ISPCTRL_PAR_CLK_POL_SHIFT; - shift += pdata->data_lane_shift * 2; + ispctrl_val |= parcfg->clk_pol << ISPCTRL_PAR_CLK_POL_SHIFT; + shift += parcfg->data_lane_shift * 2; break; case CCDC_INPUT_CSI2A: @@ -1784,58 +1797,121 @@ static void isp_unregister_entities(struct isp_device *isp) } /* - * isp_register_subdev_group - Register a group of subdevices + * isp_register_subdev - Register a sub-device * @isp: OMAP3 ISP device - * @board_info: I2C subdevs board information array + * @isp_subdev: platform data related to a sub-device * - * Register all I2C subdevices in the board_info array. The array must be - * terminated by a NULL entry, and the first entry must be the sensor. + * Register an I2C sub-device which has not been registered by other + * means (such as the Device Tree). * - * Return a pointer to the sensor media entity if it has been successfully + * Return a pointer to the sub-device if it has been successfully * registered, or NULL otherwise. */ static struct v4l2_subdev * -isp_register_subdev_group(struct isp_device *isp, - struct isp_subdev_i2c_board_info *board_info) +isp_register_subdev(struct isp_device *isp, + struct isp_platform_subdev *isp_subdev) { - struct v4l2_subdev *sensor = NULL; - unsigned int first; + struct i2c_adapter *adapter; + struct v4l2_subdev *sd; - if (board_info->board_info == NULL) + if (isp_subdev->board_info == NULL) return NULL; - for (first = 1; board_info->board_info; ++board_info, first = 0) { - struct v4l2_subdev *subdev; - struct i2c_adapter *adapter; + adapter = i2c_get_adapter(isp_subdev->i2c_adapter_id); + if (adapter == NULL) { + dev_err(isp->dev, + "%s: Unable to get I2C adapter %d for device %s\n", + __func__, isp_subdev->i2c_adapter_id, + isp_subdev->board_info->type); + return NULL; + } - adapter = i2c_get_adapter(board_info->i2c_adapter_id); - if (adapter == NULL) { - dev_err(isp->dev, "%s: Unable to get I2C adapter %d for " - "device %s\n", __func__, - board_info->i2c_adapter_id, - board_info->board_info->type); - continue; - } + sd = v4l2_i2c_new_subdev_board(&isp->v4l2_dev, adapter, + isp_subdev->board_info, NULL); + if (sd == NULL) { + dev_err(isp->dev, "%s: Unable to register subdev %s\n", + __func__, isp_subdev->board_info->type); + return NULL; + } - subdev = v4l2_i2c_new_subdev_board(&isp->v4l2_dev, adapter, - board_info->board_info, NULL); - if (subdev == NULL) { - dev_err(isp->dev, "%s: Unable to register subdev %s\n", - __func__, board_info->board_info->type); - continue; - } + return sd; +} + +static int isp_link_entity( + struct isp_device *isp, struct media_entity *entity, + enum isp_interface_type interface) +{ + struct media_entity *input; + unsigned int flags; + unsigned int pad; + unsigned int i; + + /* Connect the sensor to the correct interface module. + * Parallel sensors are connected directly to the CCDC, while + * serial sensors are connected to the CSI2a, CCP2b or CSI2c + * receiver through CSIPHY1 or CSIPHY2. + */ + switch (interface) { + case ISP_INTERFACE_PARALLEL: + input = &isp->isp_ccdc.subdev.entity; + pad = CCDC_PAD_SINK; + flags = 0; + break; + + case ISP_INTERFACE_CSI2A_PHY2: + input = &isp->isp_csi2a.subdev.entity; + pad = CSI2_PAD_SINK; + flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED; + break; + + case ISP_INTERFACE_CCP2B_PHY1: + case ISP_INTERFACE_CCP2B_PHY2: + input = &isp->isp_ccp2.subdev.entity; + pad = CCP2_PAD_SINK; + flags = 0; + break; + + case ISP_INTERFACE_CSI2C_PHY1: + input = &isp->isp_csi2c.subdev.entity; + pad = CSI2_PAD_SINK; + flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED; + break; - if (first) - sensor = subdev; + default: + dev_err(isp->dev, "%s: invalid interface type %u\n", __func__, + interface); + return -EINVAL; + } + + /* + * Not all interfaces are available on all revisions of the + * ISP. The sub-devices of those interfaces aren't initialised + * in such a case. Check this by ensuring the num_pads is + * non-zero. + */ + if (!input->num_pads) { + dev_err(isp->dev, "%s: invalid input %u\n", entity->name, + interface); + return -EINVAL; + } + + for (i = 0; i < entity->num_pads; i++) { + if (entity->pads[i].flags & MEDIA_PAD_FL_SOURCE) + break; + } + if (i == entity->num_pads) { + dev_err(isp->dev, "%s: no source pad in external entity\n", + __func__); + return -EINVAL; } - return sensor; + return media_entity_create_link(entity, i, input, pad, flags); } static int isp_register_entities(struct isp_device *isp) { struct isp_platform_data *pdata = isp->pdata; - struct isp_v4l2_subdevs_group *subdevs; + struct isp_platform_subdev *isp_subdev; int ret; isp->media_dev.dev = isp->dev; @@ -1892,74 +1968,31 @@ static int isp_register_entities(struct isp_device *isp) if (ret < 0) goto done; + /* + * Device Tree --- the external sub-devices will be registered + * later. The same goes for the sub-device node registration. + */ + if (isp->dev->of_node) + return 0; + /* Register external entities */ - for (subdevs = pdata->subdevs; subdevs && subdevs->subdevs; ++subdevs) { - struct v4l2_subdev *sensor; - struct media_entity *input; - unsigned int flags; - unsigned int pad; - unsigned int i; - - sensor = isp_register_subdev_group(isp, subdevs->subdevs); - if (sensor == NULL) - continue; + for (isp_subdev = pdata ? pdata->subdevs : NULL; + isp_subdev && isp_subdev->board_info; isp_subdev++) { + struct v4l2_subdev *sd; - sensor->host_priv = subdevs; + sd = isp_register_subdev(isp, isp_subdev); - /* Connect the sensor to the correct interface module. Parallel - * sensors are connected directly to the CCDC, while serial - * sensors are connected to the CSI2a, CCP2b or CSI2c receiver - * through CSIPHY1 or CSIPHY2. + /* + * No bus information --- this is either a flash or a + * lens subdev. */ - switch (subdevs->interface) { - case ISP_INTERFACE_PARALLEL: - input = &isp->isp_ccdc.subdev.entity; - pad = CCDC_PAD_SINK; - flags = 0; - break; - - case ISP_INTERFACE_CSI2A_PHY2: - input = &isp->isp_csi2a.subdev.entity; - pad = CSI2_PAD_SINK; - flags = MEDIA_LNK_FL_IMMUTABLE - | MEDIA_LNK_FL_ENABLED; - break; - - case ISP_INTERFACE_CCP2B_PHY1: - case ISP_INTERFACE_CCP2B_PHY2: - input = &isp->isp_ccp2.subdev.entity; - pad = CCP2_PAD_SINK; - flags = 0; - break; - - case ISP_INTERFACE_CSI2C_PHY1: - input = &isp->isp_csi2c.subdev.entity; - pad = CSI2_PAD_SINK; - flags = MEDIA_LNK_FL_IMMUTABLE - | MEDIA_LNK_FL_ENABLED; - break; - - default: - dev_err(isp->dev, "%s: invalid interface type %u\n", - __func__, subdevs->interface); - ret = -EINVAL; - goto done; - } + if (!sd || !isp_subdev->bus) + continue; - for (i = 0; i < sensor->entity.num_pads; i++) { - if (sensor->entity.pads[i].flags & MEDIA_PAD_FL_SOURCE) - break; - } - if (i == sensor->entity.num_pads) { - dev_err(isp->dev, - "%s: no source pad in external entity\n", - __func__); - ret = -EINVAL; - goto done; - } + sd->host_priv = isp_subdev->bus; - ret = media_entity_create_link(&sensor->entity, i, input, pad, - flags); + ret = isp_link_entity(isp, &sd->entity, + isp_subdev->bus->interface); if (ret < 0) goto done; } @@ -1967,8 +2000,10 @@ static int isp_register_entities(struct isp_device *isp) ret = v4l2_device_register_subdev_nodes(&isp->v4l2_dev); done: - if (ret < 0) + if (ret < 0) { isp_unregister_entities(isp); + v4l2_async_notifier_unregister(&isp->notifier); + } return ret; } @@ -2183,6 +2218,7 @@ static int isp_remove(struct platform_device *pdev) { struct isp_device *isp = platform_get_drvdata(pdev); + v4l2_async_notifier_unregister(&isp->notifier); isp_unregister_entities(isp); isp_cleanup_modules(isp); isp_xclk_cleanup(isp); @@ -2194,26 +2230,156 @@ static int isp_remove(struct platform_device *pdev) return 0; } -static int isp_map_mem_resource(struct platform_device *pdev, - struct isp_device *isp, - enum isp_mem_resources res) +enum isp_of_phy { + ISP_OF_PHY_PARALLEL = 0, + ISP_OF_PHY_CSIPHY1, + ISP_OF_PHY_CSIPHY2, +}; + +static int isp_of_parse_node(struct device *dev, struct device_node *node, + struct isp_async_subdev *isd) { - struct resource *mem; + struct isp_bus_cfg *buscfg = &isd->bus; + struct v4l2_of_endpoint vep; + unsigned int i; - /* request the mem region for the camera registers */ + v4l2_of_parse_endpoint(node, &vep); + + dev_dbg(dev, "parsing endpoint %s, interface %u\n", node->full_name, + vep.base.port); + + switch (vep.base.port) { + case ISP_OF_PHY_PARALLEL: + buscfg->interface = ISP_INTERFACE_PARALLEL; + buscfg->bus.parallel.data_lane_shift = + vep.bus.parallel.data_shift; + buscfg->bus.parallel.clk_pol = + !!(vep.bus.parallel.flags + & V4L2_MBUS_PCLK_SAMPLE_FALLING); + buscfg->bus.parallel.hs_pol = + !!(vep.bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW); + buscfg->bus.parallel.vs_pol = + !!(vep.bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW); + buscfg->bus.parallel.fld_pol = + !!(vep.bus.parallel.flags & V4L2_MBUS_FIELD_EVEN_LOW); + buscfg->bus.parallel.data_pol = + !!(vep.bus.parallel.flags & V4L2_MBUS_DATA_ACTIVE_LOW); + break; - mem = platform_get_resource(pdev, IORESOURCE_MEM, res); + case ISP_OF_PHY_CSIPHY1: + case ISP_OF_PHY_CSIPHY2: + /* FIXME: always assume CSI-2 for now. */ + switch (vep.base.port) { + case ISP_OF_PHY_CSIPHY1: + buscfg->interface = ISP_INTERFACE_CSI2C_PHY1; + break; + case ISP_OF_PHY_CSIPHY2: + buscfg->interface = ISP_INTERFACE_CSI2A_PHY2; + break; + } + buscfg->bus.csi2.lanecfg.clk.pos = vep.bus.mipi_csi2.clock_lane; + buscfg->bus.csi2.lanecfg.clk.pol = + vep.bus.mipi_csi2.lane_polarities[0]; + dev_dbg(dev, "clock lane polarity %u, pos %u\n", + buscfg->bus.csi2.lanecfg.clk.pol, + buscfg->bus.csi2.lanecfg.clk.pos); + + for (i = 0; i < ISP_CSIPHY2_NUM_DATA_LANES; i++) { + buscfg->bus.csi2.lanecfg.data[i].pos = + vep.bus.mipi_csi2.data_lanes[i]; + buscfg->bus.csi2.lanecfg.data[i].pol = + vep.bus.mipi_csi2.lane_polarities[i + 1]; + dev_dbg(dev, "data lane %u polarity %u, pos %u\n", i, + buscfg->bus.csi2.lanecfg.data[i].pol, + buscfg->bus.csi2.lanecfg.data[i].pos); + } - /* map the region */ - isp->mmio_base[res] = devm_ioremap_resource(isp->dev, mem); - if (IS_ERR(isp->mmio_base[res])) - return PTR_ERR(isp->mmio_base[res]); + /* + * FIXME: now we assume the CRC is always there. + * Implement a way to obtain this information from the + * sensor. Frame descriptors, perhaps? + */ + buscfg->bus.csi2.crc = 1; + break; - isp->mmio_base_phys[res] = mem->start; + default: + dev_warn(dev, "%s: invalid interface %u\n", node->full_name, + vep.base.port); + break; + } return 0; } +static int isp_of_parse_nodes(struct device *dev, + struct v4l2_async_notifier *notifier) +{ + struct device_node *node = NULL; + + notifier->subdevs = devm_kcalloc( + dev, ISP_MAX_SUBDEVS, sizeof(*notifier->subdevs), GFP_KERNEL); + if (!notifier->subdevs) + return -ENOMEM; + + while (notifier->num_subdevs < ISP_MAX_SUBDEVS && + (node = of_graph_get_next_endpoint(dev->of_node, node))) { + struct isp_async_subdev *isd; + + isd = devm_kzalloc(dev, sizeof(*isd), GFP_KERNEL); + if (!isd) { + of_node_put(node); + return -ENOMEM; + } + + notifier->subdevs[notifier->num_subdevs] = &isd->asd; + + if (isp_of_parse_node(dev, node, isd)) { + of_node_put(node); + return -EINVAL; + } + + isd->asd.match.of.node = of_graph_get_remote_port_parent(node); + of_node_put(node); + if (!isd->asd.match.of.node) { + dev_warn(dev, "bad remote port parent\n"); + return -EINVAL; + } + + isd->asd.match_type = V4L2_ASYNC_MATCH_OF; + notifier->num_subdevs++; + } + + return notifier->num_subdevs; +} + +static int isp_subdev_notifier_bound(struct v4l2_async_notifier *async, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd) +{ + struct isp_device *isp = container_of(async, struct isp_device, + notifier); + struct isp_async_subdev *isd = + container_of(asd, struct isp_async_subdev, asd); + int ret; + + ret = isp_link_entity(isp, &subdev->entity, isd->bus.interface); + if (ret < 0) + return ret; + + isd->sd = subdev; + isd->sd->host_priv = &isd->bus; + + return ret; +} + +static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async) +{ + struct isp_device *isp = container_of(async, struct isp_device, + notifier); + + return v4l2_device_register_subdev_nodes(&isp->v4l2_dev); +} + /* * isp_probe - Probe ISP platform device * @pdev: Pointer to ISP platform device @@ -2227,47 +2393,86 @@ static int isp_map_mem_resource(struct platform_device *pdev, */ static int isp_probe(struct platform_device *pdev) { - struct isp_platform_data *pdata = pdev->dev.platform_data; struct isp_device *isp; + struct resource *mem; int ret; int i, m; - if (pdata == NULL) - return -EINVAL; - isp = devm_kzalloc(&pdev->dev, sizeof(*isp), GFP_KERNEL); if (!isp) { dev_err(&pdev->dev, "could not allocate memory\n"); return -ENOMEM; } + if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) { + ret = of_property_read_u32(pdev->dev.of_node, "ti,phy-type", + &isp->phy_type); + if (ret) + return ret; + + isp->syscon = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "syscon"); + if (IS_ERR(isp->syscon)) + return PTR_ERR(isp->syscon); + + ret = of_property_read_u32_index(pdev->dev.of_node, "syscon", 1, + &isp->syscon_offset); + if (ret) + return ret; + + ret = isp_of_parse_nodes(&pdev->dev, &isp->notifier); + if (ret < 0) + return ret; + ret = v4l2_async_notifier_register(&isp->v4l2_dev, + &isp->notifier); + if (ret) + return ret; + } else { + isp->pdata = pdev->dev.platform_data; + isp->syscon = syscon_regmap_lookup_by_pdevname("syscon.0"); + if (IS_ERR(isp->syscon)) + return PTR_ERR(isp->syscon); + dev_warn(&pdev->dev, + "Platform data support is deprecated! Please move to DT now!\n"); + } + isp->autoidle = autoidle; mutex_init(&isp->isp_mutex); spin_lock_init(&isp->stat_lock); isp->dev = &pdev->dev; - isp->pdata = pdata; isp->ref_count = 0; ret = dma_coerce_mask_and_coherent(isp->dev, DMA_BIT_MASK(32)); if (ret) - return ret; + goto error; platform_set_drvdata(pdev, isp); /* Regulators */ - isp->isp_csiphy1.vdd = devm_regulator_get(&pdev->dev, "VDD_CSIPHY1"); - isp->isp_csiphy2.vdd = devm_regulator_get(&pdev->dev, "VDD_CSIPHY2"); + isp->isp_csiphy1.vdd = devm_regulator_get(&pdev->dev, "vdd-csiphy1"); + isp->isp_csiphy2.vdd = devm_regulator_get(&pdev->dev, "vdd-csiphy2"); /* Clocks * * The ISP clock tree is revision-dependent. We thus need to enable ICLK * manually to read the revision before calling __omap3isp_get(). + * + * Start by mapping the ISP MMIO area, which is in two pieces. + * The ISP IOMMU is in between. Map both now, and fill in the + * ISP revision specific portions a little later in the + * function. */ - ret = isp_map_mem_resource(pdev, isp, OMAP3_ISP_IOMEM_MAIN); - if (ret < 0) - goto error; + for (i = 0; i < 2; i++) { + unsigned int map_idx = i ? OMAP3_ISP_IOMEM_CSI2A_REGS1 : 0; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, i); + isp->mmio_base[map_idx] = + devm_ioremap_resource(isp->dev, mem); + if (IS_ERR(isp->mmio_base[map_idx])) + return PTR_ERR(isp->mmio_base[map_idx]); + } ret = isp_get_clocks(isp); if (ret < 0) @@ -2308,14 +2513,23 @@ static int isp_probe(struct platform_device *pdev) goto error_isp; } - for (i = 1; i < OMAP3_ISP_IOMEM_LAST; i++) { - if (isp_res_maps[m].map & 1 << i) { - ret = isp_map_mem_resource(pdev, isp, i); - if (ret) - goto error_isp; - } + if (!IS_ENABLED(CONFIG_OF) || !pdev->dev.of_node) { + isp->syscon_offset = isp_res_maps[m].syscon_offset; + isp->phy_type = isp_res_maps[m].phy_type; } + for (i = 1; i < OMAP3_ISP_IOMEM_CSI2A_REGS1; i++) + isp->mmio_base[i] = + isp->mmio_base[0] + isp_res_maps[m].offset[i]; + + for (i = OMAP3_ISP_IOMEM_CSIPHY2; i < OMAP3_ISP_IOMEM_LAST; i++) + isp->mmio_base[i] = + isp->mmio_base[OMAP3_ISP_IOMEM_CSI2A_REGS1] + + isp_res_maps[m].offset[i]; + + isp->mmio_hist_base_phys = + mem->start + isp_res_maps[m].offset[OMAP3_ISP_IOMEM_HIST]; + /* IOMMU */ ret = isp_attach_iommu(isp); if (ret < 0) { @@ -2343,6 +2557,9 @@ static int isp_probe(struct platform_device *pdev) if (ret < 0) goto error_iommu; + isp->notifier.bound = isp_subdev_notifier_bound; + isp->notifier.complete = isp_subdev_notifier_complete; + ret = isp_register_entities(isp); if (ret < 0) goto error_modules; @@ -2378,6 +2595,11 @@ static struct platform_device_id omap3isp_id_table[] = { }; MODULE_DEVICE_TABLE(platform, omap3isp_id_table); +static const struct of_device_id omap3isp_of_table[] = { + { .compatible = "ti,omap3-isp" }, + { }, +}; + static struct platform_driver omap3isp_driver = { .probe = isp_probe, .remove = isp_remove, @@ -2385,6 +2607,7 @@ static struct platform_driver omap3isp_driver = { .driver = { .name = "omap3isp", .pm = &omap3isp_pm_ops, + .of_match_table = omap3isp_of_table, }, }; diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h index cfdfc8714b6b..e579943175c4 100644 --- a/drivers/media/platform/omap3isp/isp.h +++ b/drivers/media/platform/omap3isp/isp.h @@ -18,6 +18,7 @@ #define OMAP3_ISP_CORE_H #include <media/omap3isp.h> +#include <media/v4l2-async.h> #include <media/v4l2-device.h> #include <linux/clk-provider.h> #include <linux/device.h> @@ -59,8 +60,6 @@ enum isp_mem_resources { OMAP3_ISP_IOMEM_CSI2C_REGS1, OMAP3_ISP_IOMEM_CSIPHY1, OMAP3_ISP_IOMEM_CSI2C_REGS2, - OMAP3_ISP_IOMEM_343X_CONTROL_CSIRXFE, - OMAP3_ISP_IOMEM_3630_CONTROL_CAMERA_PHY_CTRL, OMAP3_ISP_IOMEM_LAST }; @@ -93,14 +92,25 @@ enum isp_subclk_resource { /* ISP2P: OMAP 36xx */ #define ISP_REVISION_15_0 0xF0 +#define ISP_PHY_TYPE_3430 0 +#define ISP_PHY_TYPE_3630 1 + +struct regmap; + /* * struct isp_res_mapping - Map ISP io resources to ISP revision. * @isp_rev: ISP_REVISION_x_x - * @map: bitmap for enum isp_mem_resources + * @offset: register offsets of various ISP sub-blocks + * @syscon_offset: offset of the syscon register for 343x / 3630 + * (CONTROL_CSIRXFE / CONTROL_CAMERA_PHY_CTRL, respectively) + * from the syscon base address + * @phy_type: ISP_PHY_TYPE_{3430,3630} */ struct isp_res_mapping { u32 isp_rev; - u32 map; + u32 offset[OMAP3_ISP_IOMEM_LAST]; + u32 syscon_offset; + u32 phy_type; }; /* @@ -122,7 +132,6 @@ enum isp_xclk_id { struct isp_xclk { struct isp_device *isp; struct clk_hw hw; - struct clk_lookup *lookup; struct clk *clk; enum isp_xclk_id id; @@ -138,8 +147,11 @@ struct isp_xclk { * @irq_num: Currently used IRQ number. * @mmio_base: Array with kernel base addresses for ioremapped ISP register * regions. - * @mmio_base_phys: Array with physical L4 bus addresses for ISP register - * regions. + * @mmio_hist_base_phys: Physical L4 bus address for ISP hist block register + * region. + * @syscon: Regmap for the syscon register space + * @syscon_offset: Offset of the CSIPHY control register in syscon + * @phy_type: ISP_PHY_TYPE_{3430,3630} * @mapping: IOMMU mapping * @stat_lock: Spinlock for handling statistics * @isp_mutex: Mutex for serializing requests to ISP. @@ -166,6 +178,7 @@ struct isp_xclk { */ struct isp_device { struct v4l2_device v4l2_dev; + struct v4l2_async_notifier notifier; struct media_device media_dev; struct device *dev; u32 revision; @@ -175,7 +188,10 @@ struct isp_device { unsigned int irq_num; void __iomem *mmio_base[OMAP3_ISP_IOMEM_LAST]; - unsigned long mmio_base_phys[OMAP3_ISP_IOMEM_LAST]; + unsigned long mmio_hist_base_phys; + struct regmap *syscon; + u32 syscon_offset; + u32 phy_type; struct dma_iommu_mapping *mapping; @@ -209,6 +225,15 @@ struct isp_device { unsigned int sbl_resources; unsigned int subclk_resources; + +#define ISP_MAX_SUBDEVS 8 + struct v4l2_subdev *subdevs[ISP_MAX_SUBDEVS]; +}; + +struct isp_async_subdev { + struct v4l2_subdev *sd; + struct isp_bus_cfg bus; + struct v4l2_async_subdev asd; }; #define v4l2_dev_to_isp_device(dev) \ @@ -229,7 +254,7 @@ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe, void omap3isp_pipeline_cancel_stream(struct isp_pipeline *pipe); void omap3isp_configure_bridge(struct isp_device *isp, enum ccdc_input_entity input, - const struct isp_parallel_platform_data *pdata, + const struct isp_parallel_cfg *buscfg, unsigned int shift, unsigned int bridge); struct isp_device *omap3isp_get(struct isp_device *isp); diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 587489a072d5..a6a61cce43dd 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -32,7 +32,7 @@ #define CCDC_MIN_HEIGHT 32 static struct v4l2_mbus_framefmt * -__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, +__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which); static const unsigned int ccdc_fmts[] = { @@ -958,11 +958,11 @@ void omap3isp_ccdc_max_rate(struct isp_ccdc_device *ccdc, /* * ccdc_config_sync_if - Set CCDC sync interface configuration * @ccdc: Pointer to ISP CCDC device. - * @pdata: Parallel interface platform data (may be NULL) + * @parcfg: Parallel interface platform data (may be NULL) * @data_size: Data size */ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc, - struct isp_parallel_platform_data *pdata, + struct isp_parallel_cfg *parcfg, unsigned int data_size) { struct isp_device *isp = to_isp_device(ccdc); @@ -1000,19 +1000,19 @@ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc, break; } - if (pdata && pdata->data_pol) + if (parcfg && parcfg->data_pol) syn_mode |= ISPCCDC_SYN_MODE_DATAPOL; - if (pdata && pdata->hs_pol) + if (parcfg && parcfg->hs_pol) syn_mode |= ISPCCDC_SYN_MODE_HDPOL; /* The polarity of the vertical sync signal output by the BT.656 * decoder is not documented and seems to be active low. */ - if ((pdata && pdata->vs_pol) || ccdc->bt656) + if ((parcfg && parcfg->vs_pol) || ccdc->bt656) syn_mode |= ISPCCDC_SYN_MODE_VDPOL; - if (pdata && pdata->fld_pol) + if (parcfg && parcfg->fld_pol) syn_mode |= ISPCCDC_SYN_MODE_FLDPOL; isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE); @@ -1115,7 +1115,7 @@ static const u32 ccdc_sgbrg_pattern = static void ccdc_configure(struct isp_ccdc_device *ccdc) { struct isp_device *isp = to_isp_device(ccdc); - struct isp_parallel_platform_data *pdata = NULL; + struct isp_parallel_cfg *parcfg = NULL; struct v4l2_subdev *sensor; struct v4l2_mbus_framefmt *format; const struct v4l2_rect *crop; @@ -1145,7 +1145,7 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) if (!ret) ccdc->bt656 = cfg.type == V4L2_MBUS_BT656; - pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv) + parcfg = &((struct isp_bus_cfg *)sensor->host_priv) ->bus.parallel; } @@ -1175,10 +1175,10 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) else bridge = ISPCTRL_PAR_BRIDGE_DISABLE; - omap3isp_configure_bridge(isp, ccdc->input, pdata, shift, bridge); + omap3isp_configure_bridge(isp, ccdc->input, parcfg, shift, bridge); /* Configure the sync interface. */ - ccdc_config_sync_if(ccdc, pdata, depth_out); + ccdc_config_sync_if(ccdc, parcfg, depth_out); syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE); @@ -1935,21 +1935,21 @@ static int ccdc_set_stream(struct v4l2_subdev *sd, int enable) } static struct v4l2_mbus_framefmt * -__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, +__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&ccdc->subdev, cfg, pad); else return &ccdc->formats[pad]; } static struct v4l2_rect * -__ccdc_get_crop(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, +__ccdc_get_crop(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_crop(fh, CCDC_PAD_SOURCE_OF); + return v4l2_subdev_get_try_crop(&ccdc->subdev, cfg, CCDC_PAD_SOURCE_OF); else return &ccdc->crop; } @@ -1957,12 +1957,12 @@ __ccdc_get_crop(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, /* * ccdc_try_format - Try video format on a pad * @ccdc: ISP CCDC device - * @fh : V4L2 subdev file handle + * @cfg : V4L2 subdev pad configuration * @pad: Pad number * @fmt: Format */ static void -ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, +ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_pad_config *cfg, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -1998,7 +1998,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, case CCDC_PAD_SOURCE_OF: pixelcode = fmt->code; field = fmt->field; - *fmt = *__ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which); + *fmt = *__ccdc_get_format(ccdc, cfg, CCDC_PAD_SINK, which); /* In SYNC mode the bridge converts YUV formats from 2X8 to * 1X16. In BT.656 no such conversion occurs. As we don't know @@ -2023,7 +2023,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, } /* Hardcode the output size to the crop rectangle size. */ - crop = __ccdc_get_crop(ccdc, fh, which); + crop = __ccdc_get_crop(ccdc, cfg, which); fmt->width = crop->width; fmt->height = crop->height; @@ -2040,7 +2040,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, break; case CCDC_PAD_SOURCE_VP: - *fmt = *__ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which); + *fmt = *__ccdc_get_format(ccdc, cfg, CCDC_PAD_SINK, which); /* The video port interface truncates the data to 10 bits. */ info = omap3isp_video_format_info(fmt->code); @@ -2112,12 +2112,12 @@ static void ccdc_try_crop(struct isp_ccdc_device *ccdc, /* * ccdc_enum_mbus_code - Handle pixel format enumeration * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg : V4L2 subdev pad configuration * @code : pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ static int ccdc_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); @@ -2132,8 +2132,8 @@ static int ccdc_enum_mbus_code(struct v4l2_subdev *sd, break; case CCDC_PAD_SOURCE_OF: - format = __ccdc_get_format(ccdc, fh, code->pad, - V4L2_SUBDEV_FORMAT_TRY); + format = __ccdc_get_format(ccdc, cfg, code->pad, + code->which); if (format->code == MEDIA_BUS_FMT_YUYV8_2X8 || format->code == MEDIA_BUS_FMT_UYVY8_2X8) { @@ -2163,8 +2163,8 @@ static int ccdc_enum_mbus_code(struct v4l2_subdev *sd, if (code->index != 0) return -EINVAL; - format = __ccdc_get_format(ccdc, fh, code->pad, - V4L2_SUBDEV_FORMAT_TRY); + format = __ccdc_get_format(ccdc, cfg, code->pad, + code->which); /* A pixel code equal to 0 means that the video port doesn't * support the input format. Don't enumerate any pixel code. @@ -2183,7 +2183,7 @@ static int ccdc_enum_mbus_code(struct v4l2_subdev *sd, } static int ccdc_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); @@ -2195,7 +2195,7 @@ static int ccdc_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = 1; format.height = 1; - ccdc_try_format(ccdc, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + ccdc_try_format(ccdc, cfg, fse->pad, &format, fse->which); fse->min_width = format.width; fse->min_height = format.height; @@ -2205,7 +2205,7 @@ static int ccdc_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = -1; format.height = -1; - ccdc_try_format(ccdc, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + ccdc_try_format(ccdc, cfg, fse->pad, &format, fse->which); fse->max_width = format.width; fse->max_height = format.height; @@ -2215,7 +2215,7 @@ static int ccdc_enum_frame_size(struct v4l2_subdev *sd, /* * ccdc_get_selection - Retrieve a selection rectangle on a pad * @sd: ISP CCDC V4L2 subdevice - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @sel: Selection rectangle * * The only supported rectangles are the crop rectangles on the output formatter @@ -2223,7 +2223,7 @@ static int ccdc_enum_frame_size(struct v4l2_subdev *sd, * * Return 0 on success or a negative error code otherwise. */ -static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); @@ -2239,12 +2239,12 @@ static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, sel->r.width = INT_MAX; sel->r.height = INT_MAX; - format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, sel->which); + format = __ccdc_get_format(ccdc, cfg, CCDC_PAD_SINK, sel->which); ccdc_try_crop(ccdc, format, &sel->r); break; case V4L2_SEL_TGT_CROP: - sel->r = *__ccdc_get_crop(ccdc, fh, sel->which); + sel->r = *__ccdc_get_crop(ccdc, cfg, sel->which); break; default: @@ -2257,7 +2257,7 @@ static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * ccdc_set_selection - Set a selection rectangle on a pad * @sd: ISP CCDC V4L2 subdevice - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @sel: Selection rectangle * * The only supported rectangle is the actual crop rectangle on the output @@ -2265,7 +2265,7 @@ static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, * * Return 0 on success or a negative error code otherwise. */ -static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); @@ -2284,17 +2284,17 @@ static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, * rectangle. */ if (sel->flags & V4L2_SEL_FLAG_KEEP_CONFIG) { - sel->r = *__ccdc_get_crop(ccdc, fh, sel->which); + sel->r = *__ccdc_get_crop(ccdc, cfg, sel->which); return 0; } - format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, sel->which); + format = __ccdc_get_format(ccdc, cfg, CCDC_PAD_SINK, sel->which); ccdc_try_crop(ccdc, format, &sel->r); - *__ccdc_get_crop(ccdc, fh, sel->which) = sel->r; + *__ccdc_get_crop(ccdc, cfg, sel->which) = sel->r; /* Update the source format. */ - format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_OF, sel->which); - ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_OF, format, sel->which); + format = __ccdc_get_format(ccdc, cfg, CCDC_PAD_SOURCE_OF, sel->which); + ccdc_try_format(ccdc, cfg, CCDC_PAD_SOURCE_OF, format, sel->which); return 0; } @@ -2302,19 +2302,19 @@ static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * ccdc_get_format - Retrieve the video format on a pad * @sd : ISP CCDC V4L2 subdevice - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @fmt: Format * * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond * to the format type. */ -static int ccdc_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int ccdc_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __ccdc_get_format(ccdc, fh, fmt->pad, fmt->which); + format = __ccdc_get_format(ccdc, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; @@ -2325,30 +2325,30 @@ static int ccdc_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * ccdc_set_format - Set the video format on a pad * @sd : ISP CCDC V4L2 subdevice - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @fmt: Format * * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond * to the format type. */ -static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; struct v4l2_rect *crop; - format = __ccdc_get_format(ccdc, fh, fmt->pad, fmt->which); + format = __ccdc_get_format(ccdc, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; - ccdc_try_format(ccdc, fh, fmt->pad, &fmt->format, fmt->which); + ccdc_try_format(ccdc, cfg, fmt->pad, &fmt->format, fmt->which); *format = fmt->format; /* Propagate the format from sink to source */ if (fmt->pad == CCDC_PAD_SINK) { /* Reset the crop rectangle. */ - crop = __ccdc_get_crop(ccdc, fh, fmt->which); + crop = __ccdc_get_crop(ccdc, cfg, fmt->which); crop->left = 0; crop->top = 0; crop->width = fmt->format.width; @@ -2357,16 +2357,16 @@ static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, ccdc_try_crop(ccdc, &fmt->format, crop); /* Update the source formats. */ - format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_OF, + format = __ccdc_get_format(ccdc, cfg, CCDC_PAD_SOURCE_OF, fmt->which); *format = fmt->format; - ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_OF, format, + ccdc_try_format(ccdc, cfg, CCDC_PAD_SOURCE_OF, format, fmt->which); - format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_VP, + format = __ccdc_get_format(ccdc, cfg, CCDC_PAD_SOURCE_VP, fmt->which); *format = fmt->format; - ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_VP, format, + ccdc_try_format(ccdc, cfg, CCDC_PAD_SOURCE_VP, format, fmt->which); } @@ -2417,11 +2417,11 @@ static int ccdc_link_validate(struct v4l2_subdev *sd, /* We've got a parallel sensor here. */ if (ccdc->input == CCDC_INPUT_PARALLEL) { - struct isp_parallel_platform_data *pdata = - &((struct isp_v4l2_subdevs_group *) + struct isp_parallel_cfg *parcfg = + &((struct isp_bus_cfg *) media_entity_to_v4l2_subdev(link->source->entity) ->host_priv)->bus.parallel; - parallel_shift = pdata->data_lane_shift * 2; + parallel_shift = parcfg->data_lane_shift * 2; } else { parallel_shift = 0; } @@ -2453,7 +2453,7 @@ static int ccdc_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; format.format.width = 4096; format.format.height = 4096; - ccdc_set_format(sd, fh, &format); + ccdc_set_format(sd, fh ? fh->pad : NULL, &format); return 0; } diff --git a/drivers/media/platform/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c index f4aedb37e41e..38e6a974c5b1 100644 --- a/drivers/media/platform/omap3isp/ispccp2.c +++ b/drivers/media/platform/omap3isp/ispccp2.c @@ -201,14 +201,14 @@ static void ccp2_mem_enable(struct isp_ccp2_device *ccp2, u8 enable) /* * ccp2_phyif_config - Initialize CCP2 phy interface config * @ccp2: Pointer to ISP CCP2 device - * @pdata: CCP2 platform data + * @buscfg: CCP2 platform data * * Configure the CCP2 physical interface module from platform data. * * Returns -EIO if strobe is chosen in CSI1 mode, or 0 on success. */ static int ccp2_phyif_config(struct isp_ccp2_device *ccp2, - const struct isp_ccp2_platform_data *pdata) + const struct isp_ccp2_cfg *buscfg) { struct isp_device *isp = to_isp_device(ccp2); u32 val; @@ -218,16 +218,16 @@ static int ccp2_phyif_config(struct isp_ccp2_device *ccp2, ISPCCP2_CTRL_IO_OUT_SEL | ISPCCP2_CTRL_MODE; /* Data/strobe physical layer */ BIT_SET(val, ISPCCP2_CTRL_PHY_SEL_SHIFT, ISPCCP2_CTRL_PHY_SEL_MASK, - pdata->phy_layer); + buscfg->phy_layer); BIT_SET(val, ISPCCP2_CTRL_INV_SHIFT, ISPCCP2_CTRL_INV_MASK, - pdata->strobe_clk_pol); + buscfg->strobe_clk_pol); isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL); val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL); if (!(val & ISPCCP2_CTRL_MODE)) { - if (pdata->ccp2_mode == ISP_CCP2_MODE_CCP2) + if (buscfg->ccp2_mode == ISP_CCP2_MODE_CCP2) dev_warn(isp->dev, "OMAP3 CCP2 bus not available\n"); - if (pdata->phy_layer == ISP_CCP2_PHY_DATA_STROBE) + if (buscfg->phy_layer == ISP_CCP2_PHY_DATA_STROBE) /* Strobe mode requires CCP2 */ return -EIO; } @@ -347,7 +347,7 @@ static void ccp2_lcx_config(struct isp_ccp2_device *ccp2, */ static int ccp2_if_configure(struct isp_ccp2_device *ccp2) { - const struct isp_v4l2_subdevs_group *pdata; + const struct isp_bus_cfg *buscfg; struct v4l2_mbus_framefmt *format; struct media_pad *pad; struct v4l2_subdev *sensor; @@ -358,20 +358,20 @@ static int ccp2_if_configure(struct isp_ccp2_device *ccp2) pad = media_entity_remote_pad(&ccp2->pads[CCP2_PAD_SINK]); sensor = media_entity_to_v4l2_subdev(pad->entity); - pdata = sensor->host_priv; + buscfg = sensor->host_priv; - ret = ccp2_phyif_config(ccp2, &pdata->bus.ccp2); + ret = ccp2_phyif_config(ccp2, &buscfg->bus.ccp2); if (ret < 0) return ret; - ccp2_vp_config(ccp2, pdata->bus.ccp2.vpclk_div + 1); + ccp2_vp_config(ccp2, buscfg->bus.ccp2.vpclk_div + 1); v4l2_subdev_call(sensor, sensor, g_skip_top_lines, &lines); format = &ccp2->formats[CCP2_PAD_SINK]; ccp2->if_cfg.data_start = lines; - ccp2->if_cfg.crc = pdata->bus.ccp2.crc; + ccp2->if_cfg.crc = buscfg->bus.ccp2.crc; ccp2->if_cfg.format = format->code; ccp2->if_cfg.data_size = format->height; @@ -611,17 +611,17 @@ static const unsigned int ccp2_fmts[] = { /* * __ccp2_get_format - helper function for getting ccp2 format * @ccp2 : Pointer to ISP CCP2 device - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @pad : pad number * @which : wanted subdev format * return format structure or NULL on error */ static struct v4l2_mbus_framefmt * -__ccp2_get_format(struct isp_ccp2_device *ccp2, struct v4l2_subdev_fh *fh, +__ccp2_get_format(struct isp_ccp2_device *ccp2, struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&ccp2->subdev, cfg, pad); else return &ccp2->formats[pad]; } @@ -629,13 +629,13 @@ __ccp2_get_format(struct isp_ccp2_device *ccp2, struct v4l2_subdev_fh *fh, /* * ccp2_try_format - Handle try format by pad subdev method * @ccp2 : Pointer to ISP CCP2 device - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @pad : pad num * @fmt : pointer to v4l2 mbus format structure * @which : wanted subdev format */ static void ccp2_try_format(struct isp_ccp2_device *ccp2, - struct v4l2_subdev_fh *fh, unsigned int pad, + struct v4l2_subdev_pad_config *cfg, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -669,7 +669,7 @@ static void ccp2_try_format(struct isp_ccp2_device *ccp2, * When CCP2 write to memory feature will be added this * should be changed properly. */ - format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SINK, which); + format = __ccp2_get_format(ccp2, cfg, CCP2_PAD_SINK, which); memcpy(fmt, format, sizeof(*fmt)); fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; break; @@ -682,12 +682,12 @@ static void ccp2_try_format(struct isp_ccp2_device *ccp2, /* * ccp2_enum_mbus_code - Handle pixel format enumeration * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @code : pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ static int ccp2_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); @@ -702,8 +702,8 @@ static int ccp2_enum_mbus_code(struct v4l2_subdev *sd, if (code->index != 0) return -EINVAL; - format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SINK, - V4L2_SUBDEV_FORMAT_TRY); + format = __ccp2_get_format(ccp2, cfg, CCP2_PAD_SINK, + code->which); code->code = format->code; } @@ -711,7 +711,7 @@ static int ccp2_enum_mbus_code(struct v4l2_subdev *sd, } static int ccp2_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); @@ -723,7 +723,7 @@ static int ccp2_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = 1; format.height = 1; - ccp2_try_format(ccp2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + ccp2_try_format(ccp2, cfg, fse->pad, &format, fse->which); fse->min_width = format.width; fse->min_height = format.height; @@ -733,7 +733,7 @@ static int ccp2_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = -1; format.height = -1; - ccp2_try_format(ccp2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + ccp2_try_format(ccp2, cfg, fse->pad, &format, fse->which); fse->max_width = format.width; fse->max_height = format.height; @@ -743,17 +743,17 @@ static int ccp2_enum_frame_size(struct v4l2_subdev *sd, /* * ccp2_get_format - Handle get format by pads subdev method * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @fmt : pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ -static int ccp2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int ccp2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __ccp2_get_format(ccp2, fh, fmt->pad, fmt->which); + format = __ccp2_get_format(ccp2, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; @@ -764,29 +764,29 @@ static int ccp2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * ccp2_set_format - Handle set format by pads subdev method * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @fmt : pointer to v4l2 subdev format structure * returns zero */ -static int ccp2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int ccp2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __ccp2_get_format(ccp2, fh, fmt->pad, fmt->which); + format = __ccp2_get_format(ccp2, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; - ccp2_try_format(ccp2, fh, fmt->pad, &fmt->format, fmt->which); + ccp2_try_format(ccp2, cfg, fmt->pad, &fmt->format, fmt->which); *format = fmt->format; /* Propagate the format from sink to source */ if (fmt->pad == CCP2_PAD_SINK) { - format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SOURCE, + format = __ccp2_get_format(ccp2, cfg, CCP2_PAD_SOURCE, fmt->which); *format = fmt->format; - ccp2_try_format(ccp2, fh, CCP2_PAD_SOURCE, format, fmt->which); + ccp2_try_format(ccp2, cfg, CCP2_PAD_SOURCE, format, fmt->which); } return 0; @@ -811,7 +811,7 @@ static int ccp2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; format.format.width = 4096; format.format.height = 4096; - ccp2_set_format(sd, fh, &format); + ccp2_set_format(sd, fh ? fh->pad : NULL, &format); return 0; } diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c index 09c686d96ae8..a78338d012b4 100644 --- a/drivers/media/platform/omap3isp/ispcsi2.c +++ b/drivers/media/platform/omap3isp/ispcsi2.c @@ -548,7 +548,8 @@ int omap3isp_csi2_reset(struct isp_csi2_device *csi2) static int csi2_configure(struct isp_csi2_device *csi2) { - const struct isp_v4l2_subdevs_group *pdata; + struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity); + const struct isp_bus_cfg *buscfg; struct isp_device *isp = csi2->isp; struct isp_csi2_timing_cfg *timing = &csi2->timing[0]; struct v4l2_subdev *sensor; @@ -565,14 +566,19 @@ static int csi2_configure(struct isp_csi2_device *csi2) pad = media_entity_remote_pad(&csi2->pads[CSI2_PAD_SINK]); sensor = media_entity_to_v4l2_subdev(pad->entity); - pdata = sensor->host_priv; + buscfg = sensor->host_priv; csi2->frame_skip = 0; v4l2_subdev_call(sensor, sensor, g_skip_frames, &csi2->frame_skip); - csi2->ctrl.vp_out_ctrl = pdata->bus.csi2.vpclk_div; + csi2->ctrl.vp_out_ctrl = + clamp_t(unsigned int, pipe->l3_ick / pipe->external_rate - 1, + 1, 3); + dev_dbg(isp->dev, "%s: l3_ick %lu, external_rate %u, vp_out_ctrl %u\n", + __func__, pipe->l3_ick, pipe->external_rate, + csi2->ctrl.vp_out_ctrl); csi2->ctrl.frame_mode = ISP_CSI2_FRAME_IMMEDIATE; - csi2->ctrl.ecc_enable = pdata->bus.csi2.crc; + csi2->ctrl.ecc_enable = buscfg->bus.csi2.crc; timing->ionum = 1; timing->force_rx_mode = 1; @@ -829,17 +835,17 @@ static const struct isp_video_operations csi2_ispvideo_ops = { */ static struct v4l2_mbus_framefmt * -__csi2_get_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh, +__csi2_get_format(struct isp_csi2_device *csi2, struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&csi2->subdev, cfg, pad); else return &csi2->formats[pad]; } static void -csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh, +csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_pad_config *cfg, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -869,7 +875,7 @@ csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh, * compression. */ pixelcode = fmt->code; - format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK, which); + format = __csi2_get_format(csi2, cfg, CSI2_PAD_SINK, which); memcpy(fmt, format, sizeof(*fmt)); /* @@ -890,12 +896,12 @@ csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh, /* * csi2_enum_mbus_code - Handle pixel format enumeration * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @code : pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ static int csi2_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); @@ -908,8 +914,8 @@ static int csi2_enum_mbus_code(struct v4l2_subdev *sd, code->code = csi2_input_fmts[code->index]; } else { - format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK, - V4L2_SUBDEV_FORMAT_TRY); + format = __csi2_get_format(csi2, cfg, CSI2_PAD_SINK, + code->which); switch (code->index) { case 0: /* Passthrough sink pad code */ @@ -932,7 +938,7 @@ static int csi2_enum_mbus_code(struct v4l2_subdev *sd, } static int csi2_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); @@ -944,7 +950,7 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = 1; format.height = 1; - csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + csi2_try_format(csi2, cfg, fse->pad, &format, fse->which); fse->min_width = format.width; fse->min_height = format.height; @@ -954,7 +960,7 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = -1; format.height = -1; - csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + csi2_try_format(csi2, cfg, fse->pad, &format, fse->which); fse->max_width = format.width; fse->max_height = format.height; @@ -964,17 +970,17 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd, /* * csi2_get_format - Handle get format by pads subdev method * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @fmt: pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ -static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which); + format = __csi2_get_format(csi2, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; @@ -985,29 +991,29 @@ static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * csi2_set_format - Handle set format by pads subdev method * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @fmt: pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ -static int csi2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int csi2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which); + format = __csi2_get_format(csi2, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; - csi2_try_format(csi2, fh, fmt->pad, &fmt->format, fmt->which); + csi2_try_format(csi2, cfg, fmt->pad, &fmt->format, fmt->which); *format = fmt->format; /* Propagate the format from sink to source */ if (fmt->pad == CSI2_PAD_SINK) { - format = __csi2_get_format(csi2, fh, CSI2_PAD_SOURCE, + format = __csi2_get_format(csi2, cfg, CSI2_PAD_SOURCE, fmt->which); *format = fmt->format; - csi2_try_format(csi2, fh, CSI2_PAD_SOURCE, format, fmt->which); + csi2_try_format(csi2, cfg, CSI2_PAD_SOURCE, format, fmt->which); } return 0; @@ -1032,7 +1038,7 @@ static int csi2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; format.format.width = 4096; format.format.height = 4096; - csi2_set_format(sd, fh, &format); + csi2_set_format(sd, fh ? fh->pad : NULL, &format); return 0; } diff --git a/drivers/media/platform/omap3isp/ispcsiphy.c b/drivers/media/platform/omap3isp/ispcsiphy.c index e033f2237a72..495447d66cfd 100644 --- a/drivers/media/platform/omap3isp/ispcsiphy.c +++ b/drivers/media/platform/omap3isp/ispcsiphy.c @@ -16,6 +16,7 @@ #include <linux/delay.h> #include <linux/device.h> +#include <linux/regmap.h> #include <linux/regulator/consumer.h> #include "isp.h" @@ -26,10 +27,11 @@ static void csiphy_routing_cfg_3630(struct isp_csiphy *phy, enum isp_interface_type iface, bool ccp2_strobe) { - u32 reg = isp_reg_readl( - phy->isp, OMAP3_ISP_IOMEM_3630_CONTROL_CAMERA_PHY_CTRL, 0); + u32 reg; u32 shift, mode; + regmap_read(phy->isp->syscon, phy->isp->syscon_offset, ®); + switch (iface) { default: /* Should not happen in practice, but let's keep the compiler happy. */ @@ -63,8 +65,7 @@ static void csiphy_routing_cfg_3630(struct isp_csiphy *phy, reg &= ~(OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_MASK << shift); reg |= mode << shift; - isp_reg_writel(phy->isp, reg, - OMAP3_ISP_IOMEM_3630_CONTROL_CAMERA_PHY_CTRL, 0); + regmap_write(phy->isp->syscon, phy->isp->syscon_offset, reg); } static void csiphy_routing_cfg_3430(struct isp_csiphy *phy, u32 iface, bool on, @@ -78,16 +79,14 @@ static void csiphy_routing_cfg_3430(struct isp_csiphy *phy, u32 iface, bool on, return; if (!on) { - isp_reg_writel(phy->isp, 0, - OMAP3_ISP_IOMEM_343X_CONTROL_CSIRXFE, 0); + regmap_write(phy->isp->syscon, phy->isp->syscon_offset, 0); return; } if (ccp2_strobe) csirxfe |= OMAP343X_CONTROL_CSIRXFE_SELFORM; - isp_reg_writel(phy->isp, csirxfe, - OMAP3_ISP_IOMEM_343X_CONTROL_CSIRXFE, 0); + regmap_write(phy->isp->syscon, phy->isp->syscon_offset, csirxfe); } /* @@ -106,10 +105,9 @@ static void csiphy_routing_cfg(struct isp_csiphy *phy, enum isp_interface_type iface, bool on, bool ccp2_strobe) { - if (phy->isp->mmio_base[OMAP3_ISP_IOMEM_3630_CONTROL_CAMERA_PHY_CTRL] - && on) + if (phy->isp->phy_type == ISP_PHY_TYPE_3630 && on) return csiphy_routing_cfg_3630(phy, iface, ccp2_strobe); - if (phy->isp->mmio_base[OMAP3_ISP_IOMEM_343X_CONTROL_CSIRXFE]) + if (phy->isp->phy_type == ISP_PHY_TYPE_3430) return csiphy_routing_cfg_3430(phy, iface, on, ccp2_strobe); } @@ -168,18 +166,25 @@ static int omap3isp_csiphy_config(struct isp_csiphy *phy) { struct isp_csi2_device *csi2 = phy->csi2; struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity); - struct isp_v4l2_subdevs_group *subdevs = pipe->external->host_priv; + struct isp_bus_cfg *buscfg = pipe->external->host_priv; struct isp_csiphy_lanes_cfg *lanes; int csi2_ddrclk_khz; unsigned int used_lanes = 0; unsigned int i; u32 reg; - if (subdevs->interface == ISP_INTERFACE_CCP2B_PHY1 - || subdevs->interface == ISP_INTERFACE_CCP2B_PHY2) - lanes = &subdevs->bus.ccp2.lanecfg; + if (!buscfg) { + struct isp_async_subdev *isd = + container_of(pipe->external->asd, + struct isp_async_subdev, asd); + buscfg = &isd->bus; + } + + if (buscfg->interface == ISP_INTERFACE_CCP2B_PHY1 + || buscfg->interface == ISP_INTERFACE_CCP2B_PHY2) + lanes = &buscfg->bus.ccp2.lanecfg; else - lanes = &subdevs->bus.csi2.lanecfg; + lanes = &buscfg->bus.csi2.lanecfg; /* Clock and data lanes verification */ for (i = 0; i < phy->num_data_lanes; i++) { @@ -203,8 +208,8 @@ static int omap3isp_csiphy_config(struct isp_csiphy *phy) * issue since the MPU power domain is forced on whilst the * ISP is in use. */ - csiphy_routing_cfg(phy, subdevs->interface, true, - subdevs->bus.ccp2.phy_layer); + csiphy_routing_cfg(phy, buscfg->interface, true, + buscfg->bus.ccp2.phy_layer); /* DPHY timing configuration */ /* CSI-2 is DDR and we only count used lanes. */ @@ -302,11 +307,10 @@ void omap3isp_csiphy_release(struct isp_csiphy *phy) struct isp_csi2_device *csi2 = phy->csi2; struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity); - struct isp_v4l2_subdevs_group *subdevs = - pipe->external->host_priv; + struct isp_bus_cfg *buscfg = pipe->external->host_priv; - csiphy_routing_cfg(phy, subdevs->interface, false, - subdevs->bus.ccp2.phy_layer); + csiphy_routing_cfg(phy, buscfg->interface, false, + buscfg->bus.ccp2.phy_layer); csiphy_power_autoswitch_enable(phy, false); csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_OFF); regulator_disable(phy->vdd); diff --git a/drivers/media/platform/omap3isp/isph3a_aewb.c b/drivers/media/platform/omap3isp/isph3a_aewb.c index b208c5417146..ccaf92f39236 100644 --- a/drivers/media/platform/omap3isp/isph3a_aewb.c +++ b/drivers/media/platform/omap3isp/isph3a_aewb.c @@ -297,7 +297,6 @@ int omap3isp_h3a_aewb_init(struct isp_device *isp) aewb->ops = &h3a_aewb_ops; aewb->priv = aewb_cfg; - aewb->dma_ch = -1; aewb->event_type = V4L2_EVENT_OMAP3ISP_AEWB; aewb->isp = isp; diff --git a/drivers/media/platform/omap3isp/isph3a_af.c b/drivers/media/platform/omap3isp/isph3a_af.c index 8a83e195f3e3..92937f7eecef 100644 --- a/drivers/media/platform/omap3isp/isph3a_af.c +++ b/drivers/media/platform/omap3isp/isph3a_af.c @@ -360,7 +360,6 @@ int omap3isp_h3a_af_init(struct isp_device *isp) af->ops = &h3a_af_ops; af->priv = af_cfg; - af->dma_ch = -1; af->event_type = V4L2_EVENT_OMAP3ISP_AF; af->isp = isp; diff --git a/drivers/media/platform/omap3isp/isphist.c b/drivers/media/platform/omap3isp/isphist.c index ce822c34c843..7138b043a4aa 100644 --- a/drivers/media/platform/omap3isp/isphist.c +++ b/drivers/media/platform/omap3isp/isphist.c @@ -16,20 +16,18 @@ */ #include <linux/delay.h> +#include <linux/device.h> +#include <linux/dmaengine.h> +#include <linux/omap-dmaengine.h> #include <linux/slab.h> #include <linux/uaccess.h> -#include <linux/device.h> #include "isp.h" #include "ispreg.h" #include "isphist.h" -#define OMAP24XX_DMA_NO_DEVICE 0 - #define HIST_CONFIG_DMA 1 -#define HIST_USING_DMA(hist) ((hist)->dma_ch >= 0) - /* * hist_reset_mem - clear Histogram memory before start stats engine. */ @@ -62,20 +60,6 @@ static void hist_reset_mem(struct ispstat *hist) hist->wait_acc_frames = conf->num_acc_frames; } -static void hist_dma_config(struct ispstat *hist) -{ - struct isp_device *isp = hist->isp; - - hist->dma_config.data_type = OMAP_DMA_DATA_TYPE_S32; - hist->dma_config.sync_mode = OMAP_DMA_SYNC_ELEMENT; - hist->dma_config.frame_count = 1; - hist->dma_config.src_amode = OMAP_DMA_AMODE_CONSTANT; - hist->dma_config.src_start = isp->mmio_base_phys[OMAP3_ISP_IOMEM_HIST] - + ISPHIST_DATA; - hist->dma_config.dst_amode = OMAP_DMA_AMODE_POST_INC; - hist->dma_config.src_or_dst_synch = OMAP_DMA_SRC_SYNC; -} - /* * hist_setup_regs - Helper function to update Histogram registers. */ @@ -176,17 +160,12 @@ static int hist_busy(struct ispstat *hist) & ISPHIST_PCR_BUSY; } -static void hist_dma_cb(int lch, u16 ch_status, void *data) +static void hist_dma_cb(void *data) { struct ispstat *hist = data; - if (ch_status & ~OMAP_DMA_BLOCK_IRQ) { - dev_dbg(hist->isp->dev, "hist: DMA error. status = 0x%04x\n", - ch_status); - omap_stop_dma(lch); - hist_reset_mem(hist); - atomic_set(&hist->buf_err, 1); - } + /* FIXME: The DMA engine API can't report transfer errors :-/ */ + isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR); @@ -198,24 +177,57 @@ static void hist_dma_cb(int lch, u16 ch_status, void *data) static int hist_buf_dma(struct ispstat *hist) { dma_addr_t dma_addr = hist->active_buf->dma_addr; + struct dma_async_tx_descriptor *tx; + struct dma_slave_config cfg; + dma_cookie_t cookie; + int ret; if (unlikely(!dma_addr)) { dev_dbg(hist->isp->dev, "hist: invalid DMA buffer address\n"); - hist_reset_mem(hist); - return STAT_NO_BUF; + goto error; } isp_reg_writel(hist->isp, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR); isp_reg_set(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR); omap3isp_flush(hist->isp); - hist->dma_config.dst_start = dma_addr; - hist->dma_config.elem_count = hist->buf_size / sizeof(u32); - omap_set_dma_params(hist->dma_ch, &hist->dma_config); - omap_start_dma(hist->dma_ch); + memset(&cfg, 0, sizeof(cfg)); + cfg.src_addr = hist->isp->mmio_hist_base_phys + ISPHIST_DATA; + cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + cfg.src_maxburst = hist->buf_size / 4; + + ret = dmaengine_slave_config(hist->dma_ch, &cfg); + if (ret < 0) { + dev_dbg(hist->isp->dev, + "hist: DMA slave configuration failed\n"); + goto error; + } + + tx = dmaengine_prep_slave_single(hist->dma_ch, dma_addr, + hist->buf_size, DMA_DEV_TO_MEM, + DMA_CTRL_ACK); + if (tx == NULL) { + dev_dbg(hist->isp->dev, + "hist: DMA slave preparation failed\n"); + goto error; + } + + tx->callback = hist_dma_cb; + tx->callback_param = hist; + cookie = tx->tx_submit(tx); + if (dma_submit_error(cookie)) { + dev_dbg(hist->isp->dev, "hist: DMA submission failed\n"); + goto error; + } + + dma_async_issue_pending(hist->dma_ch); return STAT_BUF_WAITING_DMA; + +error: + hist_reset_mem(hist); + return STAT_NO_BUF; } static int hist_buf_pio(struct ispstat *hist) @@ -272,7 +284,7 @@ static int hist_buf_process(struct ispstat *hist) if (--(hist->wait_acc_frames)) return STAT_NO_BUF; - if (HIST_USING_DMA(hist)) + if (hist->dma_ch) ret = hist_buf_dma(hist); else ret = hist_buf_pio(hist); @@ -473,18 +485,28 @@ int omap3isp_hist_init(struct isp_device *isp) hist->isp = isp; - if (HIST_CONFIG_DMA) - ret = omap_request_dma(OMAP24XX_DMA_NO_DEVICE, "DMA_ISP_HIST", - hist_dma_cb, hist, &hist->dma_ch); - if (ret) { - if (HIST_CONFIG_DMA) - dev_warn(isp->dev, "hist: DMA request channel failed. " - "Using PIO only.\n"); - hist->dma_ch = -1; - } else { - dev_dbg(isp->dev, "hist: DMA channel = %d\n", hist->dma_ch); - hist_dma_config(hist); - omap_enable_dma_irq(hist->dma_ch, OMAP_DMA_BLOCK_IRQ); + if (HIST_CONFIG_DMA) { + struct platform_device *pdev = to_platform_device(isp->dev); + struct resource *res; + unsigned int sig = 0; + dma_cap_mask_t mask; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + res = platform_get_resource_byname(pdev, IORESOURCE_DMA, + "hist"); + if (res) + sig = res->start; + + hist->dma_ch = dma_request_slave_channel_compat(mask, + omap_dma_filter_fn, &sig, isp->dev, "hist"); + if (!hist->dma_ch) + dev_warn(isp->dev, + "hist: DMA channel request failed, using PIO\n"); + else + dev_dbg(isp->dev, "hist: using DMA channel %s\n", + dma_chan_name(hist->dma_ch)); } hist->ops = &hist_ops; @@ -493,8 +515,8 @@ int omap3isp_hist_init(struct isp_device *isp) ret = omap3isp_stat_init(hist, "histogram", &hist_subdev_ops); if (ret) { - if (HIST_USING_DMA(hist)) - omap_free_dma(hist->dma_ch); + if (hist->dma_ch) + dma_release_channel(hist->dma_ch); } return ret; @@ -505,7 +527,10 @@ int omap3isp_hist_init(struct isp_device *isp) */ void omap3isp_hist_cleanup(struct isp_device *isp) { - if (HIST_USING_DMA(&isp->isp_hist)) - omap_free_dma(isp->isp_hist.dma_ch); - omap3isp_stat_cleanup(&isp->isp_hist); + struct ispstat *hist = &isp->isp_hist; + + if (hist->dma_ch) + dma_release_channel(hist->dma_ch); + + omap3isp_stat_cleanup(hist); } diff --git a/drivers/media/platform/omap3isp/isppreview.c b/drivers/media/platform/omap3isp/isppreview.c index dd9eed45d853..15cb254ccc39 100644 --- a/drivers/media/platform/omap3isp/isppreview.c +++ b/drivers/media/platform/omap3isp/isppreview.c @@ -1686,21 +1686,21 @@ static int preview_set_stream(struct v4l2_subdev *sd, int enable) } static struct v4l2_mbus_framefmt * -__preview_get_format(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh, +__preview_get_format(struct isp_prev_device *prev, struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&prev->subdev, cfg, pad); else return &prev->formats[pad]; } static struct v4l2_rect * -__preview_get_crop(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh, +__preview_get_crop(struct isp_prev_device *prev, struct v4l2_subdev_pad_config *cfg, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_crop(fh, PREV_PAD_SINK); + return v4l2_subdev_get_try_crop(&prev->subdev, cfg, PREV_PAD_SINK); else return &prev->crop; } @@ -1727,7 +1727,7 @@ static const unsigned int preview_output_fmts[] = { /* * preview_try_format - Validate a format * @prev: ISP preview engine - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @pad: pad number * @fmt: format to be validated * @which: try/active format selector @@ -1736,7 +1736,7 @@ static const unsigned int preview_output_fmts[] = { * engine limits and the format and crop rectangles on other pads. */ static void preview_try_format(struct isp_prev_device *prev, - struct v4l2_subdev_fh *fh, unsigned int pad, + struct v4l2_subdev_pad_config *cfg, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -1777,7 +1777,7 @@ static void preview_try_format(struct isp_prev_device *prev, case PREV_PAD_SOURCE: pixelcode = fmt->code; - *fmt = *__preview_get_format(prev, fh, PREV_PAD_SINK, which); + *fmt = *__preview_get_format(prev, cfg, PREV_PAD_SINK, which); switch (pixelcode) { case MEDIA_BUS_FMT_YUYV8_1X16: @@ -1795,7 +1795,7 @@ static void preview_try_format(struct isp_prev_device *prev, * is not supported yet, hardcode the output size to the crop * rectangle size. */ - crop = __preview_get_crop(prev, fh, which); + crop = __preview_get_crop(prev, cfg, which); fmt->width = crop->width; fmt->height = crop->height; @@ -1864,12 +1864,12 @@ static void preview_try_crop(struct isp_prev_device *prev, /* * preview_enum_mbus_code - Handle pixel format enumeration * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @code : pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ static int preview_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { switch (code->pad) { @@ -1893,7 +1893,7 @@ static int preview_enum_mbus_code(struct v4l2_subdev *sd, } static int preview_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct isp_prev_device *prev = v4l2_get_subdevdata(sd); @@ -1905,7 +1905,7 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = 1; format.height = 1; - preview_try_format(prev, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + preview_try_format(prev, cfg, fse->pad, &format, fse->which); fse->min_width = format.width; fse->min_height = format.height; @@ -1915,7 +1915,7 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = -1; format.height = -1; - preview_try_format(prev, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + preview_try_format(prev, cfg, fse->pad, &format, fse->which); fse->max_width = format.width; fse->max_height = format.height; @@ -1925,7 +1925,7 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd, /* * preview_get_selection - Retrieve a selection rectangle on a pad * @sd: ISP preview V4L2 subdevice - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @sel: Selection rectangle * * The only supported rectangles are the crop rectangles on the sink pad. @@ -1933,7 +1933,7 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd, * Return 0 on success or a negative error code otherwise. */ static int preview_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct isp_prev_device *prev = v4l2_get_subdevdata(sd); @@ -1949,13 +1949,13 @@ static int preview_get_selection(struct v4l2_subdev *sd, sel->r.width = INT_MAX; sel->r.height = INT_MAX; - format = __preview_get_format(prev, fh, PREV_PAD_SINK, + format = __preview_get_format(prev, cfg, PREV_PAD_SINK, sel->which); preview_try_crop(prev, format, &sel->r); break; case V4L2_SEL_TGT_CROP: - sel->r = *__preview_get_crop(prev, fh, sel->which); + sel->r = *__preview_get_crop(prev, cfg, sel->which); break; default: @@ -1968,7 +1968,7 @@ static int preview_get_selection(struct v4l2_subdev *sd, /* * preview_set_selection - Set a selection rectangle on a pad * @sd: ISP preview V4L2 subdevice - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @sel: Selection rectangle * * The only supported rectangle is the actual crop rectangle on the sink pad. @@ -1976,7 +1976,7 @@ static int preview_get_selection(struct v4l2_subdev *sd, * Return 0 on success or a negative error code otherwise. */ static int preview_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct isp_prev_device *prev = v4l2_get_subdevdata(sd); @@ -1995,17 +1995,17 @@ static int preview_set_selection(struct v4l2_subdev *sd, * rectangle. */ if (sel->flags & V4L2_SEL_FLAG_KEEP_CONFIG) { - sel->r = *__preview_get_crop(prev, fh, sel->which); + sel->r = *__preview_get_crop(prev, cfg, sel->which); return 0; } - format = __preview_get_format(prev, fh, PREV_PAD_SINK, sel->which); + format = __preview_get_format(prev, cfg, PREV_PAD_SINK, sel->which); preview_try_crop(prev, format, &sel->r); - *__preview_get_crop(prev, fh, sel->which) = sel->r; + *__preview_get_crop(prev, cfg, sel->which) = sel->r; /* Update the source format. */ - format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, sel->which); - preview_try_format(prev, fh, PREV_PAD_SOURCE, format, sel->which); + format = __preview_get_format(prev, cfg, PREV_PAD_SOURCE, sel->which); + preview_try_format(prev, cfg, PREV_PAD_SOURCE, format, sel->which); return 0; } @@ -2013,17 +2013,17 @@ static int preview_set_selection(struct v4l2_subdev *sd, /* * preview_get_format - Handle get format by pads subdev method * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @fmt: pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ -static int preview_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int preview_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct isp_prev_device *prev = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __preview_get_format(prev, fh, fmt->pad, fmt->which); + format = __preview_get_format(prev, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; @@ -2034,28 +2034,28 @@ static int preview_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * preview_set_format - Handle set format by pads subdev method * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @fmt: pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ -static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct isp_prev_device *prev = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; struct v4l2_rect *crop; - format = __preview_get_format(prev, fh, fmt->pad, fmt->which); + format = __preview_get_format(prev, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; - preview_try_format(prev, fh, fmt->pad, &fmt->format, fmt->which); + preview_try_format(prev, cfg, fmt->pad, &fmt->format, fmt->which); *format = fmt->format; /* Propagate the format from sink to source */ if (fmt->pad == PREV_PAD_SINK) { /* Reset the crop rectangle. */ - crop = __preview_get_crop(prev, fh, fmt->which); + crop = __preview_get_crop(prev, cfg, fmt->which); crop->left = 0; crop->top = 0; crop->width = fmt->format.width; @@ -2064,9 +2064,9 @@ static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, preview_try_crop(prev, &fmt->format, crop); /* Update the source format. */ - format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, + format = __preview_get_format(prev, cfg, PREV_PAD_SOURCE, fmt->which); - preview_try_format(prev, fh, PREV_PAD_SOURCE, format, + preview_try_format(prev, cfg, PREV_PAD_SOURCE, format, fmt->which); } @@ -2093,7 +2093,7 @@ static int preview_init_formats(struct v4l2_subdev *sd, format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; format.format.width = 4096; format.format.height = 4096; - preview_set_format(sd, fh, &format); + preview_set_format(sd, fh ? fh->pad : NULL, &format); return 0; } diff --git a/drivers/media/platform/omap3isp/ispresizer.c b/drivers/media/platform/omap3isp/ispresizer.c index 2b9bc4839876..7cfb43dc0ffd 100644 --- a/drivers/media/platform/omap3isp/ispresizer.c +++ b/drivers/media/platform/omap3isp/ispresizer.c @@ -112,16 +112,16 @@ static const struct isprsz_coef filter_coefs = { * __resizer_get_format - helper function for getting resizer format * @res : pointer to resizer private structure * @pad : pad number - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @which : wanted subdev format * return zero */ static struct v4l2_mbus_framefmt * -__resizer_get_format(struct isp_res_device *res, struct v4l2_subdev_fh *fh, +__resizer_get_format(struct isp_res_device *res, struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&res->subdev, cfg, pad); else return &res->formats[pad]; } @@ -129,15 +129,15 @@ __resizer_get_format(struct isp_res_device *res, struct v4l2_subdev_fh *fh, /* * __resizer_get_crop - helper function for getting resizer crop rectangle * @res : pointer to resizer private structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @which : wanted subdev crop rectangle */ static struct v4l2_rect * -__resizer_get_crop(struct isp_res_device *res, struct v4l2_subdev_fh *fh, +__resizer_get_crop(struct isp_res_device *res, struct v4l2_subdev_pad_config *cfg, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_crop(fh, RESZ_PAD_SINK); + return v4l2_subdev_get_try_crop(&res->subdev, cfg, RESZ_PAD_SINK); else return &res->crop.request; } @@ -1215,7 +1215,7 @@ static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink, /* * resizer_get_selection - Retrieve a selection rectangle on a pad * @sd: ISP resizer V4L2 subdevice - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @sel: Selection rectangle * * The only supported rectangles are the crop rectangles on the sink pad. @@ -1223,7 +1223,7 @@ static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink, * Return 0 on success or a negative error code otherwise. */ static int resizer_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct isp_res_device *res = v4l2_get_subdevdata(sd); @@ -1234,9 +1234,9 @@ static int resizer_get_selection(struct v4l2_subdev *sd, if (sel->pad != RESZ_PAD_SINK) return -EINVAL; - format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK, + format_sink = __resizer_get_format(res, cfg, RESZ_PAD_SINK, sel->which); - format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE, + format_source = __resizer_get_format(res, cfg, RESZ_PAD_SOURCE, sel->which); switch (sel->target) { @@ -1251,7 +1251,7 @@ static int resizer_get_selection(struct v4l2_subdev *sd, break; case V4L2_SEL_TGT_CROP: - sel->r = *__resizer_get_crop(res, fh, sel->which); + sel->r = *__resizer_get_crop(res, cfg, sel->which); resizer_calc_ratios(res, &sel->r, format_source, &ratio); break; @@ -1265,7 +1265,7 @@ static int resizer_get_selection(struct v4l2_subdev *sd, /* * resizer_set_selection - Set a selection rectangle on a pad * @sd: ISP resizer V4L2 subdevice - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @sel: Selection rectangle * * The only supported rectangle is the actual crop rectangle on the sink pad. @@ -1276,7 +1276,7 @@ static int resizer_get_selection(struct v4l2_subdev *sd, * Return 0 on success or a negative error code otherwise. */ static int resizer_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct isp_res_device *res = v4l2_get_subdevdata(sd); @@ -1290,9 +1290,9 @@ static int resizer_set_selection(struct v4l2_subdev *sd, sel->pad != RESZ_PAD_SINK) return -EINVAL; - format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK, + format_sink = __resizer_get_format(res, cfg, RESZ_PAD_SINK, sel->which); - format_source = *__resizer_get_format(res, fh, RESZ_PAD_SOURCE, + format_source = *__resizer_get_format(res, cfg, RESZ_PAD_SOURCE, sel->which); dev_dbg(isp->dev, "%s(%s): req %ux%u -> (%d,%d)/%ux%u -> %ux%u\n", @@ -1310,7 +1310,7 @@ static int resizer_set_selection(struct v4l2_subdev *sd, * stored the mangled rectangle. */ resizer_try_crop(format_sink, &format_source, &sel->r); - *__resizer_get_crop(res, fh, sel->which) = sel->r; + *__resizer_get_crop(res, cfg, sel->which) = sel->r; resizer_calc_ratios(res, &sel->r, &format_source, &ratio); dev_dbg(isp->dev, "%s(%s): got %ux%u -> (%d,%d)/%ux%u -> %ux%u\n", @@ -1320,7 +1320,7 @@ static int resizer_set_selection(struct v4l2_subdev *sd, format_source.width, format_source.height); if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { - *__resizer_get_format(res, fh, RESZ_PAD_SOURCE, sel->which) = + *__resizer_get_format(res, cfg, RESZ_PAD_SOURCE, sel->which) = format_source; return 0; } @@ -1331,7 +1331,7 @@ static int resizer_set_selection(struct v4l2_subdev *sd, */ spin_lock_irqsave(&res->lock, flags); - *__resizer_get_format(res, fh, RESZ_PAD_SOURCE, sel->which) = + *__resizer_get_format(res, cfg, RESZ_PAD_SOURCE, sel->which) = format_source; res->ratio = ratio; @@ -1368,13 +1368,13 @@ static unsigned int resizer_max_in_width(struct isp_res_device *res) /* * resizer_try_format - Handle try format by pad subdev method * @res : ISP resizer device - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @pad : pad num * @fmt : pointer to v4l2 format structure * @which : wanted subdev format */ static void resizer_try_format(struct isp_res_device *res, - struct v4l2_subdev_fh *fh, unsigned int pad, + struct v4l2_subdev_pad_config *cfg, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -1395,10 +1395,10 @@ static void resizer_try_format(struct isp_res_device *res, break; case RESZ_PAD_SOURCE: - format = __resizer_get_format(res, fh, RESZ_PAD_SINK, which); + format = __resizer_get_format(res, cfg, RESZ_PAD_SINK, which); fmt->code = format->code; - crop = *__resizer_get_crop(res, fh, which); + crop = *__resizer_get_crop(res, cfg, which); resizer_calc_ratios(res, &crop, fmt, &ratio); break; } @@ -1410,12 +1410,12 @@ static void resizer_try_format(struct isp_res_device *res, /* * resizer_enum_mbus_code - Handle pixel format enumeration * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @code : pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ static int resizer_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { struct isp_res_device *res = v4l2_get_subdevdata(sd); @@ -1430,8 +1430,8 @@ static int resizer_enum_mbus_code(struct v4l2_subdev *sd, if (code->index != 0) return -EINVAL; - format = __resizer_get_format(res, fh, RESZ_PAD_SINK, - V4L2_SUBDEV_FORMAT_TRY); + format = __resizer_get_format(res, cfg, RESZ_PAD_SINK, + code->which); code->code = format->code; } @@ -1439,7 +1439,7 @@ static int resizer_enum_mbus_code(struct v4l2_subdev *sd, } static int resizer_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct isp_res_device *res = v4l2_get_subdevdata(sd); @@ -1451,7 +1451,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = 1; format.height = 1; - resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + resizer_try_format(res, cfg, fse->pad, &format, fse->which); fse->min_width = format.width; fse->min_height = format.height; @@ -1461,7 +1461,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = -1; format.height = -1; - resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + resizer_try_format(res, cfg, fse->pad, &format, fse->which); fse->max_width = format.width; fse->max_height = format.height; @@ -1471,17 +1471,17 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd, /* * resizer_get_format - Handle get format by pads subdev method * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @fmt : pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ -static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct isp_res_device *res = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __resizer_get_format(res, fh, fmt->pad, fmt->which); + format = __resizer_get_format(res, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; @@ -1492,37 +1492,37 @@ static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * resizer_set_format - Handle set format by pads subdev method * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * @fmt : pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ -static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct isp_res_device *res = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; struct v4l2_rect *crop; - format = __resizer_get_format(res, fh, fmt->pad, fmt->which); + format = __resizer_get_format(res, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; - resizer_try_format(res, fh, fmt->pad, &fmt->format, fmt->which); + resizer_try_format(res, cfg, fmt->pad, &fmt->format, fmt->which); *format = fmt->format; if (fmt->pad == RESZ_PAD_SINK) { /* reset crop rectangle */ - crop = __resizer_get_crop(res, fh, fmt->which); + crop = __resizer_get_crop(res, cfg, fmt->which); crop->left = 0; crop->top = 0; crop->width = fmt->format.width; crop->height = fmt->format.height; /* Propagate the format from sink to source */ - format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE, + format = __resizer_get_format(res, cfg, RESZ_PAD_SOURCE, fmt->which); *format = fmt->format; - resizer_try_format(res, fh, RESZ_PAD_SOURCE, format, + resizer_try_format(res, cfg, RESZ_PAD_SOURCE, format, fmt->which); } @@ -1573,7 +1573,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd, format.format.code = MEDIA_BUS_FMT_YUYV8_1X16; format.format.width = 4096; format.format.height = 4096; - resizer_set_format(sd, fh, &format); + resizer_set_format(sd, fh ? fh->pad : NULL, &format); return 0; } diff --git a/drivers/media/platform/omap3isp/ispstat.c b/drivers/media/platform/omap3isp/ispstat.c index a94e8340508f..20434e83e801 100644 --- a/drivers/media/platform/omap3isp/ispstat.c +++ b/drivers/media/platform/omap3isp/ispstat.c @@ -21,7 +21,7 @@ #include "isp.h" -#define ISP_STAT_USES_DMAENGINE(stat) ((stat)->dma_ch >= 0) +#define ISP_STAT_USES_DMAENGINE(stat) ((stat)->dma_ch != NULL) /* * MAGIC_SIZE must always be the greatest common divisor of diff --git a/drivers/media/platform/omap3isp/ispstat.h b/drivers/media/platform/omap3isp/ispstat.h index b32b29677e2c..b79380d83fcf 100644 --- a/drivers/media/platform/omap3isp/ispstat.h +++ b/drivers/media/platform/omap3isp/ispstat.h @@ -20,7 +20,6 @@ #include <linux/types.h> #include <linux/omap3isp.h> -#include <linux/omap-dma.h> #include <media/v4l2-event.h> #include "isp.h" @@ -33,6 +32,7 @@ #define STAT_NO_BUF 1 /* An error has occurred */ #define STAT_BUF_WAITING_DMA 2 /* Histogram only: DMA is running */ +struct dma_chan; struct ispstat; struct ispstat_buffer { @@ -96,7 +96,6 @@ struct ispstat { u8 inc_config; atomic_t buf_err; enum ispstat_state_t state; /* enabling/disabling state */ - struct omap_dma_channel_params dma_config; struct isp_device *isp; void *priv; /* pointer to priv config struct */ void *recover_priv; /* pointer to recover priv configuration */ @@ -110,7 +109,7 @@ struct ispstat { u32 frame_number; u32 buf_size; u32 buf_alloc_size; - int dma_ch; + struct dma_chan *dma_ch; unsigned long event_type; struct ispstat_buffer *buf; struct ispstat_buffer *active_buf; diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index 3fe9047ef466..d285af18df7f 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c @@ -452,7 +452,6 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video) enum isp_pipeline_state state; struct isp_buffer *buf; unsigned long flags; - struct timespec ts; spin_lock_irqsave(&video->irqlock, flags); if (WARN_ON(list_empty(&video->dmaqueue))) { @@ -465,9 +464,7 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video) list_del(&buf->irqlist); spin_unlock_irqrestore(&video->irqlock, flags); - ktime_get_ts(&ts); - buf->vb.v4l2_buf.timestamp.tv_sec = ts.tv_sec; - buf->vb.v4l2_buf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC; + v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); /* Do frame number propagation only if this is the output video node. * Frame number either comes from the CSI receivers or it gets @@ -524,7 +521,6 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video) buf = list_first_entry(&video->dmaqueue, struct isp_buffer, irqlist); - buf->vb.state = VB2_BUF_STATE_ACTIVE; spin_unlock_irqrestore(&video->irqlock, flags); @@ -1022,7 +1018,7 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) pipe->entities = 0; - if (video->isp->pdata->set_constraints) + if (video->isp->pdata && video->isp->pdata->set_constraints) video->isp->pdata->set_constraints(video->isp, true); pipe->l3_ick = clk_get_rate(video->isp->clock[ISP_CLK_L3_ICK]); pipe->max_rate = pipe->l3_ick; @@ -1104,7 +1100,7 @@ err_set_stream: err_check_format: media_entity_pipeline_stop(&video->video.entity); err_pipeline_start: - if (video->isp->pdata->set_constraints) + if (video->isp->pdata && video->isp->pdata->set_constraints) video->isp->pdata->set_constraints(video->isp, false); /* The DMA queue must be emptied here, otherwise CCDC interrupts that * will get triggered the next time the CCDC is powered up will try to @@ -1165,7 +1161,7 @@ isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) video->queue = NULL; video->error = false; - if (video->isp->pdata->set_constraints) + if (video->isp->pdata && video->isp->pdata->set_constraints) video->isp->pdata->set_constraints(video->isp, false); media_entity_pipeline_stop(&video->video.entity); @@ -1326,14 +1322,8 @@ static unsigned int isp_video_poll(struct file *file, poll_table *wait) static int isp_video_mmap(struct file *file, struct vm_area_struct *vma) { struct isp_video_fh *vfh = to_isp_video_fh(file->private_data); - struct isp_video *video = video_drvdata(file); - int ret; - - mutex_lock(&video->queue_lock); - ret = vb2_mmap(&vfh->queue, vma); - mutex_unlock(&video->queue_lock); - return ret; + return vb2_mmap(&vfh->queue, vma); } static struct v4l2_file_operations isp_video_fops = { diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c index 54479d60cc0d..f6a61b9ceff4 100644 --- a/drivers/media/platform/s3c-camif/camif-capture.c +++ b/drivers/media/platform/s3c-camif/camif-capture.c @@ -1219,7 +1219,7 @@ static const u32 camif_mbus_formats[] = { */ static int s3c_camif_subdev_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->index >= ARRAY_SIZE(camif_mbus_formats)) @@ -1230,14 +1230,14 @@ static int s3c_camif_subdev_enum_mbus_code(struct v4l2_subdev *sd, } static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct camif_dev *camif = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *mf = &fmt->format; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(fh, fmt->pad); + mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); fmt->format = *mf; return 0; } @@ -1297,7 +1297,7 @@ static void __camif_subdev_try_format(struct camif_dev *camif, } static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct camif_dev *camif = v4l2_get_subdevdata(sd); @@ -1325,7 +1325,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd, __camif_subdev_try_format(camif, mf, fmt->pad); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(fh, fmt->pad); + mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); *mf = fmt->format; mutex_unlock(&camif->lock); return 0; @@ -1364,7 +1364,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd, } static int s3c_camif_subdev_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct camif_dev *camif = v4l2_get_subdevdata(sd); @@ -1377,7 +1377,7 @@ static int s3c_camif_subdev_get_selection(struct v4l2_subdev *sd, return -EINVAL; if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { - sel->r = *v4l2_subdev_get_try_crop(fh, sel->pad); + sel->r = *v4l2_subdev_get_try_crop(sd, cfg, sel->pad); return 0; } @@ -1451,7 +1451,7 @@ static void __camif_try_crop(struct camif_dev *camif, struct v4l2_rect *r) } static int s3c_camif_subdev_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct camif_dev *camif = v4l2_get_subdevdata(sd); @@ -1465,7 +1465,7 @@ static int s3c_camif_subdev_set_selection(struct v4l2_subdev *sd, __camif_try_crop(camif, &sel->r); if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_try_crop(fh, sel->pad) = sel->r; + *v4l2_subdev_get_try_crop(sd, cfg, sel->pad) = sel->r; } else { unsigned long flags; unsigned int i; diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index a92ff4249d10..bfbf1575677c 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c @@ -621,6 +621,7 @@ static int s5p_jpeg_to_user_subsampling(struct s5p_jpeg_ctx *ctx) return V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY; return ctx->subsampling; case SJPEG_EXYNOS3250: + case SJPEG_EXYNOS5420: if (ctx->subsampling > 3) return V4L2_JPEG_CHROMA_SUBSAMPLING_411; return exynos3250_decoded_subsampling[ctx->subsampling]; @@ -1142,13 +1143,13 @@ static void jpeg_bound_align_image(struct s5p_jpeg_ctx *ctx, w_step = 1 << walign; h_step = 1 << halign; - if (ctx->jpeg->variant->version == SJPEG_EXYNOS3250) { + if (ctx->jpeg->variant->hw3250_compat) { /* * Rightmost and bottommost pixels are cropped by the - * Exynos3250 JPEG IP for RGB formats, for the specific - * width and height values respectively. This assignment - * will result in v4l_bound_align_image returning dimensions - * reduced by 1 for the aforementioned cases. + * Exynos3250/compatible JPEG IP for RGB formats, for the + * specific width and height values respectively. This + * assignment will result in v4l_bound_align_image returning + * dimensions reduced by 1 for the aforementioned cases. */ if (w_step == 4 && ((width & 3) == 1)) { wmax = width; @@ -1384,12 +1385,12 @@ static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f) /* * Prevent downscaling to YUV420 format by more than 2 - * for Exynos3250 SoC as it produces broken raw image + * for Exynos3250/compatible SoC as it produces broken raw image * in such cases. */ if (ct->mode == S5P_JPEG_DECODE && f_type == FMT_TYPE_CAPTURE && - ct->jpeg->variant->version == SJPEG_EXYNOS3250 && + ct->jpeg->variant->hw3250_compat && pix->pixelformat == V4L2_PIX_FMT_YUV420 && ct->scale_factor > 2) { scale_rect.width = ct->out_q.w / 2; @@ -1569,12 +1570,12 @@ static int s5p_jpeg_s_selection(struct file *file, void *fh, if (s->target == V4L2_SEL_TGT_COMPOSE) { if (ctx->mode != S5P_JPEG_DECODE) return -EINVAL; - if (ctx->jpeg->variant->version == SJPEG_EXYNOS3250) + if (ctx->jpeg->variant->hw3250_compat) ret = exynos3250_jpeg_try_downscale(ctx, rect); } else if (s->target == V4L2_SEL_TGT_CROP) { if (ctx->mode != S5P_JPEG_ENCODE) return -EINVAL; - if (ctx->jpeg->variant->version == SJPEG_EXYNOS3250) + if (ctx->jpeg->variant->hw3250_compat) ret = exynos3250_jpeg_try_crop(ctx, rect); } @@ -1604,8 +1605,9 @@ static int s5p_jpeg_adjust_subs_ctrl(struct s5p_jpeg_ctx *ctx, int *ctrl_val) case SJPEG_S5P: return 0; case SJPEG_EXYNOS3250: + case SJPEG_EXYNOS5420: /* - * The exynos3250 device can produce JPEG image only + * The exynos3250/compatible device can produce JPEG image only * of 4:4:4 subsampling when given RGB32 source image. */ if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB32) @@ -1624,7 +1626,7 @@ static int s5p_jpeg_adjust_subs_ctrl(struct s5p_jpeg_ctx *ctx, int *ctrl_val) } /* - * The exynos4x12 and exynos3250 devices require resulting + * The exynos4x12 and exynos3250/compatible devices require resulting * jpeg subsampling not to be lower than the input raw image * subsampling. */ @@ -1842,7 +1844,7 @@ static void exynos4_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx) struct s5p_jpeg *jpeg = ctx->jpeg; struct s5p_jpeg_fmt *fmt; struct vb2_buffer *vb; - struct s5p_jpeg_addr jpeg_addr; + struct s5p_jpeg_addr jpeg_addr = {}; u32 pix_size, padding_bytes = 0; jpeg_addr.cb = 0; @@ -1946,7 +1948,7 @@ static void exynos3250_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx) struct s5p_jpeg *jpeg = ctx->jpeg; struct s5p_jpeg_fmt *fmt; struct vb2_buffer *vb; - struct s5p_jpeg_addr jpeg_addr; + struct s5p_jpeg_addr jpeg_addr = {}; u32 pix_size; pix_size = ctx->cap_q.w * ctx->cap_q.h; @@ -2020,6 +2022,16 @@ static void exynos3250_jpeg_device_run(void *priv) exynos3250_jpeg_qtbl(jpeg->regs, 2, 1); exynos3250_jpeg_qtbl(jpeg->regs, 3, 1); + /* + * Some SoCs require setting Huffman tables before each run + */ + if (jpeg->variant->htbl_reinit) { + s5p_jpeg_set_hdctbl(jpeg->regs); + s5p_jpeg_set_hdctblg(jpeg->regs); + s5p_jpeg_set_hactbl(jpeg->regs); + s5p_jpeg_set_hactblg(jpeg->regs); + } + /* Y, Cb, Cr use Huffman table 0 */ exynos3250_jpeg_htbl_ac(jpeg->regs, 1); exynos3250_jpeg_htbl_dc(jpeg->regs, 1); @@ -2663,13 +2675,12 @@ static int s5p_jpeg_runtime_resume(struct device *dev) /* * JPEG IP allows storing two Huffman tables for each component. * We fill table 0 for each component and do this here only - * for S5PC210 and Exynos3250 SoCs. Exynos4x12 SoC requires - * programming its Huffman tables each time the encoding process - * is initialized, and thus it is accomplished in the device_run - * callback of m2m_ops. + * for S5PC210 and Exynos3250 SoCs. Exynos4x12 and Exynos542x SoC + * require programming their Huffman tables each time the encoding + * process is initialized, and thus it is accomplished in the + * device_run callback of m2m_ops. */ - if (jpeg->variant->version == SJPEG_S5P || - jpeg->variant->version == SJPEG_EXYNOS3250) { + if (!jpeg->variant->htbl_reinit) { s5p_jpeg_set_hdctbl(jpeg->regs); s5p_jpeg_set_hdctblg(jpeg->regs); s5p_jpeg_set_hactbl(jpeg->regs); @@ -2717,6 +2728,7 @@ static struct s5p_jpeg_variant exynos3250_jpeg_drvdata = { .jpeg_irq = exynos3250_jpeg_irq, .m2m_ops = &exynos3250_jpeg_m2m_ops, .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS3250, + .hw3250_compat = 1, }; static struct s5p_jpeg_variant exynos4_jpeg_drvdata = { @@ -2724,6 +2736,16 @@ static struct s5p_jpeg_variant exynos4_jpeg_drvdata = { .jpeg_irq = exynos4_jpeg_irq, .m2m_ops = &exynos4_jpeg_m2m_ops, .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS4, + .htbl_reinit = 1, +}; + +static struct s5p_jpeg_variant exynos5420_jpeg_drvdata = { + .version = SJPEG_EXYNOS5420, + .jpeg_irq = exynos3250_jpeg_irq, /* intentionally 3250 */ + .m2m_ops = &exynos3250_jpeg_m2m_ops, /* intentionally 3250 */ + .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS3250, /* intentionally 3250 */ + .hw3250_compat = 1, + .htbl_reinit = 1, }; static const struct of_device_id samsung_jpeg_match[] = { @@ -2739,6 +2761,9 @@ static const struct of_device_id samsung_jpeg_match[] = { }, { .compatible = "samsung,exynos4212-jpeg", .data = &exynos4_jpeg_drvdata, + }, { + .compatible = "samsung,exynos5420-jpeg", + .data = &exynos5420_jpeg_drvdata, }, {}, }; diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.h b/drivers/media/platform/s5p-jpeg/jpeg-core.h index 764b32de326b..7d9a9ed19cea 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.h +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.h @@ -67,10 +67,12 @@ #define SJPEG_SUBSAMPLING_420 0x22 /* Version numbers */ - -#define SJPEG_S5P 1 -#define SJPEG_EXYNOS3250 2 -#define SJPEG_EXYNOS4 3 +enum sjpeg_version { + SJPEG_S5P, + SJPEG_EXYNOS3250, + SJPEG_EXYNOS4, + SJPEG_EXYNOS5420, +}; enum exynos4_jpeg_result { OK_ENC_OR_DEC, @@ -130,6 +132,8 @@ struct s5p_jpeg { struct s5p_jpeg_variant { unsigned int version; unsigned int fmt_ver_flag; + unsigned int hw3250_compat:1; + unsigned int htbl_reinit:1; struct v4l2_m2m_ops *m2m_ops; irqreturn_t (*jpeg_irq)(int irq, void *priv); }; diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c index e3b8e67e005f..b5f20e722b63 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c @@ -51,18 +51,6 @@ void s5p_jpeg_input_raw_mode(void __iomem *regs, unsigned long mode) writel(reg, regs + S5P_JPGCMOD); } -void s5p_jpeg_input_raw_y16(void __iomem *regs, bool y16) -{ - unsigned long reg; - - reg = readl(regs + S5P_JPGCMOD); - if (y16) - reg |= S5P_MODE_Y16; - else - reg &= ~S5P_MODE_Y16_MASK; - writel(reg, regs + S5P_JPGCMOD); -} - void s5p_jpeg_proc_mode(void __iomem *regs, unsigned long mode) { unsigned long reg, m; @@ -208,26 +196,6 @@ void s5p_jpeg_final_mcu_num_int_enable(void __iomem *regs, bool enbl) writel(reg, regs + S5P_JPGINTSE); } -void s5p_jpeg_timer_enable(void __iomem *regs, unsigned long val) -{ - unsigned long reg; - - reg = readl(regs + S5P_JPG_TIMER_SE); - reg |= S5P_TIMER_INT_EN; - reg &= ~S5P_TIMER_INIT_MASK; - reg |= val & S5P_TIMER_INIT_MASK; - writel(reg, regs + S5P_JPG_TIMER_SE); -} - -void s5p_jpeg_timer_disable(void __iomem *regs) -{ - unsigned long reg; - - reg = readl(regs + S5P_JPG_TIMER_SE); - reg &= ~S5P_TIMER_INT_EN_MASK; - writel(reg, regs + S5P_JPG_TIMER_SE); -} - int s5p_jpeg_timer_stat(void __iomem *regs) { return (int)((readl(regs + S5P_JPG_TIMER_ST) & S5P_TIMER_INT_STAT_MASK) diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h index c11ebe86b9c9..f208fa3ed738 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h +++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h @@ -29,7 +29,6 @@ void s5p_jpeg_reset(void __iomem *regs); void s5p_jpeg_poweron(void __iomem *regs); void s5p_jpeg_input_raw_mode(void __iomem *regs, unsigned long mode); -void s5p_jpeg_input_raw_y16(void __iomem *regs, bool y16); void s5p_jpeg_proc_mode(void __iomem *regs, unsigned long mode); void s5p_jpeg_subsampling_mode(void __iomem *regs, unsigned int mode); unsigned int s5p_jpeg_get_subsampling_mode(void __iomem *regs); @@ -42,8 +41,6 @@ void s5p_jpeg_x(void __iomem *regs, unsigned int x); void s5p_jpeg_rst_int_enable(void __iomem *regs, bool enable); void s5p_jpeg_data_num_int_enable(void __iomem *regs, bool enable); void s5p_jpeg_final_mcu_num_int_enable(void __iomem *regs, bool enbl); -void s5p_jpeg_timer_enable(void __iomem *regs, unsigned long val); -void s5p_jpeg_timer_disable(void __iomem *regs); int s5p_jpeg_timer_stat(void __iomem *regs); void s5p_jpeg_clear_timer_stat(void __iomem *regs); void s5p_jpeg_enc_stream_int(void __iomem *regs, unsigned long size); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 98374e8bad3e..8333fbc2fe96 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -844,6 +844,13 @@ static int s5p_mfc_open(struct file *file) ret = -ENOENT; goto err_queue_init; } + /* One way to indicate end-of-stream for MFC is to set the + * bytesused == 0. However by default videobuf2 handles bytesused + * equal to 0 as a special case and changes its value to the size + * of the buffer. Set the allow_zero_bytesused flag so that videobuf2 + * will keep the value of bytesused intact. + */ + q->allow_zero_bytesused = 1; q->mem_ops = &vb2_dma_contig_memops; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ret = vb2_queue_init(q); diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c index 72d4f2e1efc0..751f3b618337 100644 --- a/drivers/media/platform/s5p-tv/mixer_video.c +++ b/drivers/media/platform/s5p-tv/mixer_video.c @@ -287,7 +287,7 @@ static void mxr_mplane_fill(struct v4l2_plane_pix_format *planes, u32 bl_width = divup(width, blk->width); u32 bl_height = divup(height, blk->height); u32 sizeimage = bl_width * bl_height * blk->size; - u16 bytesperline = bl_width * blk->size / blk->height; + u32 bytesperline = bl_width * blk->size / blk->height; plane->sizeimage += sizeimage; plane->bytesperline = max(plane->bytesperline, bytesperline); diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index 261f1195b49f..dde1ccc730be 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -62,7 +62,7 @@ enum sh_vou_status { struct sh_vou_device { struct v4l2_device v4l2_dev; - struct video_device *vdev; + struct video_device vdev; atomic_t use_count; struct sh_vou_pdata *pdata; spinlock_t lock; @@ -890,7 +890,7 @@ static int sh_vou_s_std(struct file *file, void *priv, v4l2_std_id std_id) dev_dbg(vou_dev->v4l2_dev.dev, "%s(): 0x%llx\n", __func__, std_id); - if (std_id & ~vou_dev->vdev->tvnorms) + if (std_id & ~vou_dev->vdev.tvnorms) return -EINVAL; ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video, @@ -1168,10 +1168,10 @@ static int sh_vou_open(struct file *file) dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - file->private_data = vou_file; - - if (mutex_lock_interruptible(&vou_dev->fop_lock)) + if (mutex_lock_interruptible(&vou_dev->fop_lock)) { + kfree(vou_file); return -ERESTARTSYS; + } if (atomic_inc_return(&vou_dev->use_count) == 1) { int ret; /* First open */ @@ -1183,6 +1183,7 @@ static int sh_vou_open(struct file *file) pm_runtime_put(vou_dev->v4l2_dev.dev); vou_dev->status = SH_VOU_IDLE; mutex_unlock(&vou_dev->fop_lock); + kfree(vou_file); return ret; } } @@ -1192,9 +1193,11 @@ static int sh_vou_open(struct file *file) V4L2_BUF_TYPE_VIDEO_OUTPUT, V4L2_FIELD_NONE, sizeof(struct videobuf_buffer), - vou_dev->vdev, &vou_dev->fop_lock); + &vou_dev->vdev, &vou_dev->fop_lock); mutex_unlock(&vou_dev->fop_lock); + file->private_data = vou_file; + return 0; } @@ -1358,21 +1361,14 @@ static int sh_vou_probe(struct platform_device *pdev) goto ev4l2devreg; } - /* Allocate memory for video device */ - vdev = video_device_alloc(); - if (vdev == NULL) { - ret = -ENOMEM; - goto evdevalloc; - } - + vdev = &vou_dev->vdev; *vdev = sh_vou_video_template; if (vou_pdata->bus_fmt == SH_VOU_BUS_8BIT) vdev->tvnorms |= V4L2_STD_PAL; vdev->v4l2_dev = &vou_dev->v4l2_dev; - vdev->release = video_device_release; + vdev->release = video_device_release_empty; vdev->lock = &vou_dev->fop_lock; - vou_dev->vdev = vdev; video_set_drvdata(vdev, vou_dev); pm_runtime_enable(&pdev->dev); @@ -1406,9 +1402,7 @@ ei2cnd: ereset: i2c_put_adapter(i2c_adap); ei2cgadap: - video_device_release(vdev); pm_runtime_disable(&pdev->dev); -evdevalloc: v4l2_device_unregister(&vou_dev->v4l2_dev); ev4l2devreg: free_irq(irq, vou_dev); @@ -1435,7 +1429,7 @@ static int sh_vou_remove(struct platform_device *pdev) if (irq > 0) free_irq(irq, vou_dev); pm_runtime_disable(&pdev->dev); - video_unregister_device(vou_dev->vdev); + video_unregister_device(&vou_dev->vdev); i2c_put_adapter(client->adapter); v4l2_device_unregister(&vou_dev->v4l2_dev); iounmap(vou_dev->base); diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c index 279ab9f6ae38..9351f64dee7b 100644 --- a/drivers/media/platform/soc_camera/rcar_vin.c +++ b/drivers/media/platform/soc_camera/rcar_vin.c @@ -977,19 +977,6 @@ static void rcar_vin_remove_device(struct soc_camera_device *icd) icd->devnum); } -/* Called with .host_lock held */ -static int rcar_vin_clock_start(struct soc_camera_host *ici) -{ - /* VIN does not have "mclk" */ - return 0; -} - -/* Called with .host_lock held */ -static void rcar_vin_clock_stop(struct soc_camera_host *ici) -{ - /* VIN does not have "mclk" */ -} - static void set_coeff(struct rcar_vin_priv *priv, unsigned short xs) { int i; @@ -1803,8 +1790,6 @@ static struct soc_camera_host_ops rcar_vin_host_ops = { .owner = THIS_MODULE, .add = rcar_vin_add_device, .remove = rcar_vin_remove_device, - .clock_start = rcar_vin_clock_start, - .clock_stop = rcar_vin_clock_stop, .get_formats = rcar_vin_get_formats, .put_formats = rcar_vin_put_formats, .get_crop = rcar_vin_get_crop, diff --git a/drivers/media/platform/soc_camera/sh_mobile_csi2.c b/drivers/media/platform/soc_camera/sh_mobile_csi2.c index c4e7aa0ee7e1..cd93241eb497 100644 --- a/drivers/media/platform/soc_camera/sh_mobile_csi2.c +++ b/drivers/media/platform/soc_camera/sh_mobile_csi2.c @@ -380,7 +380,6 @@ static int sh_csi2_remove(struct platform_device *pdev) struct sh_csi2 *priv = container_of(subdev, struct sh_csi2, subdev); v4l2_async_unregister_subdev(&priv->subdev); - v4l2_device_unregister_subdev(subdev); pm_runtime_disable(&pdev->dev); return 0; diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 66634b469c98..55370d74ff57 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -177,6 +177,30 @@ static int __soc_camera_power_off(struct soc_camera_device *icd) return 0; } +static int soc_camera_clock_start(struct soc_camera_host *ici) +{ + int ret; + + if (!ici->ops->clock_start) + return 0; + + mutex_lock(&ici->clk_lock); + ret = ici->ops->clock_start(ici); + mutex_unlock(&ici->clk_lock); + + return ret; +} + +static void soc_camera_clock_stop(struct soc_camera_host *ici) +{ + if (!ici->ops->clock_stop) + return; + + mutex_lock(&ici->clk_lock); + ici->ops->clock_stop(ici); + mutex_unlock(&ici->clk_lock); +} + const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc( struct soc_camera_device *icd, unsigned int fourcc) { @@ -584,9 +608,7 @@ static int soc_camera_add_device(struct soc_camera_device *icd) return -EBUSY; if (!icd->clk) { - mutex_lock(&ici->clk_lock); - ret = ici->ops->clock_start(ici); - mutex_unlock(&ici->clk_lock); + ret = soc_camera_clock_start(ici); if (ret < 0) return ret; } @@ -602,11 +624,8 @@ static int soc_camera_add_device(struct soc_camera_device *icd) return 0; eadd: - if (!icd->clk) { - mutex_lock(&ici->clk_lock); - ici->ops->clock_stop(ici); - mutex_unlock(&ici->clk_lock); - } + if (!icd->clk) + soc_camera_clock_stop(ici); return ret; } @@ -619,11 +638,8 @@ static void soc_camera_remove_device(struct soc_camera_device *icd) if (ici->ops->remove) ici->ops->remove(icd); - if (!icd->clk) { - mutex_lock(&ici->clk_lock); - ici->ops->clock_stop(ici); - mutex_unlock(&ici->clk_lock); - } + if (!icd->clk) + soc_camera_clock_stop(ici); ici->icd = NULL; } @@ -688,7 +704,8 @@ static int soc_camera_open(struct file *file) /* The camera could have been already on, try to reset */ if (sdesc->subdev_desc.reset) - sdesc->subdev_desc.reset(icd->pdev); + if (icd->control) + sdesc->subdev_desc.reset(icd->control); ret = soc_camera_add_device(icd); if (ret < 0) { @@ -1159,7 +1176,8 @@ static void scan_add_host(struct soc_camera_host *ici) /* The camera could have been already on, try to reset */ if (ssdd->reset) - ssdd->reset(icd->pdev); + if (icd->control) + ssdd->reset(icd->control); icd->parent = ici->v4l2_dev.dev; @@ -1178,7 +1196,6 @@ static int soc_camera_clk_enable(struct v4l2_clk *clk) { struct soc_camera_device *icd = clk->priv; struct soc_camera_host *ici; - int ret; if (!icd || !icd->parent) return -ENODEV; @@ -1192,10 +1209,7 @@ static int soc_camera_clk_enable(struct v4l2_clk *clk) * If a different client is currently being probed, the host will tell * you to go */ - mutex_lock(&ici->clk_lock); - ret = ici->ops->clock_start(ici); - mutex_unlock(&ici->clk_lock); - return ret; + return soc_camera_clock_start(ici); } static void soc_camera_clk_disable(struct v4l2_clk *clk) @@ -1208,9 +1222,7 @@ static void soc_camera_clk_disable(struct v4l2_clk *clk) ici = to_soc_camera_host(icd->parent); - mutex_lock(&ici->clk_lock); - ici->ops->clock_stop(ici); - mutex_unlock(&ici->clk_lock); + soc_camera_clock_stop(ici); module_put(ici->ops->owner); } @@ -1364,7 +1376,7 @@ static int soc_camera_i2c_init(struct soc_camera_device *icd, snprintf(clk_name, sizeof(clk_name), "%d-%04x", shd->i2c_adapter_id, shd->board_info->addr); - icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, "mclk", icd); + icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, icd); if (IS_ERR(icd->clk)) { ret = PTR_ERR(icd->clk); goto eclkreg; @@ -1445,7 +1457,7 @@ static int soc_camera_async_bound(struct v4l2_async_notifier *notifier, memcpy(&sdesc->subdev_desc, ssdd, sizeof(sdesc->subdev_desc)); if (ssdd->reset) - ssdd->reset(icd->pdev); + ssdd->reset(&client->dev); } icd->control = &client->dev; @@ -1545,7 +1557,7 @@ static int scan_async_group(struct soc_camera_host *ici, snprintf(clk_name, sizeof(clk_name), "%d-%04x", sasd->asd.match.i2c.adapter_id, sasd->asd.match.i2c.address); - icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, "mclk", icd); + icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, icd); if (IS_ERR(icd->clk)) { ret = PTR_ERR(icd->clk); goto eclkreg; @@ -1650,7 +1662,7 @@ static int soc_of_bind(struct soc_camera_host *ici, snprintf(clk_name, sizeof(clk_name), "of-%s", of_node_full_name(remote)); - icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, "mclk", icd); + icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, icd); if (IS_ERR(icd->clk)) { ret = PTR_ERR(icd->clk); goto eclkreg; @@ -1659,6 +1671,8 @@ static int soc_of_bind(struct soc_camera_host *ici, ret = v4l2_async_notifier_register(&ici->v4l2_dev, &sasc->notifier); if (!ret) return 0; + + v4l2_clk_unregister(icd->clk); eclkreg: icd->clk = NULL; platform_device_del(sasc->pdev); @@ -1750,9 +1764,7 @@ static int soc_camera_probe(struct soc_camera_host *ici, ret = -EINVAL; goto eadd; } else { - mutex_lock(&ici->clk_lock); - ret = ici->ops->clock_start(ici); - mutex_unlock(&ici->clk_lock); + ret = soc_camera_clock_start(ici); if (ret < 0) goto eadd; @@ -1792,9 +1804,7 @@ efinish: module_put(control->driver->owner); enodrv: eadddev: - mutex_lock(&ici->clk_lock); - ici->ops->clock_stop(ici); - mutex_unlock(&ici->clk_lock); + soc_camera_clock_stop(ici); } eadd: if (icd->vdev) { @@ -1888,22 +1898,34 @@ static int default_enum_framesizes(struct soc_camera_device *icd, int ret; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); const struct soc_camera_format_xlate *xlate; - __u32 pixfmt = fsize->pixel_format; - struct v4l2_frmsizeenum fsize_mbus = *fsize; + struct v4l2_subdev_frame_size_enum fse = { + .index = fsize->index, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; - xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); + xlate = soc_camera_xlate_by_fourcc(icd, fsize->pixel_format); if (!xlate) return -EINVAL; - /* map xlate-code to pixel_format, sensor only handle xlate-code*/ - fsize_mbus.pixel_format = xlate->code; + fse.code = xlate->code; - ret = v4l2_subdev_call(sd, video, enum_framesizes, &fsize_mbus); + ret = v4l2_subdev_call(sd, pad, enum_frame_size, NULL, &fse); if (ret < 0) return ret; - *fsize = fsize_mbus; - fsize->pixel_format = pixfmt; - + if (fse.min_width == fse.max_width && + fse.min_height == fse.max_height) { + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fsize->discrete.width = fse.min_width; + fsize->discrete.height = fse.min_height; + return 0; + } + fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; + fsize->stepwise.min_width = fse.min_width; + fsize->stepwise.max_width = fse.max_width; + fsize->stepwise.min_height = fse.min_height; + fsize->stepwise.max_height = fse.max_height; + fsize->stepwise.step_width = 1; + fsize->stepwise.step_height = 1; return 0; } @@ -1920,8 +1942,6 @@ int soc_camera_host_register(struct soc_camera_host *ici) ((!ici->ops->init_videobuf || !ici->ops->reqbufs) && !ici->ops->init_videobuf2) || - !ici->ops->clock_start || - !ici->ops->clock_stop || !ici->ops->poll || !ici->v4l2_dev.dev) return -EINVAL; diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c index 86989d86abfa..678ed9f353cb 100644 --- a/drivers/media/platform/via-camera.c +++ b/drivers/media/platform/via-camera.c @@ -1147,12 +1147,23 @@ static int viacam_enum_frameintervals(struct file *filp, void *priv, struct v4l2_frmivalenum *interval) { struct via_camera *cam = priv; + struct v4l2_subdev_frame_interval_enum fie = { + .index = interval->index, + .code = cam->mbus_code, + .width = cam->sensor_format.width, + .height = cam->sensor_format.height, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; int ret; mutex_lock(&cam->lock); - ret = sensor_call(cam, video, enum_frameintervals, interval); + ret = sensor_call(cam, pad, enum_frame_interval, NULL, &fie); mutex_unlock(&cam->lock); - return ret; + if (ret) + return ret; + interval->type = V4L2_FRMIVAL_TYPE_DISCRETE; + interval->discrete = fie.interval; + return 0; } diff --git a/drivers/media/platform/vim2m.c b/drivers/media/platform/vim2m.c index d9d844aab39b..4d6b4cc57c57 100644 --- a/drivers/media/platform/vim2m.c +++ b/drivers/media/platform/vim2m.c @@ -142,7 +142,7 @@ static struct vim2m_fmt *find_format(struct v4l2_format *f) struct vim2m_dev { struct v4l2_device v4l2_dev; - struct video_device *vfd; + struct video_device vfd; atomic_t num_inst; struct mutex dev_mutex; @@ -968,7 +968,7 @@ static struct video_device vim2m_videodev = { .fops = &vim2m_fops, .ioctl_ops = &vim2m_ioctl_ops, .minor = -1, - .release = video_device_release, + .release = video_device_release_empty, }; static struct v4l2_m2m_ops m2m_ops = { @@ -996,26 +996,19 @@ static int vim2m_probe(struct platform_device *pdev) atomic_set(&dev->num_inst, 0); mutex_init(&dev->dev_mutex); - vfd = video_device_alloc(); - if (!vfd) { - v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n"); - ret = -ENOMEM; - goto unreg_dev; - } - - *vfd = vim2m_videodev; + dev->vfd = vim2m_videodev; + vfd = &dev->vfd; vfd->lock = &dev->dev_mutex; vfd->v4l2_dev = &dev->v4l2_dev; ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); if (ret) { v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); - goto rel_vdev; + goto unreg_dev; } video_set_drvdata(vfd, dev); snprintf(vfd->name, sizeof(vfd->name), "%s", vim2m_videodev.name); - dev->vfd = vfd; v4l2_info(&dev->v4l2_dev, "Device registered as /dev/video%d\n", vfd->num); @@ -1033,9 +1026,7 @@ static int vim2m_probe(struct platform_device *pdev) err_m2m: v4l2_m2m_release(dev->m2m_dev); - video_unregister_device(dev->vfd); -rel_vdev: - video_device_release(vfd); + video_unregister_device(&dev->vfd); unreg_dev: v4l2_device_unregister(&dev->v4l2_dev); @@ -1049,7 +1040,7 @@ static int vim2m_remove(struct platform_device *pdev) v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME); v4l2_m2m_release(dev->m2m_dev); del_timer_sync(&dev->timer); - video_unregister_device(dev->vfd); + video_unregister_device(&dev->vfd); v4l2_device_unregister(&dev->v4l2_dev); return 0; diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index a7e033a5d291..d33f16495dbc 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c @@ -26,6 +26,7 @@ #include <linux/vmalloc.h> #include <linux/font.h> #include <linux/mutex.h> +#include <linux/platform_device.h> #include <linux/videodev2.h> #include <linux/v4l2-dv-timings.h> #include <media/videobuf2-vmalloc.h> @@ -618,7 +619,23 @@ static const struct v4l2_ioctl_ops vivid_ioctl_ops = { Initialization and module stuff ------------------------------------------------------------------*/ -static int __init vivid_create_instance(int inst) +static void vivid_dev_release(struct v4l2_device *v4l2_dev) +{ + struct vivid_dev *dev = container_of(v4l2_dev, struct vivid_dev, v4l2_dev); + + vivid_free_controls(dev); + v4l2_device_unregister(&dev->v4l2_dev); + vfree(dev->scaled_line); + vfree(dev->blended_line); + vfree(dev->edid); + vfree(dev->bitmap_cap); + vfree(dev->bitmap_out); + tpg_free(&dev->tpg); + kfree(dev->query_dv_timings_qmenu); + kfree(dev); +} + +static int vivid_create_instance(struct platform_device *pdev, int inst) { static const struct v4l2_dv_timings def_dv_timings = V4L2_DV_BT_CEA_1280X720P60; @@ -646,9 +663,12 @@ static int __init vivid_create_instance(int inst) /* register v4l2_device */ snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s-%03d", VIVID_MODULE_NAME, inst); - ret = v4l2_device_register(NULL, &dev->v4l2_dev); - if (ret) - goto free_dev; + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); + if (ret) { + kfree(dev); + return ret; + } + dev->v4l2_dev.release = vivid_dev_release; /* start detecting feature set */ @@ -1256,15 +1276,8 @@ unreg_dev: video_unregister_device(&dev->vbi_cap_dev); video_unregister_device(&dev->vid_out_dev); video_unregister_device(&dev->vid_cap_dev); - vivid_free_controls(dev); - v4l2_device_unregister(&dev->v4l2_dev); free_dev: - vfree(dev->scaled_line); - vfree(dev->blended_line); - vfree(dev->edid); - tpg_free(&dev->tpg); - kfree(dev->query_dv_timings_qmenu); - kfree(dev); + v4l2_device_put(&dev->v4l2_dev); return ret; } @@ -1274,7 +1287,7 @@ free_dev: will succeed. This is limited to the maximum number of devices that videodev supports, which is equal to VIDEO_NUM_DEVICES. */ -static int __init vivid_init(void) +static int vivid_probe(struct platform_device *pdev) { const struct font_desc *font = find_font("VGA8x16"); int ret = 0, i; @@ -1289,7 +1302,7 @@ static int __init vivid_init(void) n_devs = clamp_t(unsigned, n_devs, 1, VIVID_MAX_DEVS); for (i = 0; i < n_devs; i++) { - ret = vivid_create_instance(i); + ret = vivid_create_instance(pdev, i); if (ret) { /* If some instantiations succeeded, keep driver */ if (i) @@ -1309,7 +1322,7 @@ static int __init vivid_init(void) return ret; } -static void __exit vivid_exit(void) +static int vivid_remove(struct platform_device *pdev) { struct vivid_dev *dev; unsigned i; @@ -1358,18 +1371,48 @@ static void __exit vivid_exit(void) unregister_framebuffer(&dev->fb_info); vivid_fb_release_buffers(dev); } - v4l2_device_unregister(&dev->v4l2_dev); - vivid_free_controls(dev); - vfree(dev->scaled_line); - vfree(dev->blended_line); - vfree(dev->edid); - vfree(dev->bitmap_cap); - vfree(dev->bitmap_out); - tpg_free(&dev->tpg); - kfree(dev->query_dv_timings_qmenu); - kfree(dev); + v4l2_device_put(&dev->v4l2_dev); vivid_devs[i] = NULL; } + return 0; +} + +static void vivid_pdev_release(struct device *dev) +{ +} + +static struct platform_device vivid_pdev = { + .name = "vivid", + .dev.release = vivid_pdev_release, +}; + +static struct platform_driver vivid_pdrv = { + .probe = vivid_probe, + .remove = vivid_remove, + .driver = { + .name = "vivid", + }, +}; + +static int __init vivid_init(void) +{ + int ret; + + ret = platform_device_register(&vivid_pdev); + if (ret) + return ret; + + ret = platform_driver_register(&vivid_pdrv); + if (ret) + platform_device_unregister(&vivid_pdev); + + return ret; +} + +static void __exit vivid_exit(void) +{ + platform_driver_unregister(&vivid_pdrv); + platform_device_unregister(&vivid_pdev); } module_init(vivid_init); diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h index 4b497df4b6a4..9e15aee9a52e 100644 --- a/drivers/media/platform/vivid/vivid-core.h +++ b/drivers/media/platform/vivid/vivid-core.h @@ -79,12 +79,14 @@ extern unsigned vivid_debug; struct vivid_fmt { const char *name; u32 fourcc; /* v4l2 format id */ - u8 depth; bool is_yuv; bool can_do_overlay; + u8 vdownsampling[TPG_MAX_PLANES]; u32 alpha_mask; u8 planes; - u32 data_offset[2]; + u8 buffers; + u32 data_offset[TPG_MAX_PLANES]; + u32 bit_depth[TPG_MAX_PLANES]; }; extern struct vivid_fmt vivid_formats[]; @@ -332,7 +334,7 @@ struct vivid_dev { u32 ycbcr_enc_out; u32 quantization_out; u32 service_set_out; - u32 bytesperline_out[2]; + unsigned bytesperline_out[TPG_MAX_PLANES]; unsigned tv_field_out; unsigned tv_audio_output; bool vbi_out_have_wss; diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c index 32a798f2d953..2b9070098b08 100644 --- a/drivers/media/platform/vivid/vivid-ctrls.c +++ b/drivers/media/platform/vivid/vivid-ctrls.c @@ -818,7 +818,7 @@ static int vivid_vid_out_s_ctrl(struct v4l2_ctrl *ctrl) dev->dvi_d_out = ctrl->val == V4L2_DV_TX_MODE_DVI_D; if (!vivid_is_hdmi_out(dev)) break; - if (!dev->dvi_d_out && (bt->standards & V4L2_DV_BT_STD_CEA861)) { + if (!dev->dvi_d_out && (bt->flags & V4L2_DV_FL_IS_CE_VIDEO)) { if (bt->width == 720 && bt->height <= 576) dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M; else diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c index 39a67cfae120..1727f5453f0b 100644 --- a/drivers/media/platform/vivid/vivid-kthread-cap.c +++ b/drivers/media/platform/vivid/vivid-kthread-cap.c @@ -229,14 +229,29 @@ static void vivid_precalc_copy_rects(struct vivid_dev *dev) dev->loop_vid_overlay_cap.left, dev->loop_vid_overlay_cap.top); } +static void *plane_vaddr(struct tpg_data *tpg, struct vivid_buffer *buf, + unsigned p, unsigned bpl[TPG_MAX_PLANES], unsigned h) +{ + unsigned i; + void *vbuf; + + if (p == 0 || tpg_g_buffers(tpg) > 1) + return vb2_plane_vaddr(&buf->vb, p); + vbuf = vb2_plane_vaddr(&buf->vb, 0); + for (i = 0; i < p; i++) + vbuf += bpl[i] * h / tpg->vdownsampling[i]; + return vbuf; +} + static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf, struct vivid_buffer *vid_cap_buf) { bool blank = dev->must_blank[vid_cap_buf->vb.v4l2_buf.index]; struct tpg_data *tpg = &dev->tpg; struct vivid_buffer *vid_out_buf = NULL; - unsigned pixsize = tpg_g_twopixelsize(tpg, p) / 2; - unsigned img_width = dev->compose_cap.width; + unsigned vdiv = dev->fmt_out->vdownsampling[p]; + unsigned twopixsize = tpg_g_twopixelsize(tpg, p); + unsigned img_width = tpg_hdiv(tpg, p, dev->compose_cap.width); unsigned img_height = dev->compose_cap.height; unsigned stride_cap = tpg->bytesperline[p]; unsigned stride_out = dev->bytesperline_out[p]; @@ -255,6 +270,7 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf, unsigned vid_overlay_fract_part = 0; unsigned vid_overlay_y = 0; unsigned vid_overlay_error = 0; + unsigned vid_cap_left = tpg_hdiv(tpg, p, dev->loop_vid_cap.left); unsigned vid_cap_right; bool quick; @@ -269,25 +285,29 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf, vid_cap_buf->vb.v4l2_buf.field = vid_out_buf->vb.v4l2_buf.field; - voutbuf = vb2_plane_vaddr(&vid_out_buf->vb, p) + - vid_out_buf->vb.v4l2_planes[p].data_offset; - voutbuf += dev->loop_vid_out.left * pixsize + dev->loop_vid_out.top * stride_out; - vcapbuf += dev->compose_cap.left * pixsize + dev->compose_cap.top * stride_cap; + voutbuf = plane_vaddr(tpg, vid_out_buf, p, + dev->bytesperline_out, dev->fmt_out_rect.height); + if (p < dev->fmt_out->buffers) + voutbuf += vid_out_buf->vb.v4l2_planes[p].data_offset; + voutbuf += tpg_hdiv(tpg, p, dev->loop_vid_out.left) + + (dev->loop_vid_out.top / vdiv) * stride_out; + vcapbuf += tpg_hdiv(tpg, p, dev->compose_cap.left) + + (dev->compose_cap.top / vdiv) * stride_cap; if (dev->loop_vid_copy.width == 0 || dev->loop_vid_copy.height == 0) { /* * If there is nothing to copy, then just fill the capture window * with black. */ - for (y = 0; y < hmax; y++, vcapbuf += stride_cap) - memcpy(vcapbuf, tpg->black_line[p], img_width * pixsize); + for (y = 0; y < hmax / vdiv; y++, vcapbuf += stride_cap) + memcpy(vcapbuf, tpg->black_line[p], img_width); return 0; } if (dev->overlay_out_enabled && dev->loop_vid_overlay.width && dev->loop_vid_overlay.height) { vosdbuf = dev->video_vbase; - vosdbuf += dev->loop_fb_copy.left * pixsize + + vosdbuf += (dev->loop_fb_copy.left * twopixsize) / 2 + dev->loop_fb_copy.top * stride_osd; vid_overlay_int_part = dev->loop_vid_overlay.height / dev->loop_vid_overlay_cap.height; @@ -295,12 +315,12 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf, dev->loop_vid_overlay_cap.height; } - vid_cap_right = dev->loop_vid_cap.left + dev->loop_vid_cap.width; + vid_cap_right = tpg_hdiv(tpg, p, dev->loop_vid_cap.left + dev->loop_vid_cap.width); /* quick is true if no video scaling is needed */ quick = dev->loop_vid_out.width == dev->loop_vid_cap.width; dev->cur_scaled_line = dev->loop_vid_out.height; - for (y = 0; y < hmax; y++, vcapbuf += stride_cap) { + for (y = 0; y < hmax; y += vdiv, vcapbuf += stride_cap) { /* osdline is true if this line requires overlay blending */ bool osdline = vosdbuf && y >= dev->loop_vid_overlay_cap.top && y < dev->loop_vid_overlay_cap.top + dev->loop_vid_overlay_cap.height; @@ -311,34 +331,34 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf, */ if (y < dev->loop_vid_cap.top || y >= dev->loop_vid_cap.top + dev->loop_vid_cap.height) { - memcpy(vcapbuf, tpg->black_line[p], img_width * pixsize); + memcpy(vcapbuf, tpg->black_line[p], img_width); continue; } /* fill the left border with black */ if (dev->loop_vid_cap.left) - memcpy(vcapbuf, tpg->black_line[p], dev->loop_vid_cap.left * pixsize); + memcpy(vcapbuf, tpg->black_line[p], vid_cap_left); /* fill the right border with black */ if (vid_cap_right < img_width) - memcpy(vcapbuf + vid_cap_right * pixsize, - tpg->black_line[p], (img_width - vid_cap_right) * pixsize); + memcpy(vcapbuf + vid_cap_right, tpg->black_line[p], + img_width - vid_cap_right); if (quick && !osdline) { - memcpy(vcapbuf + dev->loop_vid_cap.left * pixsize, + memcpy(vcapbuf + vid_cap_left, voutbuf + vid_out_y * stride_out, - dev->loop_vid_cap.width * pixsize); + tpg_hdiv(tpg, p, dev->loop_vid_cap.width)); goto update_vid_out_y; } if (dev->cur_scaled_line == vid_out_y) { - memcpy(vcapbuf + dev->loop_vid_cap.left * pixsize, - dev->scaled_line, - dev->loop_vid_cap.width * pixsize); + memcpy(vcapbuf + vid_cap_left, dev->scaled_line, + tpg_hdiv(tpg, p, dev->loop_vid_cap.width)); goto update_vid_out_y; } if (!osdline) { scale_line(voutbuf + vid_out_y * stride_out, dev->scaled_line, - dev->loop_vid_out.width, dev->loop_vid_cap.width, + tpg_hdiv(tpg, p, dev->loop_vid_out.width), + tpg_hdiv(tpg, p, dev->loop_vid_cap.width), tpg_g_twopixelsize(tpg, p)); } else { /* @@ -346,7 +366,8 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf, * loop_vid_overlay rectangle. */ unsigned offset = - (dev->loop_vid_overlay.left - dev->loop_vid_copy.left) * pixsize; + ((dev->loop_vid_overlay.left - dev->loop_vid_copy.left) * + twopixsize) / 2; u8 *osd = vosdbuf + vid_overlay_y * stride_osd; scale_line(voutbuf + vid_out_y * stride_out, dev->blended_line, @@ -356,18 +377,17 @@ static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf, blend_line(dev, vid_overlay_y + dev->loop_vid_overlay.top, dev->loop_vid_overlay.left, dev->blended_line + offset, osd, - dev->loop_vid_overlay.width, pixsize); + dev->loop_vid_overlay.width, twopixsize / 2); else memcpy(dev->blended_line + offset, - osd, dev->loop_vid_overlay.width * pixsize); + osd, (dev->loop_vid_overlay.width * twopixsize) / 2); scale_line(dev->blended_line, dev->scaled_line, dev->loop_vid_copy.width, dev->loop_vid_cap.width, tpg_g_twopixelsize(tpg, p)); } dev->cur_scaled_line = vid_out_y; - memcpy(vcapbuf + dev->loop_vid_cap.left * pixsize, - dev->scaled_line, - dev->loop_vid_cap.width * pixsize); + memcpy(vcapbuf + vid_cap_left, dev->scaled_line, + tpg_hdiv(tpg, p, dev->loop_vid_cap.width)); update_vid_out_y: if (osdline) { @@ -380,21 +400,22 @@ update_vid_out_y: } vid_out_y += vid_out_int_part; vid_out_error += vid_out_fract_part; - if (vid_out_error >= dev->loop_vid_cap.height) { - vid_out_error -= dev->loop_vid_cap.height; + if (vid_out_error >= dev->loop_vid_cap.height / vdiv) { + vid_out_error -= dev->loop_vid_cap.height / vdiv; vid_out_y++; } } if (!blank) return 0; - for (; y < img_height; y++, vcapbuf += stride_cap) - memcpy(vcapbuf, tpg->contrast_line[p], img_width * pixsize); + for (; y < img_height; y += vdiv, vcapbuf += stride_cap) + memcpy(vcapbuf, tpg->contrast_line[p], img_width); return 0; } static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf) { + struct tpg_data *tpg = &dev->tpg; unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_cap) ? 2 : 1; unsigned line_height = 16 / factor; bool is_tv = vivid_is_sdtv_cap(dev); @@ -427,7 +448,7 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf) * standards. */ buf->vb.v4l2_buf.field = ((dev->vid_cap_seq_count & 1) ^ is_60hz) ? - V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM; + V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP; /* * The sequence counter counts frames, not fields. So divide * by two. @@ -436,27 +457,29 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf) } else { buf->vb.v4l2_buf.field = dev->field_cap; } - tpg_s_field(&dev->tpg, buf->vb.v4l2_buf.field); - tpg_s_perc_fill_blank(&dev->tpg, dev->must_blank[buf->vb.v4l2_buf.index]); + tpg_s_field(tpg, buf->vb.v4l2_buf.field, + dev->field_cap == V4L2_FIELD_ALTERNATE); + tpg_s_perc_fill_blank(tpg, dev->must_blank[buf->vb.v4l2_buf.index]); vivid_precalc_copy_rects(dev); - for (p = 0; p < tpg_g_planes(&dev->tpg); p++) { - void *vbuf = vb2_plane_vaddr(&buf->vb, p); + for (p = 0; p < tpg_g_planes(tpg); p++) { + void *vbuf = plane_vaddr(tpg, buf, p, + tpg->bytesperline, tpg->buf_height); /* * The first plane of a multiplanar format has a non-zero * data_offset. This helps testing whether the application * correctly supports non-zero data offsets. */ - if (dev->fmt_cap->data_offset[p]) { + if (p < tpg_g_buffers(tpg) && dev->fmt_cap->data_offset[p]) { memset(vbuf, dev->fmt_cap->data_offset[p] & 0xff, dev->fmt_cap->data_offset[p]); vbuf += dev->fmt_cap->data_offset[p]; } - tpg_calc_text_basep(&dev->tpg, basep, p, vbuf); + tpg_calc_text_basep(tpg, basep, p, vbuf); if (!is_loop || vivid_copy_buffer(dev, p, vbuf, buf)) - tpg_fillbuffer(&dev->tpg, vivid_get_std_cap(dev), p, vbuf); + tpg_fill_plane_buffer(tpg, vivid_get_std_cap(dev), p, vbuf); } dev->must_blank[buf->vb.v4l2_buf.index] = false; @@ -475,12 +498,12 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf) (dev->field_cap == V4L2_FIELD_ALTERNATE) ? (buf->vb.v4l2_buf.field == V4L2_FIELD_TOP ? " top" : " bottom") : ""); - tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); + tpg_gen_text(tpg, basep, line++ * line_height, 16, str); } if (dev->osd_mode == 0) { snprintf(str, sizeof(str), " %dx%d, input %d ", dev->src_rect.width, dev->src_rect.height, dev->input); - tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); + tpg_gen_text(tpg, basep, line++ * line_height, 16, str); gain = v4l2_ctrl_g_ctrl(dev->gain); mutex_lock(dev->ctrl_hdl_user_vid.lock); @@ -490,38 +513,38 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf) dev->contrast->cur.val, dev->saturation->cur.val, dev->hue->cur.val); - tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); + tpg_gen_text(tpg, basep, line++ * line_height, 16, str); snprintf(str, sizeof(str), " autogain %d, gain %3d, alpha 0x%02x ", dev->autogain->cur.val, gain, dev->alpha->cur.val); mutex_unlock(dev->ctrl_hdl_user_vid.lock); - tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); + tpg_gen_text(tpg, basep, line++ * line_height, 16, str); mutex_lock(dev->ctrl_hdl_user_aud.lock); snprintf(str, sizeof(str), " volume %3d, mute %d ", dev->volume->cur.val, dev->mute->cur.val); mutex_unlock(dev->ctrl_hdl_user_aud.lock); - tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); + tpg_gen_text(tpg, basep, line++ * line_height, 16, str); mutex_lock(dev->ctrl_hdl_user_gen.lock); snprintf(str, sizeof(str), " int32 %d, int64 %lld, bitmask %08x ", dev->int32->cur.val, *dev->int64->p_cur.p_s64, dev->bitmask->cur.val); - tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); + tpg_gen_text(tpg, basep, line++ * line_height, 16, str); snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ", dev->boolean->cur.val, dev->menu->qmenu[dev->menu->cur.val], dev->string->p_cur.p_char); - tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); + tpg_gen_text(tpg, basep, line++ * line_height, 16, str); snprintf(str, sizeof(str), " integer_menu %lld, value %d ", dev->int_menu->qmenu_int[dev->int_menu->cur.val], dev->int_menu->cur.val); mutex_unlock(dev->ctrl_hdl_user_gen.lock); - tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); + tpg_gen_text(tpg, basep, line++ * line_height, 16, str); if (dev->button_pressed) { dev->button_pressed--; snprintf(str, sizeof(str), " button pressed!"); - tpg_gen_text(&dev->tpg, basep, line++ * line_height, 16, str); + tpg_gen_text(tpg, basep, line++ * line_height, 16, str); } } @@ -585,6 +608,12 @@ static void vivid_overlay(struct vivid_dev *dev, struct vivid_buffer *buf) bool quick = dev->bitmap_cap == NULL && dev->clipcount_cap == 0; int x, y, w, out_x = 0; + /* + * Overlay support is only supported for formats that have a twopixelsize + * that's >= 2. Warn and bail out if that's not the case. + */ + if (WARN_ON(pixsize == 0)) + return; if ((dev->overlay_cap_field == V4L2_FIELD_TOP || dev->overlay_cap_field == V4L2_FIELD_BOTTOM) && dev->overlay_cap_field != buf->vb.v4l2_buf.field) diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.c b/drivers/media/platform/vivid/vivid-sdr-cap.c index 4af55f18829f..caf131666e37 100644 --- a/drivers/media/platform/vivid/vivid-sdr-cap.c +++ b/drivers/media/platform/vivid/vivid-sdr-cap.c @@ -27,6 +27,7 @@ #include <media/v4l2-common.h> #include <media/v4l2-event.h> #include <media/v4l2-dv-timings.h> +#include <linux/fixp-arith.h> #include "vivid-core.h" #include "vivid-ctrls.h" @@ -423,40 +424,19 @@ int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f) return 0; } -#define FIXP_FRAC (1 << 15) -#define FIXP_PI ((int)(FIXP_FRAC * 3.141592653589)) - -/* cos() from cx88 driver: cx88-dsp.c */ -static s32 fixp_cos(unsigned int x) -{ - u32 t2, t4, t6, t8; - u16 period = x / FIXP_PI; - - if (period % 2) - return -fixp_cos(x - FIXP_PI); - x = x % FIXP_PI; - if (x > FIXP_PI/2) - return -fixp_cos(FIXP_PI/2 - (x % (FIXP_PI/2))); - /* Now x is between 0 and FIXP_PI/2. - * To calculate cos(x) we use it's Taylor polinom. */ - t2 = x*x/FIXP_FRAC/2; - t4 = t2*x/FIXP_FRAC*x/FIXP_FRAC/3/4; - t6 = t4*x/FIXP_FRAC*x/FIXP_FRAC/5/6; - t8 = t6*x/FIXP_FRAC*x/FIXP_FRAC/7/8; - return FIXP_FRAC-t2+t4-t6+t8; -} - -static inline s32 fixp_sin(unsigned int x) -{ - return -fixp_cos(x + (FIXP_PI / 2)); -} +#define FIXP_N (15) +#define FIXP_FRAC (1 << FIXP_N) +#define FIXP_2PI ((int)(2 * 3.141592653589 * FIXP_FRAC)) void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf) { u8 *vbuf = vb2_plane_vaddr(&buf->vb, 0); unsigned long i; unsigned long plane_size = vb2_plane_size(&buf->vb, 0); - int fixp_src_phase_step, fixp_i, fixp_q; + s32 src_phase_step; + s32 mod_phase_step; + s32 fixp_i; + s32 fixp_q; /* * TODO: Generated beep tone goes very crackly when sample rate is @@ -466,28 +446,36 @@ void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf) /* calculate phase step */ #define BEEP_FREQ 1000 /* 1kHz beep */ - fixp_src_phase_step = DIV_ROUND_CLOSEST(2 * FIXP_PI * BEEP_FREQ, + src_phase_step = DIV_ROUND_CLOSEST(FIXP_2PI * BEEP_FREQ, dev->sdr_adc_freq); for (i = 0; i < plane_size; i += 2) { - dev->sdr_fixp_mod_phase += fixp_cos(dev->sdr_fixp_src_phase); - dev->sdr_fixp_src_phase += fixp_src_phase_step; + mod_phase_step = fixp_cos32_rad(dev->sdr_fixp_src_phase, + FIXP_2PI) >> (31 - FIXP_N); + + dev->sdr_fixp_src_phase += src_phase_step; + dev->sdr_fixp_mod_phase += mod_phase_step / 4; /* * Transfer phases to [0 / 2xPI] in order to avoid variable * overflow and make it suitable for cosine implementation * used, which does not support negative angles. */ - while (dev->sdr_fixp_mod_phase < (0 * FIXP_PI)) - dev->sdr_fixp_mod_phase += (2 * FIXP_PI); - while (dev->sdr_fixp_mod_phase > (2 * FIXP_PI)) - dev->sdr_fixp_mod_phase -= (2 * FIXP_PI); + while (dev->sdr_fixp_mod_phase < FIXP_2PI) + dev->sdr_fixp_mod_phase += FIXP_2PI; + while (dev->sdr_fixp_mod_phase > FIXP_2PI) + dev->sdr_fixp_mod_phase -= FIXP_2PI; + + while (dev->sdr_fixp_src_phase > FIXP_2PI) + dev->sdr_fixp_src_phase -= FIXP_2PI; - while (dev->sdr_fixp_src_phase > (2 * FIXP_PI)) - dev->sdr_fixp_src_phase -= (2 * FIXP_PI); + fixp_i = fixp_cos32_rad(dev->sdr_fixp_mod_phase, FIXP_2PI); + fixp_q = fixp_sin32_rad(dev->sdr_fixp_mod_phase, FIXP_2PI); - fixp_i = fixp_cos(dev->sdr_fixp_mod_phase); - fixp_q = fixp_sin(dev->sdr_fixp_mod_phase); + /* Normalize fraction values represented with 32 bit precision + * to fixed point representation with FIXP_N bits */ + fixp_i >>= (31 - FIXP_N); + fixp_q >>= (31 - FIXP_N); /* convert 'fixp float' to u8 */ /* u8 = X * 127.5f + 127.5f; where X is float [-1.0 / +1.0] */ diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c index 34493f435d5a..cb766eb154e7 100644 --- a/drivers/media/platform/vivid/vivid-tpg.c +++ b/drivers/media/platform/vivid/vivid-tpg.c @@ -35,7 +35,10 @@ const char * const tpg_pattern_strings[] = { "100% Green", "100% Blue", "16x16 Checkers", + "2x2 Checkers", "1x1 Checkers", + "2x2 Red/Green Checkers", + "1x1 Red/Green Checkers", "Alternating Hor Lines", "Alternating Vert Lines", "One Pixel Wide Cross", @@ -120,15 +123,20 @@ int tpg_alloc(struct tpg_data *tpg, unsigned max_w) tpg->max_line_width = max_w; for (pat = 0; pat < TPG_MAX_PAT_LINES; pat++) { for (plane = 0; plane < TPG_MAX_PLANES; plane++) { - unsigned pixelsz = plane ? 1 : 4; + unsigned pixelsz = plane ? 2 : 4; tpg->lines[pat][plane] = vzalloc(max_w * 2 * pixelsz); if (!tpg->lines[pat][plane]) return -ENOMEM; + if (plane == 0) + continue; + tpg->downsampled_lines[pat][plane] = vzalloc(max_w * 2 * pixelsz); + if (!tpg->downsampled_lines[pat][plane]) + return -ENOMEM; } } for (plane = 0; plane < TPG_MAX_PLANES; plane++) { - unsigned pixelsz = plane ? 1 : 4; + unsigned pixelsz = plane ? 2 : 4; tpg->contrast_line[plane] = vzalloc(max_w * pixelsz); if (!tpg->contrast_line[plane]) @@ -152,6 +160,10 @@ void tpg_free(struct tpg_data *tpg) for (plane = 0; plane < TPG_MAX_PLANES; plane++) { vfree(tpg->lines[pat][plane]); tpg->lines[pat][plane] = NULL; + if (plane == 0) + continue; + vfree(tpg->downsampled_lines[pat][plane]); + tpg->downsampled_lines[pat][plane] = NULL; } for (plane = 0; plane < TPG_MAX_PLANES; plane++) { vfree(tpg->contrast_line[plane]); @@ -167,14 +179,38 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) { tpg->fourcc = fourcc; tpg->planes = 1; + tpg->buffers = 1; tpg->recalc_colors = true; + tpg->interleaved = false; + tpg->vdownsampling[0] = 1; + tpg->hdownsampling[0] = 1; + tpg->hmask[0] = ~0; + tpg->hmask[1] = ~0; + tpg->hmask[2] = ~0; + switch (fourcc) { + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + tpg->interleaved = true; + tpg->vdownsampling[1] = 1; + tpg->hdownsampling[1] = 1; + tpg->planes = 2; + /* fall through */ + case V4L2_PIX_FMT_RGB332: case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_RGB565X: + case V4L2_PIX_FMT_RGB444: + case V4L2_PIX_FMT_XRGB444: + case V4L2_PIX_FMT_ARGB444: case V4L2_PIX_FMT_RGB555: case V4L2_PIX_FMT_XRGB555: case V4L2_PIX_FMT_ARGB555: case V4L2_PIX_FMT_RGB555X: + case V4L2_PIX_FMT_XRGB555X: + case V4L2_PIX_FMT_ARGB555X: + case V4L2_PIX_FMT_BGR666: case V4L2_PIX_FMT_RGB24: case V4L2_PIX_FMT_BGR24: case V4L2_PIX_FMT_RGB32: @@ -183,16 +219,72 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_XBGR32: case V4L2_PIX_FMT_ARGB32: case V4L2_PIX_FMT_ABGR32: + case V4L2_PIX_FMT_GREY: tpg->is_yuv = false; break; + case V4L2_PIX_FMT_YUV444: + case V4L2_PIX_FMT_YUV555: + case V4L2_PIX_FMT_YUV565: + case V4L2_PIX_FMT_YUV32: + tpg->is_yuv = true; + break; + case V4L2_PIX_FMT_YUV420M: + case V4L2_PIX_FMT_YVU420M: + tpg->buffers = 3; + /* fall through */ + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + tpg->vdownsampling[1] = 2; + tpg->vdownsampling[2] = 2; + tpg->hdownsampling[1] = 2; + tpg->hdownsampling[2] = 2; + tpg->planes = 3; + tpg->is_yuv = true; + break; + case V4L2_PIX_FMT_YUV422P: + tpg->vdownsampling[1] = 1; + tpg->vdownsampling[2] = 1; + tpg->hdownsampling[1] = 2; + tpg->hdownsampling[2] = 2; + tpg->planes = 3; + tpg->is_yuv = true; + break; case V4L2_PIX_FMT_NV16M: case V4L2_PIX_FMT_NV61M: + tpg->buffers = 2; + /* fall through */ + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + tpg->vdownsampling[1] = 1; + tpg->hdownsampling[1] = 1; + tpg->hmask[1] = ~1; tpg->planes = 2; - /* fall-through */ + tpg->is_yuv = true; + break; + case V4L2_PIX_FMT_NV12M: + case V4L2_PIX_FMT_NV21M: + tpg->buffers = 2; + /* fall through */ + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + tpg->vdownsampling[1] = 2; + tpg->hdownsampling[1] = 1; + tpg->hmask[1] = ~1; + tpg->planes = 2; + tpg->is_yuv = true; + break; + case V4L2_PIX_FMT_NV24: + case V4L2_PIX_FMT_NV42: + tpg->vdownsampling[1] = 1; + tpg->hdownsampling[1] = 1; + tpg->planes = 2; + tpg->is_yuv = true; + break; case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_YVYU: case V4L2_PIX_FMT_VYUY: + tpg->hmask[0] = ~1; tpg->is_yuv = true; break; default: @@ -200,35 +292,75 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) } switch (fourcc) { + case V4L2_PIX_FMT_RGB332: + tpg->twopixelsize[0] = 2; + break; case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_RGB565X: + case V4L2_PIX_FMT_RGB444: + case V4L2_PIX_FMT_XRGB444: + case V4L2_PIX_FMT_ARGB444: case V4L2_PIX_FMT_RGB555: case V4L2_PIX_FMT_XRGB555: case V4L2_PIX_FMT_ARGB555: case V4L2_PIX_FMT_RGB555X: + case V4L2_PIX_FMT_XRGB555X: + case V4L2_PIX_FMT_ARGB555X: case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_YVYU: case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_YUV444: + case V4L2_PIX_FMT_YUV555: + case V4L2_PIX_FMT_YUV565: tpg->twopixelsize[0] = 2 * 2; break; case V4L2_PIX_FMT_RGB24: case V4L2_PIX_FMT_BGR24: tpg->twopixelsize[0] = 2 * 3; break; + case V4L2_PIX_FMT_BGR666: case V4L2_PIX_FMT_RGB32: case V4L2_PIX_FMT_BGR32: case V4L2_PIX_FMT_XRGB32: case V4L2_PIX_FMT_XBGR32: case V4L2_PIX_FMT_ARGB32: case V4L2_PIX_FMT_ABGR32: + case V4L2_PIX_FMT_YUV32: tpg->twopixelsize[0] = 2 * 4; break; + case V4L2_PIX_FMT_GREY: + tpg->twopixelsize[0] = 2; + break; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV12M: + case V4L2_PIX_FMT_NV21M: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: case V4L2_PIX_FMT_NV16M: case V4L2_PIX_FMT_NV61M: + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: tpg->twopixelsize[0] = 2; tpg->twopixelsize[1] = 2; break; + case V4L2_PIX_FMT_YUV422P: + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_YUV420M: + case V4L2_PIX_FMT_YVU420M: + tpg->twopixelsize[0] = 2; + tpg->twopixelsize[1] = 2; + tpg->twopixelsize[2] = 2; + break; + case V4L2_PIX_FMT_NV24: + case V4L2_PIX_FMT_NV42: + tpg->twopixelsize[0] = 2; + tpg->twopixelsize[1] = 4; + break; } return true; } @@ -267,7 +399,8 @@ void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height, tpg->compose.width = width; tpg->compose.height = tpg->buf_height; for (p = 0; p < tpg->planes; p++) - tpg->bytesperline[p] = width * tpg->twopixelsize[p] / 2; + tpg->bytesperline[p] = (width * tpg->twopixelsize[p]) / + (2 * tpg->hdownsampling[p]); tpg->recalc_square_border = true; } @@ -347,9 +480,9 @@ static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b, { COEFF(0.5, 224), COEFF(-0.445, 224), COEFF(-0.055, 224) }, }; static const int bt2020[3][3] = { - { COEFF(0.2726, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) }, + { COEFF(0.2627, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) }, { COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224) }, - { COEFF(0.5, 224), COEFF(-0.4629, 224), COEFF(-0.0405, 224) }, + { COEFF(0.5, 224), COEFF(-0.4598, 224), COEFF(-0.0402, 224) }, }; bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE; unsigned y_offset = full ? 0 : 16; @@ -524,10 +657,10 @@ static void precalculate_color(struct tpg_data *tpg, int k) g <<= 4; b <<= 4; } - if (tpg->qual == TPG_QUAL_GRAY) { + if (tpg->qual == TPG_QUAL_GRAY || tpg->fourcc == V4L2_PIX_FMT_GREY) { /* Rec. 709 Luma function */ /* (0.2126, 0.7152, 0.0722) * (255 * 256) */ - r = g = b = ((13879 * r + 46688 * g + 4713 * b) >> 16) + (16 << 4); + r = g = b = (13879 * r + 46688 * g + 4713 * b) >> 16; } /* @@ -601,9 +734,29 @@ static void precalculate_color(struct tpg_data *tpg, int k) cb = clamp(cb, 16 << 4, 240 << 4); cr = clamp(cr, 16 << 4, 240 << 4); } - tpg->colors[k][0] = clamp(y >> 4, 1, 254); - tpg->colors[k][1] = clamp(cb >> 4, 1, 254); - tpg->colors[k][2] = clamp(cr >> 4, 1, 254); + y = clamp(y >> 4, 1, 254); + cb = clamp(cb >> 4, 1, 254); + cr = clamp(cr >> 4, 1, 254); + switch (tpg->fourcc) { + case V4L2_PIX_FMT_YUV444: + y >>= 4; + cb >>= 4; + cr >>= 4; + break; + case V4L2_PIX_FMT_YUV555: + y >>= 3; + cb >>= 3; + cr >>= 3; + break; + case V4L2_PIX_FMT_YUV565: + y >>= 3; + cb >>= 2; + cr >>= 3; + break; + } + tpg->colors[k][0] = y; + tpg->colors[k][1] = cb; + tpg->colors[k][2] = cr; } else { if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) { r = (r * 219) / 255 + (16 << 4); @@ -611,20 +764,39 @@ static void precalculate_color(struct tpg_data *tpg, int k) b = (b * 219) / 255 + (16 << 4); } switch (tpg->fourcc) { + case V4L2_PIX_FMT_RGB332: + r >>= 9; + g >>= 9; + b >>= 10; + break; case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_RGB565X: r >>= 7; g >>= 6; b >>= 7; break; + case V4L2_PIX_FMT_RGB444: + case V4L2_PIX_FMT_XRGB444: + case V4L2_PIX_FMT_ARGB444: + r >>= 8; + g >>= 8; + b >>= 8; + break; case V4L2_PIX_FMT_RGB555: case V4L2_PIX_FMT_XRGB555: case V4L2_PIX_FMT_ARGB555: case V4L2_PIX_FMT_RGB555X: + case V4L2_PIX_FMT_XRGB555X: + case V4L2_PIX_FMT_ARGB555X: r >>= 7; g >>= 7; b >>= 7; break; + case V4L2_PIX_FMT_BGR666: + r >>= 6; + g >>= 6; + b >>= 6; + break; default: r >>= 4; g >>= 4; @@ -665,31 +837,120 @@ static void gen_twopix(struct tpg_data *tpg, b_v = tpg->colors[color][2]; /* B or precalculated V */ switch (tpg->fourcc) { + case V4L2_PIX_FMT_GREY: + buf[0][offset] = r_y; + break; + case V4L2_PIX_FMT_YUV422P: + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YUV420M: + buf[0][offset] = r_y; + if (odd) { + buf[1][0] = (buf[1][0] + g_u) / 2; + buf[2][0] = (buf[2][0] + b_v) / 2; + buf[1][1] = buf[1][0]; + buf[2][1] = buf[2][0]; + break; + } + buf[1][0] = g_u; + buf[2][0] = b_v; + break; + case V4L2_PIX_FMT_YVU420: + case V4L2_PIX_FMT_YVU420M: + buf[0][offset] = r_y; + if (odd) { + buf[1][0] = (buf[1][0] + b_v) / 2; + buf[2][0] = (buf[2][0] + g_u) / 2; + buf[1][1] = buf[1][0]; + buf[2][1] = buf[2][0]; + break; + } + buf[1][0] = b_v; + buf[2][0] = g_u; + break; + + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV12M: + case V4L2_PIX_FMT_NV16: case V4L2_PIX_FMT_NV16M: buf[0][offset] = r_y; - buf[1][offset] = odd ? b_v : g_u; + if (odd) { + buf[1][0] = (buf[1][0] + g_u) / 2; + buf[1][1] = (buf[1][1] + b_v) / 2; + break; + } + buf[1][0] = g_u; + buf[1][1] = b_v; break; + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV21M: + case V4L2_PIX_FMT_NV61: case V4L2_PIX_FMT_NV61M: buf[0][offset] = r_y; - buf[1][offset] = odd ? g_u : b_v; + if (odd) { + buf[1][0] = (buf[1][0] + b_v) / 2; + buf[1][1] = (buf[1][1] + g_u) / 2; + break; + } + buf[1][0] = b_v; + buf[1][1] = g_u; + break; + + case V4L2_PIX_FMT_NV24: + buf[0][offset] = r_y; + buf[1][2 * offset] = g_u; + buf[1][2 * offset + 1] = b_v; + break; + + case V4L2_PIX_FMT_NV42: + buf[0][offset] = r_y; + buf[1][2 * offset] = b_v; + buf[1][2 * offset + 1] = g_u; break; case V4L2_PIX_FMT_YUYV: buf[0][offset] = r_y; - buf[0][offset + 1] = odd ? b_v : g_u; + if (odd) { + buf[0][1] = (buf[0][1] + g_u) / 2; + buf[0][3] = (buf[0][3] + b_v) / 2; + break; + } + buf[0][1] = g_u; + buf[0][3] = b_v; break; case V4L2_PIX_FMT_UYVY: - buf[0][offset] = odd ? b_v : g_u; buf[0][offset + 1] = r_y; + if (odd) { + buf[0][0] = (buf[0][0] + g_u) / 2; + buf[0][2] = (buf[0][2] + b_v) / 2; + break; + } + buf[0][0] = g_u; + buf[0][2] = b_v; break; case V4L2_PIX_FMT_YVYU: buf[0][offset] = r_y; - buf[0][offset + 1] = odd ? g_u : b_v; + if (odd) { + buf[0][1] = (buf[0][1] + b_v) / 2; + buf[0][3] = (buf[0][3] + g_u) / 2; + break; + } + buf[0][1] = b_v; + buf[0][3] = g_u; break; case V4L2_PIX_FMT_VYUY: - buf[0][offset] = odd ? g_u : b_v; buf[0][offset + 1] = r_y; + if (odd) { + buf[0][0] = (buf[0][0] + b_v) / 2; + buf[0][2] = (buf[0][2] + g_u) / 2; + break; + } + buf[0][0] = b_v; + buf[0][2] = g_u; + break; + case V4L2_PIX_FMT_RGB332: + buf[0][offset] = (r_y << 5) | (g_u << 2) | b_v; break; + case V4L2_PIX_FMT_YUV565: case V4L2_PIX_FMT_RGB565: buf[0][offset] = (g_u << 5) | b_v; buf[0][offset + 1] = (r_y << 3) | (g_u >> 3); @@ -698,15 +959,29 @@ static void gen_twopix(struct tpg_data *tpg, buf[0][offset] = (r_y << 3) | (g_u >> 3); buf[0][offset + 1] = (g_u << 5) | b_v; break; + case V4L2_PIX_FMT_RGB444: + case V4L2_PIX_FMT_XRGB444: + alpha = 0; + /* fall through */ + case V4L2_PIX_FMT_YUV444: + case V4L2_PIX_FMT_ARGB444: + buf[0][offset] = (g_u << 4) | b_v; + buf[0][offset + 1] = (alpha & 0xf0) | r_y; + break; case V4L2_PIX_FMT_RGB555: case V4L2_PIX_FMT_XRGB555: alpha = 0; /* fall through */ + case V4L2_PIX_FMT_YUV555: case V4L2_PIX_FMT_ARGB555: buf[0][offset] = (g_u << 5) | b_v; buf[0][offset + 1] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3); break; case V4L2_PIX_FMT_RGB555X: + case V4L2_PIX_FMT_XRGB555X: + alpha = 0; + /* fall through */ + case V4L2_PIX_FMT_ARGB555X: buf[0][offset] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3); buf[0][offset + 1] = (g_u << 5) | b_v; break; @@ -720,10 +995,17 @@ static void gen_twopix(struct tpg_data *tpg, buf[0][offset + 1] = g_u; buf[0][offset + 2] = r_y; break; + case V4L2_PIX_FMT_BGR666: + buf[0][offset] = (b_v << 2) | (g_u >> 4); + buf[0][offset + 1] = (g_u << 4) | (r_y >> 2); + buf[0][offset + 2] = r_y << 6; + buf[0][offset + 3] = 0; + break; case V4L2_PIX_FMT_RGB32: case V4L2_PIX_FMT_XRGB32: alpha = 0; /* fall through */ + case V4L2_PIX_FMT_YUV32: case V4L2_PIX_FMT_ARGB32: buf[0][offset] = alpha; buf[0][offset + 1] = r_y; @@ -740,15 +1022,47 @@ static void gen_twopix(struct tpg_data *tpg, buf[0][offset + 2] = r_y; buf[0][offset + 3] = alpha; break; + case V4L2_PIX_FMT_SBGGR8: + buf[0][offset] = odd ? g_u : b_v; + buf[1][offset] = odd ? r_y : g_u; + break; + case V4L2_PIX_FMT_SGBRG8: + buf[0][offset] = odd ? b_v : g_u; + buf[1][offset] = odd ? g_u : r_y; + break; + case V4L2_PIX_FMT_SGRBG8: + buf[0][offset] = odd ? r_y : g_u; + buf[1][offset] = odd ? g_u : b_v; + break; + case V4L2_PIX_FMT_SRGGB8: + buf[0][offset] = odd ? g_u : r_y; + buf[1][offset] = odd ? b_v : g_u; + break; + } +} + +unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line) +{ + switch (tpg->fourcc) { + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + return buf_line & 1; + default: + return 0; } } /* Return how many pattern lines are used by the current pattern. */ -static unsigned tpg_get_pat_lines(struct tpg_data *tpg) +static unsigned tpg_get_pat_lines(const struct tpg_data *tpg) { switch (tpg->pattern) { case TPG_PAT_CHECKERS_16X16: + case TPG_PAT_CHECKERS_2X2: case TPG_PAT_CHECKERS_1X1: + case TPG_PAT_COLOR_CHECKERS_2X2: + case TPG_PAT_COLOR_CHECKERS_1X1: case TPG_PAT_ALTERNATING_HLINES: case TPG_PAT_CROSS_1_PIXEL: case TPG_PAT_CROSS_2_PIXELS: @@ -763,14 +1077,18 @@ static unsigned tpg_get_pat_lines(struct tpg_data *tpg) } /* Which pattern line should be used for the given frame line. */ -static unsigned tpg_get_pat_line(struct tpg_data *tpg, unsigned line) +static unsigned tpg_get_pat_line(const struct tpg_data *tpg, unsigned line) { switch (tpg->pattern) { case TPG_PAT_CHECKERS_16X16: return (line >> 4) & 1; case TPG_PAT_CHECKERS_1X1: + case TPG_PAT_COLOR_CHECKERS_1X1: case TPG_PAT_ALTERNATING_HLINES: return line & 1; + case TPG_PAT_CHECKERS_2X2: + case TPG_PAT_COLOR_CHECKERS_2X2: + return (line & 2) >> 1; case TPG_PAT_100_COLORSQUARES: case TPG_PAT_100_HCOLORBAR: return (line * 8) / tpg->src_height; @@ -789,7 +1107,8 @@ static unsigned tpg_get_pat_line(struct tpg_data *tpg, unsigned line) * Which color should be used for the given pattern line and X coordinate. * Note: x is in the range 0 to 2 * tpg->src_width. */ -static enum tpg_color tpg_get_color(struct tpg_data *tpg, unsigned pat_line, unsigned x) +static enum tpg_color tpg_get_color(const struct tpg_data *tpg, + unsigned pat_line, unsigned x) { /* Maximum number of bars are TPG_COLOR_MAX - otherwise, the input print code should be modified */ @@ -836,6 +1155,15 @@ static enum tpg_color tpg_get_color(struct tpg_data *tpg, unsigned pat_line, uns case TPG_PAT_CHECKERS_1X1: return ((x & 1) ^ (pat_line & 1)) ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK; + case TPG_PAT_COLOR_CHECKERS_1X1: + return ((x & 1) ^ (pat_line & 1)) ? + TPG_COLOR_100_RED : TPG_COLOR_100_BLUE; + case TPG_PAT_CHECKERS_2X2: + return (((x >> 1) & 1) ^ (pat_line & 1)) ? + TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK; + case TPG_PAT_COLOR_CHECKERS_2X2: + return (((x >> 1) & 1) ^ (pat_line & 1)) ? + TPG_COLOR_100_RED : TPG_COLOR_100_BLUE; case TPG_PAT_ALTERNATING_HLINES: return pat_line ? TPG_COLOR_100_WHITE : TPG_COLOR_100_BLACK; case TPG_PAT_ALTERNATING_VLINES: @@ -948,6 +1276,7 @@ static void tpg_calculate_square_border(struct tpg_data *tpg) static void tpg_precalculate_line(struct tpg_data *tpg) { enum tpg_color contrast; + u8 pix[TPG_MAX_PLANES][8]; unsigned pat; unsigned p; unsigned x; @@ -974,7 +1303,6 @@ static void tpg_precalculate_line(struct tpg_data *tpg) for (x = 0; x < tpg->scaled_width * 2; x += 2) { unsigned real_x = src_x; enum tpg_color color1, color2; - u8 pix[TPG_MAX_PLANES][8]; real_x = tpg->hflip ? tpg->src_width * 2 - real_x - 2 : real_x; color1 = tpg_get_color(tpg, pat, real_x); @@ -1001,39 +1329,53 @@ static void tpg_precalculate_line(struct tpg_data *tpg) gen_twopix(tpg, pix, tpg->hflip ? color1 : color2, 1); for (p = 0; p < tpg->planes; p++) { unsigned twopixsize = tpg->twopixelsize[p]; - u8 *pos = tpg->lines[pat][p] + x * twopixsize / 2; + unsigned hdiv = tpg->hdownsampling[p]; + u8 *pos = tpg->lines[pat][p] + tpg_hdiv(tpg, p, x); - memcpy(pos, pix[p], twopixsize); + memcpy(pos, pix[p], twopixsize / hdiv); } } } - for (x = 0; x < tpg->scaled_width; x += 2) { - u8 pix[TPG_MAX_PLANES][8]; - gen_twopix(tpg, pix, contrast, 0); - gen_twopix(tpg, pix, contrast, 1); - for (p = 0; p < tpg->planes; p++) { - unsigned twopixsize = tpg->twopixelsize[p]; - u8 *pos = tpg->contrast_line[p] + x * twopixsize / 2; + if (tpg->vdownsampling[tpg->planes - 1] > 1) { + unsigned pat_lines = tpg_get_pat_lines(tpg); - memcpy(pos, pix[p], twopixsize); + for (pat = 0; pat < pat_lines; pat++) { + unsigned next_pat = (pat + 1) % pat_lines; + + for (p = 1; p < tpg->planes; p++) { + unsigned w = tpg_hdiv(tpg, p, tpg->scaled_width * 2); + u8 *pos1 = tpg->lines[pat][p]; + u8 *pos2 = tpg->lines[next_pat][p]; + u8 *dest = tpg->downsampled_lines[pat][p]; + + for (x = 0; x < w; x++, pos1++, pos2++, dest++) + *dest = ((u16)*pos1 + (u16)*pos2) / 2; + } } } - for (x = 0; x < tpg->scaled_width; x += 2) { - u8 pix[TPG_MAX_PLANES][8]; - gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0); - gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1); - for (p = 0; p < tpg->planes; p++) { - unsigned twopixsize = tpg->twopixelsize[p]; - u8 *pos = tpg->black_line[p] + x * twopixsize / 2; + gen_twopix(tpg, pix, contrast, 0); + gen_twopix(tpg, pix, contrast, 1); + for (p = 0; p < tpg->planes; p++) { + unsigned twopixsize = tpg->twopixelsize[p]; + u8 *pos = tpg->contrast_line[p]; + for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize) + memcpy(pos, pix[p], twopixsize); + } + + gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 0); + gen_twopix(tpg, pix, TPG_COLOR_100_BLACK, 1); + for (p = 0; p < tpg->planes; p++) { + unsigned twopixsize = tpg->twopixelsize[p]; + u8 *pos = tpg->black_line[p]; + + for (x = 0; x < tpg->scaled_width; x += 2, pos += twopixsize) memcpy(pos, pix[p], twopixsize); - } } - for (x = 0; x < tpg->scaled_width * 2; x += 2) { - u8 pix[TPG_MAX_PLANES][8]; + for (x = 0; x < tpg->scaled_width * 2; x += 2) { gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 0); gen_twopix(tpg, pix, TPG_COLOR_RANDOM, 1); for (p = 0; p < tpg->planes; p++) { @@ -1043,6 +1385,7 @@ static void tpg_precalculate_line(struct tpg_data *tpg) memcpy(pos, pix[p], twopixsize); } } + gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 0); gen_twopix(tpg, tpg->textbg, TPG_COLOR_TEXTBG, 1); gen_twopix(tpg, tpg->textfg, TPG_COLOR_TEXTFG, 0); @@ -1052,8 +1395,8 @@ static void tpg_precalculate_line(struct tpg_data *tpg) /* need this to do rgb24 rendering */ typedef struct { u16 __; u8 _; } __packed x24; -void tpg_gen_text(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], - int y, int x, char *text) +void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], + int y, int x, char *text) { int line; unsigned step = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1; @@ -1083,24 +1426,37 @@ void tpg_gen_text(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], div = 2; for (p = 0; p < tpg->planes; p++) { - /* Print stream time */ + unsigned vdiv = tpg->vdownsampling[p]; + unsigned hdiv = tpg->hdownsampling[p]; + + /* Print text */ #define PRINTSTR(PIXTYPE) do { \ PIXTYPE fg; \ PIXTYPE bg; \ memcpy(&fg, tpg->textfg[p], sizeof(PIXTYPE)); \ memcpy(&bg, tpg->textbg[p], sizeof(PIXTYPE)); \ \ - for (line = first; line < 16; line += step) { \ + for (line = first; line < 16; line += vdiv * step) { \ int l = tpg->vflip ? 15 - line : line; \ - PIXTYPE *pos = (PIXTYPE *)(basep[p][line & 1] + \ - ((y * step + l) / div) * tpg->bytesperline[p] + \ - x * sizeof(PIXTYPE)); \ + PIXTYPE *pos = (PIXTYPE *)(basep[p][(line / vdiv) & 1] + \ + ((y * step + l) / (vdiv * div)) * tpg->bytesperline[p] + \ + (x / hdiv) * sizeof(PIXTYPE)); \ unsigned s; \ \ for (s = 0; s < len; s++) { \ u8 chr = font8x16[text[s] * 16 + line]; \ \ - if (tpg->hflip) { \ + if (hdiv == 2 && tpg->hflip) { \ + pos[3] = (chr & (0x01 << 6) ? fg : bg); \ + pos[2] = (chr & (0x01 << 4) ? fg : bg); \ + pos[1] = (chr & (0x01 << 2) ? fg : bg); \ + pos[0] = (chr & (0x01 << 0) ? fg : bg); \ + } else if (hdiv == 2) { \ + pos[0] = (chr & (0x01 << 7) ? fg : bg); \ + pos[1] = (chr & (0x01 << 5) ? fg : bg); \ + pos[2] = (chr & (0x01 << 3) ? fg : bg); \ + pos[3] = (chr & (0x01 << 1) ? fg : bg); \ + } else if (tpg->hflip) { \ pos[7] = (chr & (0x01 << 7) ? fg : bg); \ pos[6] = (chr & (0x01 << 6) ? fg : bg); \ pos[5] = (chr & (0x01 << 5) ? fg : bg); \ @@ -1120,7 +1476,7 @@ void tpg_gen_text(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], pos[7] = (chr & (0x01 << 0) ? fg : bg); \ } \ \ - pos += tpg->hflip ? -8 : 8; \ + pos += (tpg->hflip ? -8 : 8) / hdiv; \ } \ } \ } while (0) @@ -1187,7 +1543,7 @@ void tpg_update_mv_step(struct tpg_data *tpg) } /* Map the line number relative to the crop rectangle to a frame line number */ -static unsigned tpg_calc_frameline(struct tpg_data *tpg, unsigned src_y, +static unsigned tpg_calc_frameline(const struct tpg_data *tpg, unsigned src_y, unsigned field) { switch (field) { @@ -1204,7 +1560,7 @@ static unsigned tpg_calc_frameline(struct tpg_data *tpg, unsigned src_y, * Map the line number relative to the compose rectangle to a destination * buffer line number. */ -static unsigned tpg_calc_buffer_line(struct tpg_data *tpg, unsigned y, +static unsigned tpg_calc_buffer_line(const struct tpg_data *tpg, unsigned y, unsigned field) { y += tpg->compose.top; @@ -1265,6 +1621,10 @@ static void tpg_recalc(struct tpg_data *tpg) V4L2_QUANTIZATION_LIM_RANGE; break; } + } else if (tpg->colorspace == V4L2_COLORSPACE_BT2020) { + /* R'G'B' BT.2020 is limited range */ + tpg->real_quantization = + V4L2_QUANTIZATION_LIM_RANGE; } } tpg_precalculate_colors(tpg); @@ -1283,191 +1643,388 @@ void tpg_calc_text_basep(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf) { unsigned stride = tpg->bytesperline[p]; + unsigned h = tpg->buf_height; tpg_recalc(tpg); basep[p][0] = vbuf; basep[p][1] = vbuf; + h /= tpg->vdownsampling[p]; if (tpg->field == V4L2_FIELD_SEQ_TB) - basep[p][1] += tpg->buf_height * stride / 2; + basep[p][1] += h * stride / 2; else if (tpg->field == V4L2_FIELD_SEQ_BT) - basep[p][0] += tpg->buf_height * stride / 2; + basep[p][0] += h * stride / 2; + if (p == 0 && tpg->interleaved) + tpg_calc_text_basep(tpg, basep, 1, vbuf); } -void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf) +static int tpg_pattern_avg(const struct tpg_data *tpg, + unsigned pat1, unsigned pat2) { - bool is_tv = std; - bool is_60hz = is_tv && (std & V4L2_STD_525_60); - unsigned mv_hor_old = tpg->mv_hor_count % tpg->src_width; - unsigned mv_hor_new = (tpg->mv_hor_count + tpg->mv_hor_step) % tpg->src_width; - unsigned mv_vert_old = tpg->mv_vert_count % tpg->src_height; - unsigned mv_vert_new = (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height; + unsigned pat_lines = tpg_get_pat_lines(tpg); + + if (pat1 == (pat2 + 1) % pat_lines) + return pat2; + if (pat2 == (pat1 + 1) % pat_lines) + return pat1; + return -1; +} + +/* + * This struct contains common parameters used by both the drawing of the + * test pattern and the drawing of the extras (borders, square, etc.) + */ +struct tpg_draw_params { + /* common data */ + bool is_tv; + bool is_60hz; + unsigned twopixsize; + unsigned img_width; + unsigned stride; + unsigned hmax; + unsigned frame_line; + unsigned frame_line_next; + + /* test pattern */ + unsigned mv_hor_old; + unsigned mv_hor_new; + unsigned mv_vert_old; + unsigned mv_vert_new; + + /* extras */ unsigned wss_width; - unsigned f; - int hmax = (tpg->compose.height * tpg->perc_fill) / 100; - int h; - unsigned twopixsize = tpg->twopixelsize[p]; - unsigned img_width = tpg->compose.width * twopixsize / 2; - unsigned line_offset; - unsigned left_pillar_width = 0; - unsigned right_pillar_start = img_width; - unsigned stride = tpg->bytesperline[p]; - unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1; - u8 *orig_vbuf = vbuf; + unsigned wss_random_offset; + unsigned sav_eav_f; + unsigned left_pillar_width; + unsigned right_pillar_start; +}; - /* Coarse scaling with Bresenham */ - unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height; - unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height; - unsigned src_y = 0; - unsigned error = 0; +static void tpg_fill_params_pattern(const struct tpg_data *tpg, unsigned p, + struct tpg_draw_params *params) +{ + params->mv_hor_old = + tpg_hscale_div(tpg, p, tpg->mv_hor_count % tpg->src_width); + params->mv_hor_new = + tpg_hscale_div(tpg, p, (tpg->mv_hor_count + tpg->mv_hor_step) % + tpg->src_width); + params->mv_vert_old = tpg->mv_vert_count % tpg->src_height; + params->mv_vert_new = + (tpg->mv_vert_count + tpg->mv_vert_step) % tpg->src_height; +} - tpg_recalc(tpg); +static void tpg_fill_params_extras(const struct tpg_data *tpg, + unsigned p, + struct tpg_draw_params *params) +{ + unsigned left_pillar_width = 0; + unsigned right_pillar_start = params->img_width; + + params->wss_width = tpg->crop.left < tpg->src_width / 2 ? + tpg->src_width / 2 - tpg->crop.left : 0; + if (params->wss_width > tpg->crop.width) + params->wss_width = tpg->crop.width; + params->wss_width = tpg_hscale_div(tpg, p, params->wss_width); + params->wss_random_offset = + params->twopixsize * prandom_u32_max(tpg->src_width / 2); - mv_hor_old = (mv_hor_old * tpg->scaled_width / tpg->src_width) & ~1; - mv_hor_new = (mv_hor_new * tpg->scaled_width / tpg->src_width) & ~1; - wss_width = tpg->crop.left < tpg->src_width / 2 ? - tpg->src_width / 2 - tpg->crop.left : 0; - if (wss_width > tpg->crop.width) - wss_width = tpg->crop.width; - wss_width = wss_width * tpg->scaled_width / tpg->src_width; - - vbuf += tpg->compose.left * twopixsize / 2; - line_offset = tpg->crop.left * tpg->scaled_width / tpg->src_width; - line_offset = (line_offset & ~1) * twopixsize / 2; if (tpg->crop.left < tpg->border.left) { left_pillar_width = tpg->border.left - tpg->crop.left; if (left_pillar_width > tpg->crop.width) left_pillar_width = tpg->crop.width; - left_pillar_width = (left_pillar_width * tpg->scaled_width) / tpg->src_width; - left_pillar_width = (left_pillar_width & ~1) * twopixsize / 2; + left_pillar_width = tpg_hscale_div(tpg, p, left_pillar_width); } - if (tpg->crop.left + tpg->crop.width > tpg->border.left + tpg->border.width) { - right_pillar_start = tpg->border.left + tpg->border.width - tpg->crop.left; - right_pillar_start = (right_pillar_start * tpg->scaled_width) / tpg->src_width; - right_pillar_start = (right_pillar_start & ~1) * twopixsize / 2; - if (right_pillar_start > img_width) - right_pillar_start = img_width; + params->left_pillar_width = left_pillar_width; + + if (tpg->crop.left + tpg->crop.width > + tpg->border.left + tpg->border.width) { + right_pillar_start = + tpg->border.left + tpg->border.width - tpg->crop.left; + right_pillar_start = + tpg_hscale_div(tpg, p, right_pillar_start); + if (right_pillar_start > params->img_width) + right_pillar_start = params->img_width; } + params->right_pillar_start = right_pillar_start; - f = tpg->field == (is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM); + params->sav_eav_f = tpg->field == + (params->is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM); +} - for (h = 0; h < tpg->compose.height; h++) { - bool even; - bool fill_blank = false; - unsigned frame_line; - unsigned buf_line; - unsigned pat_line_old; - unsigned pat_line_new; - u8 *linestart_older; - u8 *linestart_newer; - u8 *linestart_top; - u8 *linestart_bottom; - - frame_line = tpg_calc_frameline(tpg, src_y, tpg->field); - even = !(frame_line & 1); - buf_line = tpg_calc_buffer_line(tpg, h, tpg->field); - src_y += int_part; - error += fract_part; - if (error >= tpg->compose.height) { - error -= tpg->compose.height; - src_y++; - } +static void tpg_fill_plane_extras(const struct tpg_data *tpg, + const struct tpg_draw_params *params, + unsigned p, unsigned h, u8 *vbuf) +{ + unsigned twopixsize = params->twopixsize; + unsigned img_width = params->img_width; + unsigned frame_line = params->frame_line; + const struct v4l2_rect *sq = &tpg->square; + const struct v4l2_rect *b = &tpg->border; + const struct v4l2_rect *c = &tpg->crop; + + if (params->is_tv && !params->is_60hz && + frame_line == 0 && params->wss_width) { + /* + * Replace the first half of the top line of a 50 Hz frame + * with random data to simulate a WSS signal. + */ + u8 *wss = tpg->random_line[p] + params->wss_random_offset; - if (h >= hmax) { - if (hmax == tpg->compose.height) - continue; - if (!tpg->perc_fill_blank) - continue; - fill_blank = true; - } + memcpy(vbuf, wss, params->wss_width); + } + + if (tpg->show_border && frame_line >= b->top && + frame_line < b->top + b->height) { + unsigned bottom = b->top + b->height - 1; + unsigned left = params->left_pillar_width; + unsigned right = params->right_pillar_start; - if (tpg->vflip) - frame_line = tpg->src_height - frame_line - 1; - - if (fill_blank) { - linestart_older = tpg->contrast_line[p]; - linestart_newer = tpg->contrast_line[p]; - } else if (tpg->qual != TPG_QUAL_NOISE && - (frame_line < tpg->border.top || - frame_line >= tpg->border.top + tpg->border.height)) { - linestart_older = tpg->black_line[p]; - linestart_newer = tpg->black_line[p]; - } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) { - linestart_older = tpg->random_line[p] + - twopixsize * prandom_u32_max(tpg->src_width / 2); - linestart_newer = tpg->random_line[p] + - twopixsize * prandom_u32_max(tpg->src_width / 2); + if (frame_line == b->top || frame_line == b->top + 1 || + frame_line == bottom || frame_line == bottom - 1) { + memcpy(vbuf + left, tpg->contrast_line[p], + right - left); } else { - pat_line_old = tpg_get_pat_line(tpg, - (frame_line + mv_vert_old) % tpg->src_height); - pat_line_new = tpg_get_pat_line(tpg, - (frame_line + mv_vert_new) % tpg->src_height); - linestart_older = tpg->lines[pat_line_old][p] + - mv_hor_old * twopixsize / 2; - linestart_newer = tpg->lines[pat_line_new][p] + - mv_hor_new * twopixsize / 2; - linestart_older += line_offset; - linestart_newer += line_offset; + if (b->left >= c->left && + b->left < c->left + c->width) + memcpy(vbuf + left, + tpg->contrast_line[p], twopixsize); + if (b->left + b->width > c->left && + b->left + b->width <= c->left + c->width) + memcpy(vbuf + right - twopixsize, + tpg->contrast_line[p], twopixsize); } - if (is_60hz) { - linestart_top = linestart_newer; - linestart_bottom = linestart_older; - } else { - linestart_top = linestart_older; - linestart_bottom = linestart_newer; + } + if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top && + frame_line < b->top + b->height) { + memcpy(vbuf, tpg->black_line[p], params->left_pillar_width); + memcpy(vbuf + params->right_pillar_start, tpg->black_line[p], + img_width - params->right_pillar_start); + } + if (tpg->show_square && frame_line >= sq->top && + frame_line < sq->top + sq->height && + sq->left < c->left + c->width && + sq->left + sq->width >= c->left) { + unsigned left = sq->left; + unsigned width = sq->width; + + if (c->left > left) { + width -= c->left - left; + left = c->left; } + if (c->left + c->width < left + width) + width -= left + width - c->left - c->width; + left -= c->left; + left = tpg_hscale_div(tpg, p, left); + width = tpg_hscale_div(tpg, p, width); + memcpy(vbuf + left, tpg->contrast_line[p], width); + } + if (tpg->insert_sav) { + unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width / 3); + u8 *p = vbuf + offset; + unsigned vact = 0, hact = 0; + + p[0] = 0xff; + p[1] = 0; + p[2] = 0; + p[3] = 0x80 | (params->sav_eav_f << 6) | + (vact << 5) | (hact << 4) | + ((hact ^ vact) << 3) | + ((hact ^ params->sav_eav_f) << 2) | + ((params->sav_eav_f ^ vact) << 1) | + (hact ^ vact ^ params->sav_eav_f); + } + if (tpg->insert_eav) { + unsigned offset = tpg_hdiv(tpg, p, tpg->compose.width * 2 / 3); + u8 *p = vbuf + offset; + unsigned vact = 0, hact = 1; + + p[0] = 0xff; + p[1] = 0; + p[2] = 0; + p[3] = 0x80 | (params->sav_eav_f << 6) | + (vact << 5) | (hact << 4) | + ((hact ^ vact) << 3) | + ((hact ^ params->sav_eav_f) << 2) | + ((params->sav_eav_f ^ vact) << 1) | + (hact ^ vact ^ params->sav_eav_f); + } +} - switch (tpg->field) { - case V4L2_FIELD_INTERLACED: - case V4L2_FIELD_INTERLACED_TB: - case V4L2_FIELD_SEQ_TB: - case V4L2_FIELD_SEQ_BT: - if (even) - memcpy(vbuf + buf_line * stride, linestart_top, img_width); - else - memcpy(vbuf + buf_line * stride, linestart_bottom, img_width); - break; - case V4L2_FIELD_INTERLACED_BT: - if (even) - memcpy(vbuf + buf_line * stride, linestart_bottom, img_width); - else - memcpy(vbuf + buf_line * stride, linestart_top, img_width); - break; - case V4L2_FIELD_TOP: - memcpy(vbuf + buf_line * stride, linestart_top, img_width); - break; - case V4L2_FIELD_BOTTOM: - memcpy(vbuf + buf_line * stride, linestart_bottom, img_width); - break; - case V4L2_FIELD_NONE: - default: - memcpy(vbuf + buf_line * stride, linestart_older, img_width); - break; - } +static void tpg_fill_plane_pattern(const struct tpg_data *tpg, + const struct tpg_draw_params *params, + unsigned p, unsigned h, u8 *vbuf) +{ + unsigned twopixsize = params->twopixsize; + unsigned img_width = params->img_width; + unsigned mv_hor_old = params->mv_hor_old; + unsigned mv_hor_new = params->mv_hor_new; + unsigned mv_vert_old = params->mv_vert_old; + unsigned mv_vert_new = params->mv_vert_new; + unsigned frame_line = params->frame_line; + unsigned frame_line_next = params->frame_line_next; + unsigned line_offset = tpg_hscale_div(tpg, p, tpg->crop.left); + bool even; + bool fill_blank = false; + unsigned pat_line_old; + unsigned pat_line_new; + u8 *linestart_older; + u8 *linestart_newer; + u8 *linestart_top; + u8 *linestart_bottom; + + even = !(frame_line & 1); + + if (h >= params->hmax) { + if (params->hmax == tpg->compose.height) + return; + if (!tpg->perc_fill_blank) + return; + fill_blank = true; + } - if (is_tv && !is_60hz && frame_line == 0 && wss_width) { - /* - * Replace the first half of the top line of a 50 Hz frame - * with random data to simulate a WSS signal. - */ - u8 *wss = tpg->random_line[p] + + if (tpg->vflip) { + frame_line = tpg->src_height - frame_line - 1; + frame_line_next = tpg->src_height - frame_line_next - 1; + } + + if (fill_blank) { + linestart_older = tpg->contrast_line[p]; + linestart_newer = tpg->contrast_line[p]; + } else if (tpg->qual != TPG_QUAL_NOISE && + (frame_line < tpg->border.top || + frame_line >= tpg->border.top + tpg->border.height)) { + linestart_older = tpg->black_line[p]; + linestart_newer = tpg->black_line[p]; + } else if (tpg->pattern == TPG_PAT_NOISE || tpg->qual == TPG_QUAL_NOISE) { + linestart_older = tpg->random_line[p] + + twopixsize * prandom_u32_max(tpg->src_width / 2); + linestart_newer = tpg->random_line[p] + twopixsize * prandom_u32_max(tpg->src_width / 2); + } else { + unsigned frame_line_old = + (frame_line + mv_vert_old) % tpg->src_height; + unsigned frame_line_new = + (frame_line + mv_vert_new) % tpg->src_height; + unsigned pat_line_next_old; + unsigned pat_line_next_new; - memcpy(vbuf + buf_line * stride, wss, wss_width * twopixsize / 2); + pat_line_old = tpg_get_pat_line(tpg, frame_line_old); + pat_line_new = tpg_get_pat_line(tpg, frame_line_new); + linestart_older = tpg->lines[pat_line_old][p] + mv_hor_old; + linestart_newer = tpg->lines[pat_line_new][p] + mv_hor_new; + + if (tpg->vdownsampling[p] > 1 && frame_line != frame_line_next) { + int avg_pat; + + /* + * Now decide whether we need to use downsampled_lines[]. + * That's necessary if the two lines use different patterns. + */ + pat_line_next_old = tpg_get_pat_line(tpg, + (frame_line_next + mv_vert_old) % tpg->src_height); + pat_line_next_new = tpg_get_pat_line(tpg, + (frame_line_next + mv_vert_new) % tpg->src_height); + + switch (tpg->field) { + case V4L2_FIELD_INTERLACED: + case V4L2_FIELD_INTERLACED_BT: + case V4L2_FIELD_INTERLACED_TB: + avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_new); + if (avg_pat < 0) + break; + linestart_older = tpg->downsampled_lines[avg_pat][p] + mv_hor_old; + linestart_newer = linestart_older; + break; + case V4L2_FIELD_NONE: + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + case V4L2_FIELD_SEQ_BT: + case V4L2_FIELD_SEQ_TB: + avg_pat = tpg_pattern_avg(tpg, pat_line_old, pat_line_next_old); + if (avg_pat >= 0) + linestart_older = tpg->downsampled_lines[avg_pat][p] + + mv_hor_old; + avg_pat = tpg_pattern_avg(tpg, pat_line_new, pat_line_next_new); + if (avg_pat >= 0) + linestart_newer = tpg->downsampled_lines[avg_pat][p] + + mv_hor_new; + break; + } } + linestart_older += line_offset; + linestart_newer += line_offset; + } + if (tpg->field_alternate) { + linestart_top = linestart_bottom = linestart_older; + } else if (params->is_60hz) { + linestart_top = linestart_newer; + linestart_bottom = linestart_older; + } else { + linestart_top = linestart_older; + linestart_bottom = linestart_newer; + } + + switch (tpg->field) { + case V4L2_FIELD_INTERLACED: + case V4L2_FIELD_INTERLACED_TB: + case V4L2_FIELD_SEQ_TB: + case V4L2_FIELD_SEQ_BT: + if (even) + memcpy(vbuf, linestart_top, img_width); + else + memcpy(vbuf, linestart_bottom, img_width); + break; + case V4L2_FIELD_INTERLACED_BT: + if (even) + memcpy(vbuf, linestart_bottom, img_width); + else + memcpy(vbuf, linestart_top, img_width); + break; + case V4L2_FIELD_TOP: + memcpy(vbuf, linestart_top, img_width); + break; + case V4L2_FIELD_BOTTOM: + memcpy(vbuf, linestart_bottom, img_width); + break; + case V4L2_FIELD_NONE: + default: + memcpy(vbuf, linestart_older, img_width); + break; } +} + +void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, + unsigned p, u8 *vbuf) +{ + struct tpg_draw_params params; + unsigned factor = V4L2_FIELD_HAS_T_OR_B(tpg->field) ? 2 : 1; + + /* Coarse scaling with Bresenham */ + unsigned int_part = (tpg->crop.height / factor) / tpg->compose.height; + unsigned fract_part = (tpg->crop.height / factor) % tpg->compose.height; + unsigned src_y = 0; + unsigned error = 0; + unsigned h; + + tpg_recalc(tpg); + + params.is_tv = std; + params.is_60hz = std & V4L2_STD_525_60; + params.twopixsize = tpg->twopixelsize[p]; + params.img_width = tpg_hdiv(tpg, p, tpg->compose.width); + params.stride = tpg->bytesperline[p]; + params.hmax = (tpg->compose.height * tpg->perc_fill) / 100; + + tpg_fill_params_pattern(tpg, p, ¶ms); + tpg_fill_params_extras(tpg, p, ¶ms); + + vbuf += tpg_hdiv(tpg, p, tpg->compose.left); - vbuf = orig_vbuf; - vbuf += tpg->compose.left * twopixsize / 2; - src_y = 0; - error = 0; for (h = 0; h < tpg->compose.height; h++) { - unsigned frame_line = tpg_calc_frameline(tpg, src_y, tpg->field); - unsigned buf_line = tpg_calc_buffer_line(tpg, h, tpg->field); - const struct v4l2_rect *sq = &tpg->square; - const struct v4l2_rect *b = &tpg->border; - const struct v4l2_rect *c = &tpg->crop; + unsigned buf_line; + params.frame_line = tpg_calc_frameline(tpg, src_y, tpg->field); + params.frame_line_next = params.frame_line; + buf_line = tpg_calc_buffer_line(tpg, h, tpg->field); src_y += int_part; error += fract_part; if (error >= tpg->compose.height) { @@ -1475,80 +2032,61 @@ void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf) src_y++; } - if (tpg->show_border && frame_line >= b->top && - frame_line < b->top + b->height) { - unsigned bottom = b->top + b->height - 1; - unsigned left = left_pillar_width; - unsigned right = right_pillar_start; + /* + * For line-interleaved formats determine the 'plane' + * based on the buffer line. + */ + if (tpg_g_interleaved(tpg)) + p = tpg_g_interleaved_plane(tpg, buf_line); - if (frame_line == b->top || frame_line == b->top + 1 || - frame_line == bottom || frame_line == bottom - 1) { - memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p], - right - left); + if (tpg->vdownsampling[p] > 1) { + /* + * When doing vertical downsampling the field setting + * matters: for SEQ_BT/TB we downsample each field + * separately (i.e. lines 0+2 are combined, as are + * lines 1+3), for the other field settings we combine + * odd and even lines. Doing that for SEQ_BT/TB would + * be really weird. + */ + if (tpg->field == V4L2_FIELD_SEQ_BT || + tpg->field == V4L2_FIELD_SEQ_TB) { + unsigned next_src_y = src_y; + + if ((h & 3) >= 2) + continue; + next_src_y += int_part; + if (error + fract_part >= tpg->compose.height) + next_src_y++; + params.frame_line_next = + tpg_calc_frameline(tpg, next_src_y, tpg->field); } else { - if (b->left >= c->left && - b->left < c->left + c->width) - memcpy(vbuf + buf_line * stride + left, - tpg->contrast_line[p], twopixsize); - if (b->left + b->width > c->left && - b->left + b->width <= c->left + c->width) - memcpy(vbuf + buf_line * stride + right - twopixsize, - tpg->contrast_line[p], twopixsize); + if (h & 1) + continue; + params.frame_line_next = + tpg_calc_frameline(tpg, src_y, tpg->field); } + + buf_line /= tpg->vdownsampling[p]; } - if (tpg->qual != TPG_QUAL_NOISE && frame_line >= b->top && - frame_line < b->top + b->height) { - memcpy(vbuf + buf_line * stride, tpg->black_line[p], left_pillar_width); - memcpy(vbuf + buf_line * stride + right_pillar_start, tpg->black_line[p], - img_width - right_pillar_start); - } - if (tpg->show_square && frame_line >= sq->top && - frame_line < sq->top + sq->height && - sq->left < c->left + c->width && - sq->left + sq->width >= c->left) { - unsigned left = sq->left; - unsigned width = sq->width; - - if (c->left > left) { - width -= c->left - left; - left = c->left; - } - if (c->left + c->width < left + width) - width -= left + width - c->left - c->width; - left -= c->left; - left = (left * tpg->scaled_width) / tpg->src_width; - left = (left & ~1) * twopixsize / 2; - width = (width * tpg->scaled_width) / tpg->src_width; - width = (width & ~1) * twopixsize / 2; - memcpy(vbuf + buf_line * stride + left, tpg->contrast_line[p], width); - } - if (tpg->insert_sav) { - unsigned offset = (tpg->compose.width / 6) * twopixsize; - u8 *p = vbuf + buf_line * stride + offset; - unsigned vact = 0, hact = 0; - - p[0] = 0xff; - p[1] = 0; - p[2] = 0; - p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) | - ((hact ^ vact) << 3) | - ((hact ^ f) << 2) | - ((f ^ vact) << 1) | - (hact ^ vact ^ f); - } - if (tpg->insert_eav) { - unsigned offset = (tpg->compose.width / 6) * 2 * twopixsize; - u8 *p = vbuf + buf_line * stride + offset; - unsigned vact = 0, hact = 1; - - p[0] = 0xff; - p[1] = 0; - p[2] = 0; - p[3] = 0x80 | (f << 6) | (vact << 5) | (hact << 4) | - ((hact ^ vact) << 3) | - ((hact ^ f) << 2) | - ((f ^ vact) << 1) | - (hact ^ vact ^ f); - } + tpg_fill_plane_pattern(tpg, ¶ms, p, h, + vbuf + buf_line * params.stride); + tpg_fill_plane_extras(tpg, ¶ms, p, h, + vbuf + buf_line * params.stride); + } +} + +void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf) +{ + unsigned offset = 0; + unsigned i; + + if (tpg->buffers > 1) { + tpg_fill_plane_buffer(tpg, std, p, vbuf); + return; + } + + for (i = 0; i < tpg_g_planes(tpg); i++) { + tpg_fill_plane_buffer(tpg, std, i, vbuf + offset); + offset += tpg_calc_plane_size(tpg, i); } } diff --git a/drivers/media/platform/vivid/vivid-tpg.h b/drivers/media/platform/vivid/vivid-tpg.h index bd8b1c760b3f..a50cd2e2535b 100644 --- a/drivers/media/platform/vivid/vivid-tpg.h +++ b/drivers/media/platform/vivid/vivid-tpg.h @@ -41,7 +41,10 @@ enum tpg_pattern { TPG_PAT_GREEN, TPG_PAT_BLUE, TPG_PAT_CHECKERS_16X16, + TPG_PAT_CHECKERS_2X2, TPG_PAT_CHECKERS_1X1, + TPG_PAT_COLOR_CHECKERS_2X2, + TPG_PAT_COLOR_CHECKERS_1X1, TPG_PAT_ALTERNATING_HLINES, TPG_PAT_ALTERNATING_VLINES, TPG_PAT_CROSS_1_PIXEL, @@ -87,7 +90,7 @@ enum tpg_move_mode { extern const char * const tpg_aspect_strings[]; -#define TPG_MAX_PLANES 2 +#define TPG_MAX_PLANES 3 #define TPG_MAX_PAT_LINES 8 struct tpg_data { @@ -98,6 +101,7 @@ struct tpg_data { /* Scaled output frame size */ unsigned scaled_width; u32 field; + bool field_alternate; /* crop coordinates are frame-based */ struct v4l2_rect crop; /* compose coordinates are format-based */ @@ -134,7 +138,16 @@ struct tpg_data { enum tpg_pixel_aspect pix_aspect; unsigned rgb_range; unsigned real_rgb_range; + unsigned buffers; unsigned planes; + bool interleaved; + u8 vdownsampling[TPG_MAX_PLANES]; + u8 hdownsampling[TPG_MAX_PLANES]; + /* + * horizontal positions must be ANDed with this value to enforce + * correct boundaries for packed YUYV values. + */ + unsigned hmask[TPG_MAX_PLANES]; /* Used to store the colors in native format, either RGB or YUV */ u8 colors[TPG_COLOR_MAX][3]; u8 textfg[TPG_MAX_PLANES][8], textbg[TPG_MAX_PLANES][8]; @@ -168,6 +181,7 @@ struct tpg_data { /* Used to store TPG_MAX_PAT_LINES lines, each with up to two planes */ unsigned max_line_width; u8 *lines[TPG_MAX_PAT_LINES][TPG_MAX_PLANES]; + u8 *downsampled_lines[TPG_MAX_PAT_LINES][TPG_MAX_PLANES]; u8 *random_line[TPG_MAX_PLANES]; u8 *contrast_line[TPG_MAX_PLANES]; u8 *black_line[TPG_MAX_PLANES]; @@ -180,11 +194,15 @@ void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height, u32 field); void tpg_set_font(const u8 *f); -void tpg_gen_text(struct tpg_data *tpg, +void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], int y, int x, char *text); void tpg_calc_text_basep(struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2], unsigned p, u8 *vbuf); -void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf); +unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line); +void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std, + unsigned p, u8 *vbuf); +void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, + unsigned p, u8 *vbuf); bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc); void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop, const struct v4l2_rect *compose); @@ -323,9 +341,19 @@ static inline u32 tpg_g_quantization(const struct tpg_data *tpg) return tpg->quantization; } +static inline unsigned tpg_g_buffers(const struct tpg_data *tpg) +{ + return tpg->buffers; +} + static inline unsigned tpg_g_planes(const struct tpg_data *tpg) { - return tpg->planes; + return tpg->interleaved ? 1 : tpg->planes; +} + +static inline bool tpg_g_interleaved(const struct tpg_data *tpg) +{ + return tpg->interleaved; } static inline unsigned tpg_g_twopixelsize(const struct tpg_data *tpg, unsigned plane) @@ -333,6 +361,24 @@ static inline unsigned tpg_g_twopixelsize(const struct tpg_data *tpg, unsigned p return tpg->twopixelsize[plane]; } +static inline unsigned tpg_hdiv(const struct tpg_data *tpg, + unsigned plane, unsigned x) +{ + return ((x / tpg->hdownsampling[plane]) & tpg->hmask[plane]) * + tpg->twopixelsize[plane] / 2; +} + +static inline unsigned tpg_hscale(const struct tpg_data *tpg, unsigned x) +{ + return (x * tpg->scaled_width) / tpg->src_width; +} + +static inline unsigned tpg_hscale_div(const struct tpg_data *tpg, + unsigned plane, unsigned x) +{ + return tpg_hdiv(tpg, plane, tpg_hscale(tpg, x)); +} + static inline unsigned tpg_g_bytesperline(const struct tpg_data *tpg, unsigned plane) { return tpg->bytesperline[plane]; @@ -340,7 +386,60 @@ static inline unsigned tpg_g_bytesperline(const struct tpg_data *tpg, unsigned p static inline void tpg_s_bytesperline(struct tpg_data *tpg, unsigned plane, unsigned bpl) { - tpg->bytesperline[plane] = bpl; + unsigned p; + + if (tpg->buffers > 1) { + tpg->bytesperline[plane] = bpl; + return; + } + + for (p = 0; p < tpg_g_planes(tpg); p++) { + unsigned plane_w = bpl * tpg->twopixelsize[p] / tpg->twopixelsize[0]; + + tpg->bytesperline[p] = plane_w / tpg->hdownsampling[p]; + } +} + + +static inline unsigned tpg_g_line_width(const struct tpg_data *tpg, unsigned plane) +{ + unsigned w = 0; + unsigned p; + + if (tpg->buffers > 1) + return tpg_g_bytesperline(tpg, plane); + for (p = 0; p < tpg_g_planes(tpg); p++) { + unsigned plane_w = tpg_g_bytesperline(tpg, p); + + w += plane_w / tpg->vdownsampling[p]; + } + return w; +} + +static inline unsigned tpg_calc_line_width(const struct tpg_data *tpg, + unsigned plane, unsigned bpl) +{ + unsigned w = 0; + unsigned p; + + if (tpg->buffers > 1) + return bpl; + for (p = 0; p < tpg_g_planes(tpg); p++) { + unsigned plane_w = bpl * tpg->twopixelsize[p] / tpg->twopixelsize[0]; + + plane_w /= tpg->hdownsampling[p]; + w += plane_w / tpg->vdownsampling[p]; + } + return w; +} + +static inline unsigned tpg_calc_plane_size(const struct tpg_data *tpg, unsigned plane) +{ + if (plane >= tpg_g_planes(tpg)) + return 0; + + return tpg_g_bytesperline(tpg, plane) * tpg->buf_height / + tpg->vdownsampling[plane]; } static inline void tpg_s_buf_height(struct tpg_data *tpg, unsigned h) @@ -348,9 +447,10 @@ static inline void tpg_s_buf_height(struct tpg_data *tpg, unsigned h) tpg->buf_height = h; } -static inline void tpg_s_field(struct tpg_data *tpg, unsigned field) +static inline void tpg_s_field(struct tpg_data *tpg, unsigned field, bool alternate) { tpg->field = field; + tpg->field_alternate = alternate; } static inline void tpg_s_perc_fill(struct tpg_data *tpg, diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index 867a29a6d18f..dab5990f45a0 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -42,20 +42,26 @@ static const struct vivid_fmt formats_ovl[] = { { .name = "RGB565 (LE)", .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ - .depth = 16, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, .planes = 1, + .buffers = 1, }, { .name = "XRGB555 (LE)", .fourcc = V4L2_PIX_FMT_XRGB555, /* gggbbbbb arrrrrgg */ - .depth = 16, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, .planes = 1, + .buffers = 1, }, { .name = "ARGB555 (LE)", .fourcc = V4L2_PIX_FMT_ARGB555, /* gggbbbbb arrrrrgg */ - .depth = 16, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, .planes = 1, + .buffers = 1, }, }; @@ -94,7 +100,7 @@ static int vid_cap_queue_setup(struct vb2_queue *vq, const struct v4l2_format *f unsigned sizes[], void *alloc_ctxs[]) { struct vivid_dev *dev = vb2_get_drv_priv(vq); - unsigned planes = tpg_g_planes(&dev->tpg); + unsigned buffers = tpg_g_buffers(&dev->tpg); unsigned h = dev->fmt_cap_rect.height; unsigned p; @@ -127,39 +133,36 @@ static int vid_cap_queue_setup(struct vb2_queue *vq, const struct v4l2_format *f mp = &fmt->fmt.pix_mp; /* * Check if the number of planes in the specified format match - * the number of planes in the current format. You can't mix that. + * the number of buffers in the current format. You can't mix that. */ - if (mp->num_planes != planes) + if (mp->num_planes != buffers) return -EINVAL; vfmt = vivid_get_format(dev, mp->pixelformat); - for (p = 0; p < planes; p++) { + for (p = 0; p < buffers; p++) { sizes[p] = mp->plane_fmt[p].sizeimage; - if (sizes[0] < tpg_g_bytesperline(&dev->tpg, 0) * h + + if (sizes[p] < tpg_g_line_width(&dev->tpg, p) * h + vfmt->data_offset[p]) return -EINVAL; } } else { - for (p = 0; p < planes; p++) - sizes[p] = tpg_g_bytesperline(&dev->tpg, p) * h + + for (p = 0; p < buffers; p++) + sizes[p] = tpg_g_line_width(&dev->tpg, p) * h + dev->fmt_cap->data_offset[p]; } if (vq->num_buffers + *nbuffers < 2) *nbuffers = 2 - vq->num_buffers; - *nplanes = planes; + *nplanes = buffers; /* * videobuf2-vmalloc allocator is context-less so no need to set * alloc_ctxs array. */ - if (planes == 2) - dprintk(dev, 1, "%s, count=%d, sizes=%u, %u\n", __func__, - *nbuffers, sizes[0], sizes[1]); - else - dprintk(dev, 1, "%s, count=%d, size=%u\n", __func__, - *nbuffers, sizes[0]); + dprintk(dev, 1, "%s: count=%d\n", __func__, *nbuffers); + for (p = 0; p < buffers; p++) + dprintk(dev, 1, "%s: size[%u]=%u\n", __func__, p, sizes[p]); return 0; } @@ -168,7 +171,7 @@ static int vid_cap_buf_prepare(struct vb2_buffer *vb) { struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); unsigned long size; - unsigned planes = tpg_g_planes(&dev->tpg); + unsigned buffers = tpg_g_buffers(&dev->tpg); unsigned p; dprintk(dev, 1, "%s\n", __func__); @@ -184,13 +187,13 @@ static int vid_cap_buf_prepare(struct vb2_buffer *vb) dev->buf_prepare_error = false; return -EINVAL; } - for (p = 0; p < planes; p++) { - size = tpg_g_bytesperline(&dev->tpg, p) * dev->fmt_cap_rect.height + + for (p = 0; p < buffers; p++) { + size = tpg_g_line_width(&dev->tpg, p) * dev->fmt_cap_rect.height + dev->fmt_cap->data_offset[p]; - if (vb2_plane_size(vb, 0) < size) { + if (vb2_plane_size(vb, p) < size) { dprintk(dev, 1, "%s data will not fit into plane %u (%lu < %lu)\n", - __func__, p, vb2_plane_size(vb, 0), size); + __func__, p, vb2_plane_size(vb, p), size); return -EINVAL; } @@ -441,7 +444,7 @@ void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls) */ if (keep_controls || !dev->colorspace) break; - if (bt->standards & V4L2_DV_BT_STD_CEA861) { + if (bt->flags & V4L2_DV_FL_IS_CE_VIDEO) { if (bt->width == 720 && bt->height <= 576) v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_170M); else @@ -526,11 +529,11 @@ int vivid_g_fmt_vid_cap(struct file *file, void *priv, mp->colorspace = vivid_colorspace_cap(dev); mp->ycbcr_enc = vivid_ycbcr_enc_cap(dev); mp->quantization = vivid_quantization_cap(dev); - mp->num_planes = dev->fmt_cap->planes; + mp->num_planes = dev->fmt_cap->buffers; for (p = 0; p < mp->num_planes; p++) { mp->plane_fmt[p].bytesperline = tpg_g_bytesperline(&dev->tpg, p); mp->plane_fmt[p].sizeimage = - mp->plane_fmt[p].bytesperline * mp->height + + tpg_g_line_width(&dev->tpg, p) * mp->height + dev->fmt_cap->data_offset[p]; } return 0; @@ -596,18 +599,19 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv, /* This driver supports custom bytesperline values */ - /* Calculate the minimum supported bytesperline value */ - bytesperline = (mp->width * fmt->depth) >> 3; - /* Calculate the maximum supported bytesperline value */ - max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->depth) >> 3; - mp->num_planes = fmt->planes; + mp->num_planes = fmt->buffers; for (p = 0; p < mp->num_planes; p++) { + /* Calculate the minimum supported bytesperline value */ + bytesperline = (mp->width * fmt->bit_depth[p]) >> 3; + /* Calculate the maximum supported bytesperline value */ + max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->bit_depth[p]) >> 3; + if (pfmt[p].bytesperline > max_bpl) pfmt[p].bytesperline = max_bpl; if (pfmt[p].bytesperline < bytesperline) pfmt[p].bytesperline = bytesperline; - pfmt[p].sizeimage = pfmt[p].bytesperline * mp->height + - fmt->data_offset[p]; + pfmt[p].sizeimage = tpg_calc_line_width(&dev->tpg, p, pfmt[p].bytesperline) * + mp->height + fmt->data_offset[p]; memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved)); } mp->colorspace = vivid_colorspace_cap(dev); @@ -627,6 +631,7 @@ int vivid_s_fmt_vid_cap(struct file *file, void *priv, struct vb2_queue *q = &dev->vb_vid_cap_q; int ret = vivid_try_fmt_vid_cap(file, priv, f); unsigned factor = 1; + unsigned p; unsigned i; if (ret < 0) @@ -729,13 +734,15 @@ int vivid_s_fmt_vid_cap(struct file *file, void *priv, dev->fmt_cap_rect.width = mp->width; dev->fmt_cap_rect.height = mp->height; tpg_s_buf_height(&dev->tpg, mp->height); - tpg_s_bytesperline(&dev->tpg, 0, mp->plane_fmt[0].bytesperline); - if (tpg_g_planes(&dev->tpg) > 1) - tpg_s_bytesperline(&dev->tpg, 1, mp->plane_fmt[1].bytesperline); + tpg_s_fourcc(&dev->tpg, dev->fmt_cap->fourcc); + for (p = 0; p < tpg_g_buffers(&dev->tpg); p++) + tpg_s_bytesperline(&dev->tpg, p, mp->plane_fmt[p].bytesperline); dev->field_cap = mp->field; - tpg_s_field(&dev->tpg, dev->field_cap); + if (dev->field_cap == V4L2_FIELD_ALTERNATE) + tpg_s_field(&dev->tpg, V4L2_FIELD_TOP, true); + else + tpg_s_field(&dev->tpg, dev->field_cap, false); tpg_s_crop_compose(&dev->tpg, &dev->crop_cap, &dev->compose_cap); - tpg_s_fourcc(&dev->tpg, dev->fmt_cap->fourcc); if (vivid_is_sdtv_cap(dev)) dev->tv_field_cap = mp->field; tpg_update_mv_step(&dev->tpg); @@ -1012,8 +1019,12 @@ int vivid_vid_cap_cropcap(struct file *file, void *priv, int vidioc_enum_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_fmtdesc *f) { + struct vivid_dev *dev = video_drvdata(file); const struct vivid_fmt *fmt; + if (dev->multiplanar) + return -ENOTTY; + if (f->index >= ARRAY_SIZE(formats_ovl)) return -EINVAL; @@ -1032,6 +1043,9 @@ int vidioc_g_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_window *win = &f->fmt.win; unsigned clipcount = win->clipcount; + if (dev->multiplanar) + return -ENOTTY; + win->w.top = dev->overlay_cap_top; win->w.left = dev->overlay_cap_left; win->w.width = compose->width; @@ -1063,6 +1077,9 @@ int vidioc_try_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_window *win = &f->fmt.win; int i, j; + if (dev->multiplanar) + return -ENOTTY; + win->w.left = clamp_t(int, win->w.left, -dev->fb_cap.fmt.width, dev->fb_cap.fmt.width); win->w.top = clamp_t(int, win->w.top, @@ -1150,6 +1167,9 @@ int vivid_vid_cap_overlay(struct file *file, void *fh, unsigned i) { struct vivid_dev *dev = video_drvdata(file); + if (dev->multiplanar) + return -ENOTTY; + if (i && dev->fb_vbase_cap == NULL) return -EINVAL; @@ -1169,6 +1189,9 @@ int vivid_vid_cap_g_fbuf(struct file *file, void *fh, { struct vivid_dev *dev = video_drvdata(file); + if (dev->multiplanar) + return -ENOTTY; + *a = dev->fb_cap; a->capability = V4L2_FBUF_CAP_BITMAP_CLIPPING | V4L2_FBUF_CAP_LIST_CLIPPING; @@ -1185,6 +1208,9 @@ int vivid_vid_cap_s_fbuf(struct file *file, void *fh, struct vivid_dev *dev = video_drvdata(file); const struct vivid_fmt *fmt; + if (dev->multiplanar) + return -ENOTTY; + if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) return -EPERM; @@ -1202,7 +1228,7 @@ int vivid_vid_cap_s_fbuf(struct file *file, void *fh, fmt = vivid_get_format(dev, a->fmt.pixelformat); if (!fmt || !fmt->can_do_overlay) return -EINVAL; - if (a->fmt.bytesperline < (a->fmt.width * fmt->depth) / 8) + if (a->fmt.bytesperline < (a->fmt.width * fmt->bit_depth[0]) / 8) return -EINVAL; if (a->fmt.height * a->fmt.bytesperline < a->fmt.sizeimage) return -EINVAL; @@ -1332,7 +1358,7 @@ int vidioc_s_input(struct file *file, void *priv, unsigned i) v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_170M); break; case HDMI: - if (bt->standards & V4L2_DV_BT_STD_CEA861) { + if (bt->flags & V4L2_DV_FL_IS_CE_VIDEO) { if (dev->src_rect.width == 720 && dev->src_rect.height <= 576) v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_170M); else @@ -1552,6 +1578,65 @@ int vivid_vid_cap_s_std(struct file *file, void *priv, v4l2_std_id id) return 0; } +static void find_aspect_ratio(u32 width, u32 height, + u32 *num, u32 *denom) +{ + if (!(height % 3) && ((height * 4 / 3) == width)) { + *num = 4; + *denom = 3; + } else if (!(height % 9) && ((height * 16 / 9) == width)) { + *num = 16; + *denom = 9; + } else if (!(height % 10) && ((height * 16 / 10) == width)) { + *num = 16; + *denom = 10; + } else if (!(height % 4) && ((height * 5 / 4) == width)) { + *num = 5; + *denom = 4; + } else if (!(height % 9) && ((height * 15 / 9) == width)) { + *num = 15; + *denom = 9; + } else { /* default to 16:9 */ + *num = 16; + *denom = 9; + } +} + +static bool valid_cvt_gtf_timings(struct v4l2_dv_timings *timings) +{ + struct v4l2_bt_timings *bt = &timings->bt; + u32 total_h_pixel; + u32 total_v_lines; + u32 h_freq; + + if (!v4l2_valid_dv_timings(timings, &vivid_dv_timings_cap, + NULL, NULL)) + return false; + + total_h_pixel = V4L2_DV_BT_FRAME_WIDTH(bt); + total_v_lines = V4L2_DV_BT_FRAME_HEIGHT(bt); + + h_freq = (u32)bt->pixelclock / total_h_pixel; + + if (bt->standards == 0 || (bt->standards & V4L2_DV_BT_STD_CVT)) { + if (v4l2_detect_cvt(total_v_lines, h_freq, bt->vsync, + bt->polarities, timings)) + return true; + } + + if (bt->standards == 0 || (bt->standards & V4L2_DV_BT_STD_GTF)) { + struct v4l2_fract aspect_ratio; + + find_aspect_ratio(bt->width, bt->height, + &aspect_ratio.numerator, + &aspect_ratio.denominator); + if (v4l2_detect_gtf(total_v_lines, h_freq, bt->vsync, + bt->polarities, aspect_ratio, timings)) + return true; + } + return false; +} + int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings) { @@ -1559,13 +1644,16 @@ int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh, if (!vivid_is_hdmi_cap(dev)) return -ENODATA; - if (vb2_is_busy(&dev->vb_vid_cap_q)) - return -EBUSY; if (!v4l2_find_dv_timings_cap(timings, &vivid_dv_timings_cap, - 0, NULL, NULL)) + 0, NULL, NULL) && + !valid_cvt_gtf_timings(timings)) return -EINVAL; + if (v4l2_match_dv_timings(timings, &dev->dv_timings_cap, 0)) return 0; + if (vb2_is_busy(&dev->vb_vid_cap_q)) + return -EBUSY; + dev->dv_timings_cap = *timings; vivid_update_format_cap(dev, false); return 0; @@ -1663,18 +1751,14 @@ int vidioc_enum_frameintervals(struct file *file, void *priv, return -EINVAL; if (!vivid_is_webcam(dev)) { - static const struct v4l2_fract step = { 1, 1 }; - if (fival->index) return -EINVAL; if (fival->width < MIN_WIDTH || fival->width > MAX_WIDTH * MAX_ZOOM) return -EINVAL; if (fival->height < MIN_HEIGHT || fival->height > MAX_HEIGHT * MAX_ZOOM) return -EINVAL; - fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS; - fival->stepwise.min = tpf_min; - fival->stepwise.max = tpf_max; - fival->stepwise.step = step; + fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; + fival->discrete = dev->timeperframe_vid_cap; return 0; } diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index 6bef1e6d6788..aa446271ad34 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -33,8 +33,9 @@ const struct v4l2_dv_timings_cap vivid_dv_timings_cap = { .type = V4L2_DV_BT_656_1120, /* keep this initialization for compatibility with GCC < 4.4.6 */ .reserved = { 0 }, - V4L2_INIT_BT_TIMINGS(0, MAX_WIDTH, 0, MAX_HEIGHT, 25000000, 600000000, - V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT, + V4L2_INIT_BT_TIMINGS(0, MAX_WIDTH, 0, MAX_HEIGHT, 14000000, 775000000, + V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | + V4L2_DV_BT_STD_CVT | V4L2_DV_BT_STD_GTF, V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_INTERLACED) }; @@ -46,145 +47,435 @@ struct vivid_fmt vivid_formats[] = { { .name = "4:2:2, packed, YUYV", .fourcc = V4L2_PIX_FMT_YUYV, - .depth = 16, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, .is_yuv = true, .planes = 1, - .data_offset = { PLANE0_DATA_OFFSET, 0 }, + .buffers = 1, + .data_offset = { PLANE0_DATA_OFFSET }, }, { .name = "4:2:2, packed, UYVY", .fourcc = V4L2_PIX_FMT_UYVY, - .depth = 16, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, .is_yuv = true, .planes = 1, + .buffers = 1, }, { .name = "4:2:2, packed, YVYU", .fourcc = V4L2_PIX_FMT_YVYU, - .depth = 16, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, .is_yuv = true, .planes = 1, + .buffers = 1, }, { .name = "4:2:2, packed, VYUY", .fourcc = V4L2_PIX_FMT_VYUY, - .depth = 16, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .is_yuv = true, + .planes = 1, + .buffers = 1, + }, + { + .name = "YUV 4:2:2 triplanar", + .fourcc = V4L2_PIX_FMT_YUV422P, + .vdownsampling = { 1, 1, 1 }, + .bit_depth = { 8, 4, 4 }, + .is_yuv = true, + .planes = 3, + .buffers = 1, + }, + { + .name = "YUV 4:2:0 triplanar", + .fourcc = V4L2_PIX_FMT_YUV420, + .vdownsampling = { 1, 2, 2 }, + .bit_depth = { 8, 4, 4 }, + .is_yuv = true, + .planes = 3, + .buffers = 1, + }, + { + .name = "YVU 4:2:0 triplanar", + .fourcc = V4L2_PIX_FMT_YVU420, + .vdownsampling = { 1, 2, 2 }, + .bit_depth = { 8, 4, 4 }, + .is_yuv = true, + .planes = 3, + .buffers = 1, + }, + { + .name = "YUV 4:2:0 biplanar", + .fourcc = V4L2_PIX_FMT_NV12, + .vdownsampling = { 1, 2 }, + .bit_depth = { 8, 8 }, + .is_yuv = true, + .planes = 2, + .buffers = 1, + }, + { + .name = "YVU 4:2:0 biplanar", + .fourcc = V4L2_PIX_FMT_NV21, + .vdownsampling = { 1, 2 }, + .bit_depth = { 8, 8 }, + .is_yuv = true, + .planes = 2, + .buffers = 1, + }, + { + .name = "YUV 4:2:2 biplanar", + .fourcc = V4L2_PIX_FMT_NV16, + .vdownsampling = { 1, 1 }, + .bit_depth = { 8, 8 }, + .is_yuv = true, + .planes = 2, + .buffers = 1, + }, + { + .name = "YVU 4:2:2 biplanar", + .fourcc = V4L2_PIX_FMT_NV61, + .vdownsampling = { 1, 1 }, + .bit_depth = { 8, 8 }, + .is_yuv = true, + .planes = 2, + .buffers = 1, + }, + { + .name = "YUV 4:4:4 biplanar", + .fourcc = V4L2_PIX_FMT_NV24, + .vdownsampling = { 1, 1 }, + .bit_depth = { 8, 16 }, + .is_yuv = true, + .planes = 2, + .buffers = 1, + }, + { + .name = "YVU 4:4:4 biplanar", + .fourcc = V4L2_PIX_FMT_NV42, + .vdownsampling = { 1, 1 }, + .bit_depth = { 8, 16 }, + .is_yuv = true, + .planes = 2, + .buffers = 1, + }, + { + .name = "YUV555 (LE)", + .fourcc = V4L2_PIX_FMT_YUV555, /* uuuvvvvv ayyyyyuu */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0x8000, + }, + { + .name = "YUV565 (LE)", + .fourcc = V4L2_PIX_FMT_YUV565, /* uuuvvvvv yyyyyuuu */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .name = "YUV444", + .fourcc = V4L2_PIX_FMT_YUV444, /* uuuuvvvv aaaayyyy */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0xf000, + }, + { + .name = "YUV32 (LE)", + .fourcc = V4L2_PIX_FMT_YUV32, /* ayuv */ + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0x000000ff, + }, + { + .name = "Monochrome", + .fourcc = V4L2_PIX_FMT_GREY, + .vdownsampling = { 1 }, + .bit_depth = { 8 }, .is_yuv = true, .planes = 1, + .buffers = 1, + }, + { + .name = "RGB332", + .fourcc = V4L2_PIX_FMT_RGB332, /* rrrgggbb */ + .vdownsampling = { 1 }, + .bit_depth = { 8 }, + .planes = 1, + .buffers = 1, }, { .name = "RGB565 (LE)", .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ - .depth = 16, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, .planes = 1, + .buffers = 1, .can_do_overlay = true, }, { .name = "RGB565 (BE)", .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ - .depth = 16, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, .planes = 1, + .buffers = 1, .can_do_overlay = true, }, { + .name = "RGB444", + .fourcc = V4L2_PIX_FMT_RGB444, /* xxxxrrrr ggggbbbb */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .name = "XRGB444", + .fourcc = V4L2_PIX_FMT_XRGB444, /* xxxxrrrr ggggbbbb */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .name = "ARGB444", + .fourcc = V4L2_PIX_FMT_ARGB444, /* aaaarrrr ggggbbbb */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0x00f0, + }, + { .name = "RGB555 (LE)", - .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */ - .depth = 16, + .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb xrrrrrgg */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, .planes = 1, + .buffers = 1, .can_do_overlay = true, }, { .name = "XRGB555 (LE)", - .fourcc = V4L2_PIX_FMT_XRGB555, /* gggbbbbb arrrrrgg */ - .depth = 16, + .fourcc = V4L2_PIX_FMT_XRGB555, /* gggbbbbb xrrrrrgg */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, .planes = 1, + .buffers = 1, .can_do_overlay = true, }, { .name = "ARGB555 (LE)", .fourcc = V4L2_PIX_FMT_ARGB555, /* gggbbbbb arrrrrgg */ - .depth = 16, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, .planes = 1, + .buffers = 1, .can_do_overlay = true, .alpha_mask = 0x8000, }, { .name = "RGB555 (BE)", - .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */ - .depth = 16, + .fourcc = V4L2_PIX_FMT_RGB555X, /* xrrrrrgg gggbbbbb */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, .planes = 1, - .can_do_overlay = true, + .buffers = 1, + }, + { + .name = "XRGB555 (BE)", + .fourcc = V4L2_PIX_FMT_XRGB555X, /* xrrrrrgg gggbbbbb */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .name = "ARGB555 (BE)", + .fourcc = V4L2_PIX_FMT_ARGB555X, /* arrrrrgg gggbbbbb */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0x0080, }, { .name = "RGB24 (LE)", .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */ - .depth = 24, + .vdownsampling = { 1 }, + .bit_depth = { 24 }, .planes = 1, + .buffers = 1, }, { .name = "RGB24 (BE)", .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */ - .depth = 24, + .vdownsampling = { 1 }, + .bit_depth = { 24 }, .planes = 1, + .buffers = 1, + }, + { + .name = "BGR666", + .fourcc = V4L2_PIX_FMT_BGR666, /* bbbbbbgg ggggrrrr rrxxxxxx */ + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, }, { .name = "RGB32 (LE)", - .fourcc = V4L2_PIX_FMT_RGB32, /* argb */ - .depth = 32, + .fourcc = V4L2_PIX_FMT_RGB32, /* xrgb */ + .vdownsampling = { 1 }, + .bit_depth = { 32 }, .planes = 1, + .buffers = 1, }, { .name = "RGB32 (BE)", - .fourcc = V4L2_PIX_FMT_BGR32, /* bgra */ - .depth = 32, + .fourcc = V4L2_PIX_FMT_BGR32, /* bgrx */ + .vdownsampling = { 1 }, + .bit_depth = { 32 }, .planes = 1, + .buffers = 1, }, { .name = "XRGB32 (LE)", - .fourcc = V4L2_PIX_FMT_XRGB32, /* argb */ - .depth = 32, + .fourcc = V4L2_PIX_FMT_XRGB32, /* xrgb */ + .vdownsampling = { 1 }, + .bit_depth = { 32 }, .planes = 1, + .buffers = 1, }, { .name = "XRGB32 (BE)", - .fourcc = V4L2_PIX_FMT_XBGR32, /* bgra */ - .depth = 32, + .fourcc = V4L2_PIX_FMT_XBGR32, /* bgrx */ + .vdownsampling = { 1 }, + .bit_depth = { 32 }, .planes = 1, + .buffers = 1, }, { .name = "ARGB32 (LE)", .fourcc = V4L2_PIX_FMT_ARGB32, /* argb */ - .depth = 32, + .vdownsampling = { 1 }, + .bit_depth = { 32 }, .planes = 1, + .buffers = 1, .alpha_mask = 0x000000ff, }, { .name = "ARGB32 (BE)", .fourcc = V4L2_PIX_FMT_ABGR32, /* bgra */ - .depth = 32, + .vdownsampling = { 1 }, + .bit_depth = { 32 }, .planes = 1, + .buffers = 1, .alpha_mask = 0xff000000, }, { - .name = "4:2:2, planar, YUV", + .name = "Bayer BG/GR", + .fourcc = V4L2_PIX_FMT_SBGGR8, /* Bayer BG/GR */ + .vdownsampling = { 1 }, + .bit_depth = { 8 }, + .planes = 1, + .buffers = 1, + }, + { + .name = "Bayer GB/RG", + .fourcc = V4L2_PIX_FMT_SGBRG8, /* Bayer GB/RG */ + .vdownsampling = { 1 }, + .bit_depth = { 8 }, + .planes = 1, + .buffers = 1, + }, + { + .name = "Bayer GR/BG", + .fourcc = V4L2_PIX_FMT_SGRBG8, /* Bayer GR/BG */ + .vdownsampling = { 1 }, + .bit_depth = { 8 }, + .planes = 1, + .buffers = 1, + }, + { + .name = "Bayer RG/GB", + .fourcc = V4L2_PIX_FMT_SRGGB8, /* Bayer RG/GB */ + .vdownsampling = { 1 }, + .bit_depth = { 8 }, + .planes = 1, + .buffers = 1, + }, + { + .name = "4:2:2, biplanar, YUV", .fourcc = V4L2_PIX_FMT_NV16M, - .depth = 8, + .vdownsampling = { 1, 1 }, + .bit_depth = { 8, 8 }, .is_yuv = true, .planes = 2, + .buffers = 2, .data_offset = { PLANE0_DATA_OFFSET, 0 }, }, { - .name = "4:2:2, planar, YVU", + .name = "4:2:2, biplanar, YVU", .fourcc = V4L2_PIX_FMT_NV61M, - .depth = 8, + .vdownsampling = { 1, 1 }, + .bit_depth = { 8, 8 }, .is_yuv = true, .planes = 2, + .buffers = 2, .data_offset = { 0, PLANE0_DATA_OFFSET }, }, + { + .name = "4:2:0, triplanar, YUV", + .fourcc = V4L2_PIX_FMT_YUV420M, + .vdownsampling = { 1, 2, 2 }, + .bit_depth = { 8, 4, 4 }, + .is_yuv = true, + .planes = 3, + .buffers = 3, + }, + { + .name = "4:2:0, triplanar, YVU", + .fourcc = V4L2_PIX_FMT_YVU420M, + .vdownsampling = { 1, 2, 2 }, + .bit_depth = { 8, 4, 4 }, + .is_yuv = true, + .planes = 3, + .buffers = 3, + }, + { + .name = "4:2:0, biplanar, YUV", + .fourcc = V4L2_PIX_FMT_NV12M, + .vdownsampling = { 1, 2 }, + .bit_depth = { 8, 8 }, + .is_yuv = true, + .planes = 2, + .buffers = 2, + }, + { + .name = "4:2:0, biplanar, YVU", + .fourcc = V4L2_PIX_FMT_NV21M, + .vdownsampling = { 1, 2 }, + .bit_depth = { 8, 8 }, + .is_yuv = true, + .planes = 2, + .buffers = 2, + }, }; -/* There are 2 multiplanar formats in the list */ -#define VIVID_MPLANAR_FORMATS 2 +/* There are 6 multiplanar formats in the list */ +#define VIVID_MPLANAR_FORMATS 6 const struct vivid_fmt *vivid_get_format(struct vivid_dev *dev, u32 pixelformat) { @@ -194,7 +485,7 @@ const struct vivid_fmt *vivid_get_format(struct vivid_dev *dev, u32 pixelformat) for (k = 0; k < ARRAY_SIZE(vivid_formats); k++) { fmt = &vivid_formats[k]; if (fmt->fourcc == pixelformat) - if (fmt->planes == 1 || dev->multiplanar) + if (fmt->buffers == 1 || dev->multiplanar) return fmt; } @@ -210,6 +501,13 @@ bool vivid_vid_can_loop(struct vivid_dev *dev) return false; if (dev->field_cap != dev->field_out) return false; + /* + * While this can be supported, it is just too much work + * to actually implement. + */ + if (dev->field_cap == V4L2_FIELD_SEQ_TB || + dev->field_cap == V4L2_FIELD_SEQ_BT) + return false; if (vivid_is_svid_cap(dev) && vivid_is_svid_out(dev)) { if (!(dev->std_cap & V4L2_STD_525_60) != !(dev->std_out & V4L2_STD_525_60)) @@ -397,6 +695,9 @@ int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r) unsigned w = r->width; unsigned h = r->height; + /* sanitize w and h in case someone passes ~0 as the value */ + w &= 0xffff; + h &= 0xffff; if (!(flags & V4L2_SEL_FLAG_LE)) { w++; h++; @@ -421,8 +722,9 @@ int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r) r->top = 0; if (r->left < 0) r->left = 0; - r->left &= ~1; - r->top &= ~1; + /* sanitize left and top in case someone passes ~0 as the value */ + r->left &= 0xfffe; + r->top &= 0xfffe; if (r->left + w > MAX_WIDTH) r->left = MAX_WIDTH - w; if (r->top + h > MAX_HEIGHT) diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index 39ff79f6aa67..0af43dc7715c 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c @@ -36,9 +36,14 @@ static int vid_out_queue_setup(struct vb2_queue *vq, const struct v4l2_format *f unsigned sizes[], void *alloc_ctxs[]) { struct vivid_dev *dev = vb2_get_drv_priv(vq); - unsigned planes = dev->fmt_out->planes; + const struct vivid_fmt *vfmt = dev->fmt_out; + unsigned planes = vfmt->buffers; unsigned h = dev->fmt_out_rect.height; unsigned size = dev->bytesperline_out[0] * h; + unsigned p; + + for (p = vfmt->buffers; p < vfmt->planes; p++) + size += dev->bytesperline_out[p] * h / vfmt->vdownsampling[p]; if (dev->field_out == V4L2_FIELD_ALTERNATE) { /* @@ -74,21 +79,16 @@ static int vid_out_queue_setup(struct vb2_queue *vq, const struct v4l2_format *f if (mp->num_planes != planes) return -EINVAL; sizes[0] = mp->plane_fmt[0].sizeimage; - if (planes == 2) { - sizes[1] = mp->plane_fmt[1].sizeimage; - if (sizes[0] < dev->bytesperline_out[0] * h || - sizes[1] < dev->bytesperline_out[1] * h) - return -EINVAL; - } else if (sizes[0] < size) { + if (sizes[0] < size) return -EINVAL; + for (p = 1; p < planes; p++) { + sizes[p] = mp->plane_fmt[p].sizeimage; + if (sizes[p] < dev->bytesperline_out[p] * h) + return -EINVAL; } } else { - if (planes == 2) { - sizes[0] = dev->bytesperline_out[0] * h; - sizes[1] = dev->bytesperline_out[1] * h; - } else { - sizes[0] = size; - } + for (p = 0; p < planes; p++) + sizes[p] = p ? dev->bytesperline_out[p] * h : size; } if (vq->num_buffers + *nbuffers < 2) @@ -101,12 +101,9 @@ static int vid_out_queue_setup(struct vb2_queue *vq, const struct v4l2_format *f * alloc_ctxs array. */ - if (planes == 2) - dprintk(dev, 1, "%s, count=%d, sizes=%u, %u\n", __func__, - *nbuffers, sizes[0], sizes[1]); - else - dprintk(dev, 1, "%s, count=%d, size=%u\n", __func__, - *nbuffers, sizes[0]); + dprintk(dev, 1, "%s: count=%d\n", __func__, *nbuffers); + for (p = 0; p < planes; p++) + dprintk(dev, 1, "%s: size[%u]=%u\n", __func__, p, sizes[p]); return 0; } @@ -114,7 +111,7 @@ static int vid_out_buf_prepare(struct vb2_buffer *vb) { struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); unsigned long size; - unsigned planes = dev->fmt_out->planes; + unsigned planes; unsigned p; dprintk(dev, 1, "%s\n", __func__); @@ -122,6 +119,8 @@ static int vid_out_buf_prepare(struct vb2_buffer *vb) if (WARN_ON(NULL == dev->fmt_out)) return -EINVAL; + planes = dev->fmt_out->planes; + if (dev->buf_prepare_error) { /* * Error injection: test what happens if buf_prepare() returns @@ -220,7 +219,7 @@ const struct vb2_ops vivid_vid_out_qops = { void vivid_update_format_out(struct vivid_dev *dev) { struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt; - unsigned size; + unsigned size, p; switch (dev->output_type[dev->output]) { case SVID: @@ -249,7 +248,7 @@ void vivid_update_format_out(struct vivid_dev *dev) dev->field_out = V4L2_FIELD_ALTERNATE; else dev->field_out = V4L2_FIELD_NONE; - if (!dev->dvi_d_out && (bt->standards & V4L2_DV_BT_STD_CEA861)) { + if (!dev->dvi_d_out && (bt->flags & V4L2_DV_FL_IS_CE_VIDEO)) { if (bt->width == 720 && bt->height <= 576) dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M; else @@ -267,9 +266,9 @@ void vivid_update_format_out(struct vivid_dev *dev) if (V4L2_FIELD_HAS_T_OR_B(dev->field_out)) dev->crop_out.height /= 2; dev->fmt_out_rect = dev->crop_out; - dev->bytesperline_out[0] = (dev->sink_rect.width * dev->fmt_out->depth) / 8; - if (dev->fmt_out->planes == 2) - dev->bytesperline_out[1] = (dev->sink_rect.width * dev->fmt_out->depth) / 8; + for (p = 0; p < dev->fmt_out->planes; p++) + dev->bytesperline_out[p] = + (dev->sink_rect.width * dev->fmt_out->bit_depth[p]) / 8; } /* Map the field to something that is valid for the current output */ @@ -313,21 +312,28 @@ int vivid_g_fmt_vid_out(struct file *file, void *priv, { struct vivid_dev *dev = video_drvdata(file); struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; + const struct vivid_fmt *fmt = dev->fmt_out; unsigned p; mp->width = dev->fmt_out_rect.width; mp->height = dev->fmt_out_rect.height; mp->field = dev->field_out; - mp->pixelformat = dev->fmt_out->fourcc; + mp->pixelformat = fmt->fourcc; mp->colorspace = dev->colorspace_out; mp->ycbcr_enc = dev->ycbcr_enc_out; mp->quantization = dev->quantization_out; - mp->num_planes = dev->fmt_out->planes; + mp->num_planes = fmt->buffers; for (p = 0; p < mp->num_planes; p++) { mp->plane_fmt[p].bytesperline = dev->bytesperline_out[p]; mp->plane_fmt[p].sizeimage = mp->plane_fmt[p].bytesperline * mp->height; } + for (p = fmt->buffers; p < fmt->planes; p++) { + unsigned stride = dev->bytesperline_out[p]; + + mp->plane_fmt[0].sizeimage += + (stride * mp->height) / fmt->vdownsampling[p]; + } return 0; } @@ -386,10 +392,10 @@ int vivid_try_fmt_vid_out(struct file *file, void *priv, /* This driver supports custom bytesperline values */ /* Calculate the minimum supported bytesperline value */ - bytesperline = (mp->width * fmt->depth) >> 3; + bytesperline = (mp->width * fmt->bit_depth[0]) >> 3; /* Calculate the maximum supported bytesperline value */ - max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->depth) >> 3; - mp->num_planes = fmt->planes; + max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->bit_depth[0]) >> 3; + mp->num_planes = fmt->buffers; for (p = 0; p < mp->num_planes; p++) { if (pfmt[p].bytesperline > max_bpl) pfmt[p].bytesperline = max_bpl; @@ -398,11 +404,14 @@ int vivid_try_fmt_vid_out(struct file *file, void *priv, pfmt[p].sizeimage = pfmt[p].bytesperline * mp->height; memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved)); } + for (p = fmt->buffers; p < fmt->planes; p++) + pfmt[0].sizeimage += (pfmt[0].bytesperline * fmt->bit_depth[p]) / + (fmt->bit_depth[0] * fmt->vdownsampling[p]); mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; mp->quantization = V4L2_QUANTIZATION_DEFAULT; if (vivid_is_svid_out(dev)) { mp->colorspace = V4L2_COLORSPACE_SMPTE170M; - } else if (dev->dvi_d_out || !(bt->standards & V4L2_DV_BT_STD_CEA861)) { + } else if (dev->dvi_d_out || !(bt->flags & V4L2_DV_FL_IS_CE_VIDEO)) { mp->colorspace = V4L2_COLORSPACE_SRGB; if (dev->dvi_d_out) mp->quantization = V4L2_QUANTIZATION_LIM_RANGE; @@ -429,6 +438,7 @@ int vivid_s_fmt_vid_out(struct file *file, void *priv, struct vb2_queue *q = &dev->vb_vid_out_q; int ret = vivid_try_fmt_vid_out(file, priv, f); unsigned factor = 1; + unsigned p; if (ret < 0) return ret; @@ -524,9 +534,12 @@ int vivid_s_fmt_vid_out(struct file *file, void *priv, dev->fmt_out_rect.width = mp->width; dev->fmt_out_rect.height = mp->height; - dev->bytesperline_out[0] = mp->plane_fmt[0].bytesperline; - if (mp->num_planes > 1) - dev->bytesperline_out[1] = mp->plane_fmt[1].bytesperline; + for (p = 0; p < mp->num_planes; p++) + dev->bytesperline_out[p] = mp->plane_fmt[p].bytesperline; + for (p = dev->fmt_out->buffers; p < dev->fmt_out->planes; p++) + dev->bytesperline_out[p] = + (dev->bytesperline_out[0] * dev->fmt_out->bit_depth[p]) / + dev->fmt_out->bit_depth[0]; dev->field_out = mp->field; if (vivid_is_svid_out(dev)) dev->tv_field_out = mp->field; @@ -1114,13 +1127,13 @@ int vivid_vid_out_s_dv_timings(struct file *file, void *_fh, if (!vivid_is_hdmi_out(dev)) return -ENODATA; - if (vb2_is_busy(&dev->vb_vid_out_q)) - return -EBUSY; if (!v4l2_find_dv_timings_cap(timings, &vivid_dv_timings_cap, 0, NULL, NULL)) return -EINVAL; if (v4l2_match_dv_timings(timings, &dev->dv_timings_out, 0)) return 0; + if (vb2_is_busy(&dev->vb_vid_out_q)) + return -EBUSY; dev->dv_timings_out = *timings; vivid_update_format_out(dev); return 0; diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c index 401e2b77a0b6..7dd763311c0f 100644 --- a/drivers/media/platform/vsp1/vsp1_bru.c +++ b/drivers/media/platform/vsp1/vsp1_bru.c @@ -183,13 +183,14 @@ static int bru_s_stream(struct v4l2_subdev *subdev, int enable) */ static int bru_enum_mbus_code(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { static const unsigned int codes[] = { MEDIA_BUS_FMT_ARGB8888_1X32, MEDIA_BUS_FMT_AYUV8_1X32, }; + struct vsp1_bru *bru = to_bru(subdev); struct v4l2_mbus_framefmt *format; if (code->pad == BRU_PAD_SINK(0)) { @@ -201,7 +202,8 @@ static int bru_enum_mbus_code(struct v4l2_subdev *subdev, if (code->index) return -EINVAL; - format = v4l2_subdev_get_try_format(fh, BRU_PAD_SINK(0)); + format = vsp1_entity_get_pad_format(&bru->entity, cfg, + BRU_PAD_SINK(0), code->which); code->code = format->code; } @@ -209,7 +211,7 @@ static int bru_enum_mbus_code(struct v4l2_subdev *subdev, } static int bru_enum_frame_size(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { if (fse->index) @@ -228,12 +230,12 @@ static int bru_enum_frame_size(struct v4l2_subdev *subdev, } static struct v4l2_rect *bru_get_compose(struct vsp1_bru *bru, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, unsigned int pad, u32 which) { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_crop(fh, pad); + return v4l2_subdev_get_try_crop(&bru->entity.subdev, cfg, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &bru->inputs[pad].compose; default: @@ -241,18 +243,18 @@ static struct v4l2_rect *bru_get_compose(struct vsp1_bru *bru, } } -static int bru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, +static int bru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vsp1_bru *bru = to_bru(subdev); - fmt->format = *vsp1_entity_get_pad_format(&bru->entity, fh, fmt->pad, + fmt->format = *vsp1_entity_get_pad_format(&bru->entity, cfg, fmt->pad, fmt->which); return 0; } -static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_fh *fh, +static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_pad_config *cfg, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -268,7 +270,7 @@ static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_fh *fh, default: /* The BRU can't perform format conversion. */ - format = vsp1_entity_get_pad_format(&bru->entity, fh, + format = vsp1_entity_get_pad_format(&bru->entity, cfg, BRU_PAD_SINK(0), which); fmt->code = format->code; break; @@ -280,15 +282,15 @@ static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_fh *fh, fmt->colorspace = V4L2_COLORSPACE_SRGB; } -static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, +static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vsp1_bru *bru = to_bru(subdev); struct v4l2_mbus_framefmt *format; - bru_try_format(bru, fh, fmt->pad, &fmt->format, fmt->which); + bru_try_format(bru, cfg, fmt->pad, &fmt->format, fmt->which); - format = vsp1_entity_get_pad_format(&bru->entity, fh, fmt->pad, + format = vsp1_entity_get_pad_format(&bru->entity, cfg, fmt->pad, fmt->which); *format = fmt->format; @@ -296,7 +298,7 @@ static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, if (fmt->pad != BRU_PAD_SOURCE) { struct v4l2_rect *compose; - compose = bru_get_compose(bru, fh, fmt->pad, fmt->which); + compose = bru_get_compose(bru, cfg, fmt->pad, fmt->which); compose->left = 0; compose->top = 0; compose->width = format->width; @@ -308,7 +310,7 @@ static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, unsigned int i; for (i = 0; i <= BRU_PAD_SOURCE; ++i) { - format = vsp1_entity_get_pad_format(&bru->entity, fh, + format = vsp1_entity_get_pad_format(&bru->entity, cfg, i, fmt->which); format->code = fmt->format.code; } @@ -318,7 +320,7 @@ static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, } static int bru_get_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct vsp1_bru *bru = to_bru(subdev); @@ -335,7 +337,7 @@ static int bru_get_selection(struct v4l2_subdev *subdev, return 0; case V4L2_SEL_TGT_COMPOSE: - sel->r = *bru_get_compose(bru, fh, sel->pad, sel->which); + sel->r = *bru_get_compose(bru, cfg, sel->pad, sel->which); return 0; default: @@ -344,7 +346,7 @@ static int bru_get_selection(struct v4l2_subdev *subdev, } static int bru_set_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct vsp1_bru *bru = to_bru(subdev); @@ -360,7 +362,7 @@ static int bru_set_selection(struct v4l2_subdev *subdev, /* The compose rectangle top left corner must be inside the output * frame. */ - format = vsp1_entity_get_pad_format(&bru->entity, fh, BRU_PAD_SOURCE, + format = vsp1_entity_get_pad_format(&bru->entity, cfg, BRU_PAD_SOURCE, sel->which); sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1); sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1); @@ -368,12 +370,12 @@ static int bru_set_selection(struct v4l2_subdev *subdev, /* Scaling isn't supported, the compose rectangle size must be identical * to the sink format size. */ - format = vsp1_entity_get_pad_format(&bru->entity, fh, sel->pad, + format = vsp1_entity_get_pad_format(&bru->entity, cfg, sel->pad, sel->which); sel->r.width = format->width; sel->r.height = format->height; - compose = bru_get_compose(bru, fh, sel->pad, sel->which); + compose = bru_get_compose(bru, cfg, sel->pad, sel->which); *compose = sel->r; return 0; diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c index 79af71d5e270..a453bb4ddd37 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.c +++ b/drivers/media/platform/vsp1/vsp1_entity.c @@ -63,12 +63,12 @@ int vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming) struct v4l2_mbus_framefmt * vsp1_entity_get_pad_format(struct vsp1_entity *entity, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, unsigned int pad, u32 which) { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&entity->subdev, cfg, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &entity->formats[pad]; default: @@ -79,14 +79,14 @@ vsp1_entity_get_pad_format(struct vsp1_entity *entity, /* * vsp1_entity_init_formats - Initialize formats on all pads * @subdev: V4L2 subdevice - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad configuration * - * Initialize all pad formats with default values. If fh is not NULL, try + * Initialize all pad formats with default values. If cfg is not NULL, try * formats are initialized on the file handle. Otherwise active formats are * initialized on the device. */ void vsp1_entity_init_formats(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh) + struct v4l2_subdev_pad_config *cfg) { struct v4l2_subdev_format format; unsigned int pad; @@ -95,17 +95,17 @@ void vsp1_entity_init_formats(struct v4l2_subdev *subdev, memset(&format, 0, sizeof(format)); format.pad = pad; - format.which = fh ? V4L2_SUBDEV_FORMAT_TRY + format.which = cfg ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - v4l2_subdev_call(subdev, pad, set_fmt, fh, &format); + v4l2_subdev_call(subdev, pad, set_fmt, cfg, &format); } } static int vsp1_entity_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) { - vsp1_entity_init_formats(subdev, fh); + vsp1_entity_init_formats(subdev, fh->pad); return 0; } diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h index aa20aaa58208..62c768d1c6aa 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.h +++ b/drivers/media/platform/vsp1/vsp1_entity.h @@ -91,10 +91,10 @@ extern const struct media_entity_operations vsp1_media_ops; struct v4l2_mbus_framefmt * vsp1_entity_get_pad_format(struct vsp1_entity *entity, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, unsigned int pad, u32 which); void vsp1_entity_init_formats(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh); + struct v4l2_subdev_pad_config *cfg); bool vsp1_entity_is_streaming(struct vsp1_entity *entity); int vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming); diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c index 0bc0471746c9..8ffb817ae525 100644 --- a/drivers/media/platform/vsp1/vsp1_hsit.c +++ b/drivers/media/platform/vsp1/vsp1_hsit.c @@ -55,7 +55,7 @@ static int hsit_s_stream(struct v4l2_subdev *subdev, int enable) */ static int hsit_enum_mbus_code(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { struct vsp1_hsit *hsit = to_hsit(subdev); @@ -73,12 +73,14 @@ static int hsit_enum_mbus_code(struct v4l2_subdev *subdev, } static int hsit_enum_frame_size(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { + struct vsp1_hsit *hsit = to_hsit(subdev); struct v4l2_mbus_framefmt *format; - format = v4l2_subdev_get_try_format(fh, fse->pad); + format = vsp1_entity_get_pad_format(&hsit->entity, cfg, fse->pad, + fse->which); if (fse->index || fse->code != format->code) return -EINVAL; @@ -102,25 +104,25 @@ static int hsit_enum_frame_size(struct v4l2_subdev *subdev, } static int hsit_get_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vsp1_hsit *hsit = to_hsit(subdev); - fmt->format = *vsp1_entity_get_pad_format(&hsit->entity, fh, fmt->pad, + fmt->format = *vsp1_entity_get_pad_format(&hsit->entity, cfg, fmt->pad, fmt->which); return 0; } static int hsit_set_format(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vsp1_hsit *hsit = to_hsit(subdev); struct v4l2_mbus_framefmt *format; - format = vsp1_entity_get_pad_format(&hsit->entity, fh, fmt->pad, + format = vsp1_entity_get_pad_format(&hsit->entity, cfg, fmt->pad, fmt->which); if (fmt->pad == HSIT_PAD_SOURCE) { @@ -143,7 +145,7 @@ static int hsit_set_format(struct v4l2_subdev *subdev, fmt->format = *format; /* Propagate the format to the source pad. */ - format = vsp1_entity_get_pad_format(&hsit->entity, fh, HSIT_PAD_SOURCE, + format = vsp1_entity_get_pad_format(&hsit->entity, cfg, HSIT_PAD_SOURCE, fmt->which); *format = fmt->format; format->code = hsit->inverse ? MEDIA_BUS_FMT_ARGB8888_1X32 diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c index 17a6ca7dafe6..39fa5ef20fbb 100644 --- a/drivers/media/platform/vsp1/vsp1_lif.c +++ b/drivers/media/platform/vsp1/vsp1_lif.c @@ -74,13 +74,14 @@ static int lif_s_stream(struct v4l2_subdev *subdev, int enable) */ static int lif_enum_mbus_code(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { static const unsigned int codes[] = { MEDIA_BUS_FMT_ARGB8888_1X32, MEDIA_BUS_FMT_AYUV8_1X32, }; + struct vsp1_lif *lif = to_lif(subdev); if (code->pad == LIF_PAD_SINK) { if (code->index >= ARRAY_SIZE(codes)) @@ -96,7 +97,8 @@ static int lif_enum_mbus_code(struct v4l2_subdev *subdev, if (code->index) return -EINVAL; - format = v4l2_subdev_get_try_format(fh, LIF_PAD_SINK); + format = vsp1_entity_get_pad_format(&lif->entity, cfg, + LIF_PAD_SINK, code->which); code->code = format->code; } @@ -104,12 +106,14 @@ static int lif_enum_mbus_code(struct v4l2_subdev *subdev, } static int lif_enum_frame_size(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { + struct vsp1_lif *lif = to_lif(subdev); struct v4l2_mbus_framefmt *format; - format = v4l2_subdev_get_try_format(fh, LIF_PAD_SINK); + format = vsp1_entity_get_pad_format(&lif->entity, cfg, LIF_PAD_SINK, + fse->which); if (fse->index || fse->code != format->code) return -EINVAL; @@ -129,18 +133,18 @@ static int lif_enum_frame_size(struct v4l2_subdev *subdev, return 0; } -static int lif_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, +static int lif_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vsp1_lif *lif = to_lif(subdev); - fmt->format = *vsp1_entity_get_pad_format(&lif->entity, fh, fmt->pad, + fmt->format = *vsp1_entity_get_pad_format(&lif->entity, cfg, fmt->pad, fmt->which); return 0; } -static int lif_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, +static int lif_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vsp1_lif *lif = to_lif(subdev); @@ -151,7 +155,7 @@ static int lif_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; - format = vsp1_entity_get_pad_format(&lif->entity, fh, fmt->pad, + format = vsp1_entity_get_pad_format(&lif->entity, cfg, fmt->pad, fmt->which); if (fmt->pad == LIF_PAD_SOURCE) { @@ -173,7 +177,7 @@ static int lif_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, fmt->format = *format; /* Propagate the format to the source pad. */ - format = vsp1_entity_get_pad_format(&lif->entity, fh, LIF_PAD_SOURCE, + format = vsp1_entity_get_pad_format(&lif->entity, cfg, LIF_PAD_SOURCE, fmt->which); *format = fmt->format; diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c index 6f185c3621fe..656ec272a414 100644 --- a/drivers/media/platform/vsp1/vsp1_lut.c +++ b/drivers/media/platform/vsp1/vsp1_lut.c @@ -82,7 +82,7 @@ static int lut_s_stream(struct v4l2_subdev *subdev, int enable) */ static int lut_enum_mbus_code(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { static const unsigned int codes[] = { @@ -90,6 +90,7 @@ static int lut_enum_mbus_code(struct v4l2_subdev *subdev, MEDIA_BUS_FMT_AHSV8888_1X32, MEDIA_BUS_FMT_AYUV8_1X32, }; + struct vsp1_lut *lut = to_lut(subdev); struct v4l2_mbus_framefmt *format; if (code->pad == LUT_PAD_SINK) { @@ -104,7 +105,8 @@ static int lut_enum_mbus_code(struct v4l2_subdev *subdev, if (code->index) return -EINVAL; - format = v4l2_subdev_get_try_format(fh, LUT_PAD_SINK); + format = vsp1_entity_get_pad_format(&lut->entity, cfg, + LUT_PAD_SINK, code->which); code->code = format->code; } @@ -112,12 +114,14 @@ static int lut_enum_mbus_code(struct v4l2_subdev *subdev, } static int lut_enum_frame_size(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { + struct vsp1_lut *lut = to_lut(subdev); struct v4l2_mbus_framefmt *format; - format = v4l2_subdev_get_try_format(fh, fse->pad); + format = vsp1_entity_get_pad_format(&lut->entity, cfg, + fse->pad, fse->which); if (fse->index || fse->code != format->code) return -EINVAL; @@ -140,18 +144,18 @@ static int lut_enum_frame_size(struct v4l2_subdev *subdev, return 0; } -static int lut_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, +static int lut_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vsp1_lut *lut = to_lut(subdev); - fmt->format = *vsp1_entity_get_pad_format(&lut->entity, fh, fmt->pad, + fmt->format = *vsp1_entity_get_pad_format(&lut->entity, cfg, fmt->pad, fmt->which); return 0; } -static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, +static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vsp1_lut *lut = to_lut(subdev); @@ -163,7 +167,7 @@ static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; - format = vsp1_entity_get_pad_format(&lut->entity, fh, fmt->pad, + format = vsp1_entity_get_pad_format(&lut->entity, cfg, fmt->pad, fmt->which); if (fmt->pad == LUT_PAD_SOURCE) { @@ -182,7 +186,7 @@ static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, fmt->format = *format; /* Propagate the format to the source pad. */ - format = vsp1_entity_get_pad_format(&lut->entity, fh, LUT_PAD_SOURCE, + format = vsp1_entity_get_pad_format(&lut->entity, cfg, LUT_PAD_SOURCE, fmt->which); *format = fmt->format; diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c index 1f1ba26a834a..fa71f4695e16 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.c +++ b/drivers/media/platform/vsp1/vsp1_rwpf.c @@ -25,7 +25,7 @@ */ int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { static const unsigned int codes[] = { @@ -42,13 +42,14 @@ int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev, } int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct vsp1_rwpf *rwpf = to_rwpf(subdev); struct v4l2_mbus_framefmt *format; - format = v4l2_subdev_get_try_format(fh, fse->pad); + format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, fse->pad, + fse->which); if (fse->index || fse->code != format->code) return -EINVAL; @@ -72,11 +73,11 @@ int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev, } static struct v4l2_rect * -vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_fh *fh, u32 which) +vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_pad_config *cfg, u32 which) { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_crop(fh, RWPF_PAD_SINK); + return v4l2_subdev_get_try_crop(&rwpf->entity.subdev, cfg, RWPF_PAD_SINK); case V4L2_SUBDEV_FORMAT_ACTIVE: return &rwpf->crop; default: @@ -84,18 +85,18 @@ vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_fh *fh, u32 which) } } -int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, +int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vsp1_rwpf *rwpf = to_rwpf(subdev); - fmt->format = *vsp1_entity_get_pad_format(&rwpf->entity, fh, fmt->pad, + fmt->format = *vsp1_entity_get_pad_format(&rwpf->entity, cfg, fmt->pad, fmt->which); return 0; } -int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, +int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vsp1_rwpf *rwpf = to_rwpf(subdev); @@ -107,7 +108,7 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; - format = vsp1_entity_get_pad_format(&rwpf->entity, fh, fmt->pad, + format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, fmt->pad, fmt->which); if (fmt->pad == RWPF_PAD_SOURCE) { @@ -130,14 +131,14 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, fmt->format = *format; /* Update the sink crop rectangle. */ - crop = vsp1_rwpf_get_crop(rwpf, fh, fmt->which); + crop = vsp1_rwpf_get_crop(rwpf, cfg, fmt->which); crop->left = 0; crop->top = 0; crop->width = fmt->format.width; crop->height = fmt->format.height; /* Propagate the format to the source pad. */ - format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SOURCE, + format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SOURCE, fmt->which); *format = fmt->format; @@ -145,7 +146,7 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, } int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct vsp1_rwpf *rwpf = to_rwpf(subdev); @@ -157,11 +158,11 @@ int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, switch (sel->target) { case V4L2_SEL_TGT_CROP: - sel->r = *vsp1_rwpf_get_crop(rwpf, fh, sel->which); + sel->r = *vsp1_rwpf_get_crop(rwpf, cfg, sel->which); break; case V4L2_SEL_TGT_CROP_BOUNDS: - format = vsp1_entity_get_pad_format(&rwpf->entity, fh, + format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SINK, sel->which); sel->r.left = 0; sel->r.top = 0; @@ -177,7 +178,7 @@ int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, } int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct vsp1_rwpf *rwpf = to_rwpf(subdev); @@ -194,7 +195,7 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, /* Make sure the crop rectangle is entirely contained in the image. The * WPF top and left offsets are limited to 255. */ - format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SINK, + format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SINK, sel->which); sel->r.left = min_t(unsigned int, sel->r.left, format->width - 2); sel->r.top = min_t(unsigned int, sel->r.top, format->height - 2); @@ -207,11 +208,11 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, sel->r.height = min_t(unsigned int, sel->r.height, format->height - sel->r.top); - crop = vsp1_rwpf_get_crop(rwpf, fh, sel->which); + crop = vsp1_rwpf_get_crop(rwpf, cfg, sel->which); *crop = sel->r; /* Propagate the format to the source pad. */ - format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SOURCE, + format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SOURCE, sel->which); format->width = crop->width; format->height = crop->height; diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h index 2cf1f13d3bf9..f452dce1a931 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.h +++ b/drivers/media/platform/vsp1/vsp1_rwpf.h @@ -51,20 +51,20 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index); struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index); int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code); int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse); -int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, +int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt); -int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, +int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt); int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel); int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel); #endif /* __VSP1_RWPF_H__ */ diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c index 1129494c7cfc..6310acab60e7 100644 --- a/drivers/media/platform/vsp1/vsp1_sru.c +++ b/drivers/media/platform/vsp1/vsp1_sru.c @@ -166,13 +166,14 @@ static int sru_s_stream(struct v4l2_subdev *subdev, int enable) */ static int sru_enum_mbus_code(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { static const unsigned int codes[] = { MEDIA_BUS_FMT_ARGB8888_1X32, MEDIA_BUS_FMT_AYUV8_1X32, }; + struct vsp1_sru *sru = to_sru(subdev); struct v4l2_mbus_framefmt *format; if (code->pad == SRU_PAD_SINK) { @@ -187,7 +188,8 @@ static int sru_enum_mbus_code(struct v4l2_subdev *subdev, if (code->index) return -EINVAL; - format = v4l2_subdev_get_try_format(fh, SRU_PAD_SINK); + format = vsp1_entity_get_pad_format(&sru->entity, cfg, + SRU_PAD_SINK, code->which); code->code = format->code; } @@ -195,12 +197,14 @@ static int sru_enum_mbus_code(struct v4l2_subdev *subdev, } static int sru_enum_frame_size(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { + struct vsp1_sru *sru = to_sru(subdev); struct v4l2_mbus_framefmt *format; - format = v4l2_subdev_get_try_format(fh, SRU_PAD_SINK); + format = vsp1_entity_get_pad_format(&sru->entity, cfg, + SRU_PAD_SINK, fse->which); if (fse->index || fse->code != format->code) return -EINVAL; @@ -226,18 +230,18 @@ static int sru_enum_frame_size(struct v4l2_subdev *subdev, return 0; } -static int sru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, +static int sru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vsp1_sru *sru = to_sru(subdev); - fmt->format = *vsp1_entity_get_pad_format(&sru->entity, fh, fmt->pad, + fmt->format = *vsp1_entity_get_pad_format(&sru->entity, cfg, fmt->pad, fmt->which); return 0; } -static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_fh *fh, +static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_pad_config *cfg, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -258,7 +262,7 @@ static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_fh *fh, case SRU_PAD_SOURCE: /* The SRU can't perform format conversion. */ - format = vsp1_entity_get_pad_format(&sru->entity, fh, + format = vsp1_entity_get_pad_format(&sru->entity, cfg, SRU_PAD_SINK, which); fmt->code = format->code; @@ -288,25 +292,25 @@ static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_fh *fh, fmt->colorspace = V4L2_COLORSPACE_SRGB; } -static int sru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, +static int sru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vsp1_sru *sru = to_sru(subdev); struct v4l2_mbus_framefmt *format; - sru_try_format(sru, fh, fmt->pad, &fmt->format, fmt->which); + sru_try_format(sru, cfg, fmt->pad, &fmt->format, fmt->which); - format = vsp1_entity_get_pad_format(&sru->entity, fh, fmt->pad, + format = vsp1_entity_get_pad_format(&sru->entity, cfg, fmt->pad, fmt->which); *format = fmt->format; if (fmt->pad == SRU_PAD_SINK) { /* Propagate the format to the source pad. */ - format = vsp1_entity_get_pad_format(&sru->entity, fh, + format = vsp1_entity_get_pad_format(&sru->entity, cfg, SRU_PAD_SOURCE, fmt->which); *format = fmt->format; - sru_try_format(sru, fh, SRU_PAD_SOURCE, format, fmt->which); + sru_try_format(sru, cfg, SRU_PAD_SOURCE, format, fmt->which); } return 0; diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c index a4afec133800..ccc8243e3493 100644 --- a/drivers/media/platform/vsp1/vsp1_uds.c +++ b/drivers/media/platform/vsp1/vsp1_uds.c @@ -169,13 +169,14 @@ static int uds_s_stream(struct v4l2_subdev *subdev, int enable) */ static int uds_enum_mbus_code(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { static const unsigned int codes[] = { MEDIA_BUS_FMT_ARGB8888_1X32, MEDIA_BUS_FMT_AYUV8_1X32, }; + struct vsp1_uds *uds = to_uds(subdev); if (code->pad == UDS_PAD_SINK) { if (code->index >= ARRAY_SIZE(codes)) @@ -191,7 +192,8 @@ static int uds_enum_mbus_code(struct v4l2_subdev *subdev, if (code->index) return -EINVAL; - format = v4l2_subdev_get_try_format(fh, UDS_PAD_SINK); + format = vsp1_entity_get_pad_format(&uds->entity, cfg, + UDS_PAD_SINK, code->which); code->code = format->code; } @@ -199,12 +201,14 @@ static int uds_enum_mbus_code(struct v4l2_subdev *subdev, } static int uds_enum_frame_size(struct v4l2_subdev *subdev, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { + struct vsp1_uds *uds = to_uds(subdev); struct v4l2_mbus_framefmt *format; - format = v4l2_subdev_get_try_format(fh, UDS_PAD_SINK); + format = vsp1_entity_get_pad_format(&uds->entity, cfg, + UDS_PAD_SINK, fse->which); if (fse->index || fse->code != format->code) return -EINVAL; @@ -224,18 +228,18 @@ static int uds_enum_frame_size(struct v4l2_subdev *subdev, return 0; } -static int uds_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, +static int uds_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vsp1_uds *uds = to_uds(subdev); - fmt->format = *vsp1_entity_get_pad_format(&uds->entity, fh, fmt->pad, + fmt->format = *vsp1_entity_get_pad_format(&uds->entity, cfg, fmt->pad, fmt->which); return 0; } -static void uds_try_format(struct vsp1_uds *uds, struct v4l2_subdev_fh *fh, +static void uds_try_format(struct vsp1_uds *uds, struct v4l2_subdev_pad_config *cfg, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -256,7 +260,7 @@ static void uds_try_format(struct vsp1_uds *uds, struct v4l2_subdev_fh *fh, case UDS_PAD_SOURCE: /* The UDS scales but can't perform format conversion. */ - format = vsp1_entity_get_pad_format(&uds->entity, fh, + format = vsp1_entity_get_pad_format(&uds->entity, cfg, UDS_PAD_SINK, which); fmt->code = format->code; @@ -271,25 +275,25 @@ static void uds_try_format(struct vsp1_uds *uds, struct v4l2_subdev_fh *fh, fmt->colorspace = V4L2_COLORSPACE_SRGB; } -static int uds_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, +static int uds_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vsp1_uds *uds = to_uds(subdev); struct v4l2_mbus_framefmt *format; - uds_try_format(uds, fh, fmt->pad, &fmt->format, fmt->which); + uds_try_format(uds, cfg, fmt->pad, &fmt->format, fmt->which); - format = vsp1_entity_get_pad_format(&uds->entity, fh, fmt->pad, + format = vsp1_entity_get_pad_format(&uds->entity, cfg, fmt->pad, fmt->which); *format = fmt->format; if (fmt->pad == UDS_PAD_SINK) { /* Propagate the format to the source pad. */ - format = vsp1_entity_get_pad_format(&uds->entity, fh, + format = vsp1_entity_get_pad_format(&uds->entity, cfg, UDS_PAD_SOURCE, fmt->which); *format = fmt->format; - uds_try_format(uds, fh, UDS_PAD_SOURCE, format, fmt->which); + uds_try_format(uds, cfg, UDS_PAD_SOURCE, format, fmt->which); } return 0; diff --git a/drivers/media/platform/xilinx/Kconfig b/drivers/media/platform/xilinx/Kconfig new file mode 100644 index 000000000000..d7324c726fc2 --- /dev/null +++ b/drivers/media/platform/xilinx/Kconfig @@ -0,0 +1,23 @@ +config VIDEO_XILINX + tristate "Xilinx Video IP (EXPERIMENTAL)" + depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && OF + select VIDEOBUF2_DMA_CONTIG + ---help--- + Driver for Xilinx Video IP Pipelines + +if VIDEO_XILINX + +config VIDEO_XILINX_TPG + tristate "Xilinx Video Test Pattern Generator" + depends on VIDEO_XILINX + select VIDEO_XILINX_VTC + ---help--- + Driver for the Xilinx Video Test Pattern Generator + +config VIDEO_XILINX_VTC + tristate "Xilinx Video Timing Controller" + depends on VIDEO_XILINX + ---help--- + Driver for the Xilinx Video Timing Controller + +endif #VIDEO_XILINX diff --git a/drivers/media/platform/xilinx/Makefile b/drivers/media/platform/xilinx/Makefile new file mode 100644 index 000000000000..e8a0f2a9f733 --- /dev/null +++ b/drivers/media/platform/xilinx/Makefile @@ -0,0 +1,5 @@ +xilinx-video-objs += xilinx-dma.o xilinx-vip.o xilinx-vipp.o + +obj-$(CONFIG_VIDEO_XILINX) += xilinx-video.o +obj-$(CONFIG_VIDEO_XILINX_TPG) += xilinx-tpg.o +obj-$(CONFIG_VIDEO_XILINX_VTC) += xilinx-vtc.o diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c new file mode 100644 index 000000000000..10209c294168 --- /dev/null +++ b/drivers/media/platform/xilinx/xilinx-dma.c @@ -0,0 +1,766 @@ +/* + * Xilinx Video DMA + * + * Copyright (C) 2013-2015 Ideas on Board + * Copyright (C) 2013-2015 Xilinx, Inc. + * + * Contacts: Hyun Kwon <hyun.kwon@xilinx.com> + * Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/amba/xilinx_dma.h> +#include <linux/lcm.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/slab.h> + +#include <media/v4l2-dev.h> +#include <media/v4l2-fh.h> +#include <media/v4l2-ioctl.h> +#include <media/videobuf2-core.h> +#include <media/videobuf2-dma-contig.h> + +#include "xilinx-dma.h" +#include "xilinx-vip.h" +#include "xilinx-vipp.h" + +#define XVIP_DMA_DEF_FORMAT V4L2_PIX_FMT_YUYV +#define XVIP_DMA_DEF_WIDTH 1920 +#define XVIP_DMA_DEF_HEIGHT 1080 + +/* Minimum and maximum widths are expressed in bytes */ +#define XVIP_DMA_MIN_WIDTH 1U +#define XVIP_DMA_MAX_WIDTH 65535U +#define XVIP_DMA_MIN_HEIGHT 1U +#define XVIP_DMA_MAX_HEIGHT 8191U + +/* ----------------------------------------------------------------------------- + * Helper functions + */ + +static struct v4l2_subdev * +xvip_dma_remote_subdev(struct media_pad *local, u32 *pad) +{ + struct media_pad *remote; + + remote = media_entity_remote_pad(local); + if (remote == NULL || + media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + return NULL; + + if (pad) + *pad = remote->index; + + return media_entity_to_v4l2_subdev(remote->entity); +} + +static int xvip_dma_verify_format(struct xvip_dma *dma) +{ + struct v4l2_subdev_format fmt; + struct v4l2_subdev *subdev; + int ret; + + subdev = xvip_dma_remote_subdev(&dma->pad, &fmt.pad); + if (subdev == NULL) + return -EPIPE; + + fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt); + if (ret < 0) + return ret == -ENOIOCTLCMD ? -EINVAL : ret; + + if (dma->fmtinfo->code != fmt.format.code || + dma->format.height != fmt.format.height || + dma->format.width != fmt.format.width || + dma->format.colorspace != fmt.format.colorspace) + return -EINVAL; + + return 0; +} + +/* ----------------------------------------------------------------------------- + * Pipeline Stream Management + */ + +/** + * xvip_pipeline_start_stop - Start ot stop streaming on a pipeline + * @pipe: The pipeline + * @start: Start (when true) or stop (when false) the pipeline + * + * Walk the entities chain starting at the pipeline output video node and start + * or stop all of them. + * + * Return: 0 if successful, or the return value of the failed video::s_stream + * operation otherwise. + */ +static int xvip_pipeline_start_stop(struct xvip_pipeline *pipe, bool start) +{ + struct xvip_dma *dma = pipe->output; + struct media_entity *entity; + struct media_pad *pad; + struct v4l2_subdev *subdev; + int ret; + + entity = &dma->video.entity; + while (1) { + pad = &entity->pads[0]; + if (!(pad->flags & MEDIA_PAD_FL_SINK)) + break; + + pad = media_entity_remote_pad(pad); + if (pad == NULL || + media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + break; + + entity = pad->entity; + subdev = media_entity_to_v4l2_subdev(entity); + + ret = v4l2_subdev_call(subdev, video, s_stream, start); + if (start && ret < 0 && ret != -ENOIOCTLCMD) + return ret; + } + + return 0; +} + +/** + * xvip_pipeline_set_stream - Enable/disable streaming on a pipeline + * @pipe: The pipeline + * @on: Turn the stream on when true or off when false + * + * The pipeline is shared between all DMA engines connect at its input and + * output. While the stream state of DMA engines can be controlled + * independently, pipelines have a shared stream state that enable or disable + * all entities in the pipeline. For this reason the pipeline uses a streaming + * counter that tracks the number of DMA engines that have requested the stream + * to be enabled. + * + * When called with the @on argument set to true, this function will increment + * the pipeline streaming count. If the streaming count reaches the number of + * DMA engines in the pipeline it will enable all entities that belong to the + * pipeline. + * + * Similarly, when called with the @on argument set to false, this function will + * decrement the pipeline streaming count and disable all entities in the + * pipeline when the streaming count reaches zero. + * + * Return: 0 if successful, or the return value of the failed video::s_stream + * operation otherwise. Stopping the pipeline never fails. The pipeline state is + * not updated when the operation fails. + */ +static int xvip_pipeline_set_stream(struct xvip_pipeline *pipe, bool on) +{ + int ret = 0; + + mutex_lock(&pipe->lock); + + if (on) { + if (pipe->stream_count == pipe->num_dmas - 1) { + ret = xvip_pipeline_start_stop(pipe, true); + if (ret < 0) + goto done; + } + pipe->stream_count++; + } else { + if (--pipe->stream_count == 0) + xvip_pipeline_start_stop(pipe, false); + } + +done: + mutex_unlock(&pipe->lock); + return ret; +} + +static int xvip_pipeline_validate(struct xvip_pipeline *pipe, + struct xvip_dma *start) +{ + struct media_entity_graph graph; + struct media_entity *entity = &start->video.entity; + struct media_device *mdev = entity->parent; + unsigned int num_inputs = 0; + unsigned int num_outputs = 0; + + mutex_lock(&mdev->graph_mutex); + + /* Walk the graph to locate the video nodes. */ + media_entity_graph_walk_start(&graph, entity); + + while ((entity = media_entity_graph_walk_next(&graph))) { + struct xvip_dma *dma; + + if (entity->type != MEDIA_ENT_T_DEVNODE_V4L) + continue; + + dma = to_xvip_dma(media_entity_to_video_device(entity)); + + if (dma->pad.flags & MEDIA_PAD_FL_SINK) { + pipe->output = dma; + num_outputs++; + } else { + num_inputs++; + } + } + + mutex_unlock(&mdev->graph_mutex); + + /* We need exactly one output and zero or one input. */ + if (num_outputs != 1 || num_inputs > 1) + return -EPIPE; + + pipe->num_dmas = num_inputs + num_outputs; + + return 0; +} + +static void __xvip_pipeline_cleanup(struct xvip_pipeline *pipe) +{ + pipe->num_dmas = 0; + pipe->output = NULL; +} + +/** + * xvip_pipeline_cleanup - Cleanup the pipeline after streaming + * @pipe: the pipeline + * + * Decrease the pipeline use count and clean it up if we were the last user. + */ +static void xvip_pipeline_cleanup(struct xvip_pipeline *pipe) +{ + mutex_lock(&pipe->lock); + + /* If we're the last user clean up the pipeline. */ + if (--pipe->use_count == 0) + __xvip_pipeline_cleanup(pipe); + + mutex_unlock(&pipe->lock); +} + +/** + * xvip_pipeline_prepare - Prepare the pipeline for streaming + * @pipe: the pipeline + * @dma: DMA engine at one end of the pipeline + * + * Validate the pipeline if no user exists yet, otherwise just increase the use + * count. + * + * Return: 0 if successful or -EPIPE if the pipeline is not valid. + */ +static int xvip_pipeline_prepare(struct xvip_pipeline *pipe, + struct xvip_dma *dma) +{ + int ret; + + mutex_lock(&pipe->lock); + + /* If we're the first user validate and initialize the pipeline. */ + if (pipe->use_count == 0) { + ret = xvip_pipeline_validate(pipe, dma); + if (ret < 0) { + __xvip_pipeline_cleanup(pipe); + goto done; + } + } + + pipe->use_count++; + ret = 0; + +done: + mutex_unlock(&pipe->lock); + return ret; +} + +/* ----------------------------------------------------------------------------- + * videobuf2 queue operations + */ + +/** + * struct xvip_dma_buffer - Video DMA buffer + * @buf: vb2 buffer base object + * @queue: buffer list entry in the DMA engine queued buffers list + * @dma: DMA channel that uses the buffer + */ +struct xvip_dma_buffer { + struct vb2_buffer buf; + struct list_head queue; + struct xvip_dma *dma; +}; + +#define to_xvip_dma_buffer(vb) container_of(vb, struct xvip_dma_buffer, buf) + +static void xvip_dma_complete(void *param) +{ + struct xvip_dma_buffer *buf = param; + struct xvip_dma *dma = buf->dma; + + spin_lock(&dma->queued_lock); + list_del(&buf->queue); + spin_unlock(&dma->queued_lock); + + buf->buf.v4l2_buf.field = V4L2_FIELD_NONE; + buf->buf.v4l2_buf.sequence = dma->sequence++; + v4l2_get_timestamp(&buf->buf.v4l2_buf.timestamp); + vb2_set_plane_payload(&buf->buf, 0, dma->format.sizeimage); + vb2_buffer_done(&buf->buf, VB2_BUF_STATE_DONE); +} + +static int +xvip_dma_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) +{ + struct xvip_dma *dma = vb2_get_drv_priv(vq); + + /* Make sure the image size is large enough. */ + if (fmt && fmt->fmt.pix.sizeimage < dma->format.sizeimage) + return -EINVAL; + + *nplanes = 1; + + sizes[0] = fmt ? fmt->fmt.pix.sizeimage : dma->format.sizeimage; + alloc_ctxs[0] = dma->alloc_ctx; + + return 0; +} + +static int xvip_dma_buffer_prepare(struct vb2_buffer *vb) +{ + struct xvip_dma *dma = vb2_get_drv_priv(vb->vb2_queue); + struct xvip_dma_buffer *buf = to_xvip_dma_buffer(vb); + + buf->dma = dma; + + return 0; +} + +static void xvip_dma_buffer_queue(struct vb2_buffer *vb) +{ + struct xvip_dma *dma = vb2_get_drv_priv(vb->vb2_queue); + struct xvip_dma_buffer *buf = to_xvip_dma_buffer(vb); + struct dma_async_tx_descriptor *desc; + dma_addr_t addr = vb2_dma_contig_plane_dma_addr(vb, 0); + u32 flags; + + if (dma->queue.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK; + dma->xt.dir = DMA_DEV_TO_MEM; + dma->xt.src_sgl = false; + dma->xt.dst_sgl = true; + dma->xt.dst_start = addr; + } else { + flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK; + dma->xt.dir = DMA_MEM_TO_DEV; + dma->xt.src_sgl = true; + dma->xt.dst_sgl = false; + dma->xt.src_start = addr; + } + + dma->xt.frame_size = 1; + dma->sgl[0].size = dma->format.width * dma->fmtinfo->bpp; + dma->sgl[0].icg = dma->format.bytesperline - dma->sgl[0].size; + dma->xt.numf = dma->format.height; + + desc = dmaengine_prep_interleaved_dma(dma->dma, &dma->xt, flags); + if (!desc) { + dev_err(dma->xdev->dev, "Failed to prepare DMA transfer\n"); + vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR); + return; + } + desc->callback = xvip_dma_complete; + desc->callback_param = buf; + + spin_lock_irq(&dma->queued_lock); + list_add_tail(&buf->queue, &dma->queued_bufs); + spin_unlock_irq(&dma->queued_lock); + + dmaengine_submit(desc); + + if (vb2_is_streaming(&dma->queue)) + dma_async_issue_pending(dma->dma); +} + +static int xvip_dma_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct xvip_dma *dma = vb2_get_drv_priv(vq); + struct xvip_dma_buffer *buf, *nbuf; + struct xvip_pipeline *pipe; + int ret; + + dma->sequence = 0; + + /* + * Start streaming on the pipeline. No link touching an entity in the + * pipeline can be activated or deactivated once streaming is started. + * + * Use the pipeline object embedded in the first DMA object that starts + * streaming. + */ + pipe = dma->video.entity.pipe + ? to_xvip_pipeline(&dma->video.entity) : &dma->pipe; + + ret = media_entity_pipeline_start(&dma->video.entity, &pipe->pipe); + if (ret < 0) + goto error; + + /* Verify that the configured format matches the output of the + * connected subdev. + */ + ret = xvip_dma_verify_format(dma); + if (ret < 0) + goto error_stop; + + ret = xvip_pipeline_prepare(pipe, dma); + if (ret < 0) + goto error_stop; + + /* Start the DMA engine. This must be done before starting the blocks + * in the pipeline to avoid DMA synchronization issues. + */ + dma_async_issue_pending(dma->dma); + + /* Start the pipeline. */ + xvip_pipeline_set_stream(pipe, true); + + return 0; + +error_stop: + media_entity_pipeline_stop(&dma->video.entity); + +error: + /* Give back all queued buffers to videobuf2. */ + spin_lock_irq(&dma->queued_lock); + list_for_each_entry_safe(buf, nbuf, &dma->queued_bufs, queue) { + vb2_buffer_done(&buf->buf, VB2_BUF_STATE_QUEUED); + list_del(&buf->queue); + } + spin_unlock_irq(&dma->queued_lock); + + return ret; +} + +static void xvip_dma_stop_streaming(struct vb2_queue *vq) +{ + struct xvip_dma *dma = vb2_get_drv_priv(vq); + struct xvip_pipeline *pipe = to_xvip_pipeline(&dma->video.entity); + struct xvip_dma_buffer *buf, *nbuf; + + /* Stop the pipeline. */ + xvip_pipeline_set_stream(pipe, false); + + /* Stop and reset the DMA engine. */ + dmaengine_terminate_all(dma->dma); + + /* Cleanup the pipeline and mark it as being stopped. */ + xvip_pipeline_cleanup(pipe); + media_entity_pipeline_stop(&dma->video.entity); + + /* Give back all queued buffers to videobuf2. */ + spin_lock_irq(&dma->queued_lock); + list_for_each_entry_safe(buf, nbuf, &dma->queued_bufs, queue) { + vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR); + list_del(&buf->queue); + } + spin_unlock_irq(&dma->queued_lock); +} + +static struct vb2_ops xvip_dma_queue_qops = { + .queue_setup = xvip_dma_queue_setup, + .buf_prepare = xvip_dma_buffer_prepare, + .buf_queue = xvip_dma_buffer_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = xvip_dma_start_streaming, + .stop_streaming = xvip_dma_stop_streaming, +}; + +/* ----------------------------------------------------------------------------- + * V4L2 ioctls + */ + +static int +xvip_dma_querycap(struct file *file, void *fh, struct v4l2_capability *cap) +{ + struct v4l2_fh *vfh = file->private_data; + struct xvip_dma *dma = to_xvip_dma(vfh->vdev); + + cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING + | dma->xdev->v4l2_caps; + + if (dma->queue.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + else + cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; + + strlcpy(cap->driver, "xilinx-vipp", sizeof(cap->driver)); + strlcpy(cap->card, dma->video.name, sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s:%u", + dma->xdev->dev->of_node->name, dma->port); + + return 0; +} + +/* FIXME: without this callback function, some applications are not configured + * with correct formats, and it results in frames in wrong format. Whether this + * callback needs to be required is not clearly defined, so it should be + * clarified through the mailing list. + */ +static int +xvip_dma_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ + struct v4l2_fh *vfh = file->private_data; + struct xvip_dma *dma = to_xvip_dma(vfh->vdev); + + if (f->index > 0) + return -EINVAL; + + f->pixelformat = dma->format.pixelformat; + strlcpy(f->description, dma->fmtinfo->description, + sizeof(f->description)); + + return 0; +} + +static int +xvip_dma_get_format(struct file *file, void *fh, struct v4l2_format *format) +{ + struct v4l2_fh *vfh = file->private_data; + struct xvip_dma *dma = to_xvip_dma(vfh->vdev); + + format->fmt.pix = dma->format; + + return 0; +} + +static void +__xvip_dma_try_format(struct xvip_dma *dma, struct v4l2_pix_format *pix, + const struct xvip_video_format **fmtinfo) +{ + const struct xvip_video_format *info; + unsigned int min_width; + unsigned int max_width; + unsigned int min_bpl; + unsigned int max_bpl; + unsigned int width; + unsigned int align; + unsigned int bpl; + + /* Retrieve format information and select the default format if the + * requested format isn't supported. + */ + info = xvip_get_format_by_fourcc(pix->pixelformat); + if (IS_ERR(info)) + info = xvip_get_format_by_fourcc(XVIP_DMA_DEF_FORMAT); + + pix->pixelformat = info->fourcc; + pix->field = V4L2_FIELD_NONE; + + /* The transfer alignment requirements are expressed in bytes. Compute + * the minimum and maximum values, clamp the requested width and convert + * it back to pixels. + */ + align = lcm(dma->align, info->bpp); + min_width = roundup(XVIP_DMA_MIN_WIDTH, align); + max_width = rounddown(XVIP_DMA_MAX_WIDTH, align); + width = rounddown(pix->width * info->bpp, align); + + pix->width = clamp(width, min_width, max_width) / info->bpp; + pix->height = clamp(pix->height, XVIP_DMA_MIN_HEIGHT, + XVIP_DMA_MAX_HEIGHT); + + /* Clamp the requested bytes per line value. If the maximum bytes per + * line value is zero, the module doesn't support user configurable line + * sizes. Override the requested value with the minimum in that case. + */ + min_bpl = pix->width * info->bpp; + max_bpl = rounddown(XVIP_DMA_MAX_WIDTH, dma->align); + bpl = rounddown(pix->bytesperline, dma->align); + + pix->bytesperline = clamp(bpl, min_bpl, max_bpl); + pix->sizeimage = pix->bytesperline * pix->height; + + if (fmtinfo) + *fmtinfo = info; +} + +static int +xvip_dma_try_format(struct file *file, void *fh, struct v4l2_format *format) +{ + struct v4l2_fh *vfh = file->private_data; + struct xvip_dma *dma = to_xvip_dma(vfh->vdev); + + __xvip_dma_try_format(dma, &format->fmt.pix, NULL); + return 0; +} + +static int +xvip_dma_set_format(struct file *file, void *fh, struct v4l2_format *format) +{ + struct v4l2_fh *vfh = file->private_data; + struct xvip_dma *dma = to_xvip_dma(vfh->vdev); + const struct xvip_video_format *info; + + __xvip_dma_try_format(dma, &format->fmt.pix, &info); + + if (vb2_is_busy(&dma->queue)) + return -EBUSY; + + dma->format = format->fmt.pix; + dma->fmtinfo = info; + + return 0; +} + +static const struct v4l2_ioctl_ops xvip_dma_ioctl_ops = { + .vidioc_querycap = xvip_dma_querycap, + .vidioc_enum_fmt_vid_cap = xvip_dma_enum_format, + .vidioc_g_fmt_vid_cap = xvip_dma_get_format, + .vidioc_g_fmt_vid_out = xvip_dma_get_format, + .vidioc_s_fmt_vid_cap = xvip_dma_set_format, + .vidioc_s_fmt_vid_out = xvip_dma_set_format, + .vidioc_try_fmt_vid_cap = xvip_dma_try_format, + .vidioc_try_fmt_vid_out = xvip_dma_try_format, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, +}; + +/* ----------------------------------------------------------------------------- + * V4L2 file operations + */ + +static const struct v4l2_file_operations xvip_dma_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, +}; + +/* ----------------------------------------------------------------------------- + * Xilinx Video DMA Core + */ + +int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma, + enum v4l2_buf_type type, unsigned int port) +{ + char name[14]; + int ret; + + dma->xdev = xdev; + dma->port = port; + mutex_init(&dma->lock); + mutex_init(&dma->pipe.lock); + INIT_LIST_HEAD(&dma->queued_bufs); + spin_lock_init(&dma->queued_lock); + + dma->fmtinfo = xvip_get_format_by_fourcc(XVIP_DMA_DEF_FORMAT); + dma->format.pixelformat = dma->fmtinfo->fourcc; + dma->format.colorspace = V4L2_COLORSPACE_SRGB; + dma->format.field = V4L2_FIELD_NONE; + dma->format.width = XVIP_DMA_DEF_WIDTH; + dma->format.height = XVIP_DMA_DEF_HEIGHT; + dma->format.bytesperline = dma->format.width * dma->fmtinfo->bpp; + dma->format.sizeimage = dma->format.bytesperline * dma->format.height; + + /* Initialize the media entity... */ + dma->pad.flags = type == V4L2_BUF_TYPE_VIDEO_CAPTURE + ? MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; + + ret = media_entity_init(&dma->video.entity, 1, &dma->pad, 0); + if (ret < 0) + goto error; + + /* ... and the video node... */ + dma->video.fops = &xvip_dma_fops; + dma->video.v4l2_dev = &xdev->v4l2_dev; + dma->video.queue = &dma->queue; + snprintf(dma->video.name, sizeof(dma->video.name), "%s %s %u", + xdev->dev->of_node->name, + type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? "output" : "input", + port); + dma->video.vfl_type = VFL_TYPE_GRABBER; + dma->video.vfl_dir = type == V4L2_BUF_TYPE_VIDEO_CAPTURE + ? VFL_DIR_RX : VFL_DIR_TX; + dma->video.release = video_device_release_empty; + dma->video.ioctl_ops = &xvip_dma_ioctl_ops; + dma->video.lock = &dma->lock; + + video_set_drvdata(&dma->video, dma); + + /* ... and the buffers queue... */ + dma->alloc_ctx = vb2_dma_contig_init_ctx(dma->xdev->dev); + if (IS_ERR(dma->alloc_ctx)) + goto error; + + /* Don't enable VB2_READ and VB2_WRITE, as using the read() and write() + * V4L2 APIs would be inefficient. Testing on the command line with a + * 'cat /dev/video?' thus won't be possible, but given that the driver + * anyway requires a test tool to setup the pipeline before any video + * stream can be started, requiring a specific V4L2 test tool as well + * instead of 'cat' isn't really a drawback. + */ + dma->queue.type = type; + dma->queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; + dma->queue.lock = &dma->lock; + dma->queue.drv_priv = dma; + dma->queue.buf_struct_size = sizeof(struct xvip_dma_buffer); + dma->queue.ops = &xvip_dma_queue_qops; + dma->queue.mem_ops = &vb2_dma_contig_memops; + dma->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC + | V4L2_BUF_FLAG_TSTAMP_SRC_EOF; + ret = vb2_queue_init(&dma->queue); + if (ret < 0) { + dev_err(dma->xdev->dev, "failed to initialize VB2 queue\n"); + goto error; + } + + /* ... and the DMA channel. */ + sprintf(name, "port%u", port); + dma->dma = dma_request_slave_channel(dma->xdev->dev, name); + if (dma->dma == NULL) { + dev_err(dma->xdev->dev, "no VDMA channel found\n"); + ret = -ENODEV; + goto error; + } + + dma->align = 1 << dma->dma->device->copy_align; + + ret = video_register_device(&dma->video, VFL_TYPE_GRABBER, -1); + if (ret < 0) { + dev_err(dma->xdev->dev, "failed to register video device\n"); + goto error; + } + + return 0; + +error: + xvip_dma_cleanup(dma); + return ret; +} + +void xvip_dma_cleanup(struct xvip_dma *dma) +{ + if (video_is_registered(&dma->video)) + video_unregister_device(&dma->video); + + if (dma->dma) + dma_release_channel(dma->dma); + + if (!IS_ERR_OR_NULL(dma->alloc_ctx)) + vb2_dma_contig_cleanup_ctx(dma->alloc_ctx); + + media_entity_cleanup(&dma->video.entity); + + mutex_destroy(&dma->lock); + mutex_destroy(&dma->pipe.lock); +} diff --git a/drivers/media/platform/xilinx/xilinx-dma.h b/drivers/media/platform/xilinx/xilinx-dma.h new file mode 100644 index 000000000000..a540111f8d3d --- /dev/null +++ b/drivers/media/platform/xilinx/xilinx-dma.h @@ -0,0 +1,109 @@ +/* + * Xilinx Video DMA + * + * Copyright (C) 2013-2015 Ideas on Board + * Copyright (C) 2013-2015 Xilinx, Inc. + * + * Contacts: Hyun Kwon <hyun.kwon@xilinx.com> + * Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __XILINX_VIP_DMA_H__ +#define __XILINX_VIP_DMA_H__ + +#include <linux/dmaengine.h> +#include <linux/mutex.h> +#include <linux/spinlock.h> +#include <linux/videodev2.h> + +#include <media/media-entity.h> +#include <media/v4l2-dev.h> +#include <media/videobuf2-core.h> + +struct dma_chan; +struct xvip_composite_device; +struct xvip_video_format; + +/** + * struct xvip_pipeline - Xilinx Video IP pipeline structure + * @pipe: media pipeline + * @lock: protects the pipeline @stream_count + * @use_count: number of DMA engines using the pipeline + * @stream_count: number of DMA engines currently streaming + * @num_dmas: number of DMA engines in the pipeline + * @output: DMA engine at the output of the pipeline + */ +struct xvip_pipeline { + struct media_pipeline pipe; + + struct mutex lock; + unsigned int use_count; + unsigned int stream_count; + + unsigned int num_dmas; + struct xvip_dma *output; +}; + +static inline struct xvip_pipeline *to_xvip_pipeline(struct media_entity *e) +{ + return container_of(e->pipe, struct xvip_pipeline, pipe); +} + +/** + * struct xvip_dma - Video DMA channel + * @list: list entry in a composite device dmas list + * @video: V4L2 video device associated with the DMA channel + * @pad: media pad for the video device entity + * @xdev: composite device the DMA channel belongs to + * @pipe: pipeline belonging to the DMA channel + * @port: composite device DT node port number for the DMA channel + * @lock: protects the @format, @fmtinfo and @queue fields + * @format: active V4L2 pixel format + * @fmtinfo: format information corresponding to the active @format + * @queue: vb2 buffers queue + * @alloc_ctx: allocation context for the vb2 @queue + * @sequence: V4L2 buffers sequence number + * @queued_bufs: list of queued buffers + * @queued_lock: protects the buf_queued list + * @dma: DMA engine channel + * @align: transfer alignment required by the DMA channel (in bytes) + * @xt: dma interleaved template for dma configuration + * @sgl: data chunk structure for dma_interleaved_template + */ +struct xvip_dma { + struct list_head list; + struct video_device video; + struct media_pad pad; + + struct xvip_composite_device *xdev; + struct xvip_pipeline pipe; + unsigned int port; + + struct mutex lock; + struct v4l2_pix_format format; + const struct xvip_video_format *fmtinfo; + + struct vb2_queue queue; + void *alloc_ctx; + unsigned int sequence; + + struct list_head queued_bufs; + spinlock_t queued_lock; + + struct dma_chan *dma; + unsigned int align; + struct dma_interleaved_template xt; + struct data_chunk sgl[1]; +}; + +#define to_xvip_dma(vdev) container_of(vdev, struct xvip_dma, video) + +int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma, + enum v4l2_buf_type type, unsigned int port); +void xvip_dma_cleanup(struct xvip_dma *dma); + +#endif /* __XILINX_VIP_DMA_H__ */ diff --git a/drivers/media/platform/xilinx/xilinx-tpg.c b/drivers/media/platform/xilinx/xilinx-tpg.c new file mode 100644 index 000000000000..b5f7d5ecb7f6 --- /dev/null +++ b/drivers/media/platform/xilinx/xilinx-tpg.c @@ -0,0 +1,931 @@ +/* + * Xilinx Test Pattern Generator + * + * Copyright (C) 2013-2015 Ideas on Board + * Copyright (C) 2013-2015 Xilinx, Inc. + * + * Contacts: Hyun Kwon <hyun.kwon@xilinx.com> + * Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/device.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/xilinx-v4l2-controls.h> + +#include <media/v4l2-async.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-subdev.h> + +#include "xilinx-vip.h" +#include "xilinx-vtc.h" + +#define XTPG_CTRL_STATUS_SLAVE_ERROR (1 << 16) +#define XTPG_CTRL_IRQ_SLAVE_ERROR (1 << 16) + +#define XTPG_PATTERN_CONTROL 0x0100 +#define XTPG_PATTERN_MASK (0xf << 0) +#define XTPG_PATTERN_CONTROL_CROSS_HAIRS (1 << 4) +#define XTPG_PATTERN_CONTROL_MOVING_BOX (1 << 5) +#define XTPG_PATTERN_CONTROL_COLOR_MASK_SHIFT 6 +#define XTPG_PATTERN_CONTROL_COLOR_MASK_MASK (0xf << 6) +#define XTPG_PATTERN_CONTROL_STUCK_PIXEL (1 << 9) +#define XTPG_PATTERN_CONTROL_NOISE (1 << 10) +#define XTPG_PATTERN_CONTROL_MOTION (1 << 12) +#define XTPG_MOTION_SPEED 0x0104 +#define XTPG_CROSS_HAIRS 0x0108 +#define XTPG_CROSS_HAIRS_ROW_SHIFT 0 +#define XTPG_CROSS_HAIRS_ROW_MASK (0xfff << 0) +#define XTPG_CROSS_HAIRS_COLUMN_SHIFT 16 +#define XTPG_CROSS_HAIRS_COLUMN_MASK (0xfff << 16) +#define XTPG_ZPLATE_HOR_CONTROL 0x010c +#define XTPG_ZPLATE_VER_CONTROL 0x0110 +#define XTPG_ZPLATE_START_SHIFT 0 +#define XTPG_ZPLATE_START_MASK (0xffff << 0) +#define XTPG_ZPLATE_SPEED_SHIFT 16 +#define XTPG_ZPLATE_SPEED_MASK (0xffff << 16) +#define XTPG_BOX_SIZE 0x0114 +#define XTPG_BOX_COLOR 0x0118 +#define XTPG_STUCK_PIXEL_THRESH 0x011c +#define XTPG_NOISE_GAIN 0x0120 +#define XTPG_BAYER_PHASE 0x0124 +#define XTPG_BAYER_PHASE_RGGB 0 +#define XTPG_BAYER_PHASE_GRBG 1 +#define XTPG_BAYER_PHASE_GBRG 2 +#define XTPG_BAYER_PHASE_BGGR 3 +#define XTPG_BAYER_PHASE_OFF 4 + +/* + * The minimum blanking value is one clock cycle for the front porch, one clock + * cycle for the sync pulse and one clock cycle for the back porch. + */ +#define XTPG_MIN_HBLANK 3 +#define XTPG_MAX_HBLANK (XVTC_MAX_HSIZE - XVIP_MIN_WIDTH) +#define XTPG_MIN_VBLANK 3 +#define XTPG_MAX_VBLANK (XVTC_MAX_VSIZE - XVIP_MIN_HEIGHT) + +/** + * struct xtpg_device - Xilinx Test Pattern Generator device structure + * @xvip: Xilinx Video IP device + * @pads: media pads + * @npads: number of pads (1 or 2) + * @has_input: whether an input is connected to the sink pad + * @formats: active V4L2 media bus format for each pad + * @default_format: default V4L2 media bus format + * @vip_format: format information corresponding to the active format + * @bayer: boolean flag if TPG is set to any bayer format + * @ctrl_handler: control handler + * @hblank: horizontal blanking control + * @vblank: vertical blanking control + * @pattern: test pattern control + * @streaming: is the video stream active + * @vtc: video timing controller + * @vtmux_gpio: video timing mux GPIO + */ +struct xtpg_device { + struct xvip_device xvip; + + struct media_pad pads[2]; + unsigned int npads; + bool has_input; + + struct v4l2_mbus_framefmt formats[2]; + struct v4l2_mbus_framefmt default_format; + const struct xvip_video_format *vip_format; + bool bayer; + + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *pattern; + bool streaming; + + struct xvtc_device *vtc; + struct gpio_desc *vtmux_gpio; +}; + +static inline struct xtpg_device *to_tpg(struct v4l2_subdev *subdev) +{ + return container_of(subdev, struct xtpg_device, xvip.subdev); +} + +static u32 xtpg_get_bayer_phase(unsigned int code) +{ + switch (code) { + case MEDIA_BUS_FMT_SRGGB8_1X8: + return XTPG_BAYER_PHASE_RGGB; + case MEDIA_BUS_FMT_SGRBG8_1X8: + return XTPG_BAYER_PHASE_GRBG; + case MEDIA_BUS_FMT_SGBRG8_1X8: + return XTPG_BAYER_PHASE_GBRG; + case MEDIA_BUS_FMT_SBGGR8_1X8: + return XTPG_BAYER_PHASE_BGGR; + default: + return XTPG_BAYER_PHASE_OFF; + } +} + +static void __xtpg_update_pattern_control(struct xtpg_device *xtpg, + bool passthrough, bool pattern) +{ + u32 pattern_mask = (1 << (xtpg->pattern->maximum + 1)) - 1; + + /* + * If the TPG has no sink pad or no input connected to its sink pad + * passthrough mode can't be enabled. + */ + if (xtpg->npads == 1 || !xtpg->has_input) + passthrough = false; + + /* If passthrough mode is allowed unmask bit 0. */ + if (passthrough) + pattern_mask &= ~1; + + /* If test pattern mode is allowed unmask all other bits. */ + if (pattern) + pattern_mask &= 1; + + __v4l2_ctrl_modify_range(xtpg->pattern, 0, xtpg->pattern->maximum, + pattern_mask, pattern ? 9 : 0); +} + +static void xtpg_update_pattern_control(struct xtpg_device *xtpg, + bool passthrough, bool pattern) +{ + mutex_lock(xtpg->ctrl_handler.lock); + __xtpg_update_pattern_control(xtpg, passthrough, pattern); + mutex_unlock(xtpg->ctrl_handler.lock); +} + +/* ----------------------------------------------------------------------------- + * V4L2 Subdevice Video Operations + */ + +static int xtpg_s_stream(struct v4l2_subdev *subdev, int enable) +{ + struct xtpg_device *xtpg = to_tpg(subdev); + unsigned int width = xtpg->formats[0].width; + unsigned int height = xtpg->formats[0].height; + bool passthrough; + u32 bayer_phase; + + if (!enable) { + xvip_stop(&xtpg->xvip); + if (xtpg->vtc) + xvtc_generator_stop(xtpg->vtc); + + xtpg_update_pattern_control(xtpg, true, true); + xtpg->streaming = false; + return 0; + } + + xvip_set_frame_size(&xtpg->xvip, &xtpg->formats[0]); + + if (xtpg->vtc) { + struct xvtc_config config = { + .hblank_start = width, + .hsync_start = width + 1, + .vblank_start = height, + .vsync_start = height + 1, + }; + unsigned int htotal; + unsigned int vtotal; + + htotal = min_t(unsigned int, XVTC_MAX_HSIZE, + v4l2_ctrl_g_ctrl(xtpg->hblank) + width); + vtotal = min_t(unsigned int, XVTC_MAX_VSIZE, + v4l2_ctrl_g_ctrl(xtpg->vblank) + height); + + config.hsync_end = htotal - 1; + config.hsize = htotal; + config.vsync_end = vtotal - 1; + config.vsize = vtotal; + + xvtc_generator_start(xtpg->vtc, &config); + } + + /* + * Configure the bayer phase and video timing mux based on the + * operation mode (passthrough or test pattern generation). The test + * pattern can be modified by the control set handler, we thus need to + * take the control lock here to avoid races. + */ + mutex_lock(xtpg->ctrl_handler.lock); + + xvip_clr_and_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, + XTPG_PATTERN_MASK, xtpg->pattern->cur.val); + + /* + * Switching between passthrough and test pattern generation modes isn't + * allowed during streaming, update the control range accordingly. + */ + passthrough = xtpg->pattern->cur.val == 0; + __xtpg_update_pattern_control(xtpg, passthrough, !passthrough); + + xtpg->streaming = true; + + mutex_unlock(xtpg->ctrl_handler.lock); + + /* + * For TPG v5.0, the bayer phase needs to be off for the pass through + * mode, otherwise the external input would be subsampled. + */ + bayer_phase = passthrough ? XTPG_BAYER_PHASE_OFF + : xtpg_get_bayer_phase(xtpg->formats[0].code); + xvip_write(&xtpg->xvip, XTPG_BAYER_PHASE, bayer_phase); + + if (xtpg->vtmux_gpio) + gpiod_set_value_cansleep(xtpg->vtmux_gpio, !passthrough); + + xvip_start(&xtpg->xvip); + + return 0; +} + +/* ----------------------------------------------------------------------------- + * V4L2 Subdevice Pad Operations + */ + +static struct v4l2_mbus_framefmt * +__xtpg_get_pad_format(struct xtpg_device *xtpg, + struct v4l2_subdev_pad_config *cfg, + unsigned int pad, u32 which) +{ + switch (which) { + case V4L2_SUBDEV_FORMAT_TRY: + return v4l2_subdev_get_try_format(&xtpg->xvip.subdev, cfg, pad); + case V4L2_SUBDEV_FORMAT_ACTIVE: + return &xtpg->formats[pad]; + default: + return NULL; + } +} + +static int xtpg_get_format(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct xtpg_device *xtpg = to_tpg(subdev); + + fmt->format = *__xtpg_get_pad_format(xtpg, cfg, fmt->pad, fmt->which); + + return 0; +} + +static int xtpg_set_format(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct xtpg_device *xtpg = to_tpg(subdev); + struct v4l2_mbus_framefmt *__format; + u32 bayer_phase; + + __format = __xtpg_get_pad_format(xtpg, cfg, fmt->pad, fmt->which); + + /* In two pads mode the source pad format is always identical to the + * sink pad format. + */ + if (xtpg->npads == 2 && fmt->pad == 1) { + fmt->format = *__format; + return 0; + } + + /* Bayer phase is configurable at runtime */ + if (xtpg->bayer) { + bayer_phase = xtpg_get_bayer_phase(fmt->format.code); + if (bayer_phase != XTPG_BAYER_PHASE_OFF) + __format->code = fmt->format.code; + } + + xvip_set_format_size(__format, fmt); + + fmt->format = *__format; + + /* Propagate the format to the source pad. */ + if (xtpg->npads == 2) { + __format = __xtpg_get_pad_format(xtpg, cfg, 1, fmt->which); + *__format = fmt->format; + } + + return 0; +} + +/* ----------------------------------------------------------------------------- + * V4L2 Subdevice Operations + */ + +static int xtpg_enum_frame_size(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct v4l2_mbus_framefmt *format; + + format = v4l2_subdev_get_try_format(subdev, cfg, fse->pad); + + if (fse->index || fse->code != format->code) + return -EINVAL; + + /* Min / max values for pad 0 is always fixed in both one and two pads + * modes. In two pads mode, the source pad(= 1) size is identical to + * the sink pad size */ + if (fse->pad == 0) { + fse->min_width = XVIP_MIN_WIDTH; + fse->max_width = XVIP_MAX_WIDTH; + fse->min_height = XVIP_MIN_HEIGHT; + fse->max_height = XVIP_MAX_HEIGHT; + } else { + fse->min_width = format->width; + fse->max_width = format->width; + fse->min_height = format->height; + fse->max_height = format->height; + } + + return 0; +} + +static int xtpg_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) +{ + struct xtpg_device *xtpg = to_tpg(subdev); + struct v4l2_mbus_framefmt *format; + + format = v4l2_subdev_get_try_format(subdev, fh->pad, 0); + *format = xtpg->default_format; + + if (xtpg->npads == 2) { + format = v4l2_subdev_get_try_format(subdev, fh->pad, 1); + *format = xtpg->default_format; + } + + return 0; +} + +static int xtpg_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) +{ + return 0; +} + +static int xtpg_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct xtpg_device *xtpg = container_of(ctrl->handler, + struct xtpg_device, + ctrl_handler); + switch (ctrl->id) { + case V4L2_CID_TEST_PATTERN: + xvip_clr_and_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, + XTPG_PATTERN_MASK, ctrl->val); + return 0; + case V4L2_CID_XILINX_TPG_CROSS_HAIRS: + xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, + XTPG_PATTERN_CONTROL_CROSS_HAIRS, ctrl->val); + return 0; + case V4L2_CID_XILINX_TPG_MOVING_BOX: + xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, + XTPG_PATTERN_CONTROL_MOVING_BOX, ctrl->val); + return 0; + case V4L2_CID_XILINX_TPG_COLOR_MASK: + xvip_clr_and_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, + XTPG_PATTERN_CONTROL_COLOR_MASK_MASK, + ctrl->val << + XTPG_PATTERN_CONTROL_COLOR_MASK_SHIFT); + return 0; + case V4L2_CID_XILINX_TPG_STUCK_PIXEL: + xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, + XTPG_PATTERN_CONTROL_STUCK_PIXEL, ctrl->val); + return 0; + case V4L2_CID_XILINX_TPG_NOISE: + xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, + XTPG_PATTERN_CONTROL_NOISE, ctrl->val); + return 0; + case V4L2_CID_XILINX_TPG_MOTION: + xvip_clr_or_set(&xtpg->xvip, XTPG_PATTERN_CONTROL, + XTPG_PATTERN_CONTROL_MOTION, ctrl->val); + return 0; + case V4L2_CID_XILINX_TPG_MOTION_SPEED: + xvip_write(&xtpg->xvip, XTPG_MOTION_SPEED, ctrl->val); + return 0; + case V4L2_CID_XILINX_TPG_CROSS_HAIR_ROW: + xvip_clr_and_set(&xtpg->xvip, XTPG_CROSS_HAIRS, + XTPG_CROSS_HAIRS_ROW_MASK, + ctrl->val << XTPG_CROSS_HAIRS_ROW_SHIFT); + return 0; + case V4L2_CID_XILINX_TPG_CROSS_HAIR_COLUMN: + xvip_clr_and_set(&xtpg->xvip, XTPG_CROSS_HAIRS, + XTPG_CROSS_HAIRS_COLUMN_MASK, + ctrl->val << XTPG_CROSS_HAIRS_COLUMN_SHIFT); + return 0; + case V4L2_CID_XILINX_TPG_ZPLATE_HOR_START: + xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_HOR_CONTROL, + XTPG_ZPLATE_START_MASK, + ctrl->val << XTPG_ZPLATE_START_SHIFT); + return 0; + case V4L2_CID_XILINX_TPG_ZPLATE_HOR_SPEED: + xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_HOR_CONTROL, + XTPG_ZPLATE_SPEED_MASK, + ctrl->val << XTPG_ZPLATE_SPEED_SHIFT); + return 0; + case V4L2_CID_XILINX_TPG_ZPLATE_VER_START: + xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_VER_CONTROL, + XTPG_ZPLATE_START_MASK, + ctrl->val << XTPG_ZPLATE_START_SHIFT); + return 0; + case V4L2_CID_XILINX_TPG_ZPLATE_VER_SPEED: + xvip_clr_and_set(&xtpg->xvip, XTPG_ZPLATE_VER_CONTROL, + XTPG_ZPLATE_SPEED_MASK, + ctrl->val << XTPG_ZPLATE_SPEED_SHIFT); + return 0; + case V4L2_CID_XILINX_TPG_BOX_SIZE: + xvip_write(&xtpg->xvip, XTPG_BOX_SIZE, ctrl->val); + return 0; + case V4L2_CID_XILINX_TPG_BOX_COLOR: + xvip_write(&xtpg->xvip, XTPG_BOX_COLOR, ctrl->val); + return 0; + case V4L2_CID_XILINX_TPG_STUCK_PIXEL_THRESH: + xvip_write(&xtpg->xvip, XTPG_STUCK_PIXEL_THRESH, ctrl->val); + return 0; + case V4L2_CID_XILINX_TPG_NOISE_GAIN: + xvip_write(&xtpg->xvip, XTPG_NOISE_GAIN, ctrl->val); + return 0; + } + + return 0; +} + +static const struct v4l2_ctrl_ops xtpg_ctrl_ops = { + .s_ctrl = xtpg_s_ctrl, +}; + +static struct v4l2_subdev_core_ops xtpg_core_ops = { +}; + +static struct v4l2_subdev_video_ops xtpg_video_ops = { + .s_stream = xtpg_s_stream, +}; + +static struct v4l2_subdev_pad_ops xtpg_pad_ops = { + .enum_mbus_code = xvip_enum_mbus_code, + .enum_frame_size = xtpg_enum_frame_size, + .get_fmt = xtpg_get_format, + .set_fmt = xtpg_set_format, +}; + +static struct v4l2_subdev_ops xtpg_ops = { + .core = &xtpg_core_ops, + .video = &xtpg_video_ops, + .pad = &xtpg_pad_ops, +}; + +static const struct v4l2_subdev_internal_ops xtpg_internal_ops = { + .open = xtpg_open, + .close = xtpg_close, +}; + +/* + * Control Config + */ + +static const char *const xtpg_pattern_strings[] = { + "Passthrough", + "Horizontal Ramp", + "Vertical Ramp", + "Temporal Ramp", + "Solid Red", + "Solid Green", + "Solid Blue", + "Solid Black", + "Solid White", + "Color Bars", + "Zone Plate", + "Tartan Color Bars", + "Cross Hatch", + "None", + "Vertical/Horizontal Ramps", + "Black/White Checker Board", +}; + +static struct v4l2_ctrl_config xtpg_ctrls[] = { + { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_CROSS_HAIRS, + .name = "Test Pattern: Cross Hairs", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = false, + .max = true, + .step = 1, + .def = 0, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_MOVING_BOX, + .name = "Test Pattern: Moving Box", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = false, + .max = true, + .step = 1, + .def = 0, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_COLOR_MASK, + .name = "Test Pattern: Color Mask", + .type = V4L2_CTRL_TYPE_BITMASK, + .min = 0, + .max = 0xf, + .def = 0, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_STUCK_PIXEL, + .name = "Test Pattern: Stuck Pixel", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = false, + .max = true, + .step = 1, + .def = 0, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_NOISE, + .name = "Test Pattern: Noise", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = false, + .max = true, + .step = 1, + .def = 0, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_MOTION, + .name = "Test Pattern: Motion", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = false, + .max = true, + .step = 1, + .def = 0, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_MOTION_SPEED, + .name = "Test Pattern: Motion Speed", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = (1 << 8) - 1, + .step = 1, + .def = 4, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_CROSS_HAIR_ROW, + .name = "Test Pattern: Cross Hairs Row", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = (1 << 12) - 1, + .step = 1, + .def = 0x64, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_CROSS_HAIR_COLUMN, + .name = "Test Pattern: Cross Hairs Column", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = (1 << 12) - 1, + .step = 1, + .def = 0x64, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_ZPLATE_HOR_START, + .name = "Test Pattern: Zplate Horizontal Start Pos", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = (1 << 16) - 1, + .step = 1, + .def = 0x1e, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_ZPLATE_HOR_SPEED, + .name = "Test Pattern: Zplate Horizontal Speed", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = (1 << 16) - 1, + .step = 1, + .def = 0, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_ZPLATE_VER_START, + .name = "Test Pattern: Zplate Vertical Start Pos", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = (1 << 16) - 1, + .step = 1, + .def = 1, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_ZPLATE_VER_SPEED, + .name = "Test Pattern: Zplate Vertical Speed", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = (1 << 16) - 1, + .step = 1, + .def = 0, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_BOX_SIZE, + .name = "Test Pattern: Box Size", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = (1 << 12) - 1, + .step = 1, + .def = 0x32, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_BOX_COLOR, + .name = "Test Pattern: Box Color(RGB)", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = (1 << 24) - 1, + .step = 1, + .def = 0, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_STUCK_PIXEL_THRESH, + .name = "Test Pattern: Stuck Pixel threshold", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = (1 << 16) - 1, + .step = 1, + .def = 0, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, { + .ops = &xtpg_ctrl_ops, + .id = V4L2_CID_XILINX_TPG_NOISE_GAIN, + .name = "Test Pattern: Noise Gain", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = (1 << 8) - 1, + .step = 1, + .def = 0, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, +}; + +/* ----------------------------------------------------------------------------- + * Media Operations + */ + +static const struct media_entity_operations xtpg_media_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +/* ----------------------------------------------------------------------------- + * Power Management + */ + +static int __maybe_unused xtpg_pm_suspend(struct device *dev) +{ + struct xtpg_device *xtpg = dev_get_drvdata(dev); + + xvip_suspend(&xtpg->xvip); + + return 0; +} + +static int __maybe_unused xtpg_pm_resume(struct device *dev) +{ + struct xtpg_device *xtpg = dev_get_drvdata(dev); + + xvip_resume(&xtpg->xvip); + + return 0; +} + +/* ----------------------------------------------------------------------------- + * Platform Device Driver + */ + +static int xtpg_parse_of(struct xtpg_device *xtpg) +{ + struct device *dev = xtpg->xvip.dev; + struct device_node *node = xtpg->xvip.dev->of_node; + struct device_node *ports; + struct device_node *port; + unsigned int nports = 0; + bool has_endpoint = false; + + ports = of_get_child_by_name(node, "ports"); + if (ports == NULL) + ports = node; + + for_each_child_of_node(ports, port) { + const struct xvip_video_format *format; + struct device_node *endpoint; + + if (!port->name || of_node_cmp(port->name, "port")) + continue; + + format = xvip_of_get_format(port); + if (IS_ERR(format)) { + dev_err(dev, "invalid format in DT"); + return PTR_ERR(format); + } + + /* Get and check the format description */ + if (!xtpg->vip_format) { + xtpg->vip_format = format; + } else if (xtpg->vip_format != format) { + dev_err(dev, "in/out format mismatch in DT"); + return -EINVAL; + } + + if (nports == 0) { + endpoint = of_get_next_child(port, NULL); + if (endpoint) + has_endpoint = true; + of_node_put(endpoint); + } + + /* Count the number of ports. */ + nports++; + } + + if (nports != 1 && nports != 2) { + dev_err(dev, "invalid number of ports %u\n", nports); + return -EINVAL; + } + + xtpg->npads = nports; + if (nports == 2 && has_endpoint) + xtpg->has_input = true; + + return 0; +} + +static int xtpg_probe(struct platform_device *pdev) +{ + struct v4l2_subdev *subdev; + struct xtpg_device *xtpg; + u32 i, bayer_phase; + int ret; + + xtpg = devm_kzalloc(&pdev->dev, sizeof(*xtpg), GFP_KERNEL); + if (!xtpg) + return -ENOMEM; + + xtpg->xvip.dev = &pdev->dev; + + ret = xtpg_parse_of(xtpg); + if (ret < 0) + return ret; + + ret = xvip_init_resources(&xtpg->xvip); + if (ret < 0) + return ret; + + xtpg->vtmux_gpio = devm_gpiod_get_optional(&pdev->dev, "timing", + GPIOD_OUT_HIGH); + if (IS_ERR(xtpg->vtmux_gpio)) { + ret = PTR_ERR(xtpg->vtmux_gpio); + goto error_resource; + } + + xtpg->vtc = xvtc_of_get(pdev->dev.of_node); + if (IS_ERR(xtpg->vtc)) { + ret = PTR_ERR(xtpg->vtc); + goto error_resource; + } + + /* Reset and initialize the core */ + xvip_reset(&xtpg->xvip); + + /* Initialize V4L2 subdevice and media entity. Pad numbers depend on the + * number of pads. + */ + if (xtpg->npads == 2) { + xtpg->pads[0].flags = MEDIA_PAD_FL_SINK; + xtpg->pads[1].flags = MEDIA_PAD_FL_SOURCE; + } else { + xtpg->pads[0].flags = MEDIA_PAD_FL_SOURCE; + } + + /* Initialize the default format */ + xtpg->default_format.code = xtpg->vip_format->code; + xtpg->default_format.field = V4L2_FIELD_NONE; + xtpg->default_format.colorspace = V4L2_COLORSPACE_SRGB; + xvip_get_frame_size(&xtpg->xvip, &xtpg->default_format); + + bayer_phase = xtpg_get_bayer_phase(xtpg->vip_format->code); + if (bayer_phase != XTPG_BAYER_PHASE_OFF) + xtpg->bayer = true; + + xtpg->formats[0] = xtpg->default_format; + if (xtpg->npads == 2) + xtpg->formats[1] = xtpg->default_format; + + /* Initialize V4L2 subdevice and media entity */ + subdev = &xtpg->xvip.subdev; + v4l2_subdev_init(subdev, &xtpg_ops); + subdev->dev = &pdev->dev; + subdev->internal_ops = &xtpg_internal_ops; + strlcpy(subdev->name, dev_name(&pdev->dev), sizeof(subdev->name)); + v4l2_set_subdevdata(subdev, xtpg); + subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + subdev->entity.ops = &xtpg_media_ops; + + ret = media_entity_init(&subdev->entity, xtpg->npads, xtpg->pads, 0); + if (ret < 0) + goto error; + + v4l2_ctrl_handler_init(&xtpg->ctrl_handler, 3 + ARRAY_SIZE(xtpg_ctrls)); + + xtpg->vblank = v4l2_ctrl_new_std(&xtpg->ctrl_handler, &xtpg_ctrl_ops, + V4L2_CID_VBLANK, XTPG_MIN_VBLANK, + XTPG_MAX_VBLANK, 1, 100); + xtpg->hblank = v4l2_ctrl_new_std(&xtpg->ctrl_handler, &xtpg_ctrl_ops, + V4L2_CID_HBLANK, XTPG_MIN_HBLANK, + XTPG_MAX_HBLANK, 1, 100); + xtpg->pattern = v4l2_ctrl_new_std_menu_items(&xtpg->ctrl_handler, + &xtpg_ctrl_ops, V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(xtpg_pattern_strings) - 1, + 1, 9, xtpg_pattern_strings); + + for (i = 0; i < ARRAY_SIZE(xtpg_ctrls); i++) + v4l2_ctrl_new_custom(&xtpg->ctrl_handler, &xtpg_ctrls[i], NULL); + + if (xtpg->ctrl_handler.error) { + dev_err(&pdev->dev, "failed to add controls\n"); + ret = xtpg->ctrl_handler.error; + goto error; + } + subdev->ctrl_handler = &xtpg->ctrl_handler; + + xtpg_update_pattern_control(xtpg, true, true); + + ret = v4l2_ctrl_handler_setup(&xtpg->ctrl_handler); + if (ret < 0) { + dev_err(&pdev->dev, "failed to set controls\n"); + goto error; + } + + platform_set_drvdata(pdev, xtpg); + + xvip_print_version(&xtpg->xvip); + + ret = v4l2_async_register_subdev(subdev); + if (ret < 0) { + dev_err(&pdev->dev, "failed to register subdev\n"); + goto error; + } + + return 0; + +error: + v4l2_ctrl_handler_free(&xtpg->ctrl_handler); + media_entity_cleanup(&subdev->entity); + xvtc_put(xtpg->vtc); +error_resource: + xvip_cleanup_resources(&xtpg->xvip); + return ret; +} + +static int xtpg_remove(struct platform_device *pdev) +{ + struct xtpg_device *xtpg = platform_get_drvdata(pdev); + struct v4l2_subdev *subdev = &xtpg->xvip.subdev; + + v4l2_async_unregister_subdev(subdev); + v4l2_ctrl_handler_free(&xtpg->ctrl_handler); + media_entity_cleanup(&subdev->entity); + + xvip_cleanup_resources(&xtpg->xvip); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(xtpg_pm_ops, xtpg_pm_suspend, xtpg_pm_resume); + +static const struct of_device_id xtpg_of_id_table[] = { + { .compatible = "xlnx,v-tpg-5.0" }, + { } +}; +MODULE_DEVICE_TABLE(of, xtpg_of_id_table); + +static struct platform_driver xtpg_driver = { + .driver = { + .name = "xilinx-tpg", + .pm = &xtpg_pm_ops, + .of_match_table = xtpg_of_id_table, + }, + .probe = xtpg_probe, + .remove = xtpg_remove, +}; + +module_platform_driver(xtpg_driver); + +MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); +MODULE_DESCRIPTION("Xilinx Test Pattern Generator Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/xilinx/xilinx-vip.c b/drivers/media/platform/xilinx/xilinx-vip.c new file mode 100644 index 000000000000..311259129504 --- /dev/null +++ b/drivers/media/platform/xilinx/xilinx-vip.c @@ -0,0 +1,323 @@ +/* + * Xilinx Video IP Core + * + * Copyright (C) 2013-2015 Ideas on Board + * Copyright (C) 2013-2015 Xilinx, Inc. + * + * Contacts: Hyun Kwon <hyun.kwon@xilinx.com> + * Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/clk.h> +#include <linux/export.h> +#include <linux/kernel.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +#include <dt-bindings/media/xilinx-vip.h> + +#include "xilinx-vip.h" + +/* ----------------------------------------------------------------------------- + * Helper functions + */ + +static const struct xvip_video_format xvip_video_formats[] = { + { XVIP_VF_YUV_422, 8, NULL, MEDIA_BUS_FMT_UYVY8_1X16, + 2, V4L2_PIX_FMT_YUYV, "4:2:2, packed, YUYV" }, + { XVIP_VF_YUV_444, 8, NULL, MEDIA_BUS_FMT_VUY8_1X24, + 3, V4L2_PIX_FMT_YUV444, "4:4:4, packed, YUYV" }, + { XVIP_VF_RBG, 8, NULL, MEDIA_BUS_FMT_RBG888_1X24, + 3, 0, NULL }, + { XVIP_VF_MONO_SENSOR, 8, "mono", MEDIA_BUS_FMT_Y8_1X8, + 1, V4L2_PIX_FMT_GREY, "Greyscale 8-bit" }, + { XVIP_VF_MONO_SENSOR, 8, "rggb", MEDIA_BUS_FMT_SRGGB8_1X8, + 1, V4L2_PIX_FMT_SGRBG8, "Bayer 8-bit RGGB" }, + { XVIP_VF_MONO_SENSOR, 8, "grbg", MEDIA_BUS_FMT_SGRBG8_1X8, + 1, V4L2_PIX_FMT_SGRBG8, "Bayer 8-bit GRBG" }, + { XVIP_VF_MONO_SENSOR, 8, "gbrg", MEDIA_BUS_FMT_SGBRG8_1X8, + 1, V4L2_PIX_FMT_SGBRG8, "Bayer 8-bit GBRG" }, + { XVIP_VF_MONO_SENSOR, 8, "bggr", MEDIA_BUS_FMT_SBGGR8_1X8, + 1, V4L2_PIX_FMT_SBGGR8, "Bayer 8-bit BGGR" }, +}; + +/** + * xvip_get_format_by_code - Retrieve format information for a media bus code + * @code: the format media bus code + * + * Return: a pointer to the format information structure corresponding to the + * given V4L2 media bus format @code, or ERR_PTR if no corresponding format can + * be found. + */ +const struct xvip_video_format *xvip_get_format_by_code(unsigned int code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(xvip_video_formats); ++i) { + const struct xvip_video_format *format = &xvip_video_formats[i]; + + if (format->code == code) + return format; + } + + return ERR_PTR(-EINVAL); +} +EXPORT_SYMBOL_GPL(xvip_get_format_by_code); + +/** + * xvip_get_format_by_fourcc - Retrieve format information for a 4CC + * @fourcc: the format 4CC + * + * Return: a pointer to the format information structure corresponding to the + * given V4L2 format @fourcc, or ERR_PTR if no corresponding format can be + * found. + */ +const struct xvip_video_format *xvip_get_format_by_fourcc(u32 fourcc) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(xvip_video_formats); ++i) { + const struct xvip_video_format *format = &xvip_video_formats[i]; + + if (format->fourcc == fourcc) + return format; + } + + return ERR_PTR(-EINVAL); +} +EXPORT_SYMBOL_GPL(xvip_get_format_by_fourcc); + +/** + * xvip_of_get_format - Parse a device tree node and return format information + * @node: the device tree node + * + * Read the xlnx,video-format, xlnx,video-width and xlnx,cfa-pattern properties + * from the device tree @node passed as an argument and return the corresponding + * format information. + * + * Return: a pointer to the format information structure corresponding to the + * format name and width, or ERR_PTR if no corresponding format can be found. + */ +const struct xvip_video_format *xvip_of_get_format(struct device_node *node) +{ + const char *pattern = "mono"; + unsigned int vf_code; + unsigned int i; + u32 width; + int ret; + + ret = of_property_read_u32(node, "xlnx,video-format", &vf_code); + if (ret < 0) + return ERR_PTR(ret); + + ret = of_property_read_u32(node, "xlnx,video-width", &width); + if (ret < 0) + return ERR_PTR(ret); + + if (vf_code == XVIP_VF_MONO_SENSOR) + of_property_read_string(node, "xlnx,cfa-pattern", &pattern); + + for (i = 0; i < ARRAY_SIZE(xvip_video_formats); ++i) { + const struct xvip_video_format *format = &xvip_video_formats[i]; + + if (format->vf_code != vf_code || format->width != width) + continue; + + if (vf_code == XVIP_VF_MONO_SENSOR && + strcmp(pattern, format->pattern)) + continue; + + return format; + } + + return ERR_PTR(-EINVAL); +} +EXPORT_SYMBOL_GPL(xvip_of_get_format); + +/** + * xvip_set_format_size - Set the media bus frame format size + * @format: V4L2 frame format on media bus + * @fmt: media bus format + * + * Set the media bus frame format size. The width / height from the subdevice + * format are set to the given media bus format. The new format size is stored + * in @format. The width and height are clamped using default min / max values. + */ +void xvip_set_format_size(struct v4l2_mbus_framefmt *format, + const struct v4l2_subdev_format *fmt) +{ + format->width = clamp_t(unsigned int, fmt->format.width, + XVIP_MIN_WIDTH, XVIP_MAX_WIDTH); + format->height = clamp_t(unsigned int, fmt->format.height, + XVIP_MIN_HEIGHT, XVIP_MAX_HEIGHT); +} +EXPORT_SYMBOL_GPL(xvip_set_format_size); + +/** + * xvip_clr_or_set - Clear or set the register with a bitmask + * @xvip: Xilinx Video IP device + * @addr: address of register + * @mask: bitmask to be set or cleared + * @set: boolean flag indicating whether to set or clear + * + * Clear or set the register at address @addr with a bitmask @mask depending on + * the boolean flag @set. When the flag @set is true, the bitmask is set in + * the register, otherwise the bitmask is cleared from the register + * when the flag @set is false. + * + * Fox eample, this function can be used to set a control with a boolean value + * requested by users. If the caller knows whether to set or clear in the first + * place, the caller should call xvip_clr() or xvip_set() directly instead of + * using this function. + */ +void xvip_clr_or_set(struct xvip_device *xvip, u32 addr, u32 mask, bool set) +{ + u32 reg; + + reg = xvip_read(xvip, addr); + reg = set ? reg | mask : reg & ~mask; + xvip_write(xvip, addr, reg); +} +EXPORT_SYMBOL_GPL(xvip_clr_or_set); + +/** + * xvip_clr_and_set - Clear and set the register with a bitmask + * @xvip: Xilinx Video IP device + * @addr: address of register + * @clr: bitmask to be cleared + * @set: bitmask to be set + * + * Clear a bit(s) of mask @clr in the register at address @addr, then set + * a bit(s) of mask @set in the register after. + */ +void xvip_clr_and_set(struct xvip_device *xvip, u32 addr, u32 clr, u32 set) +{ + u32 reg; + + reg = xvip_read(xvip, addr); + reg &= ~clr; + reg |= set; + xvip_write(xvip, addr, reg); +} +EXPORT_SYMBOL_GPL(xvip_clr_and_set); + +int xvip_init_resources(struct xvip_device *xvip) +{ + struct platform_device *pdev = to_platform_device(xvip->dev); + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + xvip->iomem = devm_ioremap_resource(xvip->dev, res); + if (IS_ERR(xvip->iomem)) + return PTR_ERR(xvip->iomem); + + xvip->clk = devm_clk_get(xvip->dev, NULL); + if (IS_ERR(xvip->clk)) + return PTR_ERR(xvip->clk); + + clk_prepare_enable(xvip->clk); + return 0; +} +EXPORT_SYMBOL_GPL(xvip_init_resources); + +void xvip_cleanup_resources(struct xvip_device *xvip) +{ + clk_disable_unprepare(xvip->clk); +} +EXPORT_SYMBOL_GPL(xvip_cleanup_resources); + +/* ----------------------------------------------------------------------------- + * Subdev operations handlers + */ + +/** + * xvip_enum_mbus_code - Enumerate the media format code + * @subdev: V4L2 subdevice + * @cfg: V4L2 subdev pad configuration + * @code: returning media bus code + * + * Enumerate the media bus code of the subdevice. Return the corresponding + * pad format code. This function only works for subdevices with fixed format + * on all pads. Subdevices with multiple format should have their own + * function to enumerate mbus codes. + * + * Return: 0 if the media bus code is found, or -EINVAL if the format index + * is not valid. + */ +int xvip_enum_mbus_code(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct v4l2_mbus_framefmt *format; + + /* Enumerating frame sizes based on the active configuration isn't + * supported yet. + */ + if (code->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return -EINVAL; + + if (code->index) + return -EINVAL; + + format = v4l2_subdev_get_try_format(subdev, cfg, code->pad); + + code->code = format->code; + + return 0; +} +EXPORT_SYMBOL_GPL(xvip_enum_mbus_code); + +/** + * xvip_enum_frame_size - Enumerate the media bus frame size + * @subdev: V4L2 subdevice + * @cfg: V4L2 subdev pad configuration + * @fse: returning media bus frame size + * + * This function is a drop-in implementation of the subdev enum_frame_size pad + * operation. It assumes that the subdevice has one sink pad and one source + * pad, and that the format on the source pad is always identical to the + * format on the sink pad. Entities with different requirements need to + * implement their own enum_frame_size handlers. + * + * Return: 0 if the media bus frame size is found, or -EINVAL + * if the index or the code is not valid. + */ +int xvip_enum_frame_size(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct v4l2_mbus_framefmt *format; + + /* Enumerating frame sizes based on the active configuration isn't + * supported yet. + */ + if (fse->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return -EINVAL; + + format = v4l2_subdev_get_try_format(subdev, cfg, fse->pad); + + if (fse->index || fse->code != format->code) + return -EINVAL; + + if (fse->pad == XVIP_PAD_SINK) { + fse->min_width = XVIP_MIN_WIDTH; + fse->max_width = XVIP_MAX_WIDTH; + fse->min_height = XVIP_MIN_HEIGHT; + fse->max_height = XVIP_MAX_HEIGHT; + } else { + /* The size on the source pad is fixed and always identical to + * the size on the sink pad. + */ + fse->min_width = format->width; + fse->max_width = format->width; + fse->min_height = format->height; + fse->max_height = format->height; + } + + return 0; +} +EXPORT_SYMBOL_GPL(xvip_enum_frame_size); diff --git a/drivers/media/platform/xilinx/xilinx-vip.h b/drivers/media/platform/xilinx/xilinx-vip.h new file mode 100644 index 000000000000..42fee2026815 --- /dev/null +++ b/drivers/media/platform/xilinx/xilinx-vip.h @@ -0,0 +1,238 @@ +/* + * Xilinx Video IP Core + * + * Copyright (C) 2013-2015 Ideas on Board + * Copyright (C) 2013-2015 Xilinx, Inc. + * + * Contacts: Hyun Kwon <hyun.kwon@xilinx.com> + * Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __XILINX_VIP_H__ +#define __XILINX_VIP_H__ + +#include <linux/io.h> +#include <media/v4l2-subdev.h> + +struct clk; + +/* + * Minimum and maximum width and height common to most video IP cores. IP + * cores with different requirements must define their own values. + */ +#define XVIP_MIN_WIDTH 32 +#define XVIP_MAX_WIDTH 7680 +#define XVIP_MIN_HEIGHT 32 +#define XVIP_MAX_HEIGHT 7680 + +/* + * Pad IDs. IP cores with with multiple inputs or outputs should define + * their own values. + */ +#define XVIP_PAD_SINK 0 +#define XVIP_PAD_SOURCE 1 + +/* Xilinx Video IP Control Registers */ +#define XVIP_CTRL_CONTROL 0x0000 +#define XVIP_CTRL_CONTROL_SW_ENABLE (1 << 0) +#define XVIP_CTRL_CONTROL_REG_UPDATE (1 << 1) +#define XVIP_CTRL_CONTROL_BYPASS (1 << 4) +#define XVIP_CTRL_CONTROL_TEST_PATTERN (1 << 5) +#define XVIP_CTRL_CONTROL_FRAME_SYNC_RESET (1 << 30) +#define XVIP_CTRL_CONTROL_SW_RESET (1 << 31) +#define XVIP_CTRL_STATUS 0x0004 +#define XVIP_CTRL_STATUS_PROC_STARTED (1 << 0) +#define XVIP_CTRL_STATUS_EOF (1 << 1) +#define XVIP_CTRL_ERROR 0x0008 +#define XVIP_CTRL_ERROR_SLAVE_EOL_EARLY (1 << 0) +#define XVIP_CTRL_ERROR_SLAVE_EOL_LATE (1 << 1) +#define XVIP_CTRL_ERROR_SLAVE_SOF_EARLY (1 << 2) +#define XVIP_CTRL_ERROR_SLAVE_SOF_LATE (1 << 3) +#define XVIP_CTRL_IRQ_ENABLE 0x000c +#define XVIP_CTRL_IRQ_ENABLE_PROC_STARTED (1 << 0) +#define XVIP_CTRL_IRQ_EOF (1 << 1) +#define XVIP_CTRL_VERSION 0x0010 +#define XVIP_CTRL_VERSION_MAJOR_MASK (0xff << 24) +#define XVIP_CTRL_VERSION_MAJOR_SHIFT 24 +#define XVIP_CTRL_VERSION_MINOR_MASK (0xff << 16) +#define XVIP_CTRL_VERSION_MINOR_SHIFT 16 +#define XVIP_CTRL_VERSION_REVISION_MASK (0xf << 12) +#define XVIP_CTRL_VERSION_REVISION_SHIFT 12 +#define XVIP_CTRL_VERSION_PATCH_MASK (0xf << 8) +#define XVIP_CTRL_VERSION_PATCH_SHIFT 8 +#define XVIP_CTRL_VERSION_INTERNAL_MASK (0xff << 0) +#define XVIP_CTRL_VERSION_INTERNAL_SHIFT 0 + +/* Xilinx Video IP Timing Registers */ +#define XVIP_ACTIVE_SIZE 0x0020 +#define XVIP_ACTIVE_VSIZE_MASK (0x7ff << 16) +#define XVIP_ACTIVE_VSIZE_SHIFT 16 +#define XVIP_ACTIVE_HSIZE_MASK (0x7ff << 0) +#define XVIP_ACTIVE_HSIZE_SHIFT 0 +#define XVIP_ENCODING 0x0028 +#define XVIP_ENCODING_NBITS_8 (0 << 4) +#define XVIP_ENCODING_NBITS_10 (1 << 4) +#define XVIP_ENCODING_NBITS_12 (2 << 4) +#define XVIP_ENCODING_NBITS_16 (3 << 4) +#define XVIP_ENCODING_NBITS_MASK (3 << 4) +#define XVIP_ENCODING_NBITS_SHIFT 4 +#define XVIP_ENCODING_VIDEO_FORMAT_YUV422 (0 << 0) +#define XVIP_ENCODING_VIDEO_FORMAT_YUV444 (1 << 0) +#define XVIP_ENCODING_VIDEO_FORMAT_RGB (2 << 0) +#define XVIP_ENCODING_VIDEO_FORMAT_YUV420 (3 << 0) +#define XVIP_ENCODING_VIDEO_FORMAT_MASK (3 << 0) +#define XVIP_ENCODING_VIDEO_FORMAT_SHIFT 0 + +/** + * struct xvip_device - Xilinx Video IP device structure + * @subdev: V4L2 subdevice + * @dev: (OF) device + * @iomem: device I/O register space remapped to kernel virtual memory + * @clk: video core clock + * @saved_ctrl: saved control register for resume / suspend + */ +struct xvip_device { + struct v4l2_subdev subdev; + struct device *dev; + void __iomem *iomem; + struct clk *clk; + u32 saved_ctrl; +}; + +/** + * struct xvip_video_format - Xilinx Video IP video format description + * @vf_code: AXI4 video format code + * @width: AXI4 format width in bits per component + * @pattern: CFA pattern for Mono/Sensor formats + * @code: media bus format code + * @bpp: bytes per pixel (when stored in memory) + * @fourcc: V4L2 pixel format FCC identifier + * @description: format description, suitable for userspace + */ +struct xvip_video_format { + unsigned int vf_code; + unsigned int width; + const char *pattern; + unsigned int code; + unsigned int bpp; + u32 fourcc; + const char *description; +}; + +const struct xvip_video_format *xvip_get_format_by_code(unsigned int code); +const struct xvip_video_format *xvip_get_format_by_fourcc(u32 fourcc); +const struct xvip_video_format *xvip_of_get_format(struct device_node *node); +void xvip_set_format_size(struct v4l2_mbus_framefmt *format, + const struct v4l2_subdev_format *fmt); +int xvip_enum_mbus_code(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code); +int xvip_enum_frame_size(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse); + +static inline u32 xvip_read(struct xvip_device *xvip, u32 addr) +{ + return ioread32(xvip->iomem + addr); +} + +static inline void xvip_write(struct xvip_device *xvip, u32 addr, u32 value) +{ + iowrite32(value, xvip->iomem + addr); +} + +static inline void xvip_clr(struct xvip_device *xvip, u32 addr, u32 clr) +{ + xvip_write(xvip, addr, xvip_read(xvip, addr) & ~clr); +} + +static inline void xvip_set(struct xvip_device *xvip, u32 addr, u32 set) +{ + xvip_write(xvip, addr, xvip_read(xvip, addr) | set); +} + +void xvip_clr_or_set(struct xvip_device *xvip, u32 addr, u32 mask, bool set); +void xvip_clr_and_set(struct xvip_device *xvip, u32 addr, u32 clr, u32 set); + +int xvip_init_resources(struct xvip_device *xvip); +void xvip_cleanup_resources(struct xvip_device *xvip); + +static inline void xvip_reset(struct xvip_device *xvip) +{ + xvip_write(xvip, XVIP_CTRL_CONTROL, XVIP_CTRL_CONTROL_SW_RESET); +} + +static inline void xvip_start(struct xvip_device *xvip) +{ + xvip_set(xvip, XVIP_CTRL_CONTROL, + XVIP_CTRL_CONTROL_SW_ENABLE | XVIP_CTRL_CONTROL_REG_UPDATE); +} + +static inline void xvip_stop(struct xvip_device *xvip) +{ + xvip_clr(xvip, XVIP_CTRL_CONTROL, XVIP_CTRL_CONTROL_SW_ENABLE); +} + +static inline void xvip_resume(struct xvip_device *xvip) +{ + xvip_write(xvip, XVIP_CTRL_CONTROL, + xvip->saved_ctrl | XVIP_CTRL_CONTROL_SW_ENABLE); +} + +static inline void xvip_suspend(struct xvip_device *xvip) +{ + xvip->saved_ctrl = xvip_read(xvip, XVIP_CTRL_CONTROL); + xvip_write(xvip, XVIP_CTRL_CONTROL, + xvip->saved_ctrl & ~XVIP_CTRL_CONTROL_SW_ENABLE); +} + +static inline void xvip_set_frame_size(struct xvip_device *xvip, + const struct v4l2_mbus_framefmt *format) +{ + xvip_write(xvip, XVIP_ACTIVE_SIZE, + (format->height << XVIP_ACTIVE_VSIZE_SHIFT) | + (format->width << XVIP_ACTIVE_HSIZE_SHIFT)); +} + +static inline void xvip_get_frame_size(struct xvip_device *xvip, + struct v4l2_mbus_framefmt *format) +{ + u32 reg; + + reg = xvip_read(xvip, XVIP_ACTIVE_SIZE); + format->width = (reg & XVIP_ACTIVE_HSIZE_MASK) >> + XVIP_ACTIVE_HSIZE_SHIFT; + format->height = (reg & XVIP_ACTIVE_VSIZE_MASK) >> + XVIP_ACTIVE_VSIZE_SHIFT; +} + +static inline void xvip_enable_reg_update(struct xvip_device *xvip) +{ + xvip_set(xvip, XVIP_CTRL_CONTROL, XVIP_CTRL_CONTROL_REG_UPDATE); +} + +static inline void xvip_disable_reg_update(struct xvip_device *xvip) +{ + xvip_clr(xvip, XVIP_CTRL_CONTROL, XVIP_CTRL_CONTROL_REG_UPDATE); +} + +static inline void xvip_print_version(struct xvip_device *xvip) +{ + u32 version; + + version = xvip_read(xvip, XVIP_CTRL_VERSION); + + dev_info(xvip->dev, "device found, version %u.%02x%x\n", + ((version & XVIP_CTRL_VERSION_MAJOR_MASK) >> + XVIP_CTRL_VERSION_MAJOR_SHIFT), + ((version & XVIP_CTRL_VERSION_MINOR_MASK) >> + XVIP_CTRL_VERSION_MINOR_SHIFT), + ((version & XVIP_CTRL_VERSION_REVISION_MASK) >> + XVIP_CTRL_VERSION_REVISION_SHIFT)); +} + +#endif /* __XILINX_VIP_H__ */ diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c new file mode 100644 index 000000000000..7b7cb9c28d2c --- /dev/null +++ b/drivers/media/platform/xilinx/xilinx-vipp.c @@ -0,0 +1,669 @@ +/* + * Xilinx Video IP Composite Device + * + * Copyright (C) 2013-2015 Ideas on Board + * Copyright (C) 2013-2015 Xilinx, Inc. + * + * Contacts: Hyun Kwon <hyun.kwon@xilinx.com> + * Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/list.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_graph.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include <media/v4l2-async.h> +#include <media/v4l2-common.h> +#include <media/v4l2-device.h> +#include <media/v4l2-of.h> + +#include "xilinx-dma.h" +#include "xilinx-vipp.h" + +#define XVIPP_DMA_S2MM 0 +#define XVIPP_DMA_MM2S 1 + +/** + * struct xvip_graph_entity - Entity in the video graph + * @list: list entry in a graph entities list + * @node: the entity's DT node + * @entity: media entity, from the corresponding V4L2 subdev + * @asd: subdev asynchronous registration information + * @subdev: V4L2 subdev + */ +struct xvip_graph_entity { + struct list_head list; + struct device_node *node; + struct media_entity *entity; + + struct v4l2_async_subdev asd; + struct v4l2_subdev *subdev; +}; + +/* ----------------------------------------------------------------------------- + * Graph Management + */ + +static struct xvip_graph_entity * +xvip_graph_find_entity(struct xvip_composite_device *xdev, + const struct device_node *node) +{ + struct xvip_graph_entity *entity; + + list_for_each_entry(entity, &xdev->entities, list) { + if (entity->node == node) + return entity; + } + + return NULL; +} + +static int xvip_graph_build_one(struct xvip_composite_device *xdev, + struct xvip_graph_entity *entity) +{ + u32 link_flags = MEDIA_LNK_FL_ENABLED; + struct media_entity *local = entity->entity; + struct media_entity *remote; + struct media_pad *local_pad; + struct media_pad *remote_pad; + struct xvip_graph_entity *ent; + struct v4l2_of_link link; + struct device_node *ep = NULL; + struct device_node *next; + int ret = 0; + + dev_dbg(xdev->dev, "creating links for entity %s\n", local->name); + + while (1) { + /* Get the next endpoint and parse its link. */ + next = of_graph_get_next_endpoint(entity->node, ep); + if (next == NULL) + break; + + of_node_put(ep); + ep = next; + + dev_dbg(xdev->dev, "processing endpoint %s\n", ep->full_name); + + ret = v4l2_of_parse_link(ep, &link); + if (ret < 0) { + dev_err(xdev->dev, "failed to parse link for %s\n", + ep->full_name); + continue; + } + + /* Skip sink ports, they will be processed from the other end of + * the link. + */ + if (link.local_port >= local->num_pads) { + dev_err(xdev->dev, "invalid port number %u on %s\n", + link.local_port, link.local_node->full_name); + v4l2_of_put_link(&link); + ret = -EINVAL; + break; + } + + local_pad = &local->pads[link.local_port]; + + if (local_pad->flags & MEDIA_PAD_FL_SINK) { + dev_dbg(xdev->dev, "skipping sink port %s:%u\n", + link.local_node->full_name, link.local_port); + v4l2_of_put_link(&link); + continue; + } + + /* Skip DMA engines, they will be processed separately. */ + if (link.remote_node == xdev->dev->of_node) { + dev_dbg(xdev->dev, "skipping DMA port %s:%u\n", + link.local_node->full_name, link.local_port); + v4l2_of_put_link(&link); + continue; + } + + /* Find the remote entity. */ + ent = xvip_graph_find_entity(xdev, link.remote_node); + if (ent == NULL) { + dev_err(xdev->dev, "no entity found for %s\n", + link.remote_node->full_name); + v4l2_of_put_link(&link); + ret = -ENODEV; + break; + } + + remote = ent->entity; + + if (link.remote_port >= remote->num_pads) { + dev_err(xdev->dev, "invalid port number %u on %s\n", + link.remote_port, link.remote_node->full_name); + v4l2_of_put_link(&link); + ret = -EINVAL; + break; + } + + remote_pad = &remote->pads[link.remote_port]; + + v4l2_of_put_link(&link); + + /* Create the media link. */ + dev_dbg(xdev->dev, "creating %s:%u -> %s:%u link\n", + local->name, local_pad->index, + remote->name, remote_pad->index); + + ret = media_entity_create_link(local, local_pad->index, + remote, remote_pad->index, + link_flags); + if (ret < 0) { + dev_err(xdev->dev, + "failed to create %s:%u -> %s:%u link\n", + local->name, local_pad->index, + remote->name, remote_pad->index); + break; + } + } + + of_node_put(ep); + return ret; +} + +static struct xvip_dma * +xvip_graph_find_dma(struct xvip_composite_device *xdev, unsigned int port) +{ + struct xvip_dma *dma; + + list_for_each_entry(dma, &xdev->dmas, list) { + if (dma->port == port) + return dma; + } + + return NULL; +} + +static int xvip_graph_build_dma(struct xvip_composite_device *xdev) +{ + u32 link_flags = MEDIA_LNK_FL_ENABLED; + struct device_node *node = xdev->dev->of_node; + struct media_entity *source; + struct media_entity *sink; + struct media_pad *source_pad; + struct media_pad *sink_pad; + struct xvip_graph_entity *ent; + struct v4l2_of_link link; + struct device_node *ep = NULL; + struct device_node *next; + struct xvip_dma *dma; + int ret = 0; + + dev_dbg(xdev->dev, "creating links for DMA engines\n"); + + while (1) { + /* Get the next endpoint and parse its link. */ + next = of_graph_get_next_endpoint(node, ep); + if (next == NULL) + break; + + of_node_put(ep); + ep = next; + + dev_dbg(xdev->dev, "processing endpoint %s\n", ep->full_name); + + ret = v4l2_of_parse_link(ep, &link); + if (ret < 0) { + dev_err(xdev->dev, "failed to parse link for %s\n", + ep->full_name); + continue; + } + + /* Find the DMA engine. */ + dma = xvip_graph_find_dma(xdev, link.local_port); + if (dma == NULL) { + dev_err(xdev->dev, "no DMA engine found for port %u\n", + link.local_port); + v4l2_of_put_link(&link); + ret = -EINVAL; + break; + } + + dev_dbg(xdev->dev, "creating link for DMA engine %s\n", + dma->video.name); + + /* Find the remote entity. */ + ent = xvip_graph_find_entity(xdev, link.remote_node); + if (ent == NULL) { + dev_err(xdev->dev, "no entity found for %s\n", + link.remote_node->full_name); + v4l2_of_put_link(&link); + ret = -ENODEV; + break; + } + + if (link.remote_port >= ent->entity->num_pads) { + dev_err(xdev->dev, "invalid port number %u on %s\n", + link.remote_port, link.remote_node->full_name); + v4l2_of_put_link(&link); + ret = -EINVAL; + break; + } + + if (dma->pad.flags & MEDIA_PAD_FL_SOURCE) { + source = &dma->video.entity; + source_pad = &dma->pad; + sink = ent->entity; + sink_pad = &sink->pads[link.remote_port]; + } else { + source = ent->entity; + source_pad = &source->pads[link.remote_port]; + sink = &dma->video.entity; + sink_pad = &dma->pad; + } + + v4l2_of_put_link(&link); + + /* Create the media link. */ + dev_dbg(xdev->dev, "creating %s:%u -> %s:%u link\n", + source->name, source_pad->index, + sink->name, sink_pad->index); + + ret = media_entity_create_link(source, source_pad->index, + sink, sink_pad->index, + link_flags); + if (ret < 0) { + dev_err(xdev->dev, + "failed to create %s:%u -> %s:%u link\n", + source->name, source_pad->index, + sink->name, sink_pad->index); + break; + } + } + + of_node_put(ep); + return ret; +} + +static int xvip_graph_notify_complete(struct v4l2_async_notifier *notifier) +{ + struct xvip_composite_device *xdev = + container_of(notifier, struct xvip_composite_device, notifier); + struct xvip_graph_entity *entity; + int ret; + + dev_dbg(xdev->dev, "notify complete, all subdevs registered\n"); + + /* Create links for every entity. */ + list_for_each_entry(entity, &xdev->entities, list) { + ret = xvip_graph_build_one(xdev, entity); + if (ret < 0) + return ret; + } + + /* Create links for DMA channels. */ + ret = xvip_graph_build_dma(xdev); + if (ret < 0) + return ret; + + ret = v4l2_device_register_subdev_nodes(&xdev->v4l2_dev); + if (ret < 0) + dev_err(xdev->dev, "failed to register subdev nodes\n"); + + return ret; +} + +static int xvip_graph_notify_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd) +{ + struct xvip_composite_device *xdev = + container_of(notifier, struct xvip_composite_device, notifier); + struct xvip_graph_entity *entity; + + /* Locate the entity corresponding to the bound subdev and store the + * subdev pointer. + */ + list_for_each_entry(entity, &xdev->entities, list) { + if (entity->node != subdev->dev->of_node) + continue; + + if (entity->subdev) { + dev_err(xdev->dev, "duplicate subdev for node %s\n", + entity->node->full_name); + return -EINVAL; + } + + dev_dbg(xdev->dev, "subdev %s bound\n", subdev->name); + entity->entity = &subdev->entity; + entity->subdev = subdev; + return 0; + } + + dev_err(xdev->dev, "no entity for subdev %s\n", subdev->name); + return -EINVAL; +} + +static int xvip_graph_parse_one(struct xvip_composite_device *xdev, + struct device_node *node) +{ + struct xvip_graph_entity *entity; + struct device_node *remote; + struct device_node *ep = NULL; + struct device_node *next; + int ret = 0; + + dev_dbg(xdev->dev, "parsing node %s\n", node->full_name); + + while (1) { + next = of_graph_get_next_endpoint(node, ep); + if (next == NULL) + break; + + of_node_put(ep); + ep = next; + + dev_dbg(xdev->dev, "handling endpoint %s\n", ep->full_name); + + remote = of_graph_get_remote_port_parent(ep); + if (remote == NULL) { + ret = -EINVAL; + break; + } + + /* Skip entities that we have already processed. */ + if (remote == xdev->dev->of_node || + xvip_graph_find_entity(xdev, remote)) { + of_node_put(remote); + continue; + } + + entity = devm_kzalloc(xdev->dev, sizeof(*entity), GFP_KERNEL); + if (entity == NULL) { + of_node_put(remote); + ret = -ENOMEM; + break; + } + + entity->node = remote; + entity->asd.match_type = V4L2_ASYNC_MATCH_OF; + entity->asd.match.of.node = remote; + list_add_tail(&entity->list, &xdev->entities); + xdev->num_subdevs++; + } + + of_node_put(ep); + return ret; +} + +static int xvip_graph_parse(struct xvip_composite_device *xdev) +{ + struct xvip_graph_entity *entity; + int ret; + + /* + * Walk the links to parse the full graph. Start by parsing the + * composite node and then parse entities in turn. The list_for_each + * loop will handle entities added at the end of the list while walking + * the links. + */ + ret = xvip_graph_parse_one(xdev, xdev->dev->of_node); + if (ret < 0) + return 0; + + list_for_each_entry(entity, &xdev->entities, list) { + ret = xvip_graph_parse_one(xdev, entity->node); + if (ret < 0) + break; + } + + return ret; +} + +static int xvip_graph_dma_init_one(struct xvip_composite_device *xdev, + struct device_node *node) +{ + struct xvip_dma *dma; + enum v4l2_buf_type type; + const char *direction; + unsigned int index; + int ret; + + ret = of_property_read_string(node, "direction", &direction); + if (ret < 0) + return ret; + + if (strcmp(direction, "input") == 0) + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + else if (strcmp(direction, "output") == 0) + type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + else + return -EINVAL; + + of_property_read_u32(node, "reg", &index); + + dma = devm_kzalloc(xdev->dev, sizeof(*dma), GFP_KERNEL); + if (dma == NULL) + return -ENOMEM; + + ret = xvip_dma_init(xdev, dma, type, index); + if (ret < 0) { + dev_err(xdev->dev, "%s initialization failed\n", + node->full_name); + return ret; + } + + list_add_tail(&dma->list, &xdev->dmas); + + xdev->v4l2_caps |= type == V4L2_BUF_TYPE_VIDEO_CAPTURE + ? V4L2_CAP_VIDEO_CAPTURE : V4L2_CAP_VIDEO_OUTPUT; + + return 0; +} + +static int xvip_graph_dma_init(struct xvip_composite_device *xdev) +{ + struct device_node *ports; + struct device_node *port; + int ret; + + ports = of_get_child_by_name(xdev->dev->of_node, "ports"); + if (ports == NULL) { + dev_err(xdev->dev, "ports node not present\n"); + return -EINVAL; + } + + for_each_child_of_node(ports, port) { + ret = xvip_graph_dma_init_one(xdev, port); + if (ret < 0) + return ret; + } + + return 0; +} + +static void xvip_graph_cleanup(struct xvip_composite_device *xdev) +{ + struct xvip_graph_entity *entityp; + struct xvip_graph_entity *entity; + struct xvip_dma *dmap; + struct xvip_dma *dma; + + v4l2_async_notifier_unregister(&xdev->notifier); + + list_for_each_entry_safe(entity, entityp, &xdev->entities, list) { + of_node_put(entity->node); + list_del(&entity->list); + } + + list_for_each_entry_safe(dma, dmap, &xdev->dmas, list) { + xvip_dma_cleanup(dma); + list_del(&dma->list); + } +} + +static int xvip_graph_init(struct xvip_composite_device *xdev) +{ + struct xvip_graph_entity *entity; + struct v4l2_async_subdev **subdevs = NULL; + unsigned int num_subdevs; + unsigned int i; + int ret; + + /* Init the DMA channels. */ + ret = xvip_graph_dma_init(xdev); + if (ret < 0) { + dev_err(xdev->dev, "DMA initialization failed\n"); + goto done; + } + + /* Parse the graph to extract a list of subdevice DT nodes. */ + ret = xvip_graph_parse(xdev); + if (ret < 0) { + dev_err(xdev->dev, "graph parsing failed\n"); + goto done; + } + + if (!xdev->num_subdevs) { + dev_err(xdev->dev, "no subdev found in graph\n"); + goto done; + } + + /* Register the subdevices notifier. */ + num_subdevs = xdev->num_subdevs; + subdevs = devm_kzalloc(xdev->dev, sizeof(*subdevs) * num_subdevs, + GFP_KERNEL); + if (subdevs == NULL) { + ret = -ENOMEM; + goto done; + } + + i = 0; + list_for_each_entry(entity, &xdev->entities, list) + subdevs[i++] = &entity->asd; + + xdev->notifier.subdevs = subdevs; + xdev->notifier.num_subdevs = num_subdevs; + xdev->notifier.bound = xvip_graph_notify_bound; + xdev->notifier.complete = xvip_graph_notify_complete; + + ret = v4l2_async_notifier_register(&xdev->v4l2_dev, &xdev->notifier); + if (ret < 0) { + dev_err(xdev->dev, "notifier registration failed\n"); + goto done; + } + + ret = 0; + +done: + if (ret < 0) + xvip_graph_cleanup(xdev); + + return ret; +} + +/* ----------------------------------------------------------------------------- + * Media Controller and V4L2 + */ + +static void xvip_composite_v4l2_cleanup(struct xvip_composite_device *xdev) +{ + v4l2_device_unregister(&xdev->v4l2_dev); + media_device_unregister(&xdev->media_dev); +} + +static int xvip_composite_v4l2_init(struct xvip_composite_device *xdev) +{ + int ret; + + xdev->media_dev.dev = xdev->dev; + strlcpy(xdev->media_dev.model, "Xilinx Video Composite Device", + sizeof(xdev->media_dev.model)); + xdev->media_dev.hw_revision = 0; + + ret = media_device_register(&xdev->media_dev); + if (ret < 0) { + dev_err(xdev->dev, "media device registration failed (%d)\n", + ret); + return ret; + } + + xdev->v4l2_dev.mdev = &xdev->media_dev; + ret = v4l2_device_register(xdev->dev, &xdev->v4l2_dev); + if (ret < 0) { + dev_err(xdev->dev, "V4L2 device registration failed (%d)\n", + ret); + media_device_unregister(&xdev->media_dev); + return ret; + } + + return 0; +} + +/* ----------------------------------------------------------------------------- + * Platform Device Driver + */ + +static int xvip_composite_probe(struct platform_device *pdev) +{ + struct xvip_composite_device *xdev; + int ret; + + xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL); + if (!xdev) + return -ENOMEM; + + xdev->dev = &pdev->dev; + INIT_LIST_HEAD(&xdev->entities); + INIT_LIST_HEAD(&xdev->dmas); + + ret = xvip_composite_v4l2_init(xdev); + if (ret < 0) + return ret; + + ret = xvip_graph_init(xdev); + if (ret < 0) + goto error; + + platform_set_drvdata(pdev, xdev); + + dev_info(xdev->dev, "device registered\n"); + + return 0; + +error: + xvip_composite_v4l2_cleanup(xdev); + return ret; +} + +static int xvip_composite_remove(struct platform_device *pdev) +{ + struct xvip_composite_device *xdev = platform_get_drvdata(pdev); + + xvip_graph_cleanup(xdev); + xvip_composite_v4l2_cleanup(xdev); + + return 0; +} + +static const struct of_device_id xvip_composite_of_id_table[] = { + { .compatible = "xlnx,video" }, + { } +}; +MODULE_DEVICE_TABLE(of, xvip_composite_of_id_table); + +static struct platform_driver xvip_composite_driver = { + .driver = { + .name = "xilinx-video", + .of_match_table = xvip_composite_of_id_table, + }, + .probe = xvip_composite_probe, + .remove = xvip_composite_remove, +}; + +module_platform_driver(xvip_composite_driver); + +MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); +MODULE_DESCRIPTION("Xilinx Video IP Composite Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/xilinx/xilinx-vipp.h b/drivers/media/platform/xilinx/xilinx-vipp.h new file mode 100644 index 000000000000..faf6b6e80b3b --- /dev/null +++ b/drivers/media/platform/xilinx/xilinx-vipp.h @@ -0,0 +1,49 @@ +/* + * Xilinx Video IP Composite Device + * + * Copyright (C) 2013-2015 Ideas on Board + * Copyright (C) 2013-2015 Xilinx, Inc. + * + * Contacts: Hyun Kwon <hyun.kwon@xilinx.com> + * Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __XILINX_VIPP_H__ +#define __XILINX_VIPP_H__ + +#include <linux/list.h> +#include <linux/mutex.h> +#include <media/media-device.h> +#include <media/v4l2-async.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> + +/** + * struct xvip_composite_device - Xilinx Video IP device structure + * @v4l2_dev: V4L2 device + * @media_dev: media device + * @dev: (OF) device + * @notifier: V4L2 asynchronous subdevs notifier + * @entities: entities in the graph as a list of xvip_graph_entity + * @num_subdevs: number of subdevs in the pipeline + * @dmas: list of DMA channels at the pipeline output and input + * @v4l2_caps: V4L2 capabilities of the whole device (see VIDIOC_QUERYCAP) + */ +struct xvip_composite_device { + struct v4l2_device v4l2_dev; + struct media_device media_dev; + struct device *dev; + + struct v4l2_async_notifier notifier; + struct list_head entities; + unsigned int num_subdevs; + + struct list_head dmas; + u32 v4l2_caps; +}; + +#endif /* __XILINX_VIPP_H__ */ diff --git a/drivers/media/platform/xilinx/xilinx-vtc.c b/drivers/media/platform/xilinx/xilinx-vtc.c new file mode 100644 index 000000000000..01c750edcac5 --- /dev/null +++ b/drivers/media/platform/xilinx/xilinx-vtc.c @@ -0,0 +1,380 @@ +/* + * Xilinx Video Timing Controller + * + * Copyright (C) 2013-2015 Ideas on Board + * Copyright (C) 2013-2015 Xilinx, Inc. + * + * Contacts: Hyun Kwon <hyun.kwon@xilinx.com> + * Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include "xilinx-vip.h" +#include "xilinx-vtc.h" + +#define XVTC_CONTROL_FIELD_ID_POL_SRC (1 << 26) +#define XVTC_CONTROL_ACTIVE_CHROMA_POL_SRC (1 << 25) +#define XVTC_CONTROL_ACTIVE_VIDEO_POL_SRC (1 << 24) +#define XVTC_CONTROL_HSYNC_POL_SRC (1 << 23) +#define XVTC_CONTROL_VSYNC_POL_SRC (1 << 22) +#define XVTC_CONTROL_HBLANK_POL_SRC (1 << 21) +#define XVTC_CONTROL_VBLANK_POL_SRC (1 << 20) +#define XVTC_CONTROL_CHROMA_SRC (1 << 18) +#define XVTC_CONTROL_VBLANK_HOFF_SRC (1 << 17) +#define XVTC_CONTROL_VSYNC_END_SRC (1 << 16) +#define XVTC_CONTROL_VSYNC_START_SRC (1 << 15) +#define XVTC_CONTROL_ACTIVE_VSIZE_SRC (1 << 14) +#define XVTC_CONTROL_FRAME_VSIZE_SRC (1 << 13) +#define XVTC_CONTROL_HSYNC_END_SRC (1 << 11) +#define XVTC_CONTROL_HSYNC_START_SRC (1 << 10) +#define XVTC_CONTROL_ACTIVE_HSIZE_SRC (1 << 9) +#define XVTC_CONTROL_FRAME_HSIZE_SRC (1 << 8) +#define XVTC_CONTROL_SYNC_ENABLE (1 << 5) +#define XVTC_CONTROL_DET_ENABLE (1 << 3) +#define XVTC_CONTROL_GEN_ENABLE (1 << 2) + +#define XVTC_STATUS_FSYNC(n) ((n) << 16) +#define XVTC_STATUS_GEN_ACTIVE_VIDEO (1 << 13) +#define XVTC_STATUS_GEN_VBLANK (1 << 12) +#define XVTC_STATUS_DET_ACTIVE_VIDEO (1 << 11) +#define XVTC_STATUS_DET_VBLANK (1 << 10) +#define XVTC_STATUS_LOCK_LOSS (1 << 9) +#define XVTC_STATUS_LOCK (1 << 8) + +#define XVTC_ERROR_ACTIVE_CHROMA_LOCK (1 << 21) +#define XVTC_ERROR_ACTIVE_VIDEO_LOCK (1 << 20) +#define XVTC_ERROR_HSYNC_LOCK (1 << 19) +#define XVTC_ERROR_VSYNC_LOCK (1 << 18) +#define XVTC_ERROR_HBLANK_LOCK (1 << 17) +#define XVTC_ERROR_VBLANK_LOCK (1 << 16) + +#define XVTC_IRQ_ENABLE_FSYNC(n) ((n) << 16) +#define XVTC_IRQ_ENABLE_GEN_ACTIVE_VIDEO (1 << 13) +#define XVTC_IRQ_ENABLE_GEN_VBLANK (1 << 12) +#define XVTC_IRQ_ENABLE_DET_ACTIVE_VIDEO (1 << 11) +#define XVTC_IRQ_ENABLE_DET_VBLANK (1 << 10) +#define XVTC_IRQ_ENABLE_LOCK_LOSS (1 << 9) +#define XVTC_IRQ_ENABLE_LOCK (1 << 8) + +/* + * The following registers exist in two blocks, one at 0x0020 for the detector + * and one at 0x0060 for the generator. + */ + +#define XVTC_DETECTOR_OFFSET 0x0020 +#define XVTC_GENERATOR_OFFSET 0x0060 + +#define XVTC_ACTIVE_SIZE 0x0000 +#define XVTC_ACTIVE_VSIZE_SHIFT 16 +#define XVTC_ACTIVE_VSIZE_MASK (0x1fff << 16) +#define XVTC_ACTIVE_HSIZE_SHIFT 0 +#define XVTC_ACTIVE_HSIZE_MASK (0x1fff << 0) + +#define XVTC_TIMING_STATUS 0x0004 +#define XVTC_TIMING_STATUS_ACTIVE_VIDEO (1 << 2) +#define XVTC_TIMING_STATUS_VBLANK (1 << 1) +#define XVTC_TIMING_STATUS_LOCKED (1 << 0) + +#define XVTC_ENCODING 0x0008 +#define XVTC_ENCODING_CHROMA_PARITY_SHIFT 8 +#define XVTC_ENCODING_CHROMA_PARITY_MASK (3 << 8) +#define XVTC_ENCODING_CHROMA_PARITY_EVEN_ALL (0 << 8) +#define XVTC_ENCODING_CHROMA_PARITY_ODD_ALL (1 << 8) +#define XVTC_ENCODING_CHROMA_PARITY_EVEN_EVEN (2 << 8) +#define XVTC_ENCODING_CHROMA_PARITY_ODD_EVEN (3 << 8) +#define XVTC_ENCODING_VIDEO_FORMAT_SHIFT 0 +#define XVTC_ENCODING_VIDEO_FORMAT_MASK (0xf << 0) +#define XVTC_ENCODING_VIDEO_FORMAT_YUV422 (0 << 0) +#define XVTC_ENCODING_VIDEO_FORMAT_YUV444 (1 << 0) +#define XVTC_ENCODING_VIDEO_FORMAT_RGB (2 << 0) +#define XVTC_ENCODING_VIDEO_FORMAT_YUV420 (3 << 0) + +#define XVTC_POLARITY 0x000c +#define XVTC_POLARITY_ACTIVE_CHROMA_POL (1 << 5) +#define XVTC_POLARITY_ACTIVE_VIDEO_POL (1 << 4) +#define XVTC_POLARITY_HSYNC_POL (1 << 3) +#define XVTC_POLARITY_VSYNC_POL (1 << 2) +#define XVTC_POLARITY_HBLANK_POL (1 << 1) +#define XVTC_POLARITY_VBLANK_POL (1 << 0) + +#define XVTC_HSIZE 0x0010 +#define XVTC_HSIZE_MASK (0x1fff << 0) + +#define XVTC_VSIZE 0x0014 +#define XVTC_VSIZE_MASK (0x1fff << 0) + +#define XVTC_HSYNC 0x0018 +#define XVTC_HSYNC_END_SHIFT 16 +#define XVTC_HSYNC_END_MASK (0x1fff << 16) +#define XVTC_HSYNC_START_SHIFT 0 +#define XVTC_HSYNC_START_MASK (0x1fff << 0) + +#define XVTC_F0_VBLANK_H 0x001c +#define XVTC_F0_VBLANK_HEND_SHIFT 16 +#define XVTC_F0_VBLANK_HEND_MASK (0x1fff << 16) +#define XVTC_F0_VBLANK_HSTART_SHIFT 0 +#define XVTC_F0_VBLANK_HSTART_MASK (0x1fff << 0) + +#define XVTC_F0_VSYNC_V 0x0020 +#define XVTC_F0_VSYNC_VEND_SHIFT 16 +#define XVTC_F0_VSYNC_VEND_MASK (0x1fff << 16) +#define XVTC_F0_VSYNC_VSTART_SHIFT 0 +#define XVTC_F0_VSYNC_VSTART_MASK (0x1fff << 0) + +#define XVTC_F0_VSYNC_H 0x0024 +#define XVTC_F0_VSYNC_HEND_SHIFT 16 +#define XVTC_F0_VSYNC_HEND_MASK (0x1fff << 16) +#define XVTC_F0_VSYNC_HSTART_SHIFT 0 +#define XVTC_F0_VSYNC_HSTART_MASK (0x1fff << 0) + +#define XVTC_FRAME_SYNC_CONFIG(n) (0x0100 + 4 * (n)) +#define XVTC_FRAME_SYNC_V_START_SHIFT 16 +#define XVTC_FRAME_SYNC_V_START_MASK (0x1fff << 16) +#define XVTC_FRAME_SYNC_H_START_SHIFT 0 +#define XVTC_FRAME_SYNC_H_START_MASK (0x1fff << 0) + +#define XVTC_GENERATOR_GLOBAL_DELAY 0x0104 + +/** + * struct xvtc_device - Xilinx Video Timing Controller device structure + * @xvip: Xilinx Video IP device + * @list: entry in the global VTC list + * @has_detector: the VTC has a timing detector + * @has_generator: the VTC has a timing generator + * @config: generator timings configuration + */ +struct xvtc_device { + struct xvip_device xvip; + struct list_head list; + + bool has_detector; + bool has_generator; + + struct xvtc_config config; +}; + +static LIST_HEAD(xvtc_list); +static DEFINE_MUTEX(xvtc_lock); + +static inline void xvtc_gen_write(struct xvtc_device *xvtc, u32 addr, u32 value) +{ + xvip_write(&xvtc->xvip, XVTC_GENERATOR_OFFSET + addr, value); +} + +/* ----------------------------------------------------------------------------- + * Generator Operations + */ + +int xvtc_generator_start(struct xvtc_device *xvtc, + const struct xvtc_config *config) +{ + int ret; + + if (!xvtc->has_generator) + return -ENXIO; + + ret = clk_prepare_enable(xvtc->xvip.clk); + if (ret < 0) + return ret; + + /* We don't care about the chroma active signal, encoding parameters are + * not important for now. + */ + xvtc_gen_write(xvtc, XVTC_POLARITY, + XVTC_POLARITY_ACTIVE_CHROMA_POL | + XVTC_POLARITY_ACTIVE_VIDEO_POL | + XVTC_POLARITY_HSYNC_POL | XVTC_POLARITY_VSYNC_POL | + XVTC_POLARITY_HBLANK_POL | XVTC_POLARITY_VBLANK_POL); + + /* Hardcode the polarity to active high, as required by the video in to + * AXI4-stream core. + */ + xvtc_gen_write(xvtc, XVTC_ENCODING, 0); + + /* Configure the timings. The VBLANK and VSYNC signals assertion and + * deassertion are hardcoded to the first pixel of the line. + */ + xvtc_gen_write(xvtc, XVTC_ACTIVE_SIZE, + (config->vblank_start << XVTC_ACTIVE_VSIZE_SHIFT) | + (config->hblank_start << XVTC_ACTIVE_HSIZE_SHIFT)); + xvtc_gen_write(xvtc, XVTC_HSIZE, config->hsize); + xvtc_gen_write(xvtc, XVTC_VSIZE, config->vsize); + xvtc_gen_write(xvtc, XVTC_HSYNC, + (config->hsync_end << XVTC_HSYNC_END_SHIFT) | + (config->hsync_start << XVTC_HSYNC_START_SHIFT)); + xvtc_gen_write(xvtc, XVTC_F0_VBLANK_H, 0); + xvtc_gen_write(xvtc, XVTC_F0_VSYNC_V, + (config->vsync_end << XVTC_F0_VSYNC_VEND_SHIFT) | + (config->vsync_start << XVTC_F0_VSYNC_VSTART_SHIFT)); + xvtc_gen_write(xvtc, XVTC_F0_VSYNC_H, 0); + + /* Enable the generator. Set the source of all generator parameters to + * generator registers. + */ + xvip_write(&xvtc->xvip, XVIP_CTRL_CONTROL, + XVTC_CONTROL_ACTIVE_CHROMA_POL_SRC | + XVTC_CONTROL_ACTIVE_VIDEO_POL_SRC | + XVTC_CONTROL_HSYNC_POL_SRC | XVTC_CONTROL_VSYNC_POL_SRC | + XVTC_CONTROL_HBLANK_POL_SRC | XVTC_CONTROL_VBLANK_POL_SRC | + XVTC_CONTROL_CHROMA_SRC | XVTC_CONTROL_VBLANK_HOFF_SRC | + XVTC_CONTROL_VSYNC_END_SRC | XVTC_CONTROL_VSYNC_START_SRC | + XVTC_CONTROL_ACTIVE_VSIZE_SRC | + XVTC_CONTROL_FRAME_VSIZE_SRC | XVTC_CONTROL_HSYNC_END_SRC | + XVTC_CONTROL_HSYNC_START_SRC | + XVTC_CONTROL_ACTIVE_HSIZE_SRC | + XVTC_CONTROL_FRAME_HSIZE_SRC | XVTC_CONTROL_GEN_ENABLE | + XVIP_CTRL_CONTROL_REG_UPDATE); + + return 0; +} +EXPORT_SYMBOL_GPL(xvtc_generator_start); + +int xvtc_generator_stop(struct xvtc_device *xvtc) +{ + if (!xvtc->has_generator) + return -ENXIO; + + xvip_write(&xvtc->xvip, XVIP_CTRL_CONTROL, 0); + + clk_disable_unprepare(xvtc->xvip.clk); + + return 0; +} +EXPORT_SYMBOL_GPL(xvtc_generator_stop); + +struct xvtc_device *xvtc_of_get(struct device_node *np) +{ + struct device_node *xvtc_node; + struct xvtc_device *found = NULL; + struct xvtc_device *xvtc; + + if (!of_find_property(np, "xlnx,vtc", NULL)) + return NULL; + + xvtc_node = of_parse_phandle(np, "xlnx,vtc", 0); + if (xvtc_node == NULL) + return ERR_PTR(-EINVAL); + + mutex_lock(&xvtc_lock); + list_for_each_entry(xvtc, &xvtc_list, list) { + if (xvtc->xvip.dev->of_node == xvtc_node) { + found = xvtc; + break; + } + } + mutex_unlock(&xvtc_lock); + + of_node_put(xvtc_node); + + if (!found) + return ERR_PTR(-EPROBE_DEFER); + + return found; +} +EXPORT_SYMBOL_GPL(xvtc_of_get); + +void xvtc_put(struct xvtc_device *xvtc) +{ +} +EXPORT_SYMBOL_GPL(xvtc_put); + +/* ----------------------------------------------------------------------------- + * Registration and Unregistration + */ + +static void xvtc_register_device(struct xvtc_device *xvtc) +{ + mutex_lock(&xvtc_lock); + list_add_tail(&xvtc->list, &xvtc_list); + mutex_unlock(&xvtc_lock); +} + +static void xvtc_unregister_device(struct xvtc_device *xvtc) +{ + mutex_lock(&xvtc_lock); + list_del(&xvtc->list); + mutex_unlock(&xvtc_lock); +} + +/* ----------------------------------------------------------------------------- + * Platform Device Driver + */ + +static int xvtc_parse_of(struct xvtc_device *xvtc) +{ + struct device_node *node = xvtc->xvip.dev->of_node; + + xvtc->has_detector = of_property_read_bool(node, "xlnx,detector"); + xvtc->has_generator = of_property_read_bool(node, "xlnx,generator"); + + return 0; +} + +static int xvtc_probe(struct platform_device *pdev) +{ + struct xvtc_device *xvtc; + int ret; + + xvtc = devm_kzalloc(&pdev->dev, sizeof(*xvtc), GFP_KERNEL); + if (!xvtc) + return -ENOMEM; + + xvtc->xvip.dev = &pdev->dev; + + ret = xvtc_parse_of(xvtc); + if (ret < 0) + return ret; + + ret = xvip_init_resources(&xvtc->xvip); + if (ret < 0) + return ret; + + platform_set_drvdata(pdev, xvtc); + + xvip_print_version(&xvtc->xvip); + + xvtc_register_device(xvtc); + + return 0; +} + +static int xvtc_remove(struct platform_device *pdev) +{ + struct xvtc_device *xvtc = platform_get_drvdata(pdev); + + xvtc_unregister_device(xvtc); + + xvip_cleanup_resources(&xvtc->xvip); + + return 0; +} + +static const struct of_device_id xvtc_of_id_table[] = { + { .compatible = "xlnx,v-tc-6.1" }, + { } +}; +MODULE_DEVICE_TABLE(of, xvtc_of_id_table); + +static struct platform_driver xvtc_driver = { + .driver = { + .name = "xilinx-vtc", + .of_match_table = xvtc_of_id_table, + }, + .probe = xvtc_probe, + .remove = xvtc_remove, +}; + +module_platform_driver(xvtc_driver); + +MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); +MODULE_DESCRIPTION("Xilinx Video Timing Controller Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/xilinx/xilinx-vtc.h b/drivers/media/platform/xilinx/xilinx-vtc.h new file mode 100644 index 000000000000..e1bb2cfcf428 --- /dev/null +++ b/drivers/media/platform/xilinx/xilinx-vtc.h @@ -0,0 +1,42 @@ +/* + * Xilinx Video Timing Controller + * + * Copyright (C) 2013-2015 Ideas on Board + * Copyright (C) 2013-2015 Xilinx, Inc. + * + * Contacts: Hyun Kwon <hyun.kwon@xilinx.com> + * Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __XILINX_VTC_H__ +#define __XILINX_VTC_H__ + +struct device_node; +struct xvtc_device; + +#define XVTC_MAX_HSIZE 8191 +#define XVTC_MAX_VSIZE 8191 + +struct xvtc_config { + unsigned int hblank_start; + unsigned int hsync_start; + unsigned int hsync_end; + unsigned int hsize; + unsigned int vblank_start; + unsigned int vsync_start; + unsigned int vsync_end; + unsigned int vsize; +}; + +struct xvtc_device *xvtc_of_get(struct device_node *np); +void xvtc_put(struct xvtc_device *xvtc); + +int xvtc_generator_start(struct xvtc_device *xvtc, + const struct xvtc_config *config); +int xvtc_generator_stop(struct xvtc_device *xvtc); + +#endif /* __XILINX_VTC_H__ */ diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c index b8f36445516b..a93f681aa9d6 100644 --- a/drivers/media/radio/radio-wl1273.c +++ b/drivers/media/radio/radio-wl1273.c @@ -347,6 +347,7 @@ static int wl1273_fm_set_tx_freq(struct wl1273_device *radio, unsigned int freq) { struct wl1273_core *core = radio->core; int r = 0; + unsigned long t; if (freq < WL1273_BAND_TX_LOW) { dev_err(radio->dev, @@ -378,11 +379,11 @@ static int wl1273_fm_set_tx_freq(struct wl1273_device *radio, unsigned int freq) reinit_completion(&radio->busy); /* wait for the FR IRQ */ - r = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(2000)); - if (!r) + t = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(2000)); + if (!t) return -ETIMEDOUT; - dev_dbg(radio->dev, "WL1273_CHANL_SET: %d\n", r); + dev_dbg(radio->dev, "WL1273_CHANL_SET: %lu\n", t); /* Enable the output power */ r = core->write(core, WL1273_POWER_ENB_SET, 1); @@ -392,12 +393,12 @@ static int wl1273_fm_set_tx_freq(struct wl1273_device *radio, unsigned int freq) reinit_completion(&radio->busy); /* wait for the POWER_ENB IRQ */ - r = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(1000)); - if (!r) + t = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(1000)); + if (!t) return -ETIMEDOUT; radio->tx_frequency = freq; - dev_dbg(radio->dev, "WL1273_POWER_ENB_SET: %d\n", r); + dev_dbg(radio->dev, "WL1273_POWER_ENB_SET: %lu\n", t); return 0; } @@ -406,6 +407,7 @@ static int wl1273_fm_set_rx_freq(struct wl1273_device *radio, unsigned int freq) { struct wl1273_core *core = radio->core; int r, f; + unsigned long t; if (freq < radio->rangelow) { dev_err(radio->dev, @@ -446,8 +448,8 @@ static int wl1273_fm_set_rx_freq(struct wl1273_device *radio, unsigned int freq) reinit_completion(&radio->busy); - r = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(2000)); - if (!r) { + t = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(2000)); + if (!t) { dev_err(radio->dev, "%s: TIMEOUT\n", __func__); return -ETIMEDOUT; } @@ -826,9 +828,12 @@ static int wl1273_fm_set_seek(struct wl1273_device *radio, if (r) goto out; + /* wait for the FR IRQ */ wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(1000)); - if (!(radio->irq_received & WL1273_BL_EVENT)) + if (!(radio->irq_received & WL1273_BL_EVENT)) { + r = -ETIMEDOUT; goto out; + } radio->irq_received &= ~WL1273_BL_EVENT; @@ -854,7 +859,9 @@ static int wl1273_fm_set_seek(struct wl1273_device *radio, if (r) goto out; - wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(1000)); + /* wait for the FR IRQ */ + if (!wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(1000))) + r = -ETIMEDOUT; out: dev_dbg(radio->dev, "%s: Err: %d\n", __func__, r); return r; diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c index 909c3f92d839..1d827adab7eb 100644 --- a/drivers/media/radio/si470x/radio-si470x-common.c +++ b/drivers/media/radio/si470x/radio-si470x-common.c @@ -208,6 +208,7 @@ static int si470x_set_band(struct si470x_device *radio, int band) static int si470x_set_chan(struct si470x_device *radio, unsigned short chan) { int retval; + unsigned long time_left; bool timed_out = false; /* start tuning */ @@ -219,9 +220,9 @@ static int si470x_set_chan(struct si470x_device *radio, unsigned short chan) /* wait till tune operation has completed */ reinit_completion(&radio->completion); - retval = wait_for_completion_timeout(&radio->completion, - msecs_to_jiffies(tune_timeout)); - if (!retval) + time_left = wait_for_completion_timeout(&radio->completion, + msecs_to_jiffies(tune_timeout)); + if (time_left == 0) timed_out = true; if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) @@ -301,6 +302,7 @@ static int si470x_set_seek(struct si470x_device *radio, int band, retval; unsigned int freq; bool timed_out = false; + unsigned long time_left; /* set band */ if (seek->rangelow || seek->rangehigh) { @@ -342,9 +344,9 @@ static int si470x_set_seek(struct si470x_device *radio, /* wait till tune operation has completed */ reinit_completion(&radio->completion); - retval = wait_for_completion_timeout(&radio->completion, - msecs_to_jiffies(seek_timeout)); - if (!retval) + time_left = wait_for_completion_timeout(&radio->completion, + msecs_to_jiffies(seek_timeout)); + if (time_left == 0) timed_out = true; if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) diff --git a/drivers/media/radio/si4713/si4713.c b/drivers/media/radio/si4713/si4713.c index c90004dac170..e9d03ac69a27 100644 --- a/drivers/media/radio/si4713/si4713.c +++ b/drivers/media/radio/si4713/si4713.c @@ -383,7 +383,7 @@ static int si4713_powerup(struct si4713_device *sdev) } } - if (!IS_ERR(sdev->gpio_reset)) { + if (sdev->gpio_reset) { udelay(50); gpiod_set_value(sdev->gpio_reset, 1); } @@ -407,8 +407,7 @@ static int si4713_powerup(struct si4713_device *sdev) SI4713_STC_INT | SI4713_CTS); return err; } - if (!IS_ERR(sdev->gpio_reset)) - gpiod_set_value(sdev->gpio_reset, 0); + gpiod_set_value(sdev->gpio_reset, 0); if (sdev->vdd) { @@ -447,7 +446,7 @@ static int si4713_powerdown(struct si4713_device *sdev) v4l2_dbg(1, debug, &sdev->sd, "Power down response: 0x%02x\n", resp[0]); v4l2_dbg(1, debug, &sdev->sd, "Device in reset mode\n"); - if (!IS_ERR(sdev->gpio_reset)) + if (sdev->gpio_reset) gpiod_set_value(sdev->gpio_reset, 0); if (sdev->vdd) { @@ -1460,14 +1459,9 @@ static int si4713_probe(struct i2c_client *client, goto exit; } - sdev->gpio_reset = devm_gpiod_get(&client->dev, "reset"); - if (!IS_ERR(sdev->gpio_reset)) { - gpiod_direction_output(sdev->gpio_reset, 0); - } else if (PTR_ERR(sdev->gpio_reset) == -ENOENT) { - dev_dbg(&client->dev, "No reset GPIO assigned\n"); - } else if (PTR_ERR(sdev->gpio_reset) == -ENOSYS) { - dev_dbg(&client->dev, "No reset GPIO support\n"); - } else { + sdev->gpio_reset = devm_gpiod_get_optional(&client->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(sdev->gpio_reset)) { rval = PTR_ERR(sdev->gpio_reset); dev_err(&client->dev, "Failed to request gpio: %d\n", rval); goto exit; diff --git a/drivers/media/radio/wl128x/Kconfig b/drivers/media/radio/wl128x/Kconfig index f359be7e9dd9..9d6574bebf78 100644 --- a/drivers/media/radio/wl128x/Kconfig +++ b/drivers/media/radio/wl128x/Kconfig @@ -5,7 +5,7 @@ menu "Texas Instruments WL128x FM driver (ST based)" config RADIO_WL128X tristate "Texas Instruments WL128x FM Radio" depends on VIDEO_V4L2 && RFKILL && GPIOLIB && TTY - select TI_ST if NET + depends on TI_ST help Choose Y here if you have this FM radio chip. diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c index a5bd3f674bbd..fb42f0fd0c1f 100644 --- a/drivers/media/radio/wl128x/fmdrv_v4l2.c +++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c @@ -36,7 +36,7 @@ #include "fmdrv_rx.h" #include "fmdrv_tx.h" -static struct video_device *gradio_dev; +static struct video_device gradio_dev; static u8 radio_disconnected; /* -- V4L2 RADIO (/dev/radioX) device file operation interfaces --- */ @@ -517,7 +517,7 @@ static struct video_device fm_viddev_template = { .fops = &fm_drv_fops, .ioctl_ops = &fm_drv_ioctl_ops, .name = FM_DRV_NAME, - .release = video_device_release, + .release = video_device_release_empty, /* * To ensure both the tuner and modulator ioctls are accessible we * set the vfl_dir to M2M to indicate this. @@ -543,29 +543,21 @@ int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr) /* Init mutex for core locking */ mutex_init(&fmdev->mutex); - /* Allocate new video device */ - gradio_dev = video_device_alloc(); - if (NULL == gradio_dev) { - fmerr("Can't allocate video device\n"); - return -ENOMEM; - } - /* Setup FM driver's V4L2 properties */ - memcpy(gradio_dev, &fm_viddev_template, sizeof(fm_viddev_template)); + gradio_dev = fm_viddev_template; - video_set_drvdata(gradio_dev, fmdev); + video_set_drvdata(&gradio_dev, fmdev); - gradio_dev->lock = &fmdev->mutex; - gradio_dev->v4l2_dev = &fmdev->v4l2_dev; + gradio_dev.lock = &fmdev->mutex; + gradio_dev.v4l2_dev = &fmdev->v4l2_dev; /* Register with V4L2 subsystem as RADIO device */ - if (video_register_device(gradio_dev, VFL_TYPE_RADIO, radio_nr)) { - video_device_release(gradio_dev); + if (video_register_device(&gradio_dev, VFL_TYPE_RADIO, radio_nr)) { fmerr("Could not register video device\n"); return -ENOMEM; } - fmdev->radio_dev = gradio_dev; + fmdev->radio_dev = &gradio_dev; /* Register to v4l2 ctrl handler framework */ fmdev->radio_dev->ctrl_handler = &fmdev->ctrl_handler; @@ -611,13 +603,13 @@ void *fm_v4l2_deinit_video_device(void) struct fmdev *fmdev; - fmdev = video_get_drvdata(gradio_dev); + fmdev = video_get_drvdata(&gradio_dev); /* Unregister to v4l2 ctrl handler framework*/ v4l2_ctrl_handler_free(&fmdev->ctrl_handler); /* Unregister RADIO device from V4L2 subsystem */ - video_unregister_device(gradio_dev); + video_unregister_device(&gradio_dev); v4l2_device_unregister(&fmdev->v4l2_dev); diff --git a/drivers/media/rc/img-ir/img-ir-core.c b/drivers/media/rc/img-ir/img-ir-core.c index 77c78de4f5bf..03fe080278df 100644 --- a/drivers/media/rc/img-ir/img-ir-core.c +++ b/drivers/media/rc/img-ir/img-ir-core.c @@ -110,16 +110,32 @@ static int img_ir_probe(struct platform_device *pdev) priv->clk = devm_clk_get(&pdev->dev, "core"); if (IS_ERR(priv->clk)) dev_warn(&pdev->dev, "cannot get core clock resource\n"); + + /* Get sys clock */ + priv->sys_clk = devm_clk_get(&pdev->dev, "sys"); + if (IS_ERR(priv->sys_clk)) + dev_warn(&pdev->dev, "cannot get sys clock resource\n"); /* - * The driver doesn't need to know about the system ("sys") or power - * modulation ("mod") clocks yet + * Enabling the system clock before the register interface is + * accessed. ISR shouldn't get called with Sys Clock disabled, + * hence exiting probe with an error. */ + if (!IS_ERR(priv->sys_clk)) { + error = clk_prepare_enable(priv->sys_clk); + if (error) { + dev_err(&pdev->dev, "cannot enable sys clock\n"); + return error; + } + } /* Set up raw & hw decoder */ error = img_ir_probe_raw(priv); error2 = img_ir_probe_hw(priv); - if (error && error2) - return (error == -ENODEV) ? error2 : error; + if (error && error2) { + if (error == -ENODEV) + error = error2; + goto err_probe; + } /* Get the IRQ */ priv->irq = irq; @@ -139,6 +155,9 @@ static int img_ir_probe(struct platform_device *pdev) err_irq: img_ir_remove_hw(priv); img_ir_remove_raw(priv); +err_probe: + if (!IS_ERR(priv->sys_clk)) + clk_disable_unprepare(priv->sys_clk); return error; } @@ -146,12 +165,14 @@ static int img_ir_remove(struct platform_device *pdev) { struct img_ir_priv *priv = platform_get_drvdata(pdev); - free_irq(priv->irq, img_ir_isr); + free_irq(priv->irq, priv); img_ir_remove_hw(priv); img_ir_remove_raw(priv); if (!IS_ERR(priv->clk)) clk_disable_unprepare(priv->clk); + if (!IS_ERR(priv->sys_clk)) + clk_disable_unprepare(priv->sys_clk); return 0; } diff --git a/drivers/media/rc/img-ir/img-ir.h b/drivers/media/rc/img-ir/img-ir.h index 2ddf56083182..f1387c016d3d 100644 --- a/drivers/media/rc/img-ir/img-ir.h +++ b/drivers/media/rc/img-ir/img-ir.h @@ -138,6 +138,7 @@ struct clk; * @dev: Platform device. * @irq: IRQ number. * @clk: Input clock. + * @sys_clk: System clock. * @reg_base: Iomem base address of IR register block. * @lock: Protects IR registers and variables in this struct. * @raw: Driver data for raw decoder. @@ -147,6 +148,7 @@ struct img_ir_priv { struct device *dev; int irq; struct clk *clk; + struct clk *sys_clk; void __iomem *reg_base; spinlock_t lock; diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c index b0df62961c14..58ec5986274e 100644 --- a/drivers/media/rc/ir-hix5hd2.c +++ b/drivers/media/rc/ir-hix5hd2.c @@ -16,14 +16,6 @@ #include <linux/regmap.h> #include <media/rc-core.h> -/* Allow the driver to compile on all architectures */ -#ifndef writel_relaxed -# define writel_relaxed writel -#endif -#ifndef readl_relaxed -# define readl_relaxed readl -#endif - #define IR_ENABLE 0x00 #define IR_CONFIG 0x04 #define CNT_LEADS 0x08 diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig index 42e5a01b9192..983510d282f6 100644 --- a/drivers/media/tuners/Kconfig +++ b/drivers/media/tuners/Kconfig @@ -224,14 +224,6 @@ config MEDIA_TUNER_FC2580 help FCI FC2580 silicon tuner driver. -config MEDIA_TUNER_M88TS2022 - tristate "Montage M88TS2022 silicon tuner" - depends on MEDIA_SUPPORT && I2C - select REGMAP_I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Montage M88TS2022 silicon tuner driver. - config MEDIA_TUNER_M88RS6000T tristate "Montage M88RS6000 internal tuner" depends on MEDIA_SUPPORT && I2C diff --git a/drivers/media/tuners/Makefile b/drivers/media/tuners/Makefile index da4fe6ef73e7..06a9ab65e5fa 100644 --- a/drivers/media/tuners/Makefile +++ b/drivers/media/tuners/Makefile @@ -33,7 +33,6 @@ obj-$(CONFIG_MEDIA_TUNER_E4000) += e4000.o obj-$(CONFIG_MEDIA_TUNER_FC2580) += fc2580.o obj-$(CONFIG_MEDIA_TUNER_TUA9001) += tua9001.o obj-$(CONFIG_MEDIA_TUNER_SI2157) += si2157.o -obj-$(CONFIG_MEDIA_TUNER_M88TS2022) += m88ts2022.o obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o obj-$(CONFIG_MEDIA_TUNER_FC0013) += fc0013.o diff --git a/drivers/media/tuners/fc0011.h b/drivers/media/tuners/fc0011.h index 43ec893a6877..81bb568d6943 100644 --- a/drivers/media/tuners/fc0011.h +++ b/drivers/media/tuners/fc0011.h @@ -23,7 +23,7 @@ enum fc0011_fe_callback_commands { FC0011_FE_CALLBACK_RESET, }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_FC0011) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_FC0011) struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct fc0011_config *config); diff --git a/drivers/media/tuners/fc0012.h b/drivers/media/tuners/fc0012.h index 1d08057e3275..9ad32859bab0 100644 --- a/drivers/media/tuners/fc0012.h +++ b/drivers/media/tuners/fc0012.h @@ -49,7 +49,7 @@ struct fc0012_config { bool clock_out; }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_FC0012) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_FC0012) extern struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct fc0012_config *cfg); diff --git a/drivers/media/tuners/fc0013.h b/drivers/media/tuners/fc0013.h index d65d5b37f56e..e130bd7a3230 100644 --- a/drivers/media/tuners/fc0013.h +++ b/drivers/media/tuners/fc0013.h @@ -26,7 +26,7 @@ #include "dvb_frontend.h" #include "fc001x-common.h" -#if IS_ENABLED(CONFIG_MEDIA_TUNER_FC0013) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_FC0013) extern struct dvb_frontend *fc0013_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_address, int dual_master, diff --git a/drivers/media/tuners/fc2580.h b/drivers/media/tuners/fc2580.h index 9c43c1cc82d9..b1ce6770f88e 100644 --- a/drivers/media/tuners/fc2580.h +++ b/drivers/media/tuners/fc2580.h @@ -37,7 +37,7 @@ struct fc2580_config { u32 clock; }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_FC2580) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_FC2580) extern struct dvb_frontend *fc2580_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct fc2580_config *cfg); #else diff --git a/drivers/media/tuners/m88ts2022.c b/drivers/media/tuners/m88ts2022.c deleted file mode 100644 index 066e5431da93..000000000000 --- a/drivers/media/tuners/m88ts2022.c +++ /dev/null @@ -1,579 +0,0 @@ -/* - * Montage M88TS2022 silicon tuner driver - * - * Copyright (C) 2013 Antti Palosaari <crope@iki.fi> - * - * 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 Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. - * - * Some calculations are taken from existing TS2020 driver. - */ - -#include "m88ts2022_priv.h" - -static int m88ts2022_cmd(struct m88ts2022_dev *dev, int op, int sleep, u8 reg, - u8 mask, u8 val, u8 *reg_val) -{ - int ret, i; - unsigned int utmp; - struct m88ts2022_reg_val reg_vals[] = { - {0x51, 0x1f - op}, - {0x51, 0x1f}, - {0x50, 0x00 + op}, - {0x50, 0x00}, - }; - - for (i = 0; i < 2; i++) { - dev_dbg(&dev->client->dev, - "i=%d op=%02x reg=%02x mask=%02x val=%02x\n", - i, op, reg, mask, val); - - for (i = 0; i < ARRAY_SIZE(reg_vals); i++) { - ret = regmap_write(dev->regmap, reg_vals[i].reg, - reg_vals[i].val); - if (ret) - goto err; - } - - usleep_range(sleep * 1000, sleep * 10000); - - ret = regmap_read(dev->regmap, reg, &utmp); - if (ret) - goto err; - - if ((utmp & mask) != val) - break; - } - - if (reg_val) - *reg_val = utmp; -err: - return ret; -} - -static int m88ts2022_set_params(struct dvb_frontend *fe) -{ - struct m88ts2022_dev *dev = fe->tuner_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret; - unsigned int utmp, frequency_khz, frequency_offset_khz, f_3db_hz; - unsigned int f_ref_khz, f_vco_khz, div_ref, div_out, pll_n, gdiv28; - u8 buf[3], u8tmp, cap_code, lpf_gm, lpf_mxdiv, div_max, div_min; - u16 u16tmp; - - dev_dbg(&dev->client->dev, - "frequency=%d symbol_rate=%d rolloff=%d\n", - c->frequency, c->symbol_rate, c->rolloff); - /* - * Integer-N PLL synthesizer - * kHz is used for all calculations to keep calculations within 32-bit - */ - f_ref_khz = DIV_ROUND_CLOSEST(dev->cfg.clock, 1000); - div_ref = DIV_ROUND_CLOSEST(f_ref_khz, 2000); - - if (c->symbol_rate < 5000000) - frequency_offset_khz = 3000; /* 3 MHz */ - else - frequency_offset_khz = 0; - - frequency_khz = c->frequency + frequency_offset_khz; - - if (frequency_khz < 1103000) { - div_out = 4; - u8tmp = 0x1b; - } else { - div_out = 2; - u8tmp = 0x0b; - } - - buf[0] = u8tmp; - buf[1] = 0x40; - ret = regmap_bulk_write(dev->regmap, 0x10, buf, 2); - if (ret) - goto err; - - f_vco_khz = frequency_khz * div_out; - pll_n = f_vco_khz * div_ref / f_ref_khz; - pll_n += pll_n % 2; - dev->frequency_khz = pll_n * f_ref_khz / div_ref / div_out; - - if (pll_n < 4095) - u16tmp = pll_n - 1024; - else if (pll_n < 6143) - u16tmp = pll_n + 1024; - else - u16tmp = pll_n + 3072; - - buf[0] = (u16tmp >> 8) & 0x3f; - buf[1] = (u16tmp >> 0) & 0xff; - buf[2] = div_ref - 8; - ret = regmap_bulk_write(dev->regmap, 0x01, buf, 3); - if (ret) - goto err; - - dev_dbg(&dev->client->dev, - "frequency=%u offset=%d f_vco_khz=%u pll_n=%u div_ref=%u div_out=%u\n", - dev->frequency_khz, dev->frequency_khz - c->frequency, - f_vco_khz, pll_n, div_ref, div_out); - - ret = m88ts2022_cmd(dev, 0x10, 5, 0x15, 0x40, 0x00, NULL); - if (ret) - goto err; - - ret = regmap_read(dev->regmap, 0x14, &utmp); - if (ret) - goto err; - - utmp &= 0x7f; - if (utmp < 64) { - ret = regmap_update_bits(dev->regmap, 0x10, 0x80, 0x80); - if (ret) - goto err; - - ret = regmap_write(dev->regmap, 0x11, 0x6f); - if (ret) - goto err; - - ret = m88ts2022_cmd(dev, 0x10, 5, 0x15, 0x40, 0x00, NULL); - if (ret) - goto err; - } - - ret = regmap_read(dev->regmap, 0x14, &utmp); - if (ret) - goto err; - - utmp &= 0x1f; - if (utmp > 19) { - ret = regmap_update_bits(dev->regmap, 0x10, 0x02, 0x00); - if (ret) - goto err; - } - - ret = m88ts2022_cmd(dev, 0x08, 5, 0x3c, 0xff, 0x00, NULL); - if (ret) - goto err; - - ret = regmap_write(dev->regmap, 0x25, 0x00); - if (ret) - goto err; - - ret = regmap_write(dev->regmap, 0x27, 0x70); - if (ret) - goto err; - - ret = regmap_write(dev->regmap, 0x41, 0x09); - if (ret) - goto err; - - ret = regmap_write(dev->regmap, 0x08, 0x0b); - if (ret) - goto err; - - /* filters */ - gdiv28 = DIV_ROUND_CLOSEST(f_ref_khz * 1694U, 1000000U); - - ret = regmap_write(dev->regmap, 0x04, gdiv28); - if (ret) - goto err; - - ret = m88ts2022_cmd(dev, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp); - if (ret) - goto err; - - cap_code = u8tmp & 0x3f; - - ret = regmap_write(dev->regmap, 0x41, 0x0d); - if (ret) - goto err; - - ret = m88ts2022_cmd(dev, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp); - if (ret) - goto err; - - u8tmp &= 0x3f; - cap_code = (cap_code + u8tmp) / 2; - gdiv28 = gdiv28 * 207 / (cap_code * 2 + 151); - div_max = gdiv28 * 135 / 100; - div_min = gdiv28 * 78 / 100; - div_max = clamp_val(div_max, 0U, 63U); - - f_3db_hz = mult_frac(c->symbol_rate, 135, 200); - f_3db_hz += 2000000U + (frequency_offset_khz * 1000U); - f_3db_hz = clamp(f_3db_hz, 7000000U, 40000000U); - -#define LPF_COEFF 3200U - lpf_gm = DIV_ROUND_CLOSEST(f_3db_hz * gdiv28, LPF_COEFF * f_ref_khz); - lpf_gm = clamp_val(lpf_gm, 1U, 23U); - - lpf_mxdiv = DIV_ROUND_CLOSEST(lpf_gm * LPF_COEFF * f_ref_khz, f_3db_hz); - if (lpf_mxdiv < div_min) - lpf_mxdiv = DIV_ROUND_CLOSEST(++lpf_gm * LPF_COEFF * f_ref_khz, f_3db_hz); - lpf_mxdiv = clamp_val(lpf_mxdiv, 0U, div_max); - - ret = regmap_write(dev->regmap, 0x04, lpf_mxdiv); - if (ret) - goto err; - - ret = regmap_write(dev->regmap, 0x06, lpf_gm); - if (ret) - goto err; - - ret = m88ts2022_cmd(dev, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp); - if (ret) - goto err; - - cap_code = u8tmp & 0x3f; - - ret = regmap_write(dev->regmap, 0x41, 0x09); - if (ret) - goto err; - - ret = m88ts2022_cmd(dev, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp); - if (ret) - goto err; - - u8tmp &= 0x3f; - cap_code = (cap_code + u8tmp) / 2; - - u8tmp = cap_code | 0x80; - ret = regmap_write(dev->regmap, 0x25, u8tmp); - if (ret) - goto err; - - ret = regmap_write(dev->regmap, 0x27, 0x30); - if (ret) - goto err; - - ret = regmap_write(dev->regmap, 0x08, 0x09); - if (ret) - goto err; - - ret = m88ts2022_cmd(dev, 0x01, 20, 0x21, 0xff, 0x00, NULL); - if (ret) - goto err; -err: - if (ret) - dev_dbg(&dev->client->dev, "failed=%d\n", ret); - - return ret; -} - -static int m88ts2022_init(struct dvb_frontend *fe) -{ - struct m88ts2022_dev *dev = fe->tuner_priv; - int ret, i; - u8 u8tmp; - static const struct m88ts2022_reg_val reg_vals[] = { - {0x7d, 0x9d}, - {0x7c, 0x9a}, - {0x7a, 0x76}, - {0x3b, 0x01}, - {0x63, 0x88}, - {0x61, 0x85}, - {0x22, 0x30}, - {0x30, 0x40}, - {0x20, 0x23}, - {0x24, 0x02}, - {0x12, 0xa0}, - }; - - dev_dbg(&dev->client->dev, "\n"); - - ret = regmap_write(dev->regmap, 0x00, 0x01); - if (ret) - goto err; - - ret = regmap_write(dev->regmap, 0x00, 0x03); - if (ret) - goto err; - - switch (dev->cfg.clock_out) { - case M88TS2022_CLOCK_OUT_DISABLED: - u8tmp = 0x60; - break; - case M88TS2022_CLOCK_OUT_ENABLED: - u8tmp = 0x70; - ret = regmap_write(dev->regmap, 0x05, dev->cfg.clock_out_div); - if (ret) - goto err; - break; - case M88TS2022_CLOCK_OUT_ENABLED_XTALOUT: - u8tmp = 0x6c; - break; - default: - goto err; - } - - ret = regmap_write(dev->regmap, 0x42, u8tmp); - if (ret) - goto err; - - if (dev->cfg.loop_through) - u8tmp = 0xec; - else - u8tmp = 0x6c; - - ret = regmap_write(dev->regmap, 0x62, u8tmp); - if (ret) - goto err; - - for (i = 0; i < ARRAY_SIZE(reg_vals); i++) { - ret = regmap_write(dev->regmap, reg_vals[i].reg, reg_vals[i].val); - if (ret) - goto err; - } -err: - if (ret) - dev_dbg(&dev->client->dev, "failed=%d\n", ret); - return ret; -} - -static int m88ts2022_sleep(struct dvb_frontend *fe) -{ - struct m88ts2022_dev *dev = fe->tuner_priv; - int ret; - - dev_dbg(&dev->client->dev, "\n"); - - ret = regmap_write(dev->regmap, 0x00, 0x00); - if (ret) - goto err; -err: - if (ret) - dev_dbg(&dev->client->dev, "failed=%d\n", ret); - return ret; -} - -static int m88ts2022_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct m88ts2022_dev *dev = fe->tuner_priv; - - dev_dbg(&dev->client->dev, "\n"); - - *frequency = dev->frequency_khz; - return 0; -} - -static int m88ts2022_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct m88ts2022_dev *dev = fe->tuner_priv; - - dev_dbg(&dev->client->dev, "\n"); - - *frequency = 0; /* Zero-IF */ - return 0; -} - -static int m88ts2022_get_rf_strength(struct dvb_frontend *fe, u16 *strength) -{ - struct m88ts2022_dev *dev = fe->tuner_priv; - int ret; - u16 gain, u16tmp; - unsigned int utmp, gain1, gain2, gain3; - - ret = regmap_read(dev->regmap, 0x3d, &utmp); - if (ret) - goto err; - - gain1 = (utmp >> 0) & 0x1f; - gain1 = clamp(gain1, 0U, 15U); - - ret = regmap_read(dev->regmap, 0x21, &utmp); - if (ret) - goto err; - - gain2 = (utmp >> 0) & 0x1f; - gain2 = clamp(gain2, 2U, 16U); - - ret = regmap_read(dev->regmap, 0x66, &utmp); - if (ret) - goto err; - - gain3 = (utmp >> 3) & 0x07; - gain3 = clamp(gain3, 0U, 6U); - - gain = gain1 * 265 + gain2 * 338 + gain3 * 285; - - /* scale value to 0x0000-0xffff */ - u16tmp = (0xffff - gain); - u16tmp = clamp_val(u16tmp, 59000U, 61500U); - - *strength = (u16tmp - 59000) * 0xffff / (61500 - 59000); -err: - if (ret) - dev_dbg(&dev->client->dev, "failed=%d\n", ret); - return ret; -} - -static const struct dvb_tuner_ops m88ts2022_tuner_ops = { - .info = { - .name = "Montage M88TS2022", - .frequency_min = 950000, - .frequency_max = 2150000, - }, - - .init = m88ts2022_init, - .sleep = m88ts2022_sleep, - .set_params = m88ts2022_set_params, - - .get_frequency = m88ts2022_get_frequency, - .get_if_frequency = m88ts2022_get_if_frequency, - .get_rf_strength = m88ts2022_get_rf_strength, -}; - -static int m88ts2022_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct m88ts2022_config *cfg = client->dev.platform_data; - struct dvb_frontend *fe = cfg->fe; - struct m88ts2022_dev *dev; - int ret; - u8 u8tmp; - unsigned int utmp; - static const struct regmap_config regmap_config = { - .reg_bits = 8, - .val_bits = 8, - }; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - ret = -ENOMEM; - dev_err(&client->dev, "kzalloc() failed\n"); - goto err; - } - - memcpy(&dev->cfg, cfg, sizeof(struct m88ts2022_config)); - dev->client = client; - dev->regmap = devm_regmap_init_i2c(client, ®map_config); - if (IS_ERR(dev->regmap)) { - ret = PTR_ERR(dev->regmap); - goto err; - } - - /* check if the tuner is there */ - ret = regmap_read(dev->regmap, 0x00, &utmp); - if (ret) - goto err; - - if ((utmp & 0x03) == 0x00) { - ret = regmap_write(dev->regmap, 0x00, 0x01); - if (ret) - goto err; - - usleep_range(2000, 50000); - } - - ret = regmap_write(dev->regmap, 0x00, 0x03); - if (ret) - goto err; - - usleep_range(2000, 50000); - - ret = regmap_read(dev->regmap, 0x00, &utmp); - if (ret) - goto err; - - dev_dbg(&dev->client->dev, "chip_id=%02x\n", utmp); - - switch (utmp) { - case 0xc3: - case 0x83: - break; - default: - ret = -ENODEV; - goto err; - } - - switch (dev->cfg.clock_out) { - case M88TS2022_CLOCK_OUT_DISABLED: - u8tmp = 0x60; - break; - case M88TS2022_CLOCK_OUT_ENABLED: - u8tmp = 0x70; - ret = regmap_write(dev->regmap, 0x05, dev->cfg.clock_out_div); - if (ret) - goto err; - break; - case M88TS2022_CLOCK_OUT_ENABLED_XTALOUT: - u8tmp = 0x6c; - break; - default: - ret = -EINVAL; - goto err; - } - - ret = regmap_write(dev->regmap, 0x42, u8tmp); - if (ret) - goto err; - - if (dev->cfg.loop_through) - u8tmp = 0xec; - else - u8tmp = 0x6c; - - ret = regmap_write(dev->regmap, 0x62, u8tmp); - if (ret) - goto err; - - /* sleep */ - ret = regmap_write(dev->regmap, 0x00, 0x00); - if (ret) - goto err; - - dev_info(&dev->client->dev, "Montage M88TS2022 successfully identified\n"); - - fe->tuner_priv = dev; - memcpy(&fe->ops.tuner_ops, &m88ts2022_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - i2c_set_clientdata(client, dev); - return 0; -err: - dev_dbg(&client->dev, "failed=%d\n", ret); - kfree(dev); - return ret; -} - -static int m88ts2022_remove(struct i2c_client *client) -{ - struct m88ts2022_dev *dev = i2c_get_clientdata(client); - struct dvb_frontend *fe = dev->cfg.fe; - - dev_dbg(&client->dev, "\n"); - - memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); - fe->tuner_priv = NULL; - kfree(dev); - - return 0; -} - -static const struct i2c_device_id m88ts2022_id[] = { - {"m88ts2022", 0}, - {} -}; -MODULE_DEVICE_TABLE(i2c, m88ts2022_id); - -static struct i2c_driver m88ts2022_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "m88ts2022", - }, - .probe = m88ts2022_probe, - .remove = m88ts2022_remove, - .id_table = m88ts2022_id, -}; - -module_i2c_driver(m88ts2022_driver); - -MODULE_DESCRIPTION("Montage M88TS2022 silicon tuner driver"); -MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/tuners/m88ts2022.h b/drivers/media/tuners/m88ts2022.h deleted file mode 100644 index 659fa1b1633a..000000000000 --- a/drivers/media/tuners/m88ts2022.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Montage M88TS2022 silicon tuner driver - * - * Copyright (C) 2013 Antti Palosaari <crope@iki.fi> - * - * 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 Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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 M88TS2022_H -#define M88TS2022_H - -#include "dvb_frontend.h" - -struct m88ts2022_config { - /* - * clock - * 16000000 - 32000000 - */ - u32 clock; - - /* - * RF loop-through - */ - u8 loop_through:1; - - /* - * clock output - */ -#define M88TS2022_CLOCK_OUT_DISABLED 0 -#define M88TS2022_CLOCK_OUT_ENABLED 1 -#define M88TS2022_CLOCK_OUT_ENABLED_XTALOUT 2 - u8 clock_out:2; - - /* - * clock output divider - * 1 - 31 - */ - u8 clock_out_div:5; - - /* - * pointer to DVB frontend - */ - struct dvb_frontend *fe; -}; - -#endif diff --git a/drivers/media/tuners/m88ts2022_priv.h b/drivers/media/tuners/m88ts2022_priv.h deleted file mode 100644 index feeb5ad6beef..000000000000 --- a/drivers/media/tuners/m88ts2022_priv.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Montage M88TS2022 silicon tuner driver - * - * Copyright (C) 2013 Antti Palosaari <crope@iki.fi> - * - * 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 Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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 M88TS2022_PRIV_H -#define M88TS2022_PRIV_H - -#include "m88ts2022.h" -#include <linux/regmap.h> - -struct m88ts2022_dev { - struct m88ts2022_config cfg; - struct i2c_client *client; - struct regmap *regmap; - u32 frequency_khz; -}; - -struct m88ts2022_reg_val { - u8 reg; - u8 val; -}; - -#endif diff --git a/drivers/media/tuners/max2165.h b/drivers/media/tuners/max2165.h index 26e1dc64bb67..5054f01a78fb 100644 --- a/drivers/media/tuners/max2165.h +++ b/drivers/media/tuners/max2165.h @@ -32,7 +32,7 @@ struct max2165_config { u8 osc_clk; /* in MHz, selectable values: 4,16,18,20,22,24,26,28 */ }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_MAX2165) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_MAX2165) extern struct dvb_frontend *max2165_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct max2165_config *cfg); diff --git a/drivers/media/tuners/mc44s803.h b/drivers/media/tuners/mc44s803.h index 9aae50aca2b7..b3e614be657d 100644 --- a/drivers/media/tuners/mc44s803.h +++ b/drivers/media/tuners/mc44s803.h @@ -32,7 +32,7 @@ struct mc44s803_config { u8 dig_out; }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_MC44S803) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_MC44S803) extern struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mc44s803_config *cfg); #else diff --git a/drivers/media/tuners/mt2060.h b/drivers/media/tuners/mt2060.h index c64fc19cb278..6efed359a24f 100644 --- a/drivers/media/tuners/mt2060.h +++ b/drivers/media/tuners/mt2060.h @@ -30,7 +30,7 @@ struct mt2060_config { u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */ }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_MT2060) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_MT2060) extern struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1); #else static inline struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1) diff --git a/drivers/media/tuners/mt2063.h b/drivers/media/tuners/mt2063.h index e1acfc8e7ae3..e55e0a6dd1be 100644 --- a/drivers/media/tuners/mt2063.h +++ b/drivers/media/tuners/mt2063.h @@ -8,7 +8,7 @@ struct mt2063_config { u32 refclock; }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_MT2063) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_MT2063) struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, struct mt2063_config *config, struct i2c_adapter *i2c); diff --git a/drivers/media/tuners/mt20xx.h b/drivers/media/tuners/mt20xx.h index f56241ccaa00..9912362b415e 100644 --- a/drivers/media/tuners/mt20xx.h +++ b/drivers/media/tuners/mt20xx.h @@ -20,7 +20,7 @@ #include <linux/i2c.h> #include "dvb_frontend.h" -#if IS_ENABLED(CONFIG_MEDIA_TUNER_MT20XX) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_MT20XX) extern struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, u8 i2c_addr); diff --git a/drivers/media/tuners/mt2131.h b/drivers/media/tuners/mt2131.h index 837c854b9c65..8267a6ae5d84 100644 --- a/drivers/media/tuners/mt2131.h +++ b/drivers/media/tuners/mt2131.h @@ -30,7 +30,7 @@ struct mt2131_config { u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */ }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_MT2131) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_MT2131) extern struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2131_config *cfg, diff --git a/drivers/media/tuners/mt2266.h b/drivers/media/tuners/mt2266.h index fad6dd657d77..69abefa18c37 100644 --- a/drivers/media/tuners/mt2266.h +++ b/drivers/media/tuners/mt2266.h @@ -24,7 +24,7 @@ struct mt2266_config { u8 i2c_address; }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_MT2266) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_MT2266) extern struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg); #else static inline struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg) diff --git a/drivers/media/tuners/mxl5005s.h b/drivers/media/tuners/mxl5005s.h index ae8db885ad87..5764b12c5c7c 100644 --- a/drivers/media/tuners/mxl5005s.h +++ b/drivers/media/tuners/mxl5005s.h @@ -118,7 +118,7 @@ struct mxl5005s_config { u8 AgcMasterByte; }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_MXL5005S) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_MXL5005S) extern struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mxl5005s_config *config); diff --git a/drivers/media/tuners/mxl5007t.h b/drivers/media/tuners/mxl5007t.h index ae7037d681c5..e786d1f23ff1 100644 --- a/drivers/media/tuners/mxl5007t.h +++ b/drivers/media/tuners/mxl5007t.h @@ -77,7 +77,7 @@ struct mxl5007t_config { unsigned int clk_out_enable:1; }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_MXL5007T) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_MXL5007T) extern struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 addr, struct mxl5007t_config *cfg); diff --git a/drivers/media/tuners/qt1010.h b/drivers/media/tuners/qt1010.h index 8ab5d479749f..e3198f23437c 100644 --- a/drivers/media/tuners/qt1010.h +++ b/drivers/media/tuners/qt1010.h @@ -36,7 +36,7 @@ struct qt1010_config { * @param cfg tuner hw based configuration * @return fe pointer on success, NULL on failure */ -#if IS_ENABLED(CONFIG_MEDIA_TUNER_QT1010) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_QT1010) extern struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct qt1010_config *cfg); diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 8e040cf9cf13..71159a58860f 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -775,6 +775,19 @@ static int r820t_sysfreq_sel(struct r820t_priv *priv, u32 freq, div_buf_cur = 0x30; /* 11, 150u */ filter_cur = 0x40; /* 10, low */ break; + case SYS_DVBC_ANNEX_A: + mixer_top = 0x24; /* mixer top:13 , top-1, low-discharge */ + lna_top = 0xe5; + lna_vth_l = 0x62; + mixer_vth_l = 0x75; + air_cable1_in = 0x60; + cable2_in = 0x00; + pre_dect = 0x40; + lna_discharge = 14; + cp_cur = 0x38; /* 111, auto */ + div_buf_cur = 0x30; /* 11, 150u */ + filter_cur = 0x40; /* 10, low */ + break; default: /* DVB-T 8M */ mixer_top = 0x24; /* mixer top:13 , top-1, low-discharge */ lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */ @@ -957,7 +970,7 @@ static int r820t_set_tv_standard(struct r820t_priv *priv, ext_enable = 0x40; /* r30[6], ext enable; r30[5]:0 ext at lna max */ loop_through = 0x00; /* r5[7], lt on */ lt_att = 0x00; /* r31[7], lt att enable */ - flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */ + flt_ext_widest = 0x80; /* r15[7]: flt_ext_wide on */ polyfil_cur = 0x60; /* r25[6:5]:min */ } else if (delsys == SYS_DVBC_ANNEX_A) { if_khz = 5070; @@ -971,6 +984,18 @@ static int r820t_set_tv_standard(struct r820t_priv *priv, lt_att = 0x00; /* r31[7], lt att enable */ flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */ polyfil_cur = 0x60; /* r25[6:5]:min */ + } else if (delsys == SYS_DVBC_ANNEX_C) { + if_khz = 4063; + filt_cal_lo = 55000; + filt_gain = 0x10; /* +3db, 6mhz on */ + img_r = 0x00; /* image negative */ + filt_q = 0x10; /* r10[4]:low q(1'b1) */ + hp_cor = 0x6a; /* 1.7m disable, +0cap, 1.0mhz */ + ext_enable = 0x40; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */ + loop_through = 0x00; /* r5[7], lt on */ + lt_att = 0x00; /* r31[7], lt att enable */ + flt_ext_widest = 0x80; /* r15[7]: flt_ext_wide on */ + polyfil_cur = 0x60; /* r25[6:5]:min */ } else { if (bw <= 6) { if_khz = 3570; @@ -1186,7 +1211,7 @@ static int r820t_read_gain(struct r820t_priv *priv) if (rc < 0) return rc; - return ((data[3] & 0x0f) << 1) + ((data[3] & 0xf0) >> 4); + return ((data[3] & 0x08) << 1) + ((data[3] & 0xf0) >> 4); } #if 0 diff --git a/drivers/media/tuners/r820t.h b/drivers/media/tuners/r820t.h index 48af3548027d..b1e5661af1c7 100644 --- a/drivers/media/tuners/r820t.h +++ b/drivers/media/tuners/r820t.h @@ -42,7 +42,7 @@ struct r820t_config { bool use_predetect; }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_R820T) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_R820T) struct dvb_frontend *r820t_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct r820t_config *cfg); diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c index fcf139dfdec6..d74ae26621ca 100644 --- a/drivers/media/tuners/si2157.c +++ b/drivers/media/tuners/si2157.c @@ -244,6 +244,7 @@ static int si2157_set_params(struct dvb_frontend *fe) int ret; struct si2157_cmd cmd; u8 bandwidth, delivery_system; + u32 if_frequency = 5000000; dev_dbg(&client->dev, "delivery_system=%d frequency=%u bandwidth_hz=%u\n", @@ -266,9 +267,11 @@ static int si2157_set_params(struct dvb_frontend *fe) switch (c->delivery_system) { case SYS_ATSC: delivery_system = 0x00; + if_frequency = 3250000; break; case SYS_DVBC_ANNEX_B: delivery_system = 0x10; + if_frequency = 4000000; break; case SYS_DVBT: case SYS_DVBT2: /* it seems DVB-T and DVB-T2 both are 0x20 here */ @@ -302,6 +305,20 @@ static int si2157_set_params(struct dvb_frontend *fe) if (ret) goto err; + /* set if frequency if needed */ + if (if_frequency != dev->if_frequency) { + memcpy(cmd.args, "\x14\x00\x06\x07", 4); + cmd.args[4] = (if_frequency / 1000) & 0xff; + cmd.args[5] = ((if_frequency / 1000) >> 8) & 0xff; + cmd.wlen = 6; + cmd.rlen = 4; + ret = si2157_cmd_execute(client, &cmd); + if (ret) + goto err; + + dev->if_frequency = if_frequency; + } + /* set frequency */ memcpy(cmd.args, "\x41\x00\x00\x00\x00\x00\x00\x00", 8); cmd.args[4] = (c->frequency >> 0) & 0xff; @@ -322,14 +339,17 @@ err: static int si2157_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) { - *frequency = 5000000; /* default value of property 0x0706 */ + struct i2c_client *client = fe->tuner_priv; + struct si2157_dev *dev = i2c_get_clientdata(client); + + *frequency = dev->if_frequency; return 0; } static const struct dvb_tuner_ops si2157_ops = { .info = { .name = "Silicon Labs Si2146/2147/2148/2157/2158", - .frequency_min = 110000000, + .frequency_min = 55000000, .frequency_max = 862000000, }, @@ -360,6 +380,7 @@ static int si2157_probe(struct i2c_client *client, dev->inversion = cfg->inversion; dev->fw_loaded = false; dev->chiptype = (u8)id->driver_data; + dev->if_frequency = 5000000; /* default value of property 0x0706 */ mutex_init(&dev->i2c_mutex); /* check if the tuner is there */ diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h index 7aa53bce5593..cd8fa5b25304 100644 --- a/drivers/media/tuners/si2157_priv.h +++ b/drivers/media/tuners/si2157_priv.h @@ -28,6 +28,7 @@ struct si2157_dev { bool fw_loaded; bool inversion; u8 chiptype; + u32 if_frequency; }; #define SI2157_CHIPTYPE_SI2157 0 diff --git a/drivers/media/tuners/tda18218.h b/drivers/media/tuners/tda18218.h index 366410e0cc9a..1eacb4f84e93 100644 --- a/drivers/media/tuners/tda18218.h +++ b/drivers/media/tuners/tda18218.h @@ -30,7 +30,7 @@ struct tda18218_config { u8 loop_through:1; }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_TDA18218) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_TDA18218) extern struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct tda18218_config *cfg); #else diff --git a/drivers/media/tuners/tda18271.h b/drivers/media/tuners/tda18271.h index 4c418d63f540..0a846333ce57 100644 --- a/drivers/media/tuners/tda18271.h +++ b/drivers/media/tuners/tda18271.h @@ -121,7 +121,7 @@ enum tda18271_mode { TDA18271_DIGITAL, }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_TDA18271) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_TDA18271) extern struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, struct i2c_adapter *i2c, struct tda18271_config *cfg); diff --git a/drivers/media/tuners/tda827x.h b/drivers/media/tuners/tda827x.h index b64292152baf..abf2e2fe5350 100644 --- a/drivers/media/tuners/tda827x.h +++ b/drivers/media/tuners/tda827x.h @@ -51,7 +51,7 @@ struct tda827x_config * @param cfg optional callback function pointers. * @return FE pointer on success, NULL on failure. */ -#if IS_ENABLED(CONFIG_MEDIA_TUNER_TDA827X) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_TDA827X) extern struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c, struct tda827x_config *cfg); diff --git a/drivers/media/tuners/tda8290.h b/drivers/media/tuners/tda8290.h index cf96e585785e..901b8cac7105 100644 --- a/drivers/media/tuners/tda8290.h +++ b/drivers/media/tuners/tda8290.h @@ -38,7 +38,7 @@ struct tda829x_config { struct tda18271_std_map *tda18271_std_map; }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_TDA8290) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_TDA8290) extern int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr); extern struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, diff --git a/drivers/media/tuners/tda9887.h b/drivers/media/tuners/tda9887.h index 37a4a1123e0c..95070eca02ca 100644 --- a/drivers/media/tuners/tda9887.h +++ b/drivers/media/tuners/tda9887.h @@ -21,7 +21,7 @@ #include "dvb_frontend.h" /* ------------------------------------------------------------------------ */ -#if IS_ENABLED(CONFIG_MEDIA_TUNER_TDA9887) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_TDA9887) extern struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c_adap, u8 i2c_addr); diff --git a/drivers/media/tuners/tea5761.h b/drivers/media/tuners/tea5761.h index 933228ffb509..2d624d9919e3 100644 --- a/drivers/media/tuners/tea5761.h +++ b/drivers/media/tuners/tea5761.h @@ -20,7 +20,7 @@ #include <linux/i2c.h> #include "dvb_frontend.h" -#if IS_ENABLED(CONFIG_MEDIA_TUNER_TEA5761) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_TEA5761) extern int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); extern struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, diff --git a/drivers/media/tuners/tea5767.h b/drivers/media/tuners/tea5767.h index c39101199383..4f6f6c92db78 100644 --- a/drivers/media/tuners/tea5767.h +++ b/drivers/media/tuners/tea5767.h @@ -39,7 +39,7 @@ struct tea5767_ctrl { enum tea5767_xtal xtal_freq; }; -#if IS_ENABLED(CONFIG_MEDIA_TUNER_TEA5767) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_TEA5767) extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); extern struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, diff --git a/drivers/media/tuners/tua9001.h b/drivers/media/tuners/tua9001.h index 26358da1c100..2c3375c7aeb9 100644 --- a/drivers/media/tuners/tua9001.h +++ b/drivers/media/tuners/tua9001.h @@ -51,7 +51,7 @@ struct tua9001_config { #define TUA9001_CMD_RESETN 1 #define TUA9001_CMD_RXEN 2 -#if IS_ENABLED(CONFIG_MEDIA_TUNER_TUA9001) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_TUA9001) extern struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct tua9001_config *cfg); #else diff --git a/drivers/media/tuners/tuner-simple.h b/drivers/media/tuners/tuner-simple.h index ffd12cfe650b..6399b45b0590 100644 --- a/drivers/media/tuners/tuner-simple.h +++ b/drivers/media/tuners/tuner-simple.h @@ -20,7 +20,7 @@ #include <linux/i2c.h> #include "dvb_frontend.h" -#if IS_ENABLED(CONFIG_MEDIA_TUNER_SIMPLE) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_SIMPLE) extern struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c_adap, u8 i2c_addr, diff --git a/drivers/media/tuners/tuner-xc2028.h b/drivers/media/tuners/tuner-xc2028.h index 181d087faec4..98e4effca896 100644 --- a/drivers/media/tuners/tuner-xc2028.h +++ b/drivers/media/tuners/tuner-xc2028.h @@ -56,7 +56,7 @@ struct xc2028_config { #define XC2028_RESET_CLK 1 #define XC2028_I2C_FLUSH 2 -#if IS_ENABLED(CONFIG_MEDIA_TUNER_XC2028) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_XC2028) extern struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, struct xc2028_config *cfg); #else diff --git a/drivers/media/tuners/xc4000.h b/drivers/media/tuners/xc4000.h index 97c23de5296c..40517860cf67 100644 --- a/drivers/media/tuners/xc4000.h +++ b/drivers/media/tuners/xc4000.h @@ -50,7 +50,7 @@ struct xc4000_config { * it's passed back to a bridge during tuner_callback(). */ -#if IS_ENABLED(CONFIG_MEDIA_TUNER_XC4000) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_XC4000) extern struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct xc4000_config *cfg); diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c index 2a039de8ab9a..e6e5e90d8d95 100644 --- a/drivers/media/tuners/xc5000.c +++ b/drivers/media/tuners/xc5000.c @@ -1336,7 +1336,10 @@ static int xc5000_release(struct dvb_frontend *fe) if (priv) { cancel_delayed_work(&priv->timer_sleep); - release_firmware(priv->firmware); + if (priv->firmware) { + release_firmware(priv->firmware); + priv->firmware = NULL; + } hybrid_tuner_release_state(priv); } diff --git a/drivers/media/tuners/xc5000.h b/drivers/media/tuners/xc5000.h index 6aa534f17a30..00ba29e21fb9 100644 --- a/drivers/media/tuners/xc5000.h +++ b/drivers/media/tuners/xc5000.h @@ -58,7 +58,7 @@ struct xc5000_config { * it's passed back to a bridge during tuner_callback(). */ -#if IS_ENABLED(CONFIG_MEDIA_TUNER_XC5000) +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_XC5000) extern struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct xc5000_config *cfg); diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index a27cb5fcdef8..1a362a041ab3 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -299,29 +299,23 @@ static int au0828_init_isoc(struct au0828_dev *dev, int max_packets, * Announces that a buffer were filled and request the next */ static inline void buffer_filled(struct au0828_dev *dev, - struct au0828_dmaqueue *dma_q, - struct au0828_buffer *buf) + struct au0828_dmaqueue *dma_q, + struct au0828_buffer *buf) { - /* Advice that buffer was filled */ - au0828_isocdbg("[%p/%d] wakeup\n", buf, buf->top_field); + struct vb2_buffer *vb = &buf->vb; + struct vb2_queue *q = vb->vb2_queue; - buf->vb.v4l2_buf.sequence = dev->frame_count++; - buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED; - v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); - vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE); -} - -static inline void vbi_buffer_filled(struct au0828_dev *dev, - struct au0828_dmaqueue *dma_q, - struct au0828_buffer *buf) -{ /* Advice that buffer was filled */ au0828_isocdbg("[%p/%d] wakeup\n", buf, buf->top_field); - buf->vb.v4l2_buf.sequence = dev->vbi_frame_count++; - buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED; - v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); - vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE); + if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + vb->v4l2_buf.sequence = dev->frame_count++; + else + vb->v4l2_buf.sequence = dev->vbi_frame_count++; + + vb->v4l2_buf.field = V4L2_FIELD_INTERLACED; + v4l2_get_timestamp(&vb->v4l2_buf.timestamp); + vb2_buffer_done(vb, VB2_BUF_STATE_DONE); } /* @@ -574,9 +568,7 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb) if (fbyte & 0x40) { /* VBI */ if (vbi_buf != NULL) - vbi_buffer_filled(dev, - vbi_dma_q, - vbi_buf); + buffer_filled(dev, vbi_dma_q, vbi_buf); vbi_get_next_buf(vbi_dma_q, &vbi_buf); if (vbi_buf == NULL) vbioutp = NULL; @@ -899,12 +891,8 @@ void au0828_analog_unregister(struct au0828_dev *dev) { dprintk(1, "au0828_analog_unregister called\n"); mutex_lock(&au0828_sysfs_lock); - - if (dev->vdev) - video_unregister_device(dev->vdev); - if (dev->vbi_dev) - video_unregister_device(dev->vbi_dev); - + video_unregister_device(&dev->vdev); + video_unregister_device(&dev->vbi_dev); mutex_unlock(&au0828_sysfs_lock); } @@ -949,7 +937,7 @@ static void au0828_vbi_buffer_timeout(unsigned long data) if (buf != NULL) { vbi_data = vb2_plane_vaddr(&buf->vb, 0); memset(vbi_data, 0x00, buf->length); - vbi_buffer_filled(dev, dma_q, buf); + buffer_filled(dev, dma_q, buf); } vbi_get_next_buf(dma_q, &buf); @@ -1286,7 +1274,7 @@ static int vidioc_enum_input(struct file *file, void *priv, input->audioset = 2; } - input->std = dev->vdev->tvnorms; + input->std = dev->vdev.tvnorms; return 0; } @@ -1704,7 +1692,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { static const struct video_device au0828_video_template = { .fops = &au0828_v4l_fops, - .release = video_device_release, + .release = video_device_release_empty, .ioctl_ops = &video_ioctl_ops, .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL_M, }; @@ -1814,52 +1802,36 @@ int au0828_analog_register(struct au0828_dev *dev, dev->std = V4L2_STD_NTSC_M; au0828_s_input(dev, 0); - /* allocate and fill v4l2 video struct */ - dev->vdev = video_device_alloc(); - if (NULL == dev->vdev) { - dprintk(1, "Can't allocate video_device.\n"); - return -ENOMEM; - } - - /* allocate the VBI struct */ - dev->vbi_dev = video_device_alloc(); - if (NULL == dev->vbi_dev) { - dprintk(1, "Can't allocate vbi_device.\n"); - ret = -ENOMEM; - goto err_vdev; - } - mutex_init(&dev->vb_queue_lock); mutex_init(&dev->vb_vbi_queue_lock); /* Fill the video capture device struct */ - *dev->vdev = au0828_video_template; - dev->vdev->v4l2_dev = &dev->v4l2_dev; - dev->vdev->lock = &dev->lock; - dev->vdev->queue = &dev->vb_vidq; - dev->vdev->queue->lock = &dev->vb_queue_lock; - strcpy(dev->vdev->name, "au0828a video"); + dev->vdev = au0828_video_template; + dev->vdev.v4l2_dev = &dev->v4l2_dev; + dev->vdev.lock = &dev->lock; + dev->vdev.queue = &dev->vb_vidq; + dev->vdev.queue->lock = &dev->vb_queue_lock; + strcpy(dev->vdev.name, "au0828a video"); /* Setup the VBI device */ - *dev->vbi_dev = au0828_video_template; - dev->vbi_dev->v4l2_dev = &dev->v4l2_dev; - dev->vbi_dev->lock = &dev->lock; - dev->vbi_dev->queue = &dev->vb_vbiq; - dev->vbi_dev->queue->lock = &dev->vb_vbi_queue_lock; - strcpy(dev->vbi_dev->name, "au0828a vbi"); + dev->vbi_dev = au0828_video_template; + dev->vbi_dev.v4l2_dev = &dev->v4l2_dev; + dev->vbi_dev.lock = &dev->lock; + dev->vbi_dev.queue = &dev->vb_vbiq; + dev->vbi_dev.queue->lock = &dev->vb_vbi_queue_lock; + strcpy(dev->vbi_dev.name, "au0828a vbi"); /* initialize videobuf2 stuff */ retval = au0828_vb2_setup(dev); if (retval != 0) { dprintk(1, "unable to setup videobuf2 queues (error = %d).\n", retval); - ret = -ENODEV; - goto err_vbi_dev; + return -ENODEV; } /* Register the v4l2 device */ - video_set_drvdata(dev->vdev, dev); - retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1); + video_set_drvdata(&dev->vdev, dev); + retval = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1); if (retval != 0) { dprintk(1, "unable to register video device (error = %d).\n", retval); @@ -1868,8 +1840,8 @@ int au0828_analog_register(struct au0828_dev *dev, } /* Register the vbi device */ - video_set_drvdata(dev->vbi_dev, dev); - retval = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, -1); + video_set_drvdata(&dev->vbi_dev, dev); + retval = video_register_device(&dev->vbi_dev, VFL_TYPE_VBI, -1); if (retval != 0) { dprintk(1, "unable to register vbi device (error = %d).\n", retval); @@ -1882,14 +1854,10 @@ int au0828_analog_register(struct au0828_dev *dev, return 0; err_reg_vbi_dev: - video_unregister_device(dev->vdev); + video_unregister_device(&dev->vdev); err_reg_vdev: vb2_queue_release(&dev->vb_vidq); vb2_queue_release(&dev->vb_vbiq); -err_vbi_dev: - video_device_release(dev->vbi_dev); -err_vdev: - video_device_release(dev->vdev); return ret; } diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h index eb1518742ae6..3b480005ce3b 100644 --- a/drivers/media/usb/au0828/au0828.h +++ b/drivers/media/usb/au0828/au0828.h @@ -209,8 +209,8 @@ struct au0828_dev { struct au0828_rc *ir; #endif - struct video_device *vdev; - struct video_device *vbi_dev; + struct video_device vdev; + struct video_device vbi_dev; /* Videobuf2 */ struct vb2_queue vb_vidq; diff --git a/drivers/media/usb/cx231xx/Kconfig b/drivers/media/usb/cx231xx/Kconfig index 173c0e287a08..0cced3e5b040 100644 --- a/drivers/media/usb/cx231xx/Kconfig +++ b/drivers/media/usb/cx231xx/Kconfig @@ -47,6 +47,7 @@ config VIDEO_CX231XX_DVB select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT select DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT + select DVB_LGDT3306A if MEDIA_SUBDRV_AUTOSELECT select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT select DVB_SI2165 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index 3f295b4d1a3d..983ea8339154 100644 --- a/drivers/media/usb/cx231xx/cx231xx-417.c +++ b/drivers/media/usb/cx231xx/cx231xx-417.c @@ -1868,13 +1868,9 @@ void cx231xx_417_unregister(struct cx231xx *dev) dprintk(1, "%s()\n", __func__); dprintk(3, "%s()\n", __func__); - if (dev->v4l_device) { - if (-1 != dev->v4l_device->minor) - video_unregister_device(dev->v4l_device); - else - video_device_release(dev->v4l_device); + if (video_is_registered(&dev->v4l_device)) { + video_unregister_device(&dev->v4l_device); v4l2_ctrl_handler_free(&dev->mpeg_ctrl_handler.hdl); - dev->v4l_device = NULL; } } @@ -1911,25 +1907,21 @@ static struct cx2341x_handler_ops cx231xx_ops = { .s_video_encoding = cx231xx_s_video_encoding, }; -static struct video_device *cx231xx_video_dev_alloc( +static void cx231xx_video_dev_init( struct cx231xx *dev, struct usb_device *usbdev, - struct video_device *template, - char *type) + struct video_device *vfd, + const struct video_device *template, + const char *type) { - struct video_device *vfd; - dprintk(1, "%s()\n", __func__); - vfd = video_device_alloc(); - if (NULL == vfd) - return NULL; *vfd = *template; snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, type, cx231xx_boards[dev->model].name); vfd->v4l2_dev = &dev->v4l2_dev; vfd->lock = &dev->lock; - vfd->release = video_device_release; + vfd->release = video_device_release_empty; vfd->ctrl_handler = &dev->mpeg_ctrl_handler.hdl; video_set_drvdata(vfd, dev); if (dev->tuner_type == TUNER_ABSENT) { @@ -1938,9 +1930,6 @@ static struct video_device *cx231xx_video_dev_alloc( v4l2_disable_ioctl(vfd, VIDIOC_G_TUNER); v4l2_disable_ioctl(vfd, VIDIOC_S_TUNER); } - - return vfd; - } int cx231xx_417_register(struct cx231xx *dev) @@ -1983,9 +1972,9 @@ int cx231xx_417_register(struct cx231xx *dev) cx2341x_handler_set_50hz(&dev->mpeg_ctrl_handler, false); /* Allocate and initialize V4L video device */ - dev->v4l_device = cx231xx_video_dev_alloc(dev, - dev->udev, &cx231xx_mpeg_template, "mpeg"); - err = video_register_device(dev->v4l_device, + cx231xx_video_dev_init(dev, dev->udev, + &dev->v4l_device, &cx231xx_mpeg_template, "mpeg"); + err = video_register_device(&dev->v4l_device, VFL_TYPE_GRABBER, -1); if (err < 0) { dprintk(3, "%s: can't register mpeg device\n", dev->name); @@ -1994,7 +1983,7 @@ int cx231xx_417_register(struct cx231xx *dev) } dprintk(3, "%s: registered device video%d [mpeg]\n", - dev->name, dev->v4l_device->num); + dev->name, dev->v4l_device.num); return 0; } diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index da03733690bd..fe00da105e77 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -776,6 +776,45 @@ struct cx231xx_board cx231xx_boards[] = { .gpio = NULL, } }, }, + [CX231XX_BOARD_HAUPPAUGE_955Q] = { + .name = "Hauppauge WinTV-HVR-955Q (111401)", + .tuner_type = TUNER_ABSENT, + .tuner_addr = 0x60, + .tuner_gpio = RDE250_XCV_TUNER, + .tuner_sif_gpio = 0x05, + .tuner_scl_gpio = 0x1a, + .tuner_sda_gpio = 0x1b, + .decoder = CX231XX_AVDECODER, + .output_mode = OUT_MODE_VIP11, + .demod_xfer_mode = 0, + .ctl_pin_status_mask = 0xFFFFFFC4, + .agc_analog_digital_select_gpio = 0x0c, + .gpio_pin_status_mask = 0x4001000, + .tuner_i2c_master = I2C_1_MUX_3, + .demod_i2c_master = I2C_2, + .has_dvb = 1, + .demod_addr = 0x0e, + .norm = V4L2_STD_NTSC, + + .input = {{ + .type = CX231XX_VMUX_TELEVISION, + .vmux = CX231XX_VIN_3_1, + .amux = CX231XX_AMUX_VIDEO, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_COMPOSITE1, + .vmux = CX231XX_VIN_2_1, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_SVIDEO, + .vmux = CX231XX_VIN_1_1 | + (CX231XX_VIN_1_2 << 8) | + CX25840_SVIDEO_ON, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + } }, + }, }; const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards); @@ -805,6 +844,8 @@ struct usb_device_id cx231xx_id_table[] = { .driver_info = CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC}, {USB_DEVICE(0x2040, 0xb120), .driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER}, + {USB_DEVICE(0x2040, 0xb123), + .driver_info = CX231XX_BOARD_HAUPPAUGE_955Q}, {USB_DEVICE(0x2040, 0xb130), .driver_info = CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx}, {USB_DEVICE(0x2040, 0xb131), @@ -912,9 +953,6 @@ static inline void cx231xx_set_model(struct cx231xx *dev) */ void cx231xx_pre_card_setup(struct cx231xx *dev) { - - cx231xx_set_model(dev); - dev_info(dev->dev, "Identified as %s (card=%d)\n", dev->board.name, dev->model); @@ -1052,6 +1090,7 @@ void cx231xx_card_setup(struct cx231xx *dev) switch (dev->model) { case CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx: case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx: + case CX231XX_BOARD_HAUPPAUGE_955Q: { struct tveeprom tvee; static u8 eeprom[256]; @@ -1092,6 +1131,17 @@ void cx231xx_config_i2c(struct cx231xx *dev) call_all(dev, video, s_stream, 1); } +static void cx231xx_unregister_media_device(struct cx231xx *dev) +{ +#ifdef CONFIG_MEDIA_CONTROLLER + if (dev->media_dev) { + media_device_unregister(dev->media_dev); + kfree(dev->media_dev); + dev->media_dev = NULL; + } +#endif +} + /* * cx231xx_realease_resources() * unregisters the v4l2,i2c and usb devices @@ -1099,6 +1149,8 @@ void cx231xx_config_i2c(struct cx231xx *dev) */ void cx231xx_release_resources(struct cx231xx *dev) { + cx231xx_unregister_media_device(dev); + cx231xx_release_analog_resources(dev); cx231xx_remove_from_devlist(dev); @@ -1117,6 +1169,74 @@ void cx231xx_release_resources(struct cx231xx *dev) clear_bit(dev->devno, &cx231xx_devused); } +static void cx231xx_media_device_register(struct cx231xx *dev, + struct usb_device *udev) +{ +#ifdef CONFIG_MEDIA_CONTROLLER + struct media_device *mdev; + int ret; + + mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); + if (!mdev) + return; + + mdev->dev = dev->dev; + strlcpy(mdev->model, dev->board.name, sizeof(mdev->model)); + if (udev->serial) + strlcpy(mdev->serial, udev->serial, sizeof(mdev->serial)); + strcpy(mdev->bus_info, udev->devpath); + mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice); + mdev->driver_version = LINUX_VERSION_CODE; + + ret = media_device_register(mdev); + if (ret) { + dev_err(dev->dev, + "Couldn't create a media device. Error: %d\n", + ret); + kfree(mdev); + return; + } + + dev->media_dev = mdev; +#endif +} + +static void cx231xx_create_media_graph(struct cx231xx *dev) +{ +#ifdef CONFIG_MEDIA_CONTROLLER + struct media_device *mdev = dev->media_dev; + struct media_entity *entity; + struct media_entity *tuner = NULL, *decoder = NULL; + + if (!mdev) + return; + + media_device_for_each_entity(entity, mdev) { + switch (entity->type) { + case MEDIA_ENT_T_V4L2_SUBDEV_TUNER: + tuner = entity; + break; + case MEDIA_ENT_T_V4L2_SUBDEV_DECODER: + decoder = entity; + break; + } + } + + /* Analog setup, using tuner as a link */ + + if (!decoder) + return; + + if (tuner) + media_entity_create_link(tuner, 0, decoder, 0, + MEDIA_LNK_FL_ENABLED); + media_entity_create_link(decoder, 1, &dev->vdev.entity, 0, + MEDIA_LNK_FL_ENABLED); + media_entity_create_link(decoder, 2, &dev->vbi_dev.entity, 0, + MEDIA_LNK_FL_ENABLED); +#endif +} + /* * cx231xx_init_dev() * allocates and inits the device structs, registers i2c bus and v4l device @@ -1225,10 +1345,8 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev, } retval = cx231xx_register_analog_devices(dev); - if (retval) { - cx231xx_release_analog_resources(dev); + if (retval) goto err_analog; - } cx231xx_ir_init(dev); @@ -1236,6 +1354,8 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev, return 0; err_analog: + cx231xx_unregister_media_device(dev); + cx231xx_release_analog_resources(dev); cx231xx_remove_from_devlist(dev); err_dev_init: cx231xx_dev_uninit(dev); @@ -1438,6 +1558,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface, dev->video_mode.alt = -1; dev->dev = d; + cx231xx_set_model(dev); + dev->interface_count++; /* reset gpio dir and value */ dev->gpio_dir = 0; @@ -1502,7 +1624,13 @@ static int cx231xx_usb_probe(struct usb_interface *interface, /* save our data pointer in this interface device */ usb_set_intfdata(interface, dev); + /* Register the media controller */ + cx231xx_media_device_register(dev, udev); + /* Create v4l2 device */ +#ifdef CONFIG_MEDIA_CONTROLLER + dev->v4l2_dev.mdev = dev->media_dev; +#endif retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev); if (retval) { dev_err(d, "v4l2_device_register failed\n"); @@ -1568,6 +1696,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface, /* load other modules required */ request_modules(dev); + cx231xx_create_media_graph(dev); + return 0; err_video_alt: /* cx231xx_uninit_dev: */ @@ -1618,7 +1748,7 @@ static void cx231xx_usb_disconnect(struct usb_interface *interface) if (dev->users) { dev_warn(dev->dev, "device %s is open! Deregistration and memory deallocation are deferred on close.\n", - video_device_node_name(dev->vdev)); + video_device_node_name(&dev->vdev)); /* Even having users, it is safe to remove the RC i2c driver */ cx231xx_ir_exit(dev); diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c index 4a3f28c4e8d3..e42bde081cd7 100644 --- a/drivers/media/usb/cx231xx/cx231xx-core.c +++ b/drivers/media/usb/cx231xx/cx231xx-core.c @@ -176,16 +176,9 @@ int cx231xx_send_usb_command(struct cx231xx_i2c *i2c_bus, saddr_len = req_data->saddr_len; /* Set wValue */ - if (saddr_len == 1) /* need check saddr_len == 0 */ - ven_req.wValue = - req_data-> - dev_addr << 9 | _i2c_period << 4 | saddr_len << 2 | - _i2c_nostop << 1 | I2C_SYNC | _i2c_reserve << 6; - else - ven_req.wValue = - req_data-> - dev_addr << 9 | _i2c_period << 4 | saddr_len << 2 | - _i2c_nostop << 1 | I2C_SYNC | _i2c_reserve << 6; + ven_req.wValue = (req_data->dev_addr << 9 | _i2c_period << 4 | + saddr_len << 2 | _i2c_nostop << 1 | I2C_SYNC | + _i2c_reserve << 6); /* set channel number */ if (req_data->direction & I2C_M_RD) { diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c index dd600b994e69..610d5675bde6 100644 --- a/drivers/media/usb/cx231xx/cx231xx-dvb.c +++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c @@ -34,6 +34,7 @@ #include "si2165.h" #include "mb86a20s.h" #include "si2157.h" +#include "lgdt3306a.h" MODULE_DESCRIPTION("driver for cx231xx based DVB cards"); MODULE_AUTHOR("Srinivasa Deevi <srinivasa.deevi@conexant.com>"); @@ -160,6 +161,18 @@ static const struct si2165_config pctv_quatro_stick_1114xx_si2165_config = { .ref_freq_Hz = 24000000, }; +static struct lgdt3306a_config hauppauge_955q_lgdt3306a_config = { + .i2c_addr = 0x59, + .qam_if_khz = 4000, + .vsb_if_khz = 3250, + .deny_i2c_rptr = 1, + .spectral_inversion = 1, + .mpeg_mode = LGDT3306A_MPEG_SERIAL, + .tpclk_edge = LGDT3306A_TPCLK_RISING_EDGE, + .tpvalid_polarity = LGDT3306A_TP_VALID_HIGH, + .xtalMHz = 25, +}; + static inline void print_err_status(struct cx231xx *dev, int packet, int status) { char *errmsg = "Unknown"; @@ -455,6 +468,7 @@ static int register_dvb(struct cx231xx_dvb *dvb, mutex_init(&dvb->lock); + /* register adapter */ result = dvb_register_adapter(&dvb->adapter, dev->name, module, device, adapter_nr); @@ -464,6 +478,7 @@ static int register_dvb(struct cx231xx_dvb *dvb, dev->name, result); goto fail_adapter; } + dvb_register_media_controller(&dvb->adapter, dev->media_dev); /* Ensure all frontends negotiate bus access */ dvb->frontend->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl; @@ -536,6 +551,8 @@ static int register_dvb(struct cx231xx_dvb *dvb, /* register network adapter */ dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx); + dvb_create_media_graph(&dvb->adapter); + return 0; fail_fe_conn: @@ -807,7 +824,61 @@ static int dvb_init(struct cx231xx *dev) dev->dvb->i2c_client_tuner = client; break; } + case CX231XX_BOARD_HAUPPAUGE_955Q: + { + struct i2c_client *client; + struct i2c_board_info info; + struct si2157_config si2157_config; + + memset(&info, 0, sizeof(struct i2c_board_info)); + + dev->dvb->frontend = dvb_attach(lgdt3306a_attach, + &hauppauge_955q_lgdt3306a_config, + tuner_i2c + ); + + if (dev->dvb->frontend == NULL) { + dev_err(dev->dev, + "Failed to attach LGDT3306A frontend.\n"); + result = -EINVAL; + goto out_free; + } + + dev->dvb->frontend->ops.i2c_gate_ctrl = NULL; + + /* define general-purpose callback pointer */ + dvb->frontend->callback = cx231xx_tuner_callback; + + /* attach tuner */ + memset(&si2157_config, 0, sizeof(si2157_config)); + si2157_config.fe = dev->dvb->frontend; + si2157_config.inversion = true; + strlcpy(info.type, "si2157", I2C_NAME_SIZE); + info.addr = 0x60; + info.platform_data = &si2157_config; + request_module("si2157"); + client = i2c_new_device( + tuner_i2c, + &info); + if (client == NULL || client->dev.driver == NULL) { + dvb_frontend_detach(dev->dvb->frontend); + result = -ENODEV; + goto out_free; + } + + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + dvb_frontend_detach(dev->dvb->frontend); + result = -ENODEV; + goto out_free; + } + + dev->cx231xx_reset_analog_tuner = NULL; + + dev->dvb->i2c_client_tuner = client; + break; + } case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID: case CX231XX_BOARD_KWORLD_UB430_USB_HYBRID: diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index ecea76fe07f6..c261e160c158 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -100,6 +100,75 @@ static struct cx231xx_fmt format[] = { }; +static int cx231xx_enable_analog_tuner(struct cx231xx *dev) +{ +#ifdef CONFIG_MEDIA_CONTROLLER + struct media_device *mdev = dev->media_dev; + struct media_entity *entity, *decoder = NULL, *source; + struct media_link *link, *found_link = NULL; + int i, ret, active_links = 0; + + if (!mdev) + return 0; + + /* + * This will find the tuner that is connected into the decoder. + * Technically, this is not 100% correct, as the device may be + * using an analog input instead of the tuner. However, as we can't + * do DVB streaming while the DMA engine is being used for V4L2, + * this should be enough for the actual needs. + */ + media_device_for_each_entity(entity, mdev) { + if (entity->type == MEDIA_ENT_T_V4L2_SUBDEV_DECODER) { + decoder = entity; + break; + } + } + if (!decoder) + return 0; + + for (i = 0; i < decoder->num_links; i++) { + link = &decoder->links[i]; + if (link->sink->entity == decoder) { + found_link = link; + if (link->flags & MEDIA_LNK_FL_ENABLED) + active_links++; + break; + } + } + + if (active_links == 1 || !found_link) + return 0; + + source = found_link->source->entity; + for (i = 0; i < source->num_links; i++) { + struct media_entity *sink; + int flags = 0; + + link = &source->links[i]; + sink = link->sink->entity; + + if (sink == entity) + flags = MEDIA_LNK_FL_ENABLED; + + ret = media_entity_setup_link(link, flags); + if (ret) { + dev_err(dev->dev, + "Couldn't change link %s->%s to %s. Error %d\n", + source->name, sink->name, + flags ? "enabled" : "disabled", + ret); + return ret; + } else + dev_dbg(dev->dev, + "link %s->%s was %s\n", + source->name, sink->name, + flags ? "ENABLED" : "disabled"); + } +#endif + return 0; +} + /* ------------------------------------------------------------------ Video buffer and parser functions ------------------------------------------------------------------*/ @@ -667,6 +736,9 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) if (*count < CX231XX_MIN_BUF) *count = CX231XX_MIN_BUF; + + cx231xx_enable_analog_tuner(dev); + return 0; } @@ -756,6 +828,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, } buf->vb.state = VIDEOBUF_PREPARED; + return 0; fail: @@ -1056,7 +1129,7 @@ int cx231xx_enum_input(struct file *file, void *priv, (CX231XX_VMUX_CABLE == INPUT(n)->type)) i->type = V4L2_INPUT_TYPE_TUNER; - i->std = dev->vdev->tvnorms; + i->std = dev->vdev.tvnorms; /* If they are asking about the active input, read signal status */ if (n == dev->video_input) { @@ -1451,7 +1524,7 @@ int cx231xx_querycap(struct file *file, void *priv, cap->capabilities = cap->device_caps | V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS; - if (dev->radio_dev) + if (video_is_registered(&dev->radio_dev)) cap->capabilities |= V4L2_CAP_RADIO; return 0; @@ -1729,34 +1802,21 @@ void cx231xx_release_analog_resources(struct cx231xx *dev) /*FIXME: I2C IR should be disconnected */ - if (dev->radio_dev) { - if (video_is_registered(dev->radio_dev)) - video_unregister_device(dev->radio_dev); - else - video_device_release(dev->radio_dev); - dev->radio_dev = NULL; - } - if (dev->vbi_dev) { + if (video_is_registered(&dev->radio_dev)) + video_unregister_device(&dev->radio_dev); + if (video_is_registered(&dev->vbi_dev)) { dev_info(dev->dev, "V4L2 device %s deregistered\n", - video_device_node_name(dev->vbi_dev)); - if (video_is_registered(dev->vbi_dev)) - video_unregister_device(dev->vbi_dev); - else - video_device_release(dev->vbi_dev); - dev->vbi_dev = NULL; + video_device_node_name(&dev->vbi_dev)); + video_unregister_device(&dev->vbi_dev); } - if (dev->vdev) { + if (video_is_registered(&dev->vdev)) { dev_info(dev->dev, "V4L2 device %s deregistered\n", - video_device_node_name(dev->vdev)); + video_device_node_name(&dev->vdev)); if (dev->board.has_417) cx231xx_417_unregister(dev); - if (video_is_registered(dev->vdev)) - video_unregister_device(dev->vdev); - else - video_device_release(dev->vdev); - dev->vdev = NULL; + video_unregister_device(&dev->vdev); } v4l2_ctrl_handler_free(&dev->ctrl_handler); v4l2_ctrl_handler_free(&dev->radio_ctrl_handler); @@ -2013,7 +2073,7 @@ static struct video_device cx231xx_vbi_template; static const struct video_device cx231xx_video_template = { .fops = &cx231xx_v4l_fops, - .release = video_device_release, + .release = video_device_release_empty, .ioctl_ops = &video_ioctl_ops, .tvnorms = V4L2_STD_ALL, }; @@ -2049,19 +2109,14 @@ static struct video_device cx231xx_radio_template = { /******************************** usb interface ******************************/ -static struct video_device *cx231xx_vdev_init(struct cx231xx *dev, - const struct video_device - *template, const char *type_name) +static void cx231xx_vdev_init(struct cx231xx *dev, + struct video_device *vfd, + const struct video_device *template, + const char *type_name) { - struct video_device *vfd; - - vfd = video_device_alloc(); - if (NULL == vfd) - return NULL; - *vfd = *template; vfd->v4l2_dev = &dev->v4l2_dev; - vfd->release = video_device_release; + vfd->release = video_device_release_empty; vfd->lock = &dev->lock; snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name); @@ -2073,7 +2128,6 @@ static struct video_device *cx231xx_vdev_init(struct cx231xx *dev, v4l2_disable_ioctl(vfd, VIDIOC_G_TUNER); v4l2_disable_ioctl(vfd, VIDIOC_S_TUNER); } - return vfd; } int cx231xx_register_analog_devices(struct cx231xx *dev) @@ -2116,15 +2170,16 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) /* write code here... */ /* allocate and fill video video_device struct */ - dev->vdev = cx231xx_vdev_init(dev, &cx231xx_video_template, "video"); - if (!dev->vdev) { - dev_err(dev->dev, "cannot allocate video_device.\n"); - return -ENODEV; - } - - dev->vdev->ctrl_handler = &dev->ctrl_handler; + cx231xx_vdev_init(dev, &dev->vdev, &cx231xx_video_template, "video"); +#if defined(CONFIG_MEDIA_CONTROLLER) + dev->video_pad.flags = MEDIA_PAD_FL_SINK; + ret = media_entity_init(&dev->vdev.entity, 1, &dev->video_pad, 0); + if (ret < 0) + dev_err(dev->dev, "failed to initialize video media entity!\n"); +#endif + dev->vdev.ctrl_handler = &dev->ctrl_handler; /* register v4l2 video video_device */ - ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER, + ret = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, video_nr[dev->devno]); if (ret) { dev_err(dev->dev, @@ -2134,22 +2189,24 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) } dev_info(dev->dev, "Registered video device %s [v4l2]\n", - video_device_node_name(dev->vdev)); + video_device_node_name(&dev->vdev)); /* Initialize VBI template */ cx231xx_vbi_template = cx231xx_video_template; strcpy(cx231xx_vbi_template.name, "cx231xx-vbi"); /* Allocate and fill vbi video_device struct */ - dev->vbi_dev = cx231xx_vdev_init(dev, &cx231xx_vbi_template, "vbi"); + cx231xx_vdev_init(dev, &dev->vbi_dev, &cx231xx_vbi_template, "vbi"); - if (!dev->vbi_dev) { - dev_err(dev->dev, "cannot allocate video_device.\n"); - return -ENODEV; - } - dev->vbi_dev->ctrl_handler = &dev->ctrl_handler; +#if defined(CONFIG_MEDIA_CONTROLLER) + dev->vbi_pad.flags = MEDIA_PAD_FL_SINK; + ret = media_entity_init(&dev->vbi_dev.entity, 1, &dev->vbi_pad, 0); + if (ret < 0) + dev_err(dev->dev, "failed to initialize vbi media entity!\n"); +#endif + dev->vbi_dev.ctrl_handler = &dev->ctrl_handler; /* register v4l2 vbi video_device */ - ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, + ret = video_register_device(&dev->vbi_dev, VFL_TYPE_VBI, vbi_nr[dev->devno]); if (ret < 0) { dev_err(dev->dev, "unable to register vbi device\n"); @@ -2157,18 +2214,13 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) } dev_info(dev->dev, "Registered VBI device %s\n", - video_device_node_name(dev->vbi_dev)); + video_device_node_name(&dev->vbi_dev)); if (cx231xx_boards[dev->model].radio.type == CX231XX_RADIO) { - dev->radio_dev = cx231xx_vdev_init(dev, &cx231xx_radio_template, - "radio"); - if (!dev->radio_dev) { - dev_err(dev->dev, - "cannot allocate video_device.\n"); - return -ENODEV; - } - dev->radio_dev->ctrl_handler = &dev->radio_ctrl_handler; - ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, + cx231xx_vdev_init(dev, &dev->radio_dev, + &cx231xx_radio_template, "radio"); + dev->radio_dev.ctrl_handler = &dev->radio_ctrl_handler; + ret = video_register_device(&dev->radio_dev, VFL_TYPE_RADIO, radio_nr[dev->devno]); if (ret < 0) { dev_err(dev->dev, @@ -2176,7 +2228,7 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) return ret; } dev_info(dev->dev, "Registered radio device as %s\n", - video_device_node_name(dev->radio_dev)); + video_device_node_name(&dev->radio_dev)); } return 0; diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index 6d6f3ee812f6..00d3bce9a690 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -76,6 +76,7 @@ #define CX231XX_BOARD_KWORLD_UB445_USB_HYBRID 18 #define CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx 19 #define CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx 20 +#define CX231XX_BOARD_HAUPPAUGE_955Q 21 /* Limits minimum and default number of buffers */ #define CX231XX_MIN_BUF 4 @@ -633,7 +634,7 @@ struct cx231xx { /* video for linux */ int users; /* user count for exclusive use */ - struct video_device *vdev; /* video for linux device struct */ + struct video_device vdev; /* video for linux device struct */ v4l2_std_id norm; /* selected tv norm */ int ctl_freq; /* selected frequency */ unsigned int ctl_ainput; /* selected audio input */ @@ -655,8 +656,13 @@ struct cx231xx { struct mutex ctrl_urb_lock; /* protects urb_buf */ struct list_head inqueue, outqueue; wait_queue_head_t open, wait_frame, wait_stream; - struct video_device *vbi_dev; - struct video_device *radio_dev; + struct video_device vbi_dev; + struct video_device radio_dev; + +#if defined(CONFIG_MEDIA_CONTROLLER) + struct media_device *media_dev; + struct media_pad video_pad, vbi_pad; +#endif unsigned char eedata[256]; @@ -718,7 +724,7 @@ struct cx231xx { u8 USE_ISO; struct cx231xx_tvnorm encodernorm; struct cx231xx_tsport ts1, ts2; - struct video_device *v4l_device; + struct video_device v4l_device; atomic_t v4l_reader_count; u32 freq; unsigned int input; @@ -972,8 +978,11 @@ extern void cx231xx_417_unregister(struct cx231xx *dev); int cx231xx_ir_init(struct cx231xx *dev); void cx231xx_ir_exit(struct cx231xx *dev); #else -#define cx231xx_ir_init(dev) (0) -#define cx231xx_ir_exit(dev) (0) +static inline int cx231xx_ir_init(struct cx231xx *dev) +{ + return 0; +} +static inline void cx231xx_ir_exit(struct cx231xx *dev) {} #endif static inline unsigned int norm_maxw(struct cx231xx *dev) diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig index 0982e734fab5..9facc92c8dea 100644 --- a/drivers/media/usb/dvb-usb-v2/Kconfig +++ b/drivers/media/usb/dvb-usb-v2/Kconfig @@ -146,7 +146,7 @@ config DVB_USB_DVBSKY depends on DVB_USB_V2 select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TS2020 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT select DVB_SP2 if MEDIA_SUBDRV_AUTOSELECT help diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h index 41c6363dff08..023d91f7e654 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb.h +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb.h @@ -25,6 +25,7 @@ #include <linux/usb/input.h> #include <linux/firmware.h> #include <media/rc-core.h> +#include <media/media-device.h> #include "dvb_frontend.h" #include "dvb_demux.h" diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c index 9913e0f59485..f5df9eaba04f 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c @@ -400,10 +400,61 @@ skip_feed_stop: return ret; } +static void dvb_usbv2_media_device_register(struct dvb_usb_adapter *adap) +{ +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + struct media_device *mdev; + struct dvb_usb_device *d = adap_to_d(adap); + struct usb_device *udev = d->udev; + int ret; + + mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); + if (!mdev) + return; + + mdev->dev = &udev->dev; + strlcpy(mdev->model, d->name, sizeof(mdev->model)); + if (udev->serial) + strlcpy(mdev->serial, udev->serial, sizeof(mdev->serial)); + strcpy(mdev->bus_info, udev->devpath); + mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice); + mdev->driver_version = LINUX_VERSION_CODE; + + ret = media_device_register(mdev); + if (ret) { + dev_err(&d->udev->dev, + "Couldn't create a media device. Error: %d\n", + ret); + kfree(mdev); + return; + } + + dvb_register_media_controller(&adap->dvb_adap, mdev); + + dev_info(&d->udev->dev, "media controller created\n"); + +#endif +} + +static void dvb_usbv2_media_device_unregister(struct dvb_usb_adapter *adap) +{ +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + + if (!adap->dvb_adap.mdev) + return; + + media_device_unregister(adap->dvb_adap.mdev); + kfree(adap->dvb_adap.mdev); + adap->dvb_adap.mdev = NULL; + +#endif +} + static int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) { int ret; struct dvb_usb_device *d = adap_to_d(adap); + dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, adap->id); ret = dvb_register_adapter(&adap->dvb_adap, d->name, d->props->owner, @@ -416,6 +467,8 @@ static int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) adap->dvb_adap.priv = adap; + dvb_usbv2_media_device_register(adap); + if (d->props->read_mac_address) { ret = d->props->read_mac_address(adap, adap->dvb_adap.proposed_mac); @@ -464,6 +517,7 @@ err_dvb_net_init: err_dvb_dmxdev_init: dvb_dmx_release(&adap->demux); err_dvb_dmx_init: + dvb_usbv2_media_device_unregister(adap); dvb_unregister_adapter(&adap->dvb_adap); err_dvb_register_adapter: adap->dvb_adap.priv = NULL; @@ -480,6 +534,7 @@ static int dvb_usbv2_adapter_dvb_exit(struct dvb_usb_adapter *adap) adap->demux.dmx.close(&adap->demux.dmx); dvb_dmxdev_release(&adap->dmxdev); dvb_dmx_release(&adap->demux); + dvb_usbv2_media_device_unregister(adap); dvb_unregister_adapter(&adap->dvb_adap); } @@ -643,6 +698,8 @@ static int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) } } + dvb_create_media_graph(&adap->dvb_adap); + return 0; err_dvb_unregister_frontend: @@ -955,6 +1012,7 @@ void dvb_usbv2_disconnect(struct usb_interface *intf) struct dvb_usb_device *d = usb_get_intfdata(intf); const char *name = d->name; struct device dev = d->udev->dev; + dev_dbg(&d->udev->dev, "%s: bInterfaceNumber=%d\n", __func__, intf->cur_altsetting->desc.bInterfaceNumber); diff --git a/drivers/media/usb/dvb-usb-v2/dvbsky.c b/drivers/media/usb/dvb-usb-v2/dvbsky.c index 9b5add4499e3..cdf59bcd760c 100644 --- a/drivers/media/usb/dvb-usb-v2/dvbsky.c +++ b/drivers/media/usb/dvb-usb-v2/dvbsky.c @@ -20,7 +20,7 @@ #include "dvb_usb.h" #include "m88ds3103.h" -#include "m88ts2022.h" +#include "ts2020.h" #include "sp2.h" #include "si2168.h" #include "si2157.h" @@ -315,9 +315,7 @@ static int dvbsky_s960_attach(struct dvb_usb_adapter *adap) struct i2c_adapter *i2c_adapter; struct i2c_client *client; struct i2c_board_info info; - struct m88ts2022_config m88ts2022_config = { - .clock = 27000000, - }; + struct ts2020_config ts2020_config = {}; memset(&info, 0, sizeof(struct i2c_board_info)); /* attach demod */ @@ -332,11 +330,11 @@ static int dvbsky_s960_attach(struct dvb_usb_adapter *adap) } /* attach tuner */ - m88ts2022_config.fe = adap->fe[0]; - strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE); + ts2020_config.fe = adap->fe[0]; + strlcpy(info.type, "ts2020", I2C_NAME_SIZE); info.addr = 0x60; - info.platform_data = &m88ts2022_config; - request_module("m88ts2022"); + info.platform_data = &ts2020_config; + request_module("ts2020"); client = i2c_new_device(i2c_adapter, &info); if (client == NULL || client->dev.driver == NULL) { dvb_frontend_detach(adap->fe[0]); @@ -439,9 +437,7 @@ static int dvbsky_s960c_attach(struct dvb_usb_adapter *adap) struct i2c_client *client_tuner, *client_ci; struct i2c_board_info info; struct sp2_config sp2_config; - struct m88ts2022_config m88ts2022_config = { - .clock = 27000000, - }; + struct ts2020_config ts2020_config = {}; memset(&info, 0, sizeof(struct i2c_board_info)); /* attach demod */ @@ -456,11 +452,11 @@ static int dvbsky_s960c_attach(struct dvb_usb_adapter *adap) } /* attach tuner */ - m88ts2022_config.fe = adap->fe[0]; - strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE); + ts2020_config.fe = adap->fe[0]; + strlcpy(info.type, "ts2020", I2C_NAME_SIZE); info.addr = 0x60; - info.platform_data = &m88ts2022_config; - request_module("m88ts2022"); + info.platform_data = &ts2020_config; + request_module("ts2020"); client_tuner = i2c_new_device(i2c_adapter, &info); if (client_tuner == NULL || client_tuner->dev.driver == NULL) { ret = -ENODEV; diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index 87fc0fe29ebd..895441fe90f7 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -866,6 +866,8 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap) mn88472_config.i2c_wr_max = 22, strlcpy(info.type, "mn88472", I2C_NAME_SIZE); mn88472_config.xtal = 20500000; + mn88472_config.ts_mode = SERIAL_TS_MODE; + mn88472_config.ts_clock = VARIABLE_TS_CLOCK; info.addr = 0x18; info.platform_data = &mn88472_config; request_module(info.type); @@ -1609,7 +1611,7 @@ static int rtl2832u_get_rc_config(struct dvb_usb_device *d, rc->allowed_protos = RC_BIT_ALL; rc->driver_type = RC_DRIVER_IR_RAW; rc->query = rtl2832u_rc_query; - rc->interval = 400; + rc->interval = 200; return 0; } @@ -1724,6 +1726,8 @@ static const struct usb_device_id rtl28xxu_id_table[] = { &rtl28xxu_props, "DigitalNow Quad DVB-T Receiver", NULL) }, { DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_MINID, &rtl28xxu_props, "Leadtek Winfast DTV Dongle Mini D", NULL) }, + { DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS_PLUS, + &rtl28xxu_props, "Leadtek WinFast DTV2000DS Plus", RC_MAP_LEADTEK_Y04G0051) }, { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00d3, &rtl28xxu_props, "TerraTec Cinergy T Stick RC (Rev. 3)", NULL) }, { DVB_USB_DEVICE(USB_VID_DEXATEK, 0x1102, @@ -1754,6 +1758,8 @@ static const struct usb_device_id rtl28xxu_id_table[] = { &rtl28xxu_props, "Sveon STV21", NULL) }, { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV27, &rtl28xxu_props, "Sveon STV27", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TURBOX_DTT_2000, + &rtl28xxu_props, "TURBO-X Pure TV Tuner DTT-2000", NULL) }, /* RTL2832P devices: */ { DVB_USB_DEVICE(USB_VID_HANFTEK, 0x0131, diff --git a/drivers/media/usb/dvb-usb/Kconfig b/drivers/media/usb/dvb-usb/Kconfig index 3364200db093..128eee61570d 100644 --- a/drivers/media/usb/dvb-usb/Kconfig +++ b/drivers/media/usb/dvb-usb/Kconfig @@ -278,9 +278,10 @@ config DVB_USB_DW2102 select DVB_STV6110 if MEDIA_SUBDRV_AUTOSELECT select DVB_STV0900 if MEDIA_SUBDRV_AUTOSELECT select DVB_M88RS2000 if MEDIA_SUBDRV_AUTOSELECT + select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT help - Say Y here to support the DvbWorld, TeVii, Prof DVB-S/S2 USB2.0 - receivers. + Say Y here to support the DvbWorld, TeVii, Prof, TechnoTrend + DVB-S/S2 USB2.0 receivers. config DVB_USB_CINERGY_T2 tristate "Terratec CinergyT2/qanu USB 2.0 DVB-T receiver" diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c index f327c49d7e09..ffc3704abded 100644 --- a/drivers/media/usb/dvb-usb/cxusb.c +++ b/drivers/media/usb/dvb-usb/cxusb.c @@ -1516,28 +1516,95 @@ static void cxusb_disconnect(struct usb_interface *intf) dvb_usb_device_exit(intf); } -static struct usb_device_id cxusb_table [] = { - { USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_COLD) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_WARM) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_COLD) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_COLD) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_WARM) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_COLD) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_WARM) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) }, - { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R) }, - { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2) }, - { USB_DEVICE(USB_VID_CONEXANT, USB_PID_CONEXANT_D680_DMB) }, - { USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_D689) }, - { USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230) }, +enum cxusb_table_index { + MEDION_MD95700, + DVICO_BLUEBIRD_LG064F_COLD, + DVICO_BLUEBIRD_LG064F_WARM, + DVICO_BLUEBIRD_DUAL_1_COLD, + DVICO_BLUEBIRD_DUAL_1_WARM, + DVICO_BLUEBIRD_LGZ201_COLD, + DVICO_BLUEBIRD_LGZ201_WARM, + DVICO_BLUEBIRD_TH7579_COLD, + DVICO_BLUEBIRD_TH7579_WARM, + DIGITALNOW_BLUEBIRD_DUAL_1_COLD, + DIGITALNOW_BLUEBIRD_DUAL_1_WARM, + DVICO_BLUEBIRD_DUAL_2_COLD, + DVICO_BLUEBIRD_DUAL_2_WARM, + DVICO_BLUEBIRD_DUAL_4, + DVICO_BLUEBIRD_DVB_T_NANO_2, + DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM, + AVERMEDIA_VOLAR_A868R, + DVICO_BLUEBIRD_DUAL_4_REV_2, + CONEXANT_D680_DMB, + MYGICA_D689, + MYGICA_T230, + NR__cxusb_table_index +}; + +static struct usb_device_id cxusb_table[NR__cxusb_table_index + 1] = { + [MEDION_MD95700] = { + USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) + }, + [DVICO_BLUEBIRD_LG064F_COLD] = { + USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_COLD) + }, + [DVICO_BLUEBIRD_LG064F_WARM] = { + USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_WARM) + }, + [DVICO_BLUEBIRD_DUAL_1_COLD] = { + USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_COLD) + }, + [DVICO_BLUEBIRD_DUAL_1_WARM] = { + USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM) + }, + [DVICO_BLUEBIRD_LGZ201_COLD] = { + USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_COLD) + }, + [DVICO_BLUEBIRD_LGZ201_WARM] = { + USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_WARM) + }, + [DVICO_BLUEBIRD_TH7579_COLD] = { + USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_COLD) + }, + [DVICO_BLUEBIRD_TH7579_WARM] = { + USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_WARM) + }, + [DIGITALNOW_BLUEBIRD_DUAL_1_COLD] = { + USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD) + }, + [DIGITALNOW_BLUEBIRD_DUAL_1_WARM] = { + USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM) + }, + [DVICO_BLUEBIRD_DUAL_2_COLD] = { + USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD) + }, + [DVICO_BLUEBIRD_DUAL_2_WARM] = { + USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM) + }, + [DVICO_BLUEBIRD_DUAL_4] = { + USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4) + }, + [DVICO_BLUEBIRD_DVB_T_NANO_2] = { + USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) + }, + [DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM] = { + USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) + }, + [AVERMEDIA_VOLAR_A868R] = { + USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R) + }, + [DVICO_BLUEBIRD_DUAL_4_REV_2] = { + USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2) + }, + [CONEXANT_D680_DMB] = { + USB_DEVICE(USB_VID_CONEXANT, USB_PID_CONEXANT_D680_DMB) + }, + [MYGICA_D689] = { + USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_D689) + }, + [MYGICA_T230] = { + USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230) + }, {} /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, cxusb_table); @@ -1581,7 +1648,7 @@ static struct dvb_usb_device_properties cxusb_medion_properties = { .devices = { { "Medion MD95700 (MDUSBTV-HYBRID)", { NULL }, - { &cxusb_table[0], NULL }, + { &cxusb_table[MEDION_MD95700], NULL }, }, } }; @@ -1637,8 +1704,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = { .num_device_descs = 1, .devices = { { "DViCO FusionHDTV5 USB Gold", - { &cxusb_table[1], NULL }, - { &cxusb_table[2], NULL }, + { &cxusb_table[DVICO_BLUEBIRD_LG064F_COLD], NULL }, + { &cxusb_table[DVICO_BLUEBIRD_LG064F_WARM], NULL }, }, } }; @@ -1693,16 +1760,16 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = { .num_device_descs = 3, .devices = { { "DViCO FusionHDTV DVB-T Dual USB", - { &cxusb_table[3], NULL }, - { &cxusb_table[4], NULL }, + { &cxusb_table[DVICO_BLUEBIRD_DUAL_1_COLD], NULL }, + { &cxusb_table[DVICO_BLUEBIRD_DUAL_1_WARM], NULL }, }, { "DigitalNow DVB-T Dual USB", - { &cxusb_table[9], NULL }, - { &cxusb_table[10], NULL }, + { &cxusb_table[DIGITALNOW_BLUEBIRD_DUAL_1_COLD], NULL }, + { &cxusb_table[DIGITALNOW_BLUEBIRD_DUAL_1_WARM], NULL }, }, { "DViCO FusionHDTV DVB-T Dual Digital 2", - { &cxusb_table[11], NULL }, - { &cxusb_table[12], NULL }, + { &cxusb_table[DVICO_BLUEBIRD_DUAL_2_COLD], NULL }, + { &cxusb_table[DVICO_BLUEBIRD_DUAL_2_WARM], NULL }, }, } }; @@ -1756,8 +1823,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = { .num_device_descs = 1, .devices = { { "DViCO FusionHDTV DVB-T USB (LGZ201)", - { &cxusb_table[5], NULL }, - { &cxusb_table[6], NULL }, + { &cxusb_table[DVICO_BLUEBIRD_LGZ201_COLD], NULL }, + { &cxusb_table[DVICO_BLUEBIRD_LGZ201_WARM], NULL }, }, } }; @@ -1812,8 +1879,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = { .num_device_descs = 1, .devices = { { "DViCO FusionHDTV DVB-T USB (TH7579)", - { &cxusb_table[7], NULL }, - { &cxusb_table[8], NULL }, + { &cxusb_table[DVICO_BLUEBIRD_TH7579_COLD], NULL }, + { &cxusb_table[DVICO_BLUEBIRD_TH7579_WARM], NULL }, }, } }; @@ -1865,7 +1932,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = { .devices = { { "DViCO FusionHDTV DVB-T Dual Digital 4", { NULL }, - { &cxusb_table[13], NULL }, + { &cxusb_table[DVICO_BLUEBIRD_DUAL_4], NULL }, }, } }; @@ -1918,7 +1985,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = { .devices = { { "DViCO FusionHDTV DVB-T NANO2", { NULL }, - { &cxusb_table[14], NULL }, + { &cxusb_table[DVICO_BLUEBIRD_DVB_T_NANO_2], NULL }, }, } }; @@ -1972,8 +2039,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_prope .num_device_descs = 1, .devices = { { "DViCO FusionHDTV DVB-T NANO2 w/o firmware", - { &cxusb_table[14], NULL }, - { &cxusb_table[15], NULL }, + { &cxusb_table[DVICO_BLUEBIRD_DVB_T_NANO_2], NULL }, + { &cxusb_table[DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM], NULL }, }, } }; @@ -2017,7 +2084,7 @@ static struct dvb_usb_device_properties cxusb_aver_a868r_properties = { .devices = { { "AVerMedia AVerTVHD Volar (A868R)", { NULL }, - { &cxusb_table[16], NULL }, + { &cxusb_table[AVERMEDIA_VOLAR_A868R], NULL }, }, } }; @@ -2071,7 +2138,7 @@ struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = { .devices = { { "DViCO FusionHDTV DVB-T Dual Digital 4 (rev 2)", { NULL }, - { &cxusb_table[17], NULL }, + { &cxusb_table[DVICO_BLUEBIRD_DUAL_4_REV_2], NULL }, }, } }; @@ -2125,7 +2192,7 @@ static struct dvb_usb_device_properties cxusb_d680_dmb_properties = { { "Conexant DMB-TH Stick", { NULL }, - { &cxusb_table[18], NULL }, + { &cxusb_table[CONEXANT_D680_DMB], NULL }, }, } }; @@ -2179,7 +2246,7 @@ static struct dvb_usb_device_properties cxusb_mygica_d689_properties = { { "Mygica D689 DMB-TH", { NULL }, - { &cxusb_table[19], NULL }, + { &cxusb_table[MYGICA_D689], NULL }, }, } }; @@ -2232,7 +2299,7 @@ static struct dvb_usb_device_properties cxusb_mygica_t230_properties = { { "Mygica T230 DVB-T/T2/C", { NULL }, - { &cxusb_table[20], NULL }, + { &cxusb_table[MYGICA_T230], NULL }, }, } }; diff --git a/drivers/media/usb/dvb-usb/dib0700_core.c b/drivers/media/usb/dvb-usb/dib0700_core.c index 50856dbf5496..2b40393836ff 100644 --- a/drivers/media/usb/dvb-usb/dib0700_core.c +++ b/drivers/media/usb/dvb-usb/dib0700_core.c @@ -651,9 +651,6 @@ out: return ret; } -/* Number of keypresses to ignore before start repeating */ -#define RC_REPEAT_DELAY_V1_20 10 - /* This is the structure of the RC response packet starting in firmware 1.20 */ struct dib0700_rc_response { u8 report_id; diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c index e1757b8f5f5d..d7d55a20e959 100644 --- a/drivers/media/usb/dvb-usb/dib0700_devices.c +++ b/drivers/media/usb/dvb-usb/dib0700_devices.c @@ -510,9 +510,6 @@ static int stk7700ph_tuner_attach(struct dvb_usb_adapter *adap) static u8 rc_request[] = { REQUEST_POLL_RC, 0 }; -/* Number of keypresses to ignore before start repeating */ -#define RC_REPEAT_DELAY 6 - /* * This function is used only when firmware is < 1.20 version. Newer * firmwares use bulk mode, with functions implemented at dib0700_core, diff --git a/drivers/media/usb/dvb-usb/dvb-usb-dvb.c b/drivers/media/usb/dvb-usb/dvb-usb-dvb.c index 719413b15f20..8a260c854653 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb-dvb.c +++ b/drivers/media/usb/dvb-usb/dvb-usb-dvb.c @@ -84,14 +84,61 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed) { - deb_ts("start pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid,dvbdmxfeed->type); - return dvb_usb_ctrl_feed(dvbdmxfeed,1); + deb_ts("start pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid, + dvbdmxfeed->type); + return dvb_usb_ctrl_feed(dvbdmxfeed, 1); } static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) { deb_ts("stop pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid, dvbdmxfeed->type); - return dvb_usb_ctrl_feed(dvbdmxfeed,0); + return dvb_usb_ctrl_feed(dvbdmxfeed, 0); +} + +static void dvb_usb_media_device_register(struct dvb_usb_adapter *adap) +{ +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + struct media_device *mdev; + struct dvb_usb_device *d = adap->dev; + struct usb_device *udev = d->udev; + int ret; + + mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); + if (!mdev) + return; + + mdev->dev = &udev->dev; + strlcpy(mdev->model, d->desc->name, sizeof(mdev->model)); + if (udev->serial) + strlcpy(mdev->serial, udev->serial, sizeof(mdev->serial)); + strcpy(mdev->bus_info, udev->devpath); + mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice); + mdev->driver_version = LINUX_VERSION_CODE; + + ret = media_device_register(mdev); + if (ret) { + dev_err(&d->udev->dev, + "Couldn't create a media device. Error: %d\n", + ret); + kfree(mdev); + return; + } + dvb_register_media_controller(&adap->dvb_adap, mdev); + + dev_info(&d->udev->dev, "media controller created\n"); +#endif +} + +static void dvb_usb_media_device_unregister(struct dvb_usb_adapter *adap) +{ +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + if (!adap->dvb_adap.mdev) + return; + + media_device_unregister(adap->dvb_adap.mdev); + kfree(adap->dvb_adap.mdev); + adap->dvb_adap.mdev = NULL; +#endif } int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums) @@ -107,9 +154,11 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums) } adap->dvb_adap.priv = adap; + dvb_usb_media_device_register(adap); + if (adap->dev->props.read_mac_address) { - if (adap->dev->props.read_mac_address(adap->dev,adap->dvb_adap.proposed_mac) == 0) - info("MAC address: %pM",adap->dvb_adap.proposed_mac); + if (adap->dev->props.read_mac_address(adap->dev, adap->dvb_adap.proposed_mac) == 0) + info("MAC address: %pM", adap->dvb_adap.proposed_mac); else err("MAC address reading failed."); } @@ -128,7 +177,7 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums) adap->demux.stop_feed = dvb_usb_stop_feed; adap->demux.write_to_decoder = NULL; if ((ret = dvb_dmx_init(&adap->demux)) < 0) { - err("dvb_dmx_init failed: error %d",ret); + err("dvb_dmx_init failed: error %d", ret); goto err_dmx; } @@ -136,13 +185,13 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums) adap->dmxdev.demux = &adap->demux.dmx; adap->dmxdev.capabilities = 0; if ((ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap)) < 0) { - err("dvb_dmxdev_init failed: error %d",ret); + err("dvb_dmxdev_init failed: error %d", ret); goto err_dmx_dev; } if ((ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx)) < 0) { - err("dvb_net_init failed: error %d",ret); + err("dvb_net_init failed: error %d", ret); goto err_net_init; } @@ -154,6 +203,7 @@ err_net_init: err_dmx_dev: dvb_dmx_release(&adap->demux); err_dmx: + dvb_usb_media_device_unregister(adap); dvb_unregister_adapter(&adap->dvb_adap); err: return ret; @@ -167,6 +217,7 @@ int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap) adap->demux.dmx.close(&adap->demux.dmx); dvb_dmxdev_release(&adap->dmxdev); dvb_dmx_release(&adap->demux); + dvb_usb_media_device_unregister(adap); dvb_unregister_adapter(&adap->dvb_adap); adap->state &= ~DVB_USB_ADAP_STATE_DVB; } @@ -268,6 +319,8 @@ int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) adap->num_frontends_initialized++; } + dvb_create_media_graph(&adap->dvb_adap); + return 0; } diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c index 1a3df10d6bad..f1f357f43ff0 100644 --- a/drivers/media/usb/dvb-usb/dw2102.c +++ b/drivers/media/usb/dvb-usb/dw2102.c @@ -2,7 +2,8 @@ * DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101, * TeVii S600, S630, S650, S660, S480, S421, S632 * Prof 1100, 7500, - * Geniatech SU3000, T220 Cards + * Geniatech SU3000, T220, + * TechnoTrend S2-4600 Cards * Copyright (C) 2008-2012 Igor M. Liplianin (liplianin@me.by) * * This program is free software; you can redistribute it and/or modify it @@ -31,6 +32,8 @@ #include "m88rs2000.h" #include "tda18271.h" #include "cxd2820r.h" +#include "m88ds3103.h" +#include "ts2020.h" /* Max transfer size done by I2C transfer functions */ #define MAX_XFER_SIZE 64 @@ -112,11 +115,9 @@ "Please see linux/Documentation/dvb/ for more details " \ "on firmware-problems." -struct su3000_state { +struct dw2102_state { u8 initialized; -}; - -struct s6x0_state { + struct i2c_client *i2c_client_tuner; int (*old_set_voltage)(struct dvb_frontend *f, fe_sec_voltage_t v); }; @@ -887,7 +888,7 @@ static int su3000_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) static int su3000_power_ctrl(struct dvb_usb_device *d, int i) { - struct su3000_state *state = (struct su3000_state *)d->priv; + struct dw2102_state *state = (struct dw2102_state *)d->priv; u8 obuf[] = {0xde, 0}; info("%s: %d, initialized %d\n", __func__, i, state->initialized); @@ -973,7 +974,7 @@ static int s660_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) { struct dvb_usb_adapter *d = (struct dvb_usb_adapter *)(fe->dvb->priv); - struct s6x0_state *st = (struct s6x0_state *)d->dev->priv; + struct dw2102_state *st = (struct dw2102_state *)d->dev->priv; dw210x_set_voltage(fe, voltage); if (st->old_set_voltage) @@ -1117,6 +1118,22 @@ static struct tda18271_config tda18271_config = { .gate = TDA18271_GATE_DIGITAL, }; +static const struct m88ds3103_config tt_s2_4600_m88ds3103_config = { + .i2c_addr = 0x68, + .clock = 27000000, + .i2c_wr_max = 33, + .ts_mode = M88DS3103_TS_CI, + .ts_clk = 16000, + .ts_clk_pol = 0, + .spec_inv = 0, + .agc_inv = 0, + .clock_out = M88DS3103_CLOCK_OUT_ENABLED, + .envelope_mode = 0, + .agc = 0x99, + .lnb_hv_pol = 1, + .lnb_en_pol = 0, +}; + static u8 m88rs2000_inittab[] = { DEMOD_WRITE, 0x9a, 0x30, DEMOD_WRITE, 0x00, 0x01, @@ -1295,7 +1312,7 @@ static int stv0288_frontend_attach(struct dvb_usb_adapter *d) static int ds3000_frontend_attach(struct dvb_usb_adapter *d) { - struct s6x0_state *st = (struct s6x0_state *)d->dev->priv; + struct dw2102_state *st = d->dev->priv; u8 obuf[] = {7, 1}; d->fe_adap[0].fe = dvb_attach(ds3000_attach, &s660_ds3000_config, @@ -1461,6 +1478,84 @@ static int m88rs2000_frontend_attach(struct dvb_usb_adapter *d) return -EIO; } +static int tt_s2_4600_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *d = adap->dev; + struct dw2102_state *state = d->priv; + u8 obuf[3] = { 0xe, 0x80, 0 }; + u8 ibuf[] = { 0 }; + struct i2c_adapter *i2c_adapter; + struct i2c_client *client; + struct i2c_board_info info; + struct ts2020_config ts2020_config = {}; + + if (dvb_usb_generic_rw(d, obuf, 3, ibuf, 1, 0) < 0) + err("command 0x0e transfer failed."); + + obuf[0] = 0xe; + obuf[1] = 0x02; + obuf[2] = 1; + + if (dvb_usb_generic_rw(d, obuf, 3, ibuf, 1, 0) < 0) + err("command 0x0e transfer failed."); + msleep(300); + + obuf[0] = 0xe; + obuf[1] = 0x83; + obuf[2] = 0; + + if (dvb_usb_generic_rw(d, obuf, 3, ibuf, 1, 0) < 0) + err("command 0x0e transfer failed."); + + obuf[0] = 0xe; + obuf[1] = 0x83; + obuf[2] = 1; + + if (dvb_usb_generic_rw(d, obuf, 3, ibuf, 1, 0) < 0) + err("command 0x0e transfer failed."); + + obuf[0] = 0x51; + + if (dvb_usb_generic_rw(d, obuf, 1, ibuf, 1, 0) < 0) + err("command 0x51 transfer failed."); + + memset(&info, 0, sizeof(struct i2c_board_info)); + + adap->fe_adap[0].fe = dvb_attach(m88ds3103_attach, + &tt_s2_4600_m88ds3103_config, + &d->i2c_adap, + &i2c_adapter); + if (adap->fe_adap[0].fe == NULL) + return -ENODEV; + + /* attach tuner */ + ts2020_config.fe = adap->fe_adap[0].fe; + strlcpy(info.type, "ts2022", I2C_NAME_SIZE); + info.addr = 0x60; + info.platform_data = &ts2020_config; + request_module("ts2020"); + client = i2c_new_device(i2c_adapter, &info); + + if (client == NULL || client->dev.driver == NULL) { + dvb_frontend_detach(adap->fe_adap[0].fe); + return -ENODEV; + } + + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + dvb_frontend_detach(adap->fe_adap[0].fe); + return -ENODEV; + } + + /* delegate signal strength measurement to tuner */ + adap->fe_adap[0].fe->ops.read_signal_strength = + adap->fe_adap[0].fe->ops.tuner_ops.get_rf_strength; + + state->i2c_client_tuner = client; + + return 0; +} + static int dw2102_tuner_attach(struct dvb_usb_adapter *adap) { dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60, @@ -1561,6 +1656,7 @@ enum dw2102_table_entry { TERRATEC_CINERGY_S2_R2, GOTVIEW_SAT_HD, GENIATECH_T220, + TECHNOTREND_S2_4600, }; static struct usb_device_id dw2102_table[] = { @@ -1584,6 +1680,8 @@ static struct usb_device_id dw2102_table[] = { [TERRATEC_CINERGY_S2_R2] = {USB_DEVICE(USB_VID_TERRATEC, 0x00b0)}, [GOTVIEW_SAT_HD] = {USB_DEVICE(0x1FE1, USB_PID_GOTVIEW_SAT_HD)}, [GENIATECH_T220] = {USB_DEVICE(0x1f4d, 0xD220)}, + [TECHNOTREND_S2_4600] = {USB_DEVICE(USB_VID_TECHNOTREND, + USB_PID_TECHNOTREND_CONNECT_S2_4600)}, { } }; @@ -1857,7 +1955,7 @@ static struct dvb_usb_device_properties dw3101_properties = { static struct dvb_usb_device_properties s6x0_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = DEVICE_SPECIFIC, - .size_of_priv = sizeof(struct s6x0_state), + .size_of_priv = sizeof(struct dw2102_state), .firmware = S630_FIRMWARE, .no_reconnect = 1, @@ -1950,7 +2048,7 @@ static struct dvb_usb_device_description d632 = { static struct dvb_usb_device_properties su3000_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = DEVICE_SPECIFIC, - .size_of_priv = sizeof(struct su3000_state), + .size_of_priv = sizeof(struct dw2102_state), .power_ctrl = su3000_power_ctrl, .num_adapters = 1, .identify_state = su3000_identify_state, @@ -2015,7 +2113,7 @@ static struct dvb_usb_device_properties su3000_properties = { static struct dvb_usb_device_properties t220_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = DEVICE_SPECIFIC, - .size_of_priv = sizeof(struct su3000_state), + .size_of_priv = sizeof(struct dw2102_state), .power_ctrl = su3000_power_ctrl, .num_adapters = 1, .identify_state = su3000_identify_state, @@ -2061,6 +2159,55 @@ static struct dvb_usb_device_properties t220_properties = { } }; +static struct dvb_usb_device_properties tt_s2_4600_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = DEVICE_SPECIFIC, + .size_of_priv = sizeof(struct dw2102_state), + .power_ctrl = su3000_power_ctrl, + .num_adapters = 1, + .identify_state = su3000_identify_state, + .i2c_algo = &su3000_i2c_algo, + + .rc.core = { + .rc_interval = 250, + .rc_codes = RC_MAP_TT_1500, + .module_name = "dw2102", + .allowed_protos = RC_BIT_RC5, + .rc_query = su3000_rc_query, + }, + + .read_mac_address = su3000_read_mac_address, + + .generic_bulk_ctrl_endpoint = 0x01, + + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .streaming_ctrl = su3000_streaming_ctrl, + .frontend_attach = tt_s2_4600_frontend_attach, + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 4096, + } + } + } + } }, + } + }, + .num_device_descs = 1, + .devices = { + { "TechnoTrend TT-connect S2-4600", + { &dw2102_table[TECHNOTREND_S2_4600], NULL }, + { NULL }, + }, + } +}; + static int dw2102_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -2135,16 +2282,34 @@ static int dw2102_probe(struct usb_interface *intf, 0 == dvb_usb_device_init(intf, &su3000_properties, THIS_MODULE, NULL, adapter_nr) || 0 == dvb_usb_device_init(intf, &t220_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &tt_s2_4600_properties, THIS_MODULE, NULL, adapter_nr)) return 0; return -ENODEV; } +static void dw2102_disconnect(struct usb_interface *intf) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + struct dw2102_state *st = (struct dw2102_state *)d->priv; + struct i2c_client *client; + + /* remove I2C client for tuner */ + client = st->i2c_client_tuner; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + + dvb_usb_device_exit(intf); +} + static struct usb_driver dw2102_driver = { .name = "dw2102", .probe = dw2102_probe, - .disconnect = dvb_usb_device_exit, + .disconnect = dw2102_disconnect, .id_table = dw2102_table, }; @@ -2155,7 +2320,8 @@ MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104," " DVB-C 3101 USB2.0," " TeVii S600, S630, S650, S660, S480, S421, S632" " Prof 1100, 7500 USB2.0," - " Geniatech SU3000, T220 devices"); + " Geniatech SU3000, T220," + " TechnoTrend S2-4600 devices"); MODULE_VERSION("0.1"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(DW2101_FIRMWARE); diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig index f5d7198753c7..e382210c4ada 100644 --- a/drivers/media/usb/em28xx/Kconfig +++ b/drivers/media/usb/em28xx/Kconfig @@ -55,7 +55,7 @@ config VIDEO_EM28XX_DVB select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT + select DVB_TS2020 if MEDIA_SUBDRV_AUTOSELECT select DVB_DRX39XYJ if MEDIA_SUBDRV_AUTOSELECT select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index 7be661f73930..a4b22c2c3ba7 100644 --- a/drivers/media/usb/em28xx/em28xx-camera.c +++ b/drivers/media/usb/em28xx/em28xx-camera.c @@ -330,7 +330,7 @@ int em28xx_init_camera(struct em28xx *dev) v4l2_clk_name_i2c(clk_name, sizeof(clk_name), i2c_adapter_id(adap), client->addr); - v4l2->clk = v4l2_clk_register_fixed(clk_name, "mclk", -EINVAL); + v4l2->clk = v4l2_clk_register_fixed(clk_name, -EINVAL); if (IS_ERR(v4l2->clk)) return PTR_ERR(v4l2->clk); diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index d9704e66b8c9..394004607059 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -1157,6 +1157,15 @@ struct em28xx_board em28xx_boards[] = { .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, }, + [EM2884_BOARD_ELGATO_EYETV_HYBRID_2008] = { + .name = "Elgato EyeTV Hybrid 2008 INT", + .has_dvb = 1, + .ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS, + .tuner_type = TUNER_ABSENT, + .def_i2c_bus = 1, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_400_KHZ, + }, [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = { .name = "Hauppauge WinTV HVR 900", .tda9887_conf = TDA9887_PRESENT, @@ -2378,8 +2387,10 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM2860_BOARD_TERRATEC_GRABBY }, { USB_DEVICE(0x0ccd, 0x00b2), .driver_info = EM2884_BOARD_CINERGY_HTC_STICK }, + { USB_DEVICE(0x0fd9, 0x0018), + .driver_info = EM2884_BOARD_ELGATO_EYETV_HYBRID_2008 }, { USB_DEVICE(0x0fd9, 0x0033), - .driver_info = EM2860_BOARD_ELGATO_VIDEO_CAPTURE}, + .driver_info = EM2860_BOARD_ELGATO_VIDEO_CAPTURE }, { USB_DEVICE(0x185b, 0x2870), .driver_info = EM2870_BOARD_COMPRO_VIDEOMATE }, { USB_DEVICE(0x185b, 0x2041), diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index aee70d483264..a5b22c5a240c 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -54,7 +54,7 @@ #include "qt1010.h" #include "mb86a20s.h" #include "m88ds3103.h" -#include "m88ts2022.h" +#include "ts2020.h" #include "si2168.h" #include "si2157.h" @@ -1380,6 +1380,7 @@ static int em28xx_dvb_init(struct em28xx *dev) } } break; + case EM2884_BOARD_ELGATO_EYETV_HYBRID_2008: case EM2884_BOARD_CINERGY_HTC_STICK: terratec_htc_stick_init(dev); @@ -1491,8 +1492,7 @@ static int em28xx_dvb_init(struct em28xx *dev) struct i2c_adapter *i2c_adapter; struct i2c_client *client; struct i2c_board_info info; - struct m88ts2022_config m88ts2022_config = { - .clock = 27000000, + struct ts2020_config ts2020_config = { }; memset(&info, 0, sizeof(struct i2c_board_info)); @@ -1507,11 +1507,11 @@ static int em28xx_dvb_init(struct em28xx *dev) } /* attach tuner */ - m88ts2022_config.fe = dvb->fe[0]; - strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE); + ts2020_config.fe = dvb->fe[0]; + strlcpy(info.type, "ts2022", I2C_NAME_SIZE); info.addr = 0x60; - info.platform_data = &m88ts2022_config; - request_module("m88ts2022"); + info.platform_data = &ts2020_config; + request_module("ts2020"); client = i2c_new_device(i2c_adapter, &info); if (client == NULL || client->dev.driver == NULL) { dvb_frontend_detach(dvb->fe[0]); diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 9ecf65629b3d..14eba9c65de3 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1472,7 +1472,7 @@ static int vidioc_enum_input(struct file *file, void *priv, (EM28XX_VMUX_CABLE == INPUT(n)->type)) i->type = V4L2_INPUT_TYPE_TUNER; - i->std = dev->v4l2->vdev->tvnorms; + i->std = dev->v4l2->vdev.tvnorms; /* webcams do not have the STD API */ if (dev->board.is_webcam) i->capabilities = 0; @@ -1730,9 +1730,9 @@ static int vidioc_querycap(struct file *file, void *priv, cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS | V4L2_CAP_READWRITE | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - if (v4l2->vbi_dev) + if (video_is_registered(&v4l2->vbi_dev)) cap->capabilities |= V4L2_CAP_VBI_CAPTURE; - if (v4l2->radio_dev) + if (video_is_registered(&v4l2->radio_dev)) cap->capabilities |= V4L2_CAP_RADIO; return 0; } @@ -1966,20 +1966,20 @@ static int em28xx_v4l2_fini(struct em28xx *dev) em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE); - if (v4l2->radio_dev) { + if (video_is_registered(&v4l2->radio_dev)) { em28xx_info("V4L2 device %s deregistered\n", - video_device_node_name(v4l2->radio_dev)); - video_unregister_device(v4l2->radio_dev); + video_device_node_name(&v4l2->radio_dev)); + video_unregister_device(&v4l2->radio_dev); } - if (v4l2->vbi_dev) { + if (video_is_registered(&v4l2->vbi_dev)) { em28xx_info("V4L2 device %s deregistered\n", - video_device_node_name(v4l2->vbi_dev)); - video_unregister_device(v4l2->vbi_dev); + video_device_node_name(&v4l2->vbi_dev)); + video_unregister_device(&v4l2->vbi_dev); } - if (v4l2->vdev) { + if (video_is_registered(&v4l2->vdev)) { em28xx_info("V4L2 device %s deregistered\n", - video_device_node_name(v4l2->vdev)); - video_unregister_device(v4l2->vdev); + video_device_node_name(&v4l2->vdev)); + video_unregister_device(&v4l2->vdev); } v4l2_ctrl_handler_free(&v4l2->ctrl_handler); @@ -2127,7 +2127,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { static const struct video_device em28xx_video_template = { .fops = &em28xx_v4l_fops, .ioctl_ops = &video_ioctl_ops, - .release = video_device_release, + .release = video_device_release_empty, .tvnorms = V4L2_STD_ALL, }; @@ -2156,7 +2156,7 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = { static struct video_device em28xx_radio_template = { .fops = &radio_fops, .ioctl_ops = &radio_ioctl_ops, - .release = video_device_release, + .release = video_device_release_empty, }; /* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */ @@ -2179,17 +2179,11 @@ static unsigned short msp3400_addrs[] = { /******************************** usb interface ******************************/ -static struct video_device -*em28xx_vdev_init(struct em28xx *dev, - const struct video_device *template, - const char *type_name) +static void em28xx_vdev_init(struct em28xx *dev, + struct video_device *vfd, + const struct video_device *template, + const char *type_name) { - struct video_device *vfd; - - vfd = video_device_alloc(); - if (NULL == vfd) - return NULL; - *vfd = *template; vfd->v4l2_dev = &dev->v4l2->v4l2_dev; vfd->lock = &dev->lock; @@ -2200,7 +2194,6 @@ static struct video_device dev->name, type_name); video_set_drvdata(vfd, dev); - return vfd; } static void em28xx_tuner_setup(struct em28xx *dev, unsigned short tuner_addr) @@ -2491,38 +2484,33 @@ static int em28xx_v4l2_init(struct em28xx *dev) goto unregister_dev; /* allocate and fill video video_device struct */ - v4l2->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video"); - if (!v4l2->vdev) { - em28xx_errdev("cannot allocate video_device.\n"); - ret = -ENODEV; - goto unregister_dev; - } + em28xx_vdev_init(dev, &v4l2->vdev, &em28xx_video_template, "video"); mutex_init(&v4l2->vb_queue_lock); mutex_init(&v4l2->vb_vbi_queue_lock); - v4l2->vdev->queue = &v4l2->vb_vidq; - v4l2->vdev->queue->lock = &v4l2->vb_queue_lock; + v4l2->vdev.queue = &v4l2->vb_vidq; + v4l2->vdev.queue->lock = &v4l2->vb_queue_lock; /* disable inapplicable ioctls */ if (dev->board.is_webcam) { - v4l2_disable_ioctl(v4l2->vdev, VIDIOC_QUERYSTD); - v4l2_disable_ioctl(v4l2->vdev, VIDIOC_G_STD); - v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_STD); + v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_QUERYSTD); + v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_G_STD); + v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_S_STD); } else { - v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_PARM); + v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_S_PARM); } if (dev->tuner_type == TUNER_ABSENT) { - v4l2_disable_ioctl(v4l2->vdev, VIDIOC_G_TUNER); - v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_TUNER); - v4l2_disable_ioctl(v4l2->vdev, VIDIOC_G_FREQUENCY); - v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_FREQUENCY); + v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_G_TUNER); + v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_S_TUNER); + v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_G_FREQUENCY); + v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_S_FREQUENCY); } if (dev->int_audio_type == EM28XX_INT_AUDIO_NONE) { - v4l2_disable_ioctl(v4l2->vdev, VIDIOC_G_AUDIO); - v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_AUDIO); + v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_G_AUDIO); + v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_S_AUDIO); } /* register v4l2 video video_device */ - ret = video_register_device(v4l2->vdev, VFL_TYPE_GRABBER, + ret = video_register_device(&v4l2->vdev, VFL_TYPE_GRABBER, video_nr[dev->devno]); if (ret) { em28xx_errdev("unable to register video device (error=%i).\n", @@ -2532,27 +2520,27 @@ static int em28xx_v4l2_init(struct em28xx *dev) /* Allocate and fill vbi video_device struct */ if (em28xx_vbi_supported(dev) == 1) { - v4l2->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template, - "vbi"); + em28xx_vdev_init(dev, &v4l2->vbi_dev, &em28xx_video_template, + "vbi"); - v4l2->vbi_dev->queue = &v4l2->vb_vbiq; - v4l2->vbi_dev->queue->lock = &v4l2->vb_vbi_queue_lock; + v4l2->vbi_dev.queue = &v4l2->vb_vbiq; + v4l2->vbi_dev.queue->lock = &v4l2->vb_vbi_queue_lock; /* disable inapplicable ioctls */ - v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_S_PARM); + v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_S_PARM); if (dev->tuner_type == TUNER_ABSENT) { - v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_G_TUNER); - v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_S_TUNER); - v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_G_FREQUENCY); - v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_S_FREQUENCY); + v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_G_TUNER); + v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_S_TUNER); + v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_G_FREQUENCY); + v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_S_FREQUENCY); } if (dev->int_audio_type == EM28XX_INT_AUDIO_NONE) { - v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_G_AUDIO); - v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_S_AUDIO); + v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_G_AUDIO); + v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_S_AUDIO); } /* register v4l2 vbi video_device */ - ret = video_register_device(v4l2->vbi_dev, VFL_TYPE_VBI, + ret = video_register_device(&v4l2->vbi_dev, VFL_TYPE_VBI, vbi_nr[dev->devno]); if (ret < 0) { em28xx_errdev("unable to register vbi device\n"); @@ -2561,29 +2549,24 @@ static int em28xx_v4l2_init(struct em28xx *dev) } if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) { - v4l2->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template, - "radio"); - if (!v4l2->radio_dev) { - em28xx_errdev("cannot allocate video_device.\n"); - ret = -ENODEV; - goto unregister_dev; - } - ret = video_register_device(v4l2->radio_dev, VFL_TYPE_RADIO, + em28xx_vdev_init(dev, &v4l2->radio_dev, &em28xx_radio_template, + "radio"); + ret = video_register_device(&v4l2->radio_dev, VFL_TYPE_RADIO, radio_nr[dev->devno]); if (ret < 0) { em28xx_errdev("can't register radio device\n"); goto unregister_dev; } em28xx_info("Registered radio device as %s\n", - video_device_node_name(v4l2->radio_dev)); + video_device_node_name(&v4l2->radio_dev)); } em28xx_info("V4L2 video device registered as %s\n", - video_device_node_name(v4l2->vdev)); + video_device_node_name(&v4l2->vdev)); - if (v4l2->vbi_dev) + if (video_is_registered(&v4l2->vbi_dev)) em28xx_info("V4L2 VBI device registered as %s\n", - video_device_node_name(v4l2->vbi_dev)); + video_device_node_name(&v4l2->vbi_dev)); /* Save some power by putting tuner to sleep */ v4l2_device_call_all(&v4l2->v4l2_dev, 0, core, s_power, 0); diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 9c7075344109..e6559c6f143c 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -143,6 +143,7 @@ #define EM28178_BOARD_PCTV_292E 94 #define EM2861_BOARD_LEADTEK_VC100 95 #define EM28178_BOARD_TERRATEC_T2_STICK_HD 96 +#define EM2884_BOARD_ELGATO_EYETV_HYBRID_2008 97 /* Limits minimum and default number of buffers */ #define EM28XX_MIN_BUF 4 @@ -512,9 +513,9 @@ struct em28xx_v4l2 { struct v4l2_ctrl_handler ctrl_handler; struct v4l2_clk *clk; - struct video_device *vdev; - struct video_device *vbi_dev; - struct video_device *radio_dev; + struct video_device vdev; + struct video_device vbi_dev; + struct video_device radio_dev; /* Videobuf2 */ struct vb2_queue vb_vidq; diff --git a/drivers/media/usb/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c index a9c866d6d82d..146071b8e116 100644 --- a/drivers/media/usb/gspca/ov534.c +++ b/drivers/media/usb/gspca/ov534.c @@ -816,21 +816,16 @@ static void sethue(struct gspca_dev *gspca_dev, s32 val) s16 huesin; s16 huecos; - /* fixp_sin and fixp_cos accept only positive values, while - * our val is between -90 and 90 - */ - val += 360; - /* According to the datasheet the registers expect HUESIN and * HUECOS to be the result of the trigonometric functions, * scaled by 0x80. * - * The 0x100 here represents the maximun absolute value + * The 0x7fff here represents the maximum absolute value * returned byt fixp_sin and fixp_cos, so the scaling will * consider the result like in the interval [-1.0, 1.0]. */ - huesin = fixp_sin(val) * 0x80 / 0x100; - huecos = fixp_cos(val) * 0x80 / 0x100; + huesin = fixp_sin16(val) * 0x80 / 0x7fff; + huecos = fixp_cos16(val) * 0x80 / 0x7fff; if (huesin < 0) { sccb_reg_write(gspca_dev, 0xab, diff --git a/drivers/media/usb/gspca/topro.c b/drivers/media/usb/gspca/topro.c index 5fcd1eec2004..c70ff406b07a 100644 --- a/drivers/media/usb/gspca/topro.c +++ b/drivers/media/usb/gspca/topro.c @@ -969,7 +969,9 @@ static void jpeg_set_qual(u8 *jpeg_hdr, { int i, sc; - if (quality < 50) + if (quality <= 0) + sc = 5000; + else if (quality < 50) sc = 5000 / quality; else sc = 200 - quality * 2; diff --git a/drivers/media/usb/hdpvr/hdpvr-core.c b/drivers/media/usb/hdpvr/hdpvr-core.c index 42b4cdf28cfd..3fc64197b4e6 100644 --- a/drivers/media/usb/hdpvr/hdpvr-core.c +++ b/drivers/media/usb/hdpvr/hdpvr-core.c @@ -69,10 +69,6 @@ MODULE_DEVICE_TABLE(usb, hdpvr_table); void hdpvr_delete(struct hdpvr_device *dev) { hdpvr_free_buffers(dev); - - if (dev->video_dev) - video_device_release(dev->video_dev); - usb_put_dev(dev->udev); } @@ -397,7 +393,7 @@ static int hdpvr_probe(struct usb_interface *interface, /* let the user know what node this device is now attached to */ v4l2_info(&dev->v4l2_dev, "device now attached to %s\n", - video_device_node_name(dev->video_dev)); + video_device_node_name(&dev->video_dev)); return 0; reg_fail: @@ -420,7 +416,7 @@ static void hdpvr_disconnect(struct usb_interface *interface) struct hdpvr_device *dev = to_hdpvr_dev(usb_get_intfdata(interface)); v4l2_info(&dev->v4l2_dev, "device %s disconnected\n", - video_device_node_name(dev->video_dev)); + video_device_node_name(&dev->video_dev)); /* prevent more I/O from starting and stop any ongoing */ mutex_lock(&dev->io_mutex); dev->status = STATUS_DISCONNECTED; @@ -436,7 +432,7 @@ static void hdpvr_disconnect(struct usb_interface *interface) #if IS_ENABLED(CONFIG_I2C) i2c_del_adapter(&dev->i2c_adapter); #endif - video_unregister_device(dev->video_dev); + video_unregister_device(&dev->video_dev); atomic_dec(&dev_nr); } diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index 59d15fd242ba..d8d8c0f519fc 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -797,7 +797,7 @@ static int vidioc_s_input(struct file *file, void *_fh, * Comment this out for now, but if the legacy mode can be * removed in the future, then this code should be enabled * again. - dev->video_dev->tvnorms = + dev->video_dev.tvnorms = (index != HDPVR_COMPONENT) ? V4L2_STD_ALL : 0; */ } @@ -1228,19 +1228,12 @@ int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent, } /* setup and register video device */ - dev->video_dev = video_device_alloc(); - if (!dev->video_dev) { - v4l2_err(&dev->v4l2_dev, "video_device_alloc() failed\n"); - res = -ENOMEM; - goto error; - } - - *dev->video_dev = hdpvr_video_template; - strcpy(dev->video_dev->name, "Hauppauge HD PVR"); - dev->video_dev->v4l2_dev = &dev->v4l2_dev; - video_set_drvdata(dev->video_dev, dev); + dev->video_dev = hdpvr_video_template; + strcpy(dev->video_dev.name, "Hauppauge HD PVR"); + dev->video_dev.v4l2_dev = &dev->v4l2_dev; + video_set_drvdata(&dev->video_dev, dev); - res = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, devnum); + res = video_register_device(&dev->video_dev, VFL_TYPE_GRABBER, devnum); if (res < 0) { v4l2_err(&dev->v4l2_dev, "video_device registration failed\n"); goto error; diff --git a/drivers/media/usb/hdpvr/hdpvr.h b/drivers/media/usb/hdpvr/hdpvr.h index dc685d44cb3e..a3194304182d 100644 --- a/drivers/media/usb/hdpvr/hdpvr.h +++ b/drivers/media/usb/hdpvr/hdpvr.h @@ -66,7 +66,7 @@ struct hdpvr_options { /* Structure to hold all of our device specific stuff */ struct hdpvr_device { /* the v4l device for this device */ - struct video_device *video_dev; + struct video_device video_dev; /* the control handler for this device */ struct v4l2_ctrl_handler hdl; /* the usb device for this device */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index 35e4ea530494..1c5f85bf7ed4 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -21,7 +21,6 @@ #include <linux/kernel.h> #include <linux/slab.h> -#include <linux/version.h> #include "pvrusb2-context.h" #include "pvrusb2-hdw.h" #include "pvrusb2.h" @@ -32,6 +31,7 @@ #include <linux/module.h> #include <media/v4l2-dev.h> #include <media/v4l2-device.h> +#include <media/v4l2-fh.h> #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> @@ -50,14 +50,11 @@ struct pvr2_v4l2_dev { }; struct pvr2_v4l2_fh { + struct v4l2_fh fh; struct pvr2_channel channel; struct pvr2_v4l2_dev *pdi; - enum v4l2_priority prio; struct pvr2_ioread *rhp; struct file *file; - struct pvr2_v4l2 *vhead; - struct pvr2_v4l2_fh *vnext; - struct pvr2_v4l2_fh *vprev; wait_queue_head_t wait_data; int fw_mode_flag; /* Map contiguous ordinal value to input id */ @@ -67,10 +64,6 @@ struct pvr2_v4l2_fh { struct pvr2_v4l2 { struct pvr2_channel channel; - struct pvr2_v4l2_fh *vfirst; - struct pvr2_v4l2_fh *vlast; - - struct v4l2_prio_state prio; /* streams - Note that these must be separately, individually, * allocated pointers. This is because the v4l core is going to @@ -169,23 +162,6 @@ static int pvr2_querycap(struct file *file, void *priv, struct v4l2_capability * return 0; } -static int pvr2_g_priority(struct file *file, void *priv, enum v4l2_priority *p) -{ - struct pvr2_v4l2_fh *fh = file->private_data; - struct pvr2_v4l2 *vp = fh->vhead; - - *p = v4l2_prio_max(&vp->prio); - return 0; -} - -static int pvr2_s_priority(struct file *file, void *priv, enum v4l2_priority prio) -{ - struct pvr2_v4l2_fh *fh = file->private_data; - struct pvr2_v4l2 *vp = fh->vhead; - - return v4l2_prio_change(&vp->prio, &fh->prio, prio); -} - static int pvr2_g_std(struct file *file, void *priv, v4l2_std_id *std) { struct pvr2_v4l2_fh *fh = file->private_data; @@ -805,8 +781,6 @@ static int pvr2_log_status(struct file *file, void *priv) static const struct v4l2_ioctl_ops pvr2_ioctl_ops = { .vidioc_querycap = pvr2_querycap, - .vidioc_g_priority = pvr2_g_priority, - .vidioc_s_priority = pvr2_s_priority, .vidioc_s_audio = pvr2_s_audio, .vidioc_g_audio = pvr2_g_audio, .vidioc_enumaudio = pvr2_enumaudio, @@ -911,7 +885,9 @@ static void pvr2_v4l2_internal_check(struct pvr2_channel *chp) if (!vp->channel.mc_head->disconnect_flag) return; pvr2_v4l2_dev_disassociate_parent(vp->dev_video); pvr2_v4l2_dev_disassociate_parent(vp->dev_radio); - if (vp->vfirst) return; + if (!list_empty(&vp->dev_video->devbase.fh_list) || + !list_empty(&vp->dev_radio->devbase.fh_list)) + return; pvr2_v4l2_destroy_no_lock(vp); } @@ -921,7 +897,6 @@ static long pvr2_v4l2_ioctl(struct file *file, { struct pvr2_v4l2_fh *fh = file->private_data; - struct pvr2_v4l2 *vp = fh->vhead; struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; long ret = -EINVAL; @@ -934,18 +909,6 @@ static long pvr2_v4l2_ioctl(struct file *file, return -EFAULT; } - /* check priority */ - switch (cmd) { - case VIDIOC_S_CTRL: - case VIDIOC_S_STD: - case VIDIOC_S_INPUT: - case VIDIOC_S_TUNER: - case VIDIOC_S_FREQUENCY: - ret = v4l2_prio_check(&vp->prio, fh->prio); - if (ret) - return ret; - } - ret = video_ioctl2(file, cmd, arg); pvr2_hdw_commit_ctl(hdw); @@ -970,7 +933,7 @@ static long pvr2_v4l2_ioctl(struct file *file, static int pvr2_v4l2_release(struct file *file) { struct pvr2_v4l2_fh *fhp = file->private_data; - struct pvr2_v4l2 *vp = fhp->vhead; + struct pvr2_v4l2 *vp = fhp->pdi->v4lp; struct pvr2_hdw *hdw = fhp->channel.mc_head->hdw; pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_release"); @@ -984,22 +947,10 @@ static int pvr2_v4l2_release(struct file *file) fhp->rhp = NULL; } - v4l2_prio_close(&vp->prio, fhp->prio); + v4l2_fh_del(&fhp->fh); + v4l2_fh_exit(&fhp->fh); file->private_data = NULL; - if (fhp->vnext) { - fhp->vnext->vprev = fhp->vprev; - } else { - vp->vlast = fhp->vprev; - } - if (fhp->vprev) { - fhp->vprev->vnext = fhp->vnext; - } else { - vp->vfirst = fhp->vnext; - } - fhp->vnext = NULL; - fhp->vprev = NULL; - fhp->vhead = NULL; pvr2_channel_done(&fhp->channel); pvr2_trace(PVR2_TRACE_STRUCT, "Destroying pvr_v4l2_fh id=%p",fhp); @@ -1008,7 +959,9 @@ static int pvr2_v4l2_release(struct file *file) fhp->input_map = NULL; } kfree(fhp); - if (vp->channel.mc_head->disconnect_flag && !vp->vfirst) { + if (vp->channel.mc_head->disconnect_flag && + list_empty(&vp->dev_video->devbase.fh_list) && + list_empty(&vp->dev_radio->devbase.fh_list)) { pvr2_v4l2_destroy_no_lock(vp); } return 0; @@ -1043,6 +996,7 @@ static int pvr2_v4l2_open(struct file *file) return -ENOMEM; } + v4l2_fh_init(&fhp->fh, &dip->devbase); init_waitqueue_head(&fhp->wait_data); fhp->pdi = dip; @@ -1093,21 +1047,11 @@ static int pvr2_v4l2_open(struct file *file) fhp->input_map[input_cnt++] = idx; } - fhp->vnext = NULL; - fhp->vprev = vp->vlast; - if (vp->vlast) { - vp->vlast->vnext = fhp; - } else { - vp->vfirst = fhp; - } - vp->vlast = fhp; - fhp->vhead = vp; - fhp->file = file; file->private_data = fhp; - v4l2_prio_open(&vp->prio, &fhp->prio); fhp->fw_mode_flag = pvr2_hdw_cpufw_get_enabled(hdw); + v4l2_fh_add(&fhp->fh); return 0; } @@ -1247,7 +1191,7 @@ static const struct v4l2_file_operations vdev_fops = { .open = pvr2_v4l2_open, .release = pvr2_v4l2_release, .read = pvr2_v4l2_read, - .ioctl = pvr2_v4l2_ioctl, + .unlocked_ioctl = pvr2_v4l2_ioctl, .poll = pvr2_v4l2_poll, }; diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c index 94e10b10b66e..c945e4c2fbd4 100644 --- a/drivers/media/usb/siano/smsusb.c +++ b/drivers/media/usb/siano/smsusb.c @@ -19,6 +19,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. ****************************************************************/ +#include "smscoreapi.h" + #include <linux/kernel.h> #include <linux/init.h> #include <linux/usb.h> @@ -26,14 +28,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #include <linux/slab.h> #include <linux/module.h> -#include "smscoreapi.h" #include "sms-cards.h" #include "smsendian.h" -static int sms_dbg; -module_param_named(debug, sms_dbg, int, 0644); -MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); - #define USB1_BUFFER_SIZE 0x1000 #define USB2_BUFFER_SIZE 0x2000 @@ -87,7 +84,7 @@ static void smsusb_onresponse(struct urb *urb) struct smsusb_device_t *dev = surb->dev; if (urb->status == -ESHUTDOWN) { - sms_err("error, urb status %d (-ESHUTDOWN), %d bytes", + pr_err("error, urb status %d (-ESHUTDOWN), %d bytes\n", urb->status, urb->actual_length); return; } @@ -109,9 +106,7 @@ static void smsusb_onresponse(struct urb *urb) /* sanity check */ if (((int) phdr->msg_length + surb->cb->offset) > urb->actual_length) { - sms_err("invalid response " - "msglen %d offset %d " - "size %d", + pr_err("invalid response msglen %d offset %d size %d\n", phdr->msg_length, surb->cb->offset, urb->actual_length); @@ -125,7 +120,7 @@ static void smsusb_onresponse(struct urb *urb) } else surb->cb->offset = 0; - sms_debug("received %s(%d) size: %d", + pr_debug("received %s(%d) size: %d\n", smscore_translate_msg(phdr->msg_type), phdr->msg_type, phdr->msg_length); @@ -134,12 +129,11 @@ static void smsusb_onresponse(struct urb *urb) smscore_onresponse(dev->coredev, surb->cb); surb->cb = NULL; } else { - sms_err("invalid response " - "msglen %d actual %d", + pr_err("invalid response msglen %d actual %d\n", phdr->msg_length, urb->actual_length); } } else - sms_err("error, urb status %d, %d bytes", + pr_err("error, urb status %d, %d bytes\n", urb->status, urb->actual_length); @@ -153,7 +147,7 @@ static int smsusb_submit_urb(struct smsusb_device_t *dev, if (!surb->cb) { surb->cb = smscore_getbuffer(dev->coredev); if (!surb->cb) { - sms_err("smscore_getbuffer(...) returned NULL"); + pr_err("smscore_getbuffer(...) returned NULL\n"); return -ENOMEM; } } @@ -194,7 +188,7 @@ static int smsusb_start_streaming(struct smsusb_device_t *dev) for (i = 0; i < MAX_URBS; i++) { rc = smsusb_submit_urb(dev, &dev->surbs[i]); if (rc < 0) { - sms_err("smsusb_submit_urb(...) failed"); + pr_err("smsusb_submit_urb(...) failed\n"); smsusb_stop_streaming(dev); break; } @@ -210,11 +204,11 @@ static int smsusb_sendrequest(void *context, void *buffer, size_t size) int dummy; if (dev->state != SMSUSB_ACTIVE) { - sms_debug("Device not active yet"); + pr_debug("Device not active yet\n"); return -ENOENT; } - sms_debug("sending %s(%d) size: %d", + pr_debug("sending %s(%d) size: %d\n", smscore_translate_msg(phdr->msg_type), phdr->msg_type, phdr->msg_length); @@ -249,7 +243,7 @@ static int smsusb1_load_firmware(struct usb_device *udev, int id, int board_id) id = sms_get_board(board_id)->default_mode; if (id < DEVICE_MODE_DVBT || id > DEVICE_MODE_DVBT_BDA) { - sms_err("invalid firmware id specified %d", id); + pr_err("invalid firmware id specified %d\n", id); return -EINVAL; } @@ -257,13 +251,13 @@ static int smsusb1_load_firmware(struct usb_device *udev, int id, int board_id) rc = request_firmware(&fw, fw_filename, &udev->dev); if (rc < 0) { - sms_warn("failed to open \"%s\" mode %d, " - "trying again with default firmware", fw_filename, id); + pr_warn("failed to open '%s' mode %d, trying again with default firmware\n", + fw_filename, id); fw_filename = smsusb1_fw_lkup[id]; rc = request_firmware(&fw, fw_filename, &udev->dev); if (rc < 0) { - sms_warn("failed to open \"%s\" mode %d", + pr_warn("failed to open '%s' mode %d\n", fw_filename, id); return rc; @@ -277,14 +271,14 @@ static int smsusb1_load_firmware(struct usb_device *udev, int id, int board_id) rc = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 2), fw_buffer, fw->size, &dummy, 1000); - sms_info("sent %zu(%d) bytes, rc %d", fw->size, dummy, rc); + pr_debug("sent %zu(%d) bytes, rc %d\n", fw->size, dummy, rc); kfree(fw_buffer); } else { - sms_err("failed to allocate firmware buffer"); + pr_err("failed to allocate firmware buffer\n"); rc = -ENOMEM; } - sms_info("read FW %s, size=%zu", fw_filename, fw->size); + pr_debug("read FW %s, size=%zu\n", fw_filename, fw->size); release_firmware(fw); @@ -300,7 +294,7 @@ static void smsusb1_detectmode(void *context, int *mode) if (!product_string) { product_string = "none"; - sms_err("product string not found"); + pr_err("product string not found\n"); } else if (strstr(product_string, "DVBH")) *mode = 1; else if (strstr(product_string, "BDA")) @@ -310,7 +304,7 @@ static void smsusb1_detectmode(void *context, int *mode) else if (strstr(product_string, "TDMB")) *mode = 2; - sms_info("%d \"%s\"", *mode, product_string); + pr_debug("%d \"%s\"\n", *mode, product_string); } static int smsusb1_setmode(void *context, int mode) @@ -319,7 +313,7 @@ static int smsusb1_setmode(void *context, int mode) sizeof(struct sms_msg_hdr), 0 }; if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) { - sms_err("invalid firmware id specified %d", mode); + pr_err("invalid firmware id specified %d\n", mode); return -EINVAL; } @@ -339,25 +333,61 @@ static void smsusb_term_device(struct usb_interface *intf) if (dev->coredev) smscore_unregister_device(dev->coredev); - sms_info("device 0x%p destroyed", dev); + pr_debug("device 0x%p destroyed\n", dev); kfree(dev); } usb_set_intfdata(intf, NULL); } +static void *siano_media_device_register(struct smsusb_device_t *dev, + int board_id) +{ +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + struct media_device *mdev; + struct usb_device *udev = dev->udev; + struct sms_board *board = sms_get_board(board_id); + int ret; + + mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); + if (!mdev) + return NULL; + + mdev->dev = &udev->dev; + strlcpy(mdev->model, board->name, sizeof(mdev->model)); + if (udev->serial) + strlcpy(mdev->serial, udev->serial, sizeof(mdev->serial)); + strcpy(mdev->bus_info, udev->devpath); + mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice); + mdev->driver_version = LINUX_VERSION_CODE; + + ret = media_device_register(mdev); + if (ret) { + pr_err("Couldn't create a media device. Error: %d\n", + ret); + kfree(mdev); + return NULL; + } + + pr_info("media controller created\n"); + + return mdev; +#else + return NULL; +#endif +} + static int smsusb_init_device(struct usb_interface *intf, int board_id) { struct smsdevice_params_t params; struct smsusb_device_t *dev; + void *mdev; int i, rc; /* create device object */ dev = kzalloc(sizeof(struct smsusb_device_t), GFP_KERNEL); - if (!dev) { - sms_err("kzalloc(sizeof(struct smsusb_device_t) failed"); + if (!dev) return -ENOMEM; - } memset(¶ms, 0, sizeof(params)); usb_set_intfdata(intf, dev); @@ -374,7 +404,7 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id) params.detectmode_handler = smsusb1_detectmode; break; case SMS_UNKNOWN_TYPE: - sms_err("Unspecified sms device type!"); + pr_err("Unspecified sms device type!\n"); /* fall-thru */ default: dev->buffer_size = USB2_BUFFER_SIZE; @@ -393,7 +423,7 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id) dev->out_ep = intf->cur_altsetting->endpoint[i].desc.bEndpointAddress; } - sms_info("in_ep = %02x, out_ep = %02x", + pr_debug("in_ep = %02x, out_ep = %02x\n", dev->in_ep, dev->out_ep); params.device = &dev->udev->dev; @@ -403,11 +433,17 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id) params.context = dev; usb_make_path(dev->udev, params.devpath, sizeof(params.devpath)); + mdev = siano_media_device_register(dev, board_id); + /* register in smscore */ - rc = smscore_register_device(¶ms, &dev->coredev); + rc = smscore_register_device(¶ms, &dev->coredev, mdev); if (rc < 0) { - sms_err("smscore_register_device(...) failed, rc %d", rc); + pr_err("smscore_register_device(...) failed, rc %d\n", rc); smsusb_term_device(intf); +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + media_device_unregister(mdev); +#endif + kfree(mdev); return rc; } @@ -421,10 +457,10 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id) usb_init_urb(&dev->surbs[i].urb); } - sms_info("smsusb_start_streaming(...)."); + pr_debug("smsusb_start_streaming(...).\n"); rc = smsusb_start_streaming(dev); if (rc < 0) { - sms_err("smsusb_start_streaming(...) failed"); + pr_err("smsusb_start_streaming(...) failed\n"); smsusb_term_device(intf); return rc; } @@ -433,12 +469,12 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id) rc = smscore_start_device(dev->coredev); if (rc < 0) { - sms_err("smscore_start_device(...) failed"); + pr_err("smscore_start_device(...) failed\n"); smsusb_term_device(intf); return rc; } - sms_info("device 0x%p created", dev); + pr_debug("device 0x%p created\n", dev); return rc; } @@ -450,13 +486,13 @@ static int smsusb_probe(struct usb_interface *intf, char devpath[32]; int i, rc; - sms_info("board id=%lu, interface number %d", + pr_info("board id=%lu, interface number %d\n", id->driver_info, intf->cur_altsetting->desc.bInterfaceNumber); if (sms_get_board(id->driver_info)->intf_num != intf->cur_altsetting->desc.bInterfaceNumber) { - sms_debug("interface %d won't be used. Expecting interface %d to popup", + pr_debug("interface %d won't be used. Expecting interface %d to popup\n", intf->cur_altsetting->desc.bInterfaceNumber, sms_get_board(id->driver_info)->intf_num); return -ENODEV; @@ -467,15 +503,15 @@ static int smsusb_probe(struct usb_interface *intf, intf->cur_altsetting->desc.bInterfaceNumber, 0); if (rc < 0) { - sms_err("usb_set_interface failed, rc %d", rc); + pr_err("usb_set_interface failed, rc %d\n", rc); return rc; } } - sms_info("smsusb_probe %d", + pr_debug("smsusb_probe %d\n", intf->cur_altsetting->desc.bInterfaceNumber); for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) { - sms_info("endpoint %d %02x %02x %d", i, + pr_debug("endpoint %d %02x %02x %d\n", i, intf->cur_altsetting->endpoint[i].desc.bEndpointAddress, intf->cur_altsetting->endpoint[i].desc.bmAttributes, intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize); @@ -489,7 +525,7 @@ static int smsusb_probe(struct usb_interface *intf, } if ((udev->actconfig->desc.bNumInterfaces == 2) && (intf->cur_altsetting->desc.bInterfaceNumber == 0)) { - sms_debug("rom interface 0 is not used"); + pr_debug("rom interface 0 is not used\n"); return -ENODEV; } @@ -498,23 +534,25 @@ static int smsusb_probe(struct usb_interface *intf, snprintf(devpath, sizeof(devpath), "usb\\%d-%s", udev->bus->busnum, udev->devpath); - sms_info("stellar device in cold state was found at %s.", devpath); + pr_info("stellar device in cold state was found at %s.\n", + devpath); rc = smsusb1_load_firmware( udev, smscore_registry_getmode(devpath), id->driver_info); /* This device will reset and gain another USB ID */ if (!rc) - sms_info("stellar device now in warm state"); + pr_info("stellar device now in warm state\n"); else - sms_err("Failed to put stellar in warm state. Error: %d", rc); + pr_err("Failed to put stellar in warm state. Error: %d\n", + rc); return rc; } else { rc = smsusb_init_device(intf, id->driver_info); } - sms_info("Device initialized with return code %d", rc); + pr_info("Device initialized with return code %d\n", rc); sms_board_load_modules(id->driver_info); return rc; } diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index 65a326c5128f..749ad5603c9e 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -240,6 +240,11 @@ static int stk1160_stop_streaming(struct stk1160 *dev) if (mutex_lock_interruptible(&dev->v4l_lock)) return -ERESTARTSYS; + /* + * Once URBs are cancelled, the URB complete handler + * won't be running. This is required to safely release the + * current buffer (dev->isoc_ctl.buf). + */ stk1160_cancel_isoc(dev); /* @@ -620,8 +625,16 @@ void stk1160_clear_queue(struct stk1160 *dev) stk1160_info("buffer [%p/%d] aborted\n", buf, buf->vb.v4l2_buf.index); } - /* It's important to clear current buffer */ - dev->isoc_ctl.buf = NULL; + + /* It's important to release the current buffer */ + if (dev->isoc_ctl.buf) { + buf = dev->isoc_ctl.buf; + dev->isoc_ctl.buf = NULL; + + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + stk1160_info("buffer [%p/%d] aborted\n", + buf, buf->vb.v4l2_buf.index); + } spin_unlock_irqrestore(&dev->buf_lock, flags); } diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index e08fa587332f..c21c4c004f97 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -556,10 +556,8 @@ static int stk_free_sio_buffers(struct stk_camera *dev) nbufs = dev->n_sbufs; dev->n_sbufs = 0; spin_unlock_irqrestore(&dev->spinlock, flags); - for (i = 0; i < nbufs; i++) { - if (dev->sio_bufs[i].buffer != NULL) - vfree(dev->sio_bufs[i].buffer); - } + for (i = 0; i < nbufs; i++) + vfree(dev->sio_bufs[i].buffer); kfree(dev->sio_bufs); dev->sio_bufs = NULL; return 0; diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index 0f14d3ccc7b4..77ce9efe1f24 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c @@ -1576,7 +1576,7 @@ static struct video_device tm6000_template = { .name = "tm6000", .fops = &tm6000_fops, .ioctl_ops = &video_ioctl_ops, - .release = video_device_release, + .release = video_device_release_empty, .tvnorms = TM6000_STD, }; @@ -1609,25 +1609,19 @@ static struct video_device tm6000_radio_template = { * ------------------------------------------------------------------ */ -static struct video_device *vdev_init(struct tm6000_core *dev, +static void vdev_init(struct tm6000_core *dev, + struct video_device *vfd, const struct video_device *template, const char *type_name) { - struct video_device *vfd; - - vfd = video_device_alloc(); - if (NULL == vfd) - return NULL; - *vfd = *template; vfd->v4l2_dev = &dev->v4l2_dev; - vfd->release = video_device_release; + vfd->release = video_device_release_empty; vfd->lock = &dev->lock; snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name); video_set_drvdata(vfd, dev); - return vfd; } int tm6000_v4l2_register(struct tm6000_core *dev) @@ -1658,62 +1652,46 @@ int tm6000_v4l2_register(struct tm6000_core *dev) if (ret) goto free_ctrl; - dev->vfd = vdev_init(dev, &tm6000_template, "video"); + vdev_init(dev, &dev->vfd, &tm6000_template, "video"); - if (!dev->vfd) { - printk(KERN_INFO "%s: can't register video device\n", - dev->name); - ret = -ENOMEM; - goto free_ctrl; - } - dev->vfd->ctrl_handler = &dev->ctrl_handler; + dev->vfd.ctrl_handler = &dev->ctrl_handler; /* init video dma queues */ INIT_LIST_HEAD(&dev->vidq.active); INIT_LIST_HEAD(&dev->vidq.queued); - ret = video_register_device(dev->vfd, VFL_TYPE_GRABBER, video_nr); + ret = video_register_device(&dev->vfd, VFL_TYPE_GRABBER, video_nr); if (ret < 0) { printk(KERN_INFO "%s: can't register video device\n", dev->name); - video_device_release(dev->vfd); - dev->vfd = NULL; goto free_ctrl; } printk(KERN_INFO "%s: registered device %s\n", - dev->name, video_device_node_name(dev->vfd)); + dev->name, video_device_node_name(&dev->vfd)); if (dev->caps.has_radio) { - dev->radio_dev = vdev_init(dev, &tm6000_radio_template, + vdev_init(dev, &dev->radio_dev, &tm6000_radio_template, "radio"); - if (!dev->radio_dev) { - printk(KERN_INFO "%s: can't register radio device\n", - dev->name); - ret = -ENXIO; - goto unreg_video; - } - - dev->radio_dev->ctrl_handler = &dev->radio_ctrl_handler; - ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, + dev->radio_dev.ctrl_handler = &dev->radio_ctrl_handler; + ret = video_register_device(&dev->radio_dev, VFL_TYPE_RADIO, radio_nr); if (ret < 0) { printk(KERN_INFO "%s: can't register radio device\n", dev->name); - video_device_release(dev->radio_dev); goto unreg_video; } printk(KERN_INFO "%s: registered device %s\n", - dev->name, video_device_node_name(dev->radio_dev)); + dev->name, video_device_node_name(&dev->radio_dev)); } printk(KERN_INFO "Trident TVMaster TM5600/TM6000/TM6010 USB2 board (Load status: %d)\n", ret); return ret; unreg_video: - video_unregister_device(dev->vfd); + video_unregister_device(&dev->vfd); free_ctrl: v4l2_ctrl_handler_free(&dev->ctrl_handler); v4l2_ctrl_handler_free(&dev->radio_ctrl_handler); @@ -1722,19 +1700,12 @@ free_ctrl: int tm6000_v4l2_unregister(struct tm6000_core *dev) { - video_unregister_device(dev->vfd); + video_unregister_device(&dev->vfd); /* if URB buffers are still allocated free them now */ tm6000_free_urb_buffers(dev); - if (dev->radio_dev) { - if (video_is_registered(dev->radio_dev)) - video_unregister_device(dev->radio_dev); - else - video_device_release(dev->radio_dev); - dev->radio_dev = NULL; - } - + video_unregister_device(&dev->radio_dev); return 0; } diff --git a/drivers/media/usb/tm6000/tm6000.h b/drivers/media/usb/tm6000/tm6000.h index 08bd0740dd23..f2127944776f 100644 --- a/drivers/media/usb/tm6000/tm6000.h +++ b/drivers/media/usb/tm6000/tm6000.h @@ -220,8 +220,8 @@ struct tm6000_core { struct tm6000_fh *resources; /* Points to fh that is streaming */ bool is_res_read; - struct video_device *vfd; - struct video_device *radio_dev; + struct video_device vfd; + struct video_device radio_dev; struct tm6000_dmaqueue vidq; struct v4l2_device v4l2_dev; struct v4l2_ctrl_handler ctrl_handler; diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c index cd2fbf11e3b4..12b403e78d52 100644 --- a/drivers/media/usb/usbvision/usbvision-video.c +++ b/drivers/media/usb/usbvision/usbvision-video.c @@ -471,7 +471,7 @@ static int vidioc_g_register(struct file *file, void *priv, /* NT100x has a 8-bit register space */ err_code = usbvision_read_reg(usbvision, reg->reg&0xff); if (err_code < 0) { - dev_err(&usbvision->vdev->dev, + dev_err(&usbvision->vdev.dev, "%s: VIDIOC_DBG_G_REGISTER failed: error %d\n", __func__, err_code); return err_code; @@ -490,7 +490,7 @@ static int vidioc_s_register(struct file *file, void *priv, /* NT100x has a 8-bit register space */ err_code = usbvision_write_reg(usbvision, reg->reg & 0xff, reg->val); if (err_code < 0) { - dev_err(&usbvision->vdev->dev, + dev_err(&usbvision->vdev.dev, "%s: VIDIOC_DBG_S_REGISTER failed: error %d\n", __func__, err_code); return err_code; @@ -1157,7 +1157,7 @@ static int usbvision_radio_open(struct file *file) if (mutex_lock_interruptible(&usbvision->v4l2_lock)) return -ERESTARTSYS; if (usbvision->user) { - dev_err(&usbvision->rdev->dev, + dev_err(&usbvision->rdev.dev, "%s: Someone tried to open an already opened USBVision Radio!\n", __func__); err_code = -EBUSY; @@ -1280,7 +1280,7 @@ static struct video_device usbvision_video_template = { .fops = &usbvision_fops, .ioctl_ops = &usbvision_ioctl_ops, .name = "usbvision-video", - .release = video_device_release, + .release = video_device_release_empty, .tvnorms = USBVISION_NORMS, }; @@ -1312,58 +1312,46 @@ static const struct v4l2_ioctl_ops usbvision_radio_ioctl_ops = { static struct video_device usbvision_radio_template = { .fops = &usbvision_radio_fops, .name = "usbvision-radio", - .release = video_device_release, + .release = video_device_release_empty, .ioctl_ops = &usbvision_radio_ioctl_ops, }; -static struct video_device *usbvision_vdev_init(struct usb_usbvision *usbvision, - struct video_device *vdev_template, - char *name) +static void usbvision_vdev_init(struct usb_usbvision *usbvision, + struct video_device *vdev, + const struct video_device *vdev_template, + const char *name) { struct usb_device *usb_dev = usbvision->dev; - struct video_device *vdev; if (usb_dev == NULL) { dev_err(&usbvision->dev->dev, "%s: usbvision->dev is not set\n", __func__); - return NULL; + return; } - vdev = video_device_alloc(); - if (NULL == vdev) - return NULL; *vdev = *vdev_template; vdev->lock = &usbvision->v4l2_lock; vdev->v4l2_dev = &usbvision->v4l2_dev; snprintf(vdev->name, sizeof(vdev->name), "%s", name); video_set_drvdata(vdev, usbvision); - return vdev; } /* unregister video4linux devices */ static void usbvision_unregister_video(struct usb_usbvision *usbvision) { /* Radio Device: */ - if (usbvision->rdev) { + if (video_is_registered(&usbvision->rdev)) { PDEBUG(DBG_PROBE, "unregister %s [v4l2]", - video_device_node_name(usbvision->rdev)); - if (video_is_registered(usbvision->rdev)) - video_unregister_device(usbvision->rdev); - else - video_device_release(usbvision->rdev); - usbvision->rdev = NULL; + video_device_node_name(&usbvision->rdev)); + video_unregister_device(&usbvision->rdev); } /* Video Device: */ - if (usbvision->vdev) { + if (video_is_registered(&usbvision->vdev)) { PDEBUG(DBG_PROBE, "unregister %s [v4l2]", - video_device_node_name(usbvision->vdev)); - if (video_is_registered(usbvision->vdev)) - video_unregister_device(usbvision->vdev); - else - video_device_release(usbvision->vdev); - usbvision->vdev = NULL; + video_device_node_name(&usbvision->vdev)); + video_unregister_device(&usbvision->vdev); } } @@ -1371,28 +1359,22 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision) static int usbvision_register_video(struct usb_usbvision *usbvision) { /* Video Device: */ - usbvision->vdev = usbvision_vdev_init(usbvision, - &usbvision_video_template, - "USBVision Video"); - if (usbvision->vdev == NULL) - goto err_exit; - if (video_register_device(usbvision->vdev, VFL_TYPE_GRABBER, video_nr) < 0) + usbvision_vdev_init(usbvision, &usbvision->vdev, + &usbvision_video_template, "USBVision Video"); + if (video_register_device(&usbvision->vdev, VFL_TYPE_GRABBER, video_nr) < 0) goto err_exit; printk(KERN_INFO "USBVision[%d]: registered USBVision Video device %s [v4l2]\n", - usbvision->nr, video_device_node_name(usbvision->vdev)); + usbvision->nr, video_device_node_name(&usbvision->vdev)); /* Radio Device: */ if (usbvision_device_data[usbvision->dev_model].radio) { /* usbvision has radio */ - usbvision->rdev = usbvision_vdev_init(usbvision, - &usbvision_radio_template, - "USBVision Radio"); - if (usbvision->rdev == NULL) - goto err_exit; - if (video_register_device(usbvision->rdev, VFL_TYPE_RADIO, radio_nr) < 0) + usbvision_vdev_init(usbvision, &usbvision->rdev, + &usbvision_radio_template, "USBVision Radio"); + if (video_register_device(&usbvision->rdev, VFL_TYPE_RADIO, radio_nr) < 0) goto err_exit; printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device %s [v4l2]\n", - usbvision->nr, video_device_node_name(usbvision->rdev)); + usbvision->nr, video_device_node_name(&usbvision->rdev)); } /* all done */ return 0; @@ -1461,7 +1443,7 @@ static void usbvision_release(struct usb_usbvision *usbvision) usbvision->initialized = 0; - usbvision_remove_sysfs(usbvision->vdev); + usbvision_remove_sysfs(&usbvision->vdev); usbvision_unregister_video(usbvision); kfree(usbvision->alt_max_pkt_size); @@ -1525,7 +1507,7 @@ static int usbvision_probe(struct usb_interface *intf, const struct usb_host_interface *interface; struct usb_usbvision *usbvision = NULL; const struct usb_endpoint_descriptor *endpoint; - int model, i; + int model, i, ret; PDEBUG(DBG_PROBE, "VID=%#04x, PID=%#04x, ifnum=%u", dev->descriptor.idVendor, @@ -1534,7 +1516,8 @@ static int usbvision_probe(struct usb_interface *intf, model = devid->driver_info; if (model < 0 || model >= usbvision_device_data_size) { PDEBUG(DBG_PROBE, "model out of bounds %d", model); - return -ENODEV; + ret = -ENODEV; + goto err_usb; } printk(KERN_INFO "%s: %s found\n", __func__, usbvision_device_data[model].model_string); @@ -1549,18 +1532,21 @@ static int usbvision_probe(struct usb_interface *intf, __func__, ifnum); dev_err(&intf->dev, "%s: Endpoint attributes %d", __func__, endpoint->bmAttributes); - return -ENODEV; + ret = -ENODEV; + goto err_usb; } if (usb_endpoint_dir_out(endpoint)) { dev_err(&intf->dev, "%s: interface %d. has ISO OUT endpoint!\n", __func__, ifnum); - return -ENODEV; + ret = -ENODEV; + goto err_usb; } usbvision = usbvision_alloc(dev, intf); if (usbvision == NULL) { dev_err(&intf->dev, "%s: couldn't allocate USBVision struct\n", __func__); - return -ENOMEM; + ret = -ENOMEM; + goto err_usb; } if (dev->descriptor.bNumConfigurations > 1) @@ -1579,8 +1565,8 @@ static int usbvision_probe(struct usb_interface *intf, usbvision->alt_max_pkt_size = kmalloc(32 * usbvision->num_alt, GFP_KERNEL); if (usbvision->alt_max_pkt_size == NULL) { dev_err(&intf->dev, "usbvision: out of memory!\n"); - usbvision_release(usbvision); - return -ENOMEM; + ret = -ENOMEM; + goto err_pkt; } for (i = 0; i < usbvision->num_alt; i++) { @@ -1611,10 +1597,16 @@ static int usbvision_probe(struct usb_interface *intf, usbvision_configure_video(usbvision); usbvision_register_video(usbvision); - usbvision_create_sysfs(usbvision->vdev); + usbvision_create_sysfs(&usbvision->vdev); PDEBUG(DBG_PROBE, "success"); return 0; + +err_pkt: + usbvision_release(usbvision); +err_usb: + usb_put_dev(dev); + return ret; } diff --git a/drivers/media/usb/usbvision/usbvision.h b/drivers/media/usb/usbvision/usbvision.h index 77aeb1ed9a81..140a1f67566e 100644 --- a/drivers/media/usb/usbvision/usbvision.h +++ b/drivers/media/usb/usbvision/usbvision.h @@ -357,8 +357,8 @@ extern struct usb_device_id usbvision_table[]; struct usb_usbvision { struct v4l2_device v4l2_dev; - struct video_device *vdev; /* Video Device */ - struct video_device *rdev; /* Radio Device */ + struct video_device vdev; /* Video Device */ + struct video_device rdev; /* Radio Device */ /* i2c Declaration Section*/ struct i2c_adapter i2c_adap; diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index cf27006c29dc..5970dd6a1c1c 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -1669,10 +1669,6 @@ static void uvc_delete(struct uvc_device *dev) #ifdef CONFIG_MEDIA_CONTROLLER uvc_mc_cleanup_entity(entity); #endif - if (entity->vdev) { - video_device_release(entity->vdev); - entity->vdev = NULL; - } kfree(entity); } @@ -1717,11 +1713,10 @@ static void uvc_unregister_video(struct uvc_device *dev) atomic_inc(&dev->nstreams); list_for_each_entry(stream, &dev->streams, list) { - if (stream->vdev == NULL) + if (!video_is_registered(&stream->vdev)) continue; - video_unregister_device(stream->vdev); - stream->vdev = NULL; + video_unregister_device(&stream->vdev); uvc_debugfs_cleanup_stream(stream); } @@ -1736,7 +1731,7 @@ static void uvc_unregister_video(struct uvc_device *dev) static int uvc_register_video(struct uvc_device *dev, struct uvc_streaming *stream) { - struct video_device *vdev; + struct video_device *vdev = &stream->vdev; int ret; /* Initialize the video buffers queue. */ @@ -1757,12 +1752,6 @@ static int uvc_register_video(struct uvc_device *dev, uvc_debugfs_init_stream(stream); /* Register the device with V4L. */ - vdev = video_device_alloc(); - if (vdev == NULL) { - uvc_printk(KERN_ERR, "Failed to allocate video device (%d).\n", - ret); - return -ENOMEM; - } /* We already hold a reference to dev->udev. The video device will be * unregistered before the reference is released, so we don't need to @@ -1780,15 +1769,12 @@ static int uvc_register_video(struct uvc_device *dev, /* Set the driver data before calling video_register_device, otherwise * uvc_v4l2_open might race us. */ - stream->vdev = vdev; video_set_drvdata(vdev, stream); ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); if (ret < 0) { uvc_printk(KERN_ERR, "Failed to register video device (%d).\n", ret); - stream->vdev = NULL; - video_device_release(vdev); return ret; } @@ -1827,7 +1813,7 @@ static int uvc_register_terms(struct uvc_device *dev, if (ret < 0) return ret; - term->vdev = stream->vdev; + term->vdev = &stream->vdev; } return 0; @@ -2461,6 +2447,14 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_PROBE_MINMAX | UVC_QUIRK_PROBE_EXTRAFIELDS }, + /* Aveo Technology USB 2.0 Camera (Tasco USB Microscope) */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x1871, + .idProduct = 0x0516, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0 }, /* Ecamm Pico iMage */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index 10c554e7655c..87a19f33e460 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -306,25 +306,14 @@ int uvc_queue_streamoff(struct uvc_video_queue *queue, enum v4l2_buf_type type) int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma) { - int ret; - - mutex_lock(&queue->mutex); - ret = vb2_mmap(&queue->queue, vma); - mutex_unlock(&queue->mutex); - - return ret; + return vb2_mmap(&queue->queue, vma); } #ifndef CONFIG_MMU unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue, unsigned long pgoff) { - unsigned long ret; - - mutex_lock(&queue->mutex); - ret = vb2_get_unmapped_area(&queue->queue, 0, 0, pgoff, 0); - mutex_unlock(&queue->mutex); - return ret; + return vb2_get_unmapped_area(&queue->queue, 0, 0, pgoff, 0); } #endif diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 43e953f73e02..c4b1ac6750d8 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -511,7 +511,7 @@ static int uvc_v4l2_open(struct file *file) stream->dev->users++; mutex_unlock(&stream->dev->lock); - v4l2_fh_init(&handle->vfh, stream->vdev); + v4l2_fh_init(&handle->vfh, &stream->vdev); v4l2_fh_add(&handle->vfh); handle->chain = stream->chain; handle->stream = stream; @@ -882,6 +882,35 @@ static int uvc_ioctl_queryctrl(struct file *file, void *fh, return uvc_query_v4l2_ctrl(chain, qc); } +static int uvc_ioctl_query_ext_ctrl(struct file *file, void *fh, + struct v4l2_query_ext_ctrl *qec) +{ + struct uvc_fh *handle = fh; + struct uvc_video_chain *chain = handle->chain; + struct v4l2_queryctrl qc = { qec->id }; + int ret; + + ret = uvc_query_v4l2_ctrl(chain, &qc); + if (ret) + return ret; + + qec->id = qc.id; + qec->type = qc.type; + strlcpy(qec->name, qc.name, sizeof(qec->name)); + qec->minimum = qc.minimum; + qec->maximum = qc.maximum; + qec->step = qc.step; + qec->default_value = qc.default_value; + qec->flags = qc.flags; + qec->elem_size = 4; + qec->elems = 1; + qec->nr_of_dims = 0; + memset(qec->dims, 0, sizeof(qec->dims)); + memset(qec->reserved, 0, sizeof(qec->reserved)); + + return 0; +} + static int uvc_ioctl_g_ctrl(struct file *file, void *fh, struct v4l2_control *ctrl) { @@ -1018,26 +1047,37 @@ static int uvc_ioctl_querymenu(struct file *file, void *fh, return uvc_query_v4l2_menu(chain, qm); } -static int uvc_ioctl_cropcap(struct file *file, void *fh, - struct v4l2_cropcap *ccap) +static int uvc_ioctl_g_selection(struct file *file, void *fh, + struct v4l2_selection *sel) { struct uvc_fh *handle = fh; struct uvc_streaming *stream = handle->stream; - if (ccap->type != stream->type) + if (sel->type != stream->type) return -EINVAL; - ccap->bounds.left = 0; - ccap->bounds.top = 0; + switch (sel->target) { + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + if (stream->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + break; + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + if (stream->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + break; + default: + return -EINVAL; + } + + sel->r.left = 0; + sel->r.top = 0; mutex_lock(&stream->mutex); - ccap->bounds.width = stream->cur_frame->wWidth; - ccap->bounds.height = stream->cur_frame->wHeight; + sel->r.width = stream->cur_frame->wWidth; + sel->r.height = stream->cur_frame->wHeight; mutex_unlock(&stream->mutex); - ccap->defrect = ccap->bounds; - - ccap->pixelaspect.numerator = 1; - ccap->pixelaspect.denominator = 1; return 0; } @@ -1133,6 +1173,9 @@ static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh, uvc_simplify_fraction(&fival->discrete.numerator, &fival->discrete.denominator, 8, 333); } else { + if (fival->index) + return -EINVAL; + fival->type = V4L2_FRMIVAL_TYPE_STEPWISE; fival->stepwise.min.numerator = frame->dwFrameInterval[0]; fival->stepwise.min.denominator = 10000000; @@ -1443,13 +1486,14 @@ const struct v4l2_ioctl_ops uvc_ioctl_ops = { .vidioc_g_input = uvc_ioctl_g_input, .vidioc_s_input = uvc_ioctl_s_input, .vidioc_queryctrl = uvc_ioctl_queryctrl, + .vidioc_query_ext_ctrl = uvc_ioctl_query_ext_ctrl, .vidioc_g_ctrl = uvc_ioctl_g_ctrl, .vidioc_s_ctrl = uvc_ioctl_s_ctrl, .vidioc_g_ext_ctrls = uvc_ioctl_g_ext_ctrls, .vidioc_s_ext_ctrls = uvc_ioctl_s_ext_ctrls, .vidioc_try_ext_ctrls = uvc_ioctl_try_ext_ctrls, .vidioc_querymenu = uvc_ioctl_querymenu, - .vidioc_cropcap = uvc_ioctl_cropcap, + .vidioc_g_selection = uvc_ioctl_g_selection, .vidioc_g_parm = uvc_ioctl_g_parm, .vidioc_s_parm = uvc_ioctl_s_parm, .vidioc_enum_framesizes = uvc_ioctl_enum_framesizes, diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index c63e5b55e143..1b594c203992 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -443,7 +443,7 @@ struct uvc_stats_stream { struct uvc_streaming { struct list_head list; struct uvc_device *dev; - struct video_device *vdev; + struct video_device vdev; struct uvc_video_chain *chain; atomic_t active; diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c index 559f8372e2eb..abdcffabcb59 100644 --- a/drivers/media/v4l2-core/tuner-core.c +++ b/drivers/media/v4l2-core/tuner-core.c @@ -134,6 +134,9 @@ struct tuner { unsigned int type; /* chip type id */ void *config; const char *name; +#if defined(CONFIG_MEDIA_CONTROLLER) + struct media_pad pad; +#endif }; /* @@ -434,6 +437,10 @@ static void set_type(struct i2c_client *c, unsigned int type, t->name = analog_ops->info.name; } +#ifdef CONFIG_MEDIA_CONTROLLER + t->sd.entity.name = t->name; +#endif + tuner_dbg("type set to %s\n", t->name); t->mode_mask = new_mode_mask; @@ -592,6 +599,9 @@ static int tuner_probe(struct i2c_client *client, struct tuner *t; struct tuner *radio; struct tuner *tv; +#ifdef CONFIG_MEDIA_CONTROLLER + int ret; +#endif t = kzalloc(sizeof(struct tuner), GFP_KERNEL); if (NULL == t) @@ -684,6 +694,18 @@ static int tuner_probe(struct i2c_client *client, /* Should be just before return */ register_client: +#if defined(CONFIG_MEDIA_CONTROLLER) + t->pad.flags = MEDIA_PAD_FL_SOURCE; + t->sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_TUNER; + t->sd.entity.name = t->name; + + ret = media_entity_init(&t->sd.entity, 1, &t->pad, 0); + if (ret < 0) { + tuner_err("failed to initialize media entity!\n"); + kfree(t); + return -ENODEV; + } +#endif /* Sets a default mode */ if (t->mode_mask & T_ANALOG_TV) t->mode = V4L2_TUNER_ANALOG_TV; diff --git a/drivers/media/v4l2-core/v4l2-clk.c b/drivers/media/v4l2-core/v4l2-clk.c index e18cc0469cf8..34e416a554f6 100644 --- a/drivers/media/v4l2-core/v4l2-clk.c +++ b/drivers/media/v4l2-core/v4l2-clk.c @@ -9,6 +9,7 @@ */ #include <linux/atomic.h> +#include <linux/clk.h> #include <linux/device.h> #include <linux/errno.h> #include <linux/list.h> @@ -23,17 +24,13 @@ static DEFINE_MUTEX(clk_lock); static LIST_HEAD(clk_list); -static struct v4l2_clk *v4l2_clk_find(const char *dev_id, const char *id) +static struct v4l2_clk *v4l2_clk_find(const char *dev_id) { struct v4l2_clk *clk; - list_for_each_entry(clk, &clk_list, list) { - if (strcmp(dev_id, clk->dev_id)) - continue; - - if (!id || !clk->id || !strcmp(clk->id, id)) + list_for_each_entry(clk, &clk_list, list) + if (!strcmp(dev_id, clk->dev_id)) return clk; - } return ERR_PTR(-ENODEV); } @@ -41,9 +38,24 @@ static struct v4l2_clk *v4l2_clk_find(const char *dev_id, const char *id) struct v4l2_clk *v4l2_clk_get(struct device *dev, const char *id) { struct v4l2_clk *clk; + struct clk *ccf_clk = clk_get(dev, id); + + if (PTR_ERR(ccf_clk) == -EPROBE_DEFER) + return ERR_PTR(-EPROBE_DEFER); + + if (!IS_ERR_OR_NULL(ccf_clk)) { + clk = kzalloc(sizeof(*clk), GFP_KERNEL); + if (!clk) { + clk_put(ccf_clk); + return ERR_PTR(-ENOMEM); + } + clk->clk = ccf_clk; + + return clk; + } mutex_lock(&clk_lock); - clk = v4l2_clk_find(dev_name(dev), id); + clk = v4l2_clk_find(dev_name(dev)); if (!IS_ERR(clk)) atomic_inc(&clk->use_count); @@ -60,6 +72,12 @@ void v4l2_clk_put(struct v4l2_clk *clk) if (IS_ERR(clk)) return; + if (clk->clk) { + clk_put(clk->clk); + kfree(clk); + return; + } + mutex_lock(&clk_lock); list_for_each_entry(tmp, &clk_list, list) @@ -97,8 +115,12 @@ static void v4l2_clk_unlock_driver(struct v4l2_clk *clk) int v4l2_clk_enable(struct v4l2_clk *clk) { - int ret = v4l2_clk_lock_driver(clk); + int ret; + + if (clk->clk) + return clk_prepare_enable(clk->clk); + ret = v4l2_clk_lock_driver(clk); if (ret < 0) return ret; @@ -124,11 +146,14 @@ void v4l2_clk_disable(struct v4l2_clk *clk) { int enable; + if (clk->clk) + return clk_disable_unprepare(clk->clk); + mutex_lock(&clk->lock); enable = --clk->enable; - if (WARN(enable < 0, "Unbalanced %s() on %s:%s!\n", __func__, - clk->dev_id, clk->id)) + if (WARN(enable < 0, "Unbalanced %s() on %s!\n", __func__, + clk->dev_id)) clk->enable++; else if (!enable && clk->ops->disable) clk->ops->disable(clk); @@ -141,8 +166,12 @@ EXPORT_SYMBOL(v4l2_clk_disable); unsigned long v4l2_clk_get_rate(struct v4l2_clk *clk) { - int ret = v4l2_clk_lock_driver(clk); + int ret; + + if (clk->clk) + return clk_get_rate(clk->clk); + ret = v4l2_clk_lock_driver(clk); if (ret < 0) return ret; @@ -161,7 +190,16 @@ EXPORT_SYMBOL(v4l2_clk_get_rate); int v4l2_clk_set_rate(struct v4l2_clk *clk, unsigned long rate) { - int ret = v4l2_clk_lock_driver(clk); + int ret; + + if (clk->clk) { + long r = clk_round_rate(clk->clk, rate); + if (r < 0) + return r; + return clk_set_rate(clk->clk, r); + } + + ret = v4l2_clk_lock_driver(clk); if (ret < 0) return ret; @@ -181,7 +219,7 @@ EXPORT_SYMBOL(v4l2_clk_set_rate); struct v4l2_clk *v4l2_clk_register(const struct v4l2_clk_ops *ops, const char *dev_id, - const char *id, void *priv) + void *priv) { struct v4l2_clk *clk; int ret; @@ -193,9 +231,8 @@ struct v4l2_clk *v4l2_clk_register(const struct v4l2_clk_ops *ops, if (!clk) return ERR_PTR(-ENOMEM); - clk->id = kstrdup(id, GFP_KERNEL); clk->dev_id = kstrdup(dev_id, GFP_KERNEL); - if ((id && !clk->id) || !clk->dev_id) { + if (!clk->dev_id) { ret = -ENOMEM; goto ealloc; } @@ -205,7 +242,7 @@ struct v4l2_clk *v4l2_clk_register(const struct v4l2_clk_ops *ops, mutex_init(&clk->lock); mutex_lock(&clk_lock); - if (!IS_ERR(v4l2_clk_find(dev_id, id))) { + if (!IS_ERR(v4l2_clk_find(dev_id))) { mutex_unlock(&clk_lock); ret = -EEXIST; goto eexist; @@ -217,7 +254,6 @@ struct v4l2_clk *v4l2_clk_register(const struct v4l2_clk_ops *ops, eexist: ealloc: - kfree(clk->id); kfree(clk->dev_id); kfree(clk); return ERR_PTR(ret); @@ -227,15 +263,14 @@ EXPORT_SYMBOL(v4l2_clk_register); void v4l2_clk_unregister(struct v4l2_clk *clk) { if (WARN(atomic_read(&clk->use_count), - "%s(): Refusing to unregister ref-counted %s:%s clock!\n", - __func__, clk->dev_id, clk->id)) + "%s(): Refusing to unregister ref-counted %s clock!\n", + __func__, clk->dev_id)) return; mutex_lock(&clk_lock); list_del(&clk->list); mutex_unlock(&clk_lock); - kfree(clk->id); kfree(clk->dev_id); kfree(clk); } @@ -253,7 +288,7 @@ static unsigned long fixed_get_rate(struct v4l2_clk *clk) } struct v4l2_clk *__v4l2_clk_register_fixed(const char *dev_id, - const char *id, unsigned long rate, struct module *owner) + unsigned long rate, struct module *owner) { struct v4l2_clk *clk; struct v4l2_clk_fixed *priv = kzalloc(sizeof(*priv), GFP_KERNEL); @@ -265,7 +300,7 @@ struct v4l2_clk *__v4l2_clk_register_fixed(const char *dev_id, priv->ops.get_rate = fixed_get_rate; priv->ops.owner = owner; - clk = v4l2_clk_register(&priv->ops, dev_id, id, priv); + clk = v4l2_clk_register(&priv->ops, dev_id, priv); if (IS_ERR(clk)) kfree(priv); diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 45c5b4710601..e3a3468002e6 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -991,7 +991,8 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_AUTO_FOCUS_START: case V4L2_CID_AUTO_FOCUS_STOP: *type = V4L2_CTRL_TYPE_BUTTON; - *flags |= V4L2_CTRL_FLAG_WRITE_ONLY; + *flags |= V4L2_CTRL_FLAG_WRITE_ONLY | + V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; *min = *max = *step = *def = 0; break; case V4L2_CID_POWER_LINE_FREQUENCY: @@ -1172,7 +1173,8 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_FOCUS_RELATIVE: case V4L2_CID_IRIS_RELATIVE: case V4L2_CID_ZOOM_RELATIVE: - *flags |= V4L2_CTRL_FLAG_WRITE_ONLY; + *flags |= V4L2_CTRL_FLAG_WRITE_ONLY | + V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; break; case V4L2_CID_FLASH_STROBE_STATUS: case V4L2_CID_AUTO_FOCUS_STATUS: @@ -1609,6 +1611,19 @@ static int cluster_changed(struct v4l2_ctrl *master) if (ctrl == NULL) continue; + + if (ctrl->flags & V4L2_CTRL_FLAG_EXECUTE_ON_WRITE) + changed = ctrl_changed = true; + + /* + * Set has_changed to false to avoid generating + * the event V4L2_EVENT_CTRL_CH_VALUE + */ + if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) { + ctrl->has_changed = false; + continue; + } + for (idx = 0; !ctrl_changed && idx < ctrl->elems; idx++) ctrl_changed = !ctrl->type_ops->equal(ctrl, idx, ctrl->p_cur, ctrl->p_new); @@ -1974,7 +1989,8 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, sz_extra = 0; if (type == V4L2_CTRL_TYPE_BUTTON) - flags |= V4L2_CTRL_FLAG_WRITE_ONLY; + flags |= V4L2_CTRL_FLAG_WRITE_ONLY | + V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; else if (type == V4L2_CTRL_TYPE_CTRL_CLASS) flags |= V4L2_CTRL_FLAG_READ_ONLY; else if (type == V4L2_CTRL_TYPE_INTEGER64 || diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index 86bb93fd7db8..71a1b93b0790 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -357,34 +357,6 @@ static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ret = vdev->fops->unlocked_ioctl(filp, cmd, arg); if (lock) mutex_unlock(lock); - } else if (vdev->fops->ioctl) { - /* This code path is a replacement for the BKL. It is a major - * hack but it will have to do for those drivers that are not - * yet converted to use unlocked_ioctl. - * - * All drivers implement struct v4l2_device, so we use the - * lock defined there to serialize the ioctls. - * - * However, if the driver sleeps, then it blocks all ioctls - * since the lock is still held. This is very common for - * VIDIOC_DQBUF since that normally waits for a frame to arrive. - * As a result any other ioctl calls will proceed very, very - * slowly since each call will have to wait for the VIDIOC_QBUF - * to finish. Things that should take 0.01s may now take 10-20 - * seconds. - * - * The workaround is to *not* take the lock for VIDIOC_DQBUF. - * This actually works OK for videobuf-based drivers, since - * videobuf will take its own internal lock. - */ - struct mutex *m = &vdev->v4l2_dev->ioctl_lock; - - if (cmd != VIDIOC_DQBUF && mutex_lock_interruptible(m)) - return -ERESTARTSYS; - if (video_is_registered(vdev)) - ret = vdev->fops->ioctl(filp, cmd, arg); - if (cmd != VIDIOC_DQBUF) - mutex_unlock(m); } else ret = -ENOTTY; @@ -560,10 +532,9 @@ static void determine_valid_ioctls(struct video_device *vdev) /* vfl_type and vfl_dir independent ioctls */ SET_VALID_IOCTL(ops, VIDIOC_QUERYCAP, vidioc_querycap); - if (ops->vidioc_g_priority) - set_bit(_IOC_NR(VIDIOC_G_PRIORITY), valid_ioctls); - if (ops->vidioc_s_priority) - set_bit(_IOC_NR(VIDIOC_S_PRIORITY), valid_ioctls); + set_bit(_IOC_NR(VIDIOC_G_PRIORITY), valid_ioctls); + set_bit(_IOC_NR(VIDIOC_S_PRIORITY), valid_ioctls); + /* Note: the control handler can also be passed through the filehandle, and that can't be tested here. If the bit for these control ioctls is set, then the ioctl is valid. But if it is 0, then it can still @@ -640,6 +611,14 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_TRY_DECODER_CMD, vidioc_try_decoder_cmd); SET_VALID_IOCTL(ops, VIDIOC_ENUM_FRAMESIZES, vidioc_enum_framesizes); SET_VALID_IOCTL(ops, VIDIOC_ENUM_FRAMEINTERVALS, vidioc_enum_frameintervals); + if (ops->vidioc_g_crop || ops->vidioc_g_selection) + set_bit(_IOC_NR(VIDIOC_G_CROP), valid_ioctls); + if (ops->vidioc_s_crop || ops->vidioc_s_selection) + set_bit(_IOC_NR(VIDIOC_S_CROP), valid_ioctls); + SET_VALID_IOCTL(ops, VIDIOC_G_SELECTION, vidioc_g_selection); + SET_VALID_IOCTL(ops, VIDIOC_S_SELECTION, vidioc_s_selection); + if (ops->vidioc_cropcap || ops->vidioc_g_selection) + set_bit(_IOC_NR(VIDIOC_CROPCAP), valid_ioctls); } else if (is_vbi) { /* vbi specific ioctls */ if ((is_rx && (ops->vidioc_g_fmt_vbi_cap || @@ -708,14 +687,6 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_G_AUDOUT, vidioc_g_audout); SET_VALID_IOCTL(ops, VIDIOC_S_AUDOUT, vidioc_s_audout); } - if (ops->vidioc_g_crop || ops->vidioc_g_selection) - set_bit(_IOC_NR(VIDIOC_G_CROP), valid_ioctls); - if (ops->vidioc_s_crop || ops->vidioc_s_selection) - set_bit(_IOC_NR(VIDIOC_S_CROP), valid_ioctls); - SET_VALID_IOCTL(ops, VIDIOC_G_SELECTION, vidioc_g_selection); - SET_VALID_IOCTL(ops, VIDIOC_S_SELECTION, vidioc_s_selection); - if (ops->vidioc_cropcap || ops->vidioc_g_selection) - set_bit(_IOC_NR(VIDIOC_CROPCAP), valid_ioctls); if (ops->vidioc_g_parm || (vdev->vfl_type == VFL_TYPE_GRABBER && ops->vidioc_g_std)) set_bit(_IOC_NR(VIDIOC_G_PARM), valid_ioctls); @@ -943,8 +914,8 @@ int __video_register_device(struct video_device *vdev, int type, int nr, vdev->vfl_type != VFL_TYPE_SUBDEV) { vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L; vdev->entity.name = vdev->name; - vdev->entity.info.v4l.major = VIDEO_MAJOR; - vdev->entity.info.v4l.minor = vdev->minor; + vdev->entity.info.dev.major = VIDEO_MAJOR; + vdev->entity.info.dev.minor = vdev->minor; ret = media_device_register_entity(vdev->v4l2_dev->mdev, &vdev->entity); if (ret < 0) diff --git a/drivers/media/v4l2-core/v4l2-device.c b/drivers/media/v4l2-core/v4l2-device.c index 015f92aab44a..5b0a30b9252b 100644 --- a/drivers/media/v4l2-core/v4l2-device.c +++ b/drivers/media/v4l2-core/v4l2-device.c @@ -37,7 +37,6 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev) INIT_LIST_HEAD(&v4l2_dev->subdevs); spin_lock_init(&v4l2_dev->lock); - mutex_init(&v4l2_dev->ioctl_lock); v4l2_prio_init(&v4l2_dev->prio); kref_init(&v4l2_dev->ref); get_device(dev); @@ -248,8 +247,8 @@ int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev) goto clean_up; } #if defined(CONFIG_MEDIA_CONTROLLER) - sd->entity.info.v4l.major = VIDEO_MAJOR; - sd->entity.info.v4l.minor = vdev->minor; + sd->entity.info.dev.major = VIDEO_MAJOR; + sd->entity.info.dev.minor = vdev->minor; #endif sd->devnode = vdev; } diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c index b1d8dbb39665..c0e96382feba 100644 --- a/drivers/media/v4l2-core/v4l2-dv-timings.c +++ b/drivers/media/v4l2-core/v4l2-dv-timings.c @@ -282,7 +282,7 @@ void v4l2_print_dv_timings(const char *dev_prefix, const char *prefix, (bt->polarities & V4L2_DV_VSYNC_POS_POL) ? "+" : "-", bt->vsync, bt->vbackporch); pr_info("%s: pixelclock: %llu\n", dev_prefix, bt->pixelclock); - pr_info("%s: flags (0x%x):%s%s%s%s\n", dev_prefix, bt->flags, + pr_info("%s: flags (0x%x):%s%s%s%s%s\n", dev_prefix, bt->flags, (bt->flags & V4L2_DV_FL_REDUCED_BLANKING) ? " REDUCED_BLANKING" : "", (bt->flags & V4L2_DV_FL_CAN_REDUCE_FPS) ? @@ -290,7 +290,9 @@ void v4l2_print_dv_timings(const char *dev_prefix, const char *prefix, (bt->flags & V4L2_DV_FL_REDUCED_FPS) ? " REDUCED_FPS" : "", (bt->flags & V4L2_DV_FL_HALF_LINE) ? - " HALF_LINE" : ""); + " HALF_LINE" : "", + (bt->flags & V4L2_DV_FL_IS_CE_VIDEO) ? + " CE_VIDEO" : ""); pr_info("%s: standards (0x%x):%s%s%s%s\n", dev_prefix, bt->standards, (bt->standards & V4L2_DV_BT_STD_CEA861) ? " CEA" : "", (bt->standards & V4L2_DV_BT_STD_DMT) ? " DMT" : "", diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index b08407225db1..aa407cb5f830 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -257,7 +257,7 @@ static void v4l_print_format(const void *arg, bool write_only) pr_cont(", width=%u, height=%u, " "pixelformat=%c%c%c%c, field=%s, " "bytesperline=%u, sizeimage=%u, colorspace=%d, " - "flags %x, ycbcr_enc=%u, quantization=%u\n", + "flags=0x%x, ycbcr_enc=%u, quantization=%u\n", pix->width, pix->height, (pix->pixelformat & 0xff), (pix->pixelformat >> 8) & 0xff, @@ -273,7 +273,7 @@ static void v4l_print_format(const void *arg, bool write_only) mp = &p->fmt.pix_mp; pr_cont(", width=%u, height=%u, " "format=%c%c%c%c, field=%s, " - "colorspace=%d, num_planes=%u, flags=%x, " + "colorspace=%d, num_planes=%u, flags=0x%x, " "ycbcr_enc=%u, quantization=%u\n", mp->width, mp->height, (mp->pixelformat & 0xff), @@ -901,6 +901,8 @@ static int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv) */ if (!allow_priv && c->ctrl_class == V4L2_CID_PRIVATE_BASE) return 0; + if (c->ctrl_class == 0) + return 1; /* Check that all controls are from the same control class. */ for (i = 0; i < c->count; i++) { if (V4L2_CTRL_ID2CLASS(c->controls[i].id) != c->ctrl_class) { @@ -1046,8 +1048,6 @@ static int v4l_g_priority(const struct v4l2_ioctl_ops *ops, struct video_device *vfd; u32 *p = arg; - if (ops->vidioc_g_priority) - return ops->vidioc_g_priority(file, fh, arg); vfd = video_devdata(file); *p = v4l2_prio_max(vfd->prio); return 0; @@ -1060,9 +1060,9 @@ static int v4l_s_priority(const struct v4l2_ioctl_ops *ops, struct v4l2_fh *vfh; u32 *p = arg; - if (ops->vidioc_s_priority) - return ops->vidioc_s_priority(file, fh, *p); vfd = video_devdata(file); + if (!test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) + return -ENOTTY; vfh = file->private_data; return v4l2_prio_change(vfd->prio, &vfh->prio, *p); } diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index 80c588f4e429..73824a5ada83 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -97,7 +97,7 @@ EXPORT_SYMBOL(v4l2_m2m_get_vq); */ void *v4l2_m2m_next_buf(struct v4l2_m2m_queue_ctx *q_ctx) { - struct v4l2_m2m_buffer *b = NULL; + struct v4l2_m2m_buffer *b; unsigned long flags; spin_lock_irqsave(&q_ctx->rdy_spinlock, flags); @@ -119,7 +119,7 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_next_buf); */ void *v4l2_m2m_buf_remove(struct v4l2_m2m_queue_ctx *q_ctx) { - struct v4l2_m2m_buffer *b = NULL; + struct v4l2_m2m_buffer *b; unsigned long flags; spin_lock_irqsave(&q_ctx->rdy_spinlock, flags); diff --git a/drivers/media/v4l2-core/v4l2-of.c b/drivers/media/v4l2-core/v4l2-of.c index b4ed9a955fbe..83143d39dea7 100644 --- a/drivers/media/v4l2-core/v4l2-of.c +++ b/drivers/media/v4l2-core/v4l2-of.c @@ -19,11 +19,10 @@ #include <media/v4l2-of.h> -static void v4l2_of_parse_csi_bus(const struct device_node *node, - struct v4l2_of_endpoint *endpoint) +static int v4l2_of_parse_csi_bus(const struct device_node *node, + struct v4l2_of_endpoint *endpoint) { struct v4l2_of_bus_mipi_csi2 *bus = &endpoint->bus.mipi_csi2; - u32 data_lanes[ARRAY_SIZE(bus->data_lanes)]; struct property *prop; bool have_clk_lane = false; unsigned int flags = 0; @@ -32,16 +31,34 @@ static void v4l2_of_parse_csi_bus(const struct device_node *node, prop = of_find_property(node, "data-lanes", NULL); if (prop) { const __be32 *lane = NULL; - int i; + unsigned int i; - for (i = 0; i < ARRAY_SIZE(data_lanes); i++) { - lane = of_prop_next_u32(prop, lane, &data_lanes[i]); + for (i = 0; i < ARRAY_SIZE(bus->data_lanes); i++) { + lane = of_prop_next_u32(prop, lane, &v); if (!lane) break; + bus->data_lanes[i] = v; } bus->num_data_lanes = i; - while (i--) - bus->data_lanes[i] = data_lanes[i]; + } + + prop = of_find_property(node, "lane-polarities", NULL); + if (prop) { + const __be32 *polarity = NULL; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(bus->lane_polarities); i++) { + polarity = of_prop_next_u32(prop, polarity, &v); + if (!polarity) + break; + bus->lane_polarities[i] = v; + } + + if (i < 1 + bus->num_data_lanes /* clock + data */) { + pr_warn("%s: too few lane-polarities entries (need %u, got %u)\n", + node->full_name, 1 + bus->num_data_lanes, i); + return -EINVAL; + } } if (!of_property_read_u32(node, "clock-lanes", &v)) { @@ -56,6 +73,8 @@ static void v4l2_of_parse_csi_bus(const struct device_node *node, bus->flags = flags; endpoint->bus_type = V4L2_MBUS_CSI2; + + return 0; } static void v4l2_of_parse_parallel_bus(const struct device_node *node, @@ -127,11 +146,15 @@ static void v4l2_of_parse_parallel_bus(const struct device_node *node, int v4l2_of_parse_endpoint(const struct device_node *node, struct v4l2_of_endpoint *endpoint) { + int rval; + of_graph_parse_endpoint(node, &endpoint->base); endpoint->bus_type = 0; memset(&endpoint->bus, 0, sizeof(endpoint->bus)); - v4l2_of_parse_csi_bus(node, endpoint); + rval = v4l2_of_parse_csi_bus(node, endpoint); + if (rval) + return rval; /* * Parse the parallel video bus properties only if none * of the MIPI CSI-2 specific properties were found. @@ -142,3 +165,64 @@ int v4l2_of_parse_endpoint(const struct device_node *node, return 0; } EXPORT_SYMBOL(v4l2_of_parse_endpoint); + +/** + * v4l2_of_parse_link() - parse a link between two endpoints + * @node: pointer to the endpoint at the local end of the link + * @link: pointer to the V4L2 OF link data structure + * + * Fill the link structure with the local and remote nodes and port numbers. + * The local_node and remote_node fields are set to point to the local and + * remote port's parent nodes respectively (the port parent node being the + * parent node of the port node if that node isn't a 'ports' node, or the + * grand-parent node of the port node otherwise). + * + * A reference is taken to both the local and remote nodes, the caller must use + * v4l2_of_put_link() to drop the references when done with the link. + * + * Return: 0 on success, or -ENOLINK if the remote endpoint can't be found. + */ +int v4l2_of_parse_link(const struct device_node *node, + struct v4l2_of_link *link) +{ + struct device_node *np; + + memset(link, 0, sizeof(*link)); + + np = of_get_parent(node); + of_property_read_u32(np, "reg", &link->local_port); + np = of_get_next_parent(np); + if (of_node_cmp(np->name, "ports") == 0) + np = of_get_next_parent(np); + link->local_node = np; + + np = of_parse_phandle(node, "remote-endpoint", 0); + if (!np) { + of_node_put(link->local_node); + return -ENOLINK; + } + + np = of_get_parent(np); + of_property_read_u32(np, "reg", &link->remote_port); + np = of_get_next_parent(np); + if (of_node_cmp(np->name, "ports") == 0) + np = of_get_next_parent(np); + link->remote_node = np; + + return 0; +} +EXPORT_SYMBOL(v4l2_of_parse_link); + +/** + * v4l2_of_put_link() - drop references to nodes in a link + * @link: pointer to the V4L2 OF link data structure + * + * Drop references to the local and remote nodes in the link. This function must + * be called on every link parsed with v4l2_of_parse_link(). + */ +void v4l2_of_put_link(struct v4l2_of_link *link) +{ + of_node_put(link->local_node); + of_node_put(link->remote_node); +} +EXPORT_SYMBOL(v4l2_of_put_link); diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 19a034e79be4..63596063b213 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -93,8 +93,7 @@ static int subdev_open(struct file *file) err: #if defined(CONFIG_MEDIA_CONTROLLER) - if (entity) - media_entity_put(entity); + media_entity_put(entity); #endif v4l2_fh_del(&subdev_fh->vfh); v4l2_fh_exit(&subdev_fh->vfh); @@ -262,7 +261,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (rval) return rval; - return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh, format); + return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh->pad, format); } case VIDIOC_SUBDEV_S_FMT: { @@ -272,7 +271,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (rval) return rval; - return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh, format); + return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh->pad, format); } case VIDIOC_SUBDEV_G_CROP: { @@ -289,7 +288,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) sel.target = V4L2_SEL_TGT_CROP; rval = v4l2_subdev_call( - sd, pad, get_selection, subdev_fh, &sel); + sd, pad, get_selection, subdev_fh->pad, &sel); crop->rect = sel.r; @@ -311,7 +310,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) sel.r = crop->rect; rval = v4l2_subdev_call( - sd, pad, set_selection, subdev_fh, &sel); + sd, pad, set_selection, subdev_fh->pad, &sel); crop->rect = sel.r; @@ -321,20 +320,28 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_ENUM_MBUS_CODE: { struct v4l2_subdev_mbus_code_enum *code = arg; + if (code->which != V4L2_SUBDEV_FORMAT_TRY && + code->which != V4L2_SUBDEV_FORMAT_ACTIVE) + return -EINVAL; + if (code->pad >= sd->entity.num_pads) return -EINVAL; - return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh, + return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh->pad, code); } case VIDIOC_SUBDEV_ENUM_FRAME_SIZE: { struct v4l2_subdev_frame_size_enum *fse = arg; + if (fse->which != V4L2_SUBDEV_FORMAT_TRY && + fse->which != V4L2_SUBDEV_FORMAT_ACTIVE) + return -EINVAL; + if (fse->pad >= sd->entity.num_pads) return -EINVAL; - return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh, + return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh->pad, fse); } @@ -359,10 +366,14 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL: { struct v4l2_subdev_frame_interval_enum *fie = arg; + if (fie->which != V4L2_SUBDEV_FORMAT_TRY && + fie->which != V4L2_SUBDEV_FORMAT_ACTIVE) + return -EINVAL; + if (fie->pad >= sd->entity.num_pads) return -EINVAL; - return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh, + return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh->pad, fie); } @@ -374,7 +385,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) return rval; return v4l2_subdev_call( - sd, pad, get_selection, subdev_fh, sel); + sd, pad, get_selection, subdev_fh->pad, sel); } case VIDIOC_SUBDEV_S_SELECTION: { @@ -385,7 +396,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) return rval; return v4l2_subdev_call( - sd, pad, set_selection, subdev_fh, sel); + sd, pad, set_selection, subdev_fh->pad, sel); } case VIDIOC_G_EDID: { diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index cc16e76a2493..0931eaa75768 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -1247,6 +1247,16 @@ static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b { unsigned int plane; + if (V4L2_TYPE_IS_OUTPUT(b->type)) { + if (WARN_ON_ONCE(b->bytesused == 0)) { + pr_warn_once("use of bytesused == 0 is deprecated and will be removed in the future,\n"); + if (vb->vb2_queue->allow_zero_bytesused) + pr_warn_once("use VIDIOC_DECODER_CMD(V4L2_DEC_CMD_STOP) instead.\n"); + else + pr_warn_once("use the actual size instead.\n"); + } + } + if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) { if (b->memory == V4L2_MEMORY_USERPTR) { for (plane = 0; plane < vb->num_planes; ++plane) { @@ -1276,13 +1286,22 @@ static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b * userspace clearly never bothered to set it and * it's a safe assumption that they really meant to * use the full plane sizes. + * + * Some drivers, e.g. old codec drivers, use bytesused == 0 + * as a way to indicate that streaming is finished. + * In that case, the driver should use the + * allow_zero_bytesused flag to keep old userspace + * applications working. */ for (plane = 0; plane < vb->num_planes; ++plane) { struct v4l2_plane *pdst = &v4l2_planes[plane]; struct v4l2_plane *psrc = &b->m.planes[plane]; - pdst->bytesused = psrc->bytesused ? - psrc->bytesused : pdst->length; + if (vb->vb2_queue->allow_zero_bytesused) + pdst->bytesused = psrc->bytesused; + else + pdst->bytesused = psrc->bytesused ? + psrc->bytesused : pdst->length; pdst->data_offset = psrc->data_offset; } } @@ -1295,6 +1314,11 @@ static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b * * If bytesused == 0 for the output buffer, then fall back * to the full buffer size as that's a sensible default. + * + * Some drivers, e.g. old codec drivers, use bytesused == 0 as + * a way to indicate that streaming is finished. In that case, + * the driver should use the allow_zero_bytesused flag to keep + * old userspace applications working. */ if (b->memory == V4L2_MEMORY_USERPTR) { v4l2_planes[0].m.userptr = b->m.userptr; @@ -1306,10 +1330,13 @@ static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b v4l2_planes[0].length = b->length; } - if (V4L2_TYPE_IS_OUTPUT(b->type)) - v4l2_planes[0].bytesused = b->bytesused ? - b->bytesused : v4l2_planes[0].length; - else + if (V4L2_TYPE_IS_OUTPUT(b->type)) { + if (vb->vb2_queue->allow_zero_bytesused) + v4l2_planes[0].bytesused = b->bytesused; + else + v4l2_planes[0].bytesused = b->bytesused ? + b->bytesused : v4l2_planes[0].length; + } else v4l2_planes[0].bytesused = 0; } @@ -2760,7 +2787,8 @@ struct vb2_fileio_data { unsigned int initial_index; unsigned int q_count; unsigned int dq_count; - unsigned int flags; + unsigned read_once:1; + unsigned write_immediately:1; }; /** @@ -2798,14 +2826,16 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read) */ count = 1; - dprintk(3, "setting up file io: mode %s, count %d, flags %08x\n", - (read) ? "read" : "write", count, q->io_flags); + dprintk(3, "setting up file io: mode %s, count %d, read_once %d, write_immediately %d\n", + (read) ? "read" : "write", count, q->fileio_read_once, + q->fileio_write_immediately); fileio = kzalloc(sizeof(struct vb2_fileio_data), GFP_KERNEL); if (fileio == NULL) return -ENOMEM; - fileio->flags = q->io_flags; + fileio->read_once = q->fileio_read_once; + fileio->write_immediately = q->fileio_write_immediately; /* * Request buffers and use MMAP type to force driver @@ -3028,13 +3058,11 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ /* * Queue next buffer if required. */ - if (buf->pos == buf->size || - (!read && (fileio->flags & VB2_FILEIO_WRITE_IMMEDIATELY))) { + if (buf->pos == buf->size || (!read && fileio->write_immediately)) { /* * Check if this is the last buffer to read. */ - if (read && (fileio->flags & VB2_FILEIO_READ_ONCE) && - fileio->dq_count == 1) { + if (read && fileio->read_once && fileio->dq_count == 1) { dprintk(3, "read limit reached\n"); return __vb2_cleanup_fileio(q); } @@ -3411,6 +3439,8 @@ ssize_t vb2_fop_write(struct file *file, const char __user *buf, struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock; int err = -EBUSY; + if (!(vdev->queue->io_modes & VB2_WRITE)) + return -EINVAL; if (lock && mutex_lock_interruptible(lock)) return -ERESTARTSYS; if (vb2_queue_is_busy(vdev, file)) @@ -3433,6 +3463,8 @@ ssize_t vb2_fop_read(struct file *file, char __user *buf, struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock; int err = -EBUSY; + if (!(vdev->queue->io_modes & VB2_READ)) + return -EINVAL; if (lock && mutex_lock_interruptible(lock)) return -ERESTARTSYS; if (vb2_queue_is_busy(vdev, file)) diff --git a/drivers/staging/media/bcm2048/radio-bcm2048.c b/drivers/staging/media/bcm2048/radio-bcm2048.c index 538250667918..bd50fb204019 100644 --- a/drivers/staging/media/bcm2048/radio-bcm2048.c +++ b/drivers/staging/media/bcm2048/radio-bcm2048.c @@ -279,7 +279,7 @@ struct region_info { struct bcm2048_device { struct i2c_client *client; - struct video_device *videodev; + struct video_device videodev; struct work_struct work; struct completion compl; struct mutex mutex; @@ -1579,7 +1579,7 @@ static void bcm2048_parse_rt_match_d(struct bcm2048_device *bdev, int i, bcm2048_parse_rds_rt_block(bdev, i, index+2, crc); } -static int bcm2048_parse_rds_rt(struct bcm2048_device *bdev) +static void bcm2048_parse_rds_rt(struct bcm2048_device *bdev) { int i, index = 0, crc, match_b = 0, match_c = 0, match_d = 0; @@ -1615,8 +1615,6 @@ static int bcm2048_parse_rds_rt(struct bcm2048_device *bdev) match_b = 1; } } - - return 0; } static void bcm2048_parse_rds_ps_block(struct bcm2048_device *bdev, int i, @@ -2274,7 +2272,7 @@ done: */ static const struct v4l2_file_operations bcm2048_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, /* for RDS read support */ .open = bcm2048_fops_open, .release = bcm2048_fops_release, @@ -2585,7 +2583,7 @@ static struct v4l2_ioctl_ops bcm2048_ioctl_ops = { static struct video_device bcm2048_viddev_template = { .fops = &bcm2048_fops, .name = BCM2048_DRIVER_NAME, - .release = video_device_release, + .release = video_device_release_empty, .ioctl_ops = &bcm2048_ioctl_ops, }; @@ -2604,13 +2602,6 @@ static int bcm2048_i2c_driver_probe(struct i2c_client *client, goto exit; } - bdev->videodev = video_device_alloc(); - if (!bdev->videodev) { - dev_dbg(&client->dev, "Failed to alloc video device.\n"); - err = -ENOMEM; - goto free_bdev; - } - bdev->client = client; i2c_set_clientdata(client, bdev); mutex_init(&bdev->mutex); @@ -2623,16 +2614,16 @@ static int bcm2048_i2c_driver_probe(struct i2c_client *client, client->name, bdev); if (err < 0) { dev_err(&client->dev, "Could not request IRQ\n"); - goto free_vdev; + goto free_bdev; } dev_dbg(&client->dev, "IRQ requested.\n"); } else { dev_dbg(&client->dev, "IRQ not configured. Using timeouts.\n"); } - *bdev->videodev = bcm2048_viddev_template; - video_set_drvdata(bdev->videodev, bdev); - if (video_register_device(bdev->videodev, VFL_TYPE_RADIO, radio_nr)) { + bdev->videodev = bcm2048_viddev_template; + video_set_drvdata(&bdev->videodev, bdev); + if (video_register_device(&bdev->videodev, VFL_TYPE_RADIO, radio_nr)) { dev_dbg(&client->dev, "Could not register video device.\n"); err = -EIO; goto free_irq; @@ -2655,18 +2646,13 @@ static int bcm2048_i2c_driver_probe(struct i2c_client *client, free_sysfs: bcm2048_sysfs_unregister_properties(bdev, ARRAY_SIZE(attrs)); free_registration: - video_unregister_device(bdev->videodev); - /* video_unregister_device frees bdev->videodev */ - bdev->videodev = NULL; + video_unregister_device(&bdev->videodev); skip_release = 1; free_irq: if (client->irq) free_irq(client->irq, bdev); -free_vdev: - if (!skip_release) - video_device_release(bdev->videodev); - i2c_set_clientdata(client, NULL); free_bdev: + i2c_set_clientdata(client, NULL); kfree(bdev); exit: return err; @@ -2675,16 +2661,13 @@ exit: static int __exit bcm2048_i2c_driver_remove(struct i2c_client *client) { struct bcm2048_device *bdev = i2c_get_clientdata(client); - struct video_device *vd; if (!client->adapter) return -ENODEV; if (bdev) { - vd = bdev->videodev; - bcm2048_sysfs_unregister_properties(bdev, ARRAY_SIZE(attrs)); - video_unregister_device(vd); + video_unregister_device(&bdev->videodev); if (bdev->power_state) bcm2048_set_power_state(bdev, BCM2048_POWER_OFF); diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c b/drivers/staging/media/davinci_vpfe/dm365_ipipe.c index a425f71dfb97..1bbb90ce0086 100644 --- a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c +++ b/drivers/staging/media/davinci_vpfe/dm365_ipipe.c @@ -1414,17 +1414,17 @@ static int ipipe_set_stream(struct v4l2_subdev *sd, int enable) * __ipipe_get_format() - helper function for getting ipipe format * @ipipe: pointer to ipipe private structure. * @pad: pad number. - * @fh: V4L2 subdev file handle. + * @cfg: V4L2 subdev pad config * @which: wanted subdev format. * */ static struct v4l2_mbus_framefmt * __ipipe_get_format(struct vpfe_ipipe_device *ipipe, - struct v4l2_subdev_fh *fh, unsigned int pad, + struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&ipipe->subdev, cfg, pad); return &ipipe->formats[pad]; } @@ -1432,14 +1432,14 @@ __ipipe_get_format(struct vpfe_ipipe_device *ipipe, /* * ipipe_try_format() - Handle try format by pad subdev method * @ipipe: VPFE ipipe device. - * @fh: V4L2 subdev file handle. + * @cfg: V4L2 subdev pad config * @pad: pad num. * @fmt: pointer to v4l2 format structure. * @which : wanted subdev format */ static void ipipe_try_format(struct vpfe_ipipe_device *ipipe, - struct v4l2_subdev_fh *fh, unsigned int pad, + struct v4l2_subdev_pad_config *cfg, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -1475,22 +1475,22 @@ ipipe_try_format(struct vpfe_ipipe_device *ipipe, /* * ipipe_set_format() - Handle set format by pads subdev method * @sd: pointer to v4l2 subdev structure - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @fmt: pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ static int -ipipe_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +ipipe_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vpfe_ipipe_device *ipipe = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __ipipe_get_format(ipipe, fh, fmt->pad, fmt->which); + format = __ipipe_get_format(ipipe, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; - ipipe_try_format(ipipe, fh, fmt->pad, &fmt->format, fmt->which); + ipipe_try_format(ipipe, cfg, fmt->pad, &fmt->format, fmt->which); *format = fmt->format; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) @@ -1512,11 +1512,11 @@ ipipe_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * ipipe_get_format() - Handle get format by pads subdev method. * @sd: pointer to v4l2 subdev structure. - * @fh: V4L2 subdev file handle. + * @cfg: V4L2 subdev pad config * @fmt: pointer to v4l2 subdev format structure. */ static int -ipipe_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +ipipe_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vpfe_ipipe_device *ipipe = v4l2_get_subdevdata(sd); @@ -1524,7 +1524,7 @@ ipipe_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) fmt->format = ipipe->formats[fmt->pad]; else - fmt->format = *(v4l2_subdev_get_try_format(fh, fmt->pad)); + fmt->format = *(v4l2_subdev_get_try_format(sd, cfg, fmt->pad)); return 0; } @@ -1532,11 +1532,11 @@ ipipe_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * ipipe_enum_frame_size() - enum frame sizes on pads * @sd: pointer to v4l2 subdev structure. - * @fh: V4L2 subdev file handle. + * @cfg: V4L2 subdev pad config * @fse: pointer to v4l2_subdev_frame_size_enum structure. */ static int -ipipe_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +ipipe_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct vpfe_ipipe_device *ipipe = v4l2_get_subdevdata(sd); @@ -1548,8 +1548,7 @@ ipipe_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, format.code = fse->code; format.width = 1; format.height = 1; - ipipe_try_format(ipipe, fh, fse->pad, &format, - V4L2_SUBDEV_FORMAT_TRY); + ipipe_try_format(ipipe, cfg, fse->pad, &format, fse->which); fse->min_width = format.width; fse->min_height = format.height; @@ -1559,8 +1558,7 @@ ipipe_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, format.code = fse->code; format.width = -1; format.height = -1; - ipipe_try_format(ipipe, fh, fse->pad, &format, - V4L2_SUBDEV_FORMAT_TRY); + ipipe_try_format(ipipe, cfg, fse->pad, &format, fse->which); fse->max_width = format.width; fse->max_height = format.height; @@ -1570,11 +1568,11 @@ ipipe_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * ipipe_enum_mbus_code() - enum mbus codes for pads * @sd: pointer to v4l2 subdev structure. - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @code: pointer to v4l2_subdev_mbus_code_enum structure */ static int -ipipe_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +ipipe_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { switch (code->pad) { @@ -1630,9 +1628,8 @@ static int ipipe_s_ctrl(struct v4l2_ctrl *ctrl) * @sd: pointer to v4l2 subdev structure. * @fh: V4L2 subdev file handle * - * Initialize all pad formats with default values. If fh is not NULL, try - * formats are initialized on the file handle. Otherwise active formats are - * initialized on the device. + * Initialize all pad formats with default values. Try formats are initialized + * on the file handle. */ static int ipipe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) @@ -1641,19 +1638,19 @@ ipipe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) memset(&format, 0, sizeof(format)); format.pad = IPIPE_PAD_SINK; - format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + format.which = V4L2_SUBDEV_FORMAT_TRY; format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12; format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A; format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A; - ipipe_set_format(sd, fh, &format); + ipipe_set_format(sd, fh->pad, &format); memset(&format, 0, sizeof(format)); format.pad = IPIPE_PAD_SOURCE; - format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + format.which = V4L2_SUBDEV_FORMAT_TRY; format.format.code = MEDIA_BUS_FMT_UYVY8_2X8; format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A; format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A; - ipipe_set_format(sd, fh, &format); + ipipe_set_format(sd, fh->pad, &format); return 0; } diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c b/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c index 87d42e18377d..0495bccd5172 100644 --- a/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c +++ b/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c @@ -544,12 +544,12 @@ static int ipipeif_set_stream(struct v4l2_subdev *sd, int enable) /* * ipipeif_enum_mbus_code() - Handle pixel format enumeration * @sd: pointer to v4l2 subdev structure - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @code: pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { switch (code->pad) { @@ -577,11 +577,11 @@ static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd, /* * ipipeif_get_format() - Handle get format by pads subdev method * @sd: pointer to v4l2 subdev structure - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @fmt: pointer to v4l2 subdev format structure */ static int -ipipeif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +ipipeif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); @@ -589,7 +589,7 @@ ipipeif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) fmt->format = ipipeif->formats[fmt->pad]; else - fmt->format = *(v4l2_subdev_get_try_format(fh, fmt->pad)); + fmt->format = *(v4l2_subdev_get_try_format(sd, cfg, fmt->pad)); return 0; } @@ -600,14 +600,14 @@ ipipeif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * ipipeif_try_format() - Handle try format by pad subdev method * @ipipeif: VPFE ipipeif device. - * @fh: V4L2 subdev file handle. + * @cfg: V4L2 subdev pad config * @pad: pad num. * @fmt: pointer to v4l2 format structure. * @which : wanted subdev format */ static void ipipeif_try_format(struct vpfe_ipipeif_device *ipipeif, - struct v4l2_subdev_fh *fh, unsigned int pad, + struct v4l2_subdev_pad_config *cfg, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -641,7 +641,7 @@ ipipeif_try_format(struct vpfe_ipipeif_device *ipipeif, } static int -ipipeif_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +ipipeif_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); @@ -653,8 +653,7 @@ ipipeif_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, format.code = fse->code; format.width = 1; format.height = 1; - ipipeif_try_format(ipipeif, fh, fse->pad, &format, - V4L2_SUBDEV_FORMAT_TRY); + ipipeif_try_format(ipipeif, cfg, fse->pad, &format, fse->which); fse->min_width = format.width; fse->min_height = format.height; @@ -664,8 +663,7 @@ ipipeif_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, format.code = fse->code; format.width = -1; format.height = -1; - ipipeif_try_format(ipipeif, fh, fse->pad, &format, - V4L2_SUBDEV_FORMAT_TRY); + ipipeif_try_format(ipipeif, cfg, fse->pad, &format, fse->which); fse->max_width = format.width; fse->max_height = format.height; @@ -675,18 +673,18 @@ ipipeif_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * __ipipeif_get_format() - helper function for getting ipipeif format * @ipipeif: pointer to ipipeif private structure. + * @cfg: V4L2 subdev pad config * @pad: pad number. - * @fh: V4L2 subdev file handle. * @which: wanted subdev format. * */ static struct v4l2_mbus_framefmt * __ipipeif_get_format(struct vpfe_ipipeif_device *ipipeif, - struct v4l2_subdev_fh *fh, unsigned int pad, + struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&ipipeif->subdev, cfg, pad); return &ipipeif->formats[pad]; } @@ -694,22 +692,22 @@ __ipipeif_get_format(struct vpfe_ipipeif_device *ipipeif, /* * ipipeif_set_format() - Handle set format by pads subdev method * @sd: pointer to v4l2 subdev structure - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @fmt: pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ static int -ipipeif_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +ipipeif_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __ipipeif_get_format(ipipeif, fh, fmt->pad, fmt->which); + format = __ipipeif_get_format(ipipeif, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; - ipipeif_try_format(ipipeif, fh, fmt->pad, &fmt->format, fmt->which); + ipipeif_try_format(ipipeif, cfg, fmt->pad, &fmt->format, fmt->which); *format = fmt->format; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) @@ -757,9 +755,8 @@ static void ipipeif_set_default_config(struct vpfe_ipipeif_device *ipipeif) * @sd: VPFE ipipeif V4L2 subdevice * @fh: V4L2 subdev file handle * - * Initialize all pad formats with default values. If fh is not NULL, try - * formats are initialized on the file handle. Otherwise active formats are - * initialized on the device. + * Initialize all pad formats with default values. Try formats are initialized + * on the file handle. */ static int ipipeif_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) @@ -769,19 +766,19 @@ ipipeif_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) memset(&format, 0, sizeof(format)); format.pad = IPIPEIF_PAD_SINK; - format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + format.which = V4L2_SUBDEV_FORMAT_TRY; format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12; format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A; format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A; - ipipeif_set_format(sd, fh, &format); + ipipeif_set_format(sd, fh->pad, &format); memset(&format, 0, sizeof(format)); format.pad = IPIPEIF_PAD_SOURCE; - format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + format.which = V4L2_SUBDEV_FORMAT_TRY; format.format.code = MEDIA_BUS_FMT_UYVY8_2X8; format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A; format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A; - ipipeif_set_format(sd, fh, &format); + ipipeif_set_format(sd, fh->pad, &format); ipipeif_set_default_config(ipipeif); diff --git a/drivers/staging/media/davinci_vpfe/dm365_isif.c b/drivers/staging/media/davinci_vpfe/dm365_isif.c index bcf762bc233d..80907b464412 100644 --- a/drivers/staging/media/davinci_vpfe/dm365_isif.c +++ b/drivers/staging/media/davinci_vpfe/dm365_isif.c @@ -278,11 +278,11 @@ isif_config_format(struct vpfe_device *vpfe_dev, unsigned int pad) /* * isif_try_format() - Try video format on a pad * @isif: VPFE isif device - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @fmt: pointer to v4l2 subdev format structure */ static void -isif_try_format(struct vpfe_isif_device *isif, struct v4l2_subdev_fh *fh, +isif_try_format(struct vpfe_isif_device *isif, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { unsigned int width = fmt->format.width; @@ -1394,11 +1394,11 @@ static int isif_set_stream(struct v4l2_subdev *sd, int enable) * __isif_get_format() - helper function for getting isif format * @isif: pointer to isif private structure. * @pad: pad number. - * @fh: V4L2 subdev file handle. + * @cfg: V4L2 subdev pad config * @which: wanted subdev format. */ static struct v4l2_mbus_framefmt * -__isif_get_format(struct vpfe_isif_device *isif, struct v4l2_subdev_fh *fh, +__isif_get_format(struct vpfe_isif_device *isif, struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) { @@ -1407,32 +1407,32 @@ __isif_get_format(struct vpfe_isif_device *isif, struct v4l2_subdev_fh *fh, fmt.pad = pad; fmt.which = which; - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&isif->subdev, cfg, pad); } return &isif->formats[pad]; } /* -* isif_set_format() - set format on pad -* @sd : VPFE ISIF device -* @fh : V4L2 subdev file handle -* @fmt : pointer to v4l2 subdev format structure -* -* Return 0 on success or -EINVAL if format or pad is invalid -*/ + * isif_set_format() - set format on pad + * @sd : VPFE ISIF device + * @cfg : V4L2 subdev pad config + * @fmt : pointer to v4l2 subdev format structure + * + * Return 0 on success or -EINVAL if format or pad is invalid + */ static int -isif_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +isif_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd); struct vpfe_device *vpfe_dev = to_vpfe_device(isif); struct v4l2_mbus_framefmt *format; - format = __isif_get_format(isif, fh, fmt->pad, fmt->which); + format = __isif_get_format(isif, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; - isif_try_format(isif, fh, fmt); + isif_try_format(isif, cfg, fmt); memcpy(format, &fmt->format, sizeof(*format)); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) @@ -1447,20 +1447,20 @@ isif_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * isif_get_format() - Retrieve the video format on a pad * @sd: VPFE ISIF V4L2 subdevice - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @fmt: pointer to v4l2 subdev format structure * * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond * to the format type. */ static int -isif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +isif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __isif_get_format(vpfe_isif, fh, fmt->pad, fmt->which); + format = __isif_get_format(vpfe_isif, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; @@ -1472,11 +1472,11 @@ isif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * isif_enum_frame_size() - enum frame sizes on pads * @sd: VPFE isif V4L2 subdevice - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @code: pointer to v4l2_subdev_frame_size_enum structure */ static int -isif_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +isif_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd); @@ -1489,8 +1489,8 @@ isif_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, format.format.code = fse->code; format.format.width = 1; format.format.height = 1; - format.which = V4L2_SUBDEV_FORMAT_TRY; - isif_try_format(isif, fh, &format); + format.which = fse->which; + isif_try_format(isif, cfg, &format); fse->min_width = format.format.width; fse->min_height = format.format.height; @@ -1501,8 +1501,8 @@ isif_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, format.format.code = fse->code; format.format.width = -1; format.format.height = -1; - format.which = V4L2_SUBDEV_FORMAT_TRY; - isif_try_format(isif, fh, &format); + format.which = fse->which; + isif_try_format(isif, cfg, &format); fse->max_width = format.format.width; fse->max_height = format.format.height; @@ -1512,11 +1512,11 @@ isif_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * isif_enum_mbus_code() - enum mbus codes for pads * @sd: VPFE isif V4L2 subdevice - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @code: pointer to v4l2_subdev_mbus_code_enum structure */ static int -isif_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +isif_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { switch (code->pad) { @@ -1537,14 +1537,14 @@ isif_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * isif_pad_set_selection() - set crop rectangle on pad * @sd: VPFE isif V4L2 subdevice - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @code: pointer to v4l2_subdev_mbus_code_enum structure * * Return 0 on success, -EINVAL if pad is invalid */ static int isif_pad_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd); @@ -1554,7 +1554,7 @@ isif_pad_set_selection(struct v4l2_subdev *sd, if (sel->pad != ISIF_PAD_SINK || sel->target != V4L2_SEL_TGT_CROP) return -EINVAL; - format = __isif_get_format(vpfe_isif, fh, sel->pad, sel->which); + format = __isif_get_format(vpfe_isif, cfg, sel->pad, sel->which); if (format == NULL) return -EINVAL; @@ -1577,7 +1577,7 @@ isif_pad_set_selection(struct v4l2_subdev *sd, } else { struct v4l2_rect *rect; - rect = v4l2_subdev_get_try_crop(fh, ISIF_PAD_SINK); + rect = v4l2_subdev_get_try_crop(sd, cfg, ISIF_PAD_SINK); memcpy(rect, &vpfe_isif->crop, sizeof(*rect)); } return 0; @@ -1586,14 +1586,14 @@ isif_pad_set_selection(struct v4l2_subdev *sd, /* * isif_pad_get_selection() - get crop rectangle on pad * @sd: VPFE isif V4L2 subdevice - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @code: pointer to v4l2_subdev_mbus_code_enum structure * * Return 0 on success, -EINVAL if pad is invalid */ static int isif_pad_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd); @@ -1605,7 +1605,7 @@ isif_pad_get_selection(struct v4l2_subdev *sd, if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_rect *rect; - rect = v4l2_subdev_get_try_crop(fh, ISIF_PAD_SINK); + rect = v4l2_subdev_get_try_crop(sd, cfg, ISIF_PAD_SINK); memcpy(&sel->r, rect, sizeof(*rect)); } else { sel->r = vpfe_isif->crop; @@ -1619,9 +1619,8 @@ isif_pad_get_selection(struct v4l2_subdev *sd, * @sd: VPFE isif V4L2 subdevice * @fh: V4L2 subdev file handle * - * Initialize all pad formats with default values. If fh is not NULL, try - * formats are initialized on the file handle. Otherwise active formats are - * initialized on the device. + * Initialize all pad formats with default values. Try formats are initialized + * on the file handle. */ static int isif_init_formats(struct v4l2_subdev *sd, @@ -1632,27 +1631,27 @@ isif_init_formats(struct v4l2_subdev *sd, memset(&format, 0, sizeof(format)); format.pad = ISIF_PAD_SINK; - format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + format.which = V4L2_SUBDEV_FORMAT_TRY; format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12; format.format.width = MAX_WIDTH; format.format.height = MAX_HEIGHT; - isif_set_format(sd, fh, &format); + isif_set_format(sd, fh->pad, &format); memset(&format, 0, sizeof(format)); format.pad = ISIF_PAD_SOURCE; - format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + format.which = V4L2_SUBDEV_FORMAT_TRY; format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12; format.format.width = MAX_WIDTH; format.format.height = MAX_HEIGHT; - isif_set_format(sd, fh, &format); + isif_set_format(sd, fh->pad, &format); memset(&sel, 0, sizeof(sel)); sel.pad = ISIF_PAD_SINK; - sel.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + sel.which = V4L2_SUBDEV_FORMAT_TRY; sel.target = V4L2_SEL_TGT_CROP; sel.r.width = MAX_WIDTH; sel.r.height = MAX_HEIGHT; - isif_pad_set_selection(sd, fh, &sel); + isif_pad_set_selection(sd, fh->pad, &sel); return 0; } diff --git a/drivers/staging/media/davinci_vpfe/dm365_resizer.c b/drivers/staging/media/davinci_vpfe/dm365_resizer.c index 75e70e14b724..fee44dd45ccd 100644 --- a/drivers/staging/media/davinci_vpfe/dm365_resizer.c +++ b/drivers/staging/media/davinci_vpfe/dm365_resizer.c @@ -1289,19 +1289,19 @@ static int resizer_set_stream(struct v4l2_subdev *sd, int enable) /* * __resizer_get_format() - helper function for getting resizer format * @sd: pointer to subdev. - * @fh: V4L2 subdev file handle. + * @cfg: V4L2 subdev pad config * @pad: pad number. * @which: wanted subdev format. * Retun wanted mbus frame format. */ static struct v4l2_mbus_framefmt * -__resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +__resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd); if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(sd, cfg, pad); if (&resizer->crop_resizer.subdev == sd) return &resizer->crop_resizer.formats[pad]; if (&resizer->resizer_a.subdev == sd) @@ -1314,13 +1314,13 @@ __resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * resizer_try_format() - Handle try format by pad subdev method * @sd: pointer to subdev. - * @fh: V4L2 subdev file handle. + * @cfg: V4L2 subdev pad config * @pad: pad num. * @fmt: pointer to v4l2 format structure. * @which: wanted subdev format. */ static void -resizer_try_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +resizer_try_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -1388,21 +1388,21 @@ resizer_try_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * resizer_set_format() - Handle set format by pads subdev method * @sd: pointer to v4l2 subdev structure - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @fmt: pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ -static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __resizer_get_format(sd, fh, fmt->pad, fmt->which); + format = __resizer_get_format(sd, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; - resizer_try_format(sd, fh, fmt->pad, &fmt->format, fmt->which); + resizer_try_format(sd, cfg, fmt->pad, &fmt->format, fmt->which); *format = fmt->format; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) @@ -1448,16 +1448,16 @@ static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * resizer_get_format() - Retrieve the video format on a pad * @sd: pointer to v4l2 subdev structure. - * @fh: V4L2 subdev file handle. + * @cfg: V4L2 subdev pad config * @fmt: pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ -static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct v4l2_mbus_framefmt *format; - format = __resizer_get_format(sd, fh, fmt->pad, fmt->which); + format = __resizer_get_format(sd, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; @@ -1469,11 +1469,11 @@ static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * resizer_enum_frame_size() - enum frame sizes on pads * @sd: Pointer to subdevice. - * @fh: V4L2 subdev file handle. + * @cfg: V4L2 subdev pad config * @code: pointer to v4l2_subdev_frame_size_enum structure. */ static int resizer_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct v4l2_mbus_framefmt format; @@ -1484,8 +1484,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = 1; format.height = 1; - resizer_try_format(sd, fh, fse->pad, &format, - V4L2_SUBDEV_FORMAT_TRY); + resizer_try_format(sd, cfg, fse->pad, &format, fse->which); fse->min_width = format.width; fse->min_height = format.height; @@ -1495,8 +1494,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = -1; format.height = -1; - resizer_try_format(sd, fh, fse->pad, &format, - V4L2_SUBDEV_FORMAT_TRY); + resizer_try_format(sd, cfg, fse->pad, &format, fse->which); fse->max_width = format.width; fse->max_height = format.height; @@ -1506,11 +1504,11 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd, /* * resizer_enum_mbus_code() - enum mbus codes for pads * @sd: Pointer to subdevice. - * @fh: V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @code: pointer to v4l2_subdev_mbus_code_enum structure */ static int resizer_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { if (code->pad == RESIZER_PAD_SINK) { @@ -1533,14 +1531,13 @@ static int resizer_enum_mbus_code(struct v4l2_subdev *sd, * @sd: Pointer to subdevice. * @fh: V4L2 subdev file handle. * - * Initialize all pad formats with default values. If fh is not NULL, try - * formats are initialized on the file handle. Otherwise active formats are - * initialized on the device. + * Initialize all pad formats with default values. Try formats are + * initialized on the file handle. */ static int resizer_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { - __u32 which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + __u32 which = V4L2_SUBDEV_FORMAT_TRY; struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd); struct v4l2_subdev_format format; @@ -1551,7 +1548,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd, format.format.code = MEDIA_BUS_FMT_YUYV8_2X8; format.format.width = MAX_IN_WIDTH; format.format.height = MAX_IN_HEIGHT; - resizer_set_format(sd, fh, &format); + resizer_set_format(sd, fh->pad, &format); memset(&format, 0, sizeof(format)); format.pad = RESIZER_CROP_PAD_SOURCE; @@ -1559,7 +1556,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd, format.format.code = MEDIA_BUS_FMT_UYVY8_2X8; format.format.width = MAX_IN_WIDTH; format.format.height = MAX_IN_WIDTH; - resizer_set_format(sd, fh, &format); + resizer_set_format(sd, fh->pad, &format); memset(&format, 0, sizeof(format)); format.pad = RESIZER_CROP_PAD_SOURCE2; @@ -1567,7 +1564,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd, format.format.code = MEDIA_BUS_FMT_UYVY8_2X8; format.format.width = MAX_IN_WIDTH; format.format.height = MAX_IN_WIDTH; - resizer_set_format(sd, fh, &format); + resizer_set_format(sd, fh->pad, &format); } else if (&resizer->resizer_a.subdev == sd) { memset(&format, 0, sizeof(format)); format.pad = RESIZER_PAD_SINK; @@ -1575,7 +1572,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd, format.format.code = MEDIA_BUS_FMT_YUYV8_2X8; format.format.width = MAX_IN_WIDTH; format.format.height = MAX_IN_HEIGHT; - resizer_set_format(sd, fh, &format); + resizer_set_format(sd, fh->pad, &format); memset(&format, 0, sizeof(format)); format.pad = RESIZER_PAD_SOURCE; @@ -1583,7 +1580,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd, format.format.code = MEDIA_BUS_FMT_UYVY8_2X8; format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A; format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A; - resizer_set_format(sd, fh, &format); + resizer_set_format(sd, fh->pad, &format); } else if (&resizer->resizer_b.subdev == sd) { memset(&format, 0, sizeof(format)); format.pad = RESIZER_PAD_SINK; @@ -1591,7 +1588,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd, format.format.code = MEDIA_BUS_FMT_YUYV8_2X8; format.format.width = MAX_IN_WIDTH; format.format.height = MAX_IN_HEIGHT; - resizer_set_format(sd, fh, &format); + resizer_set_format(sd, fh->pad, &format); memset(&format, 0, sizeof(format)); format.pad = RESIZER_PAD_SOURCE; @@ -1599,7 +1596,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd, format.format.code = MEDIA_BUS_FMT_UYVY8_2X8; format.format.width = IPIPE_MAX_OUTPUT_WIDTH_B; format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_B; - resizer_set_format(sd, fh, &format); + resizer_set_format(sd, fh->pad, &format); } return 0; diff --git a/drivers/staging/media/dt3155v4l/dt3155v4l.c b/drivers/staging/media/dt3155v4l/dt3155v4l.c index 293ffda503e0..52a8ffe560b1 100644 --- a/drivers/staging/media/dt3155v4l/dt3155v4l.c +++ b/drivers/staging/media/dt3155v4l/dt3155v4l.c @@ -244,7 +244,7 @@ dt3155_wait_prepare(struct vb2_queue *q) { struct dt3155_priv *pd = vb2_get_drv_priv(q); - mutex_unlock(pd->vdev->lock); + mutex_unlock(pd->vdev.lock); } static void @@ -252,7 +252,7 @@ dt3155_wait_finish(struct vb2_queue *q) { struct dt3155_priv *pd = vb2_get_drv_priv(q); - mutex_lock(pd->vdev->lock); + mutex_lock(pd->vdev.lock); } static int @@ -824,7 +824,7 @@ static struct video_device dt3155_vdev = { .fops = &dt3155_fops, .ioctl_ops = &dt3155_ioctl_ops, .minor = -1, - .release = video_device_release, + .release = video_device_release_empty, .tvnorms = DT3155_CURRENT_NORM, }; @@ -901,28 +901,24 @@ dt3155_probe(struct pci_dev *pdev, const struct pci_device_id *id) err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); if (err) return -ENODEV; - pd = kzalloc(sizeof(*pd), GFP_KERNEL); + pd = devm_kzalloc(&pdev->dev, sizeof(*pd), GFP_KERNEL); if (!pd) return -ENOMEM; - pd->vdev = video_device_alloc(); - if (!pd->vdev) { - err = -ENOMEM; - goto err_video_device_alloc; - } - *pd->vdev = dt3155_vdev; + + pd->vdev = dt3155_vdev; pci_set_drvdata(pdev, pd); /* for use in dt3155_remove() */ - video_set_drvdata(pd->vdev, pd); /* for use in video_fops */ + video_set_drvdata(&pd->vdev, pd); /* for use in video_fops */ pd->users = 0; pd->pdev = pdev; INIT_LIST_HEAD(&pd->dmaq); mutex_init(&pd->mux); - pd->vdev->lock = &pd->mux; /* for locking v4l2_file_operations */ + pd->vdev.lock = &pd->mux; /* for locking v4l2_file_operations */ spin_lock_init(&pd->lock); pd->csr2 = csr2_init; pd->config = config_init; err = pci_enable_device(pdev); if (err) - goto err_enable_dev; + return err; err = pci_request_region(pdev, 0, pci_name(pdev)); if (err) goto err_req_region; @@ -934,13 +930,13 @@ dt3155_probe(struct pci_dev *pdev, const struct pci_device_id *id) err = dt3155_init_board(pdev); if (err) goto err_init_board; - err = video_register_device(pd->vdev, VFL_TYPE_GRABBER, -1); + err = video_register_device(&pd->vdev, VFL_TYPE_GRABBER, -1); if (err) goto err_init_board; if (dt3155_alloc_coherent(&pdev->dev, DT3155_CHUNK_SIZE, DMA_MEMORY_MAP)) dev_info(&pdev->dev, "preallocated 8 buffers\n"); - dev_info(&pdev->dev, "/dev/video%i is ready\n", pd->vdev->minor); + dev_info(&pdev->dev, "/dev/video%i is ready\n", pd->vdev.minor); return 0; /* success */ err_init_board: @@ -949,10 +945,6 @@ err_pci_iomap: pci_release_region(pdev, 0); err_req_region: pci_disable_device(pdev); -err_enable_dev: - video_device_release(pd->vdev); -err_video_device_alloc: - kfree(pd); return err; } @@ -962,15 +954,10 @@ dt3155_remove(struct pci_dev *pdev) struct dt3155_priv *pd = pci_get_drvdata(pdev); dt3155_free_coherent(&pdev->dev); - video_unregister_device(pd->vdev); + video_unregister_device(&pd->vdev); pci_iounmap(pdev, pd->regs); pci_release_region(pdev, 0); pci_disable_device(pdev); - /* - * video_device_release() is invoked automatically - * see: struct video_device dt3155_vdev - */ - kfree(pd); } static const struct pci_device_id pci_ids[] = { diff --git a/drivers/staging/media/dt3155v4l/dt3155v4l.h b/drivers/staging/media/dt3155v4l/dt3155v4l.h index 2e4f89d402e4..96f01a0c7581 100644 --- a/drivers/staging/media/dt3155v4l/dt3155v4l.h +++ b/drivers/staging/media/dt3155v4l/dt3155v4l.h @@ -178,7 +178,7 @@ struct dt3155_stats { /** * struct dt3155_priv - private data structure * - * @vdev: pointer to video_device structure + * @vdev: video_device structure * @pdev: pointer to pci_dev structure * @q pointer to vb2_queue structure * @curr_buf: pointer to curren buffer @@ -193,7 +193,7 @@ struct dt3155_stats { * @config: local copy of config register */ struct dt3155_priv { - struct video_device *vdev; + struct video_device vdev; struct pci_dev *pdev; struct vb2_queue *q; struct vb2_buffer *curr_buf; diff --git a/drivers/staging/media/mn88472/mn88472.c b/drivers/staging/media/mn88472/mn88472.c index 6eebe564e557..ed379abcacc0 100644 --- a/drivers/staging/media/mn88472/mn88472.c +++ b/drivers/staging/media/mn88472/mn88472.c @@ -19,7 +19,7 @@ static int mn88472_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *s) { - s->min_delay_ms = 400; + s->min_delay_ms = 800; return 0; } @@ -178,8 +178,32 @@ static int mn88472_set_frontend(struct dvb_frontend *fe) ret = regmap_write(dev->regmap[0], 0x46, 0x00); ret = regmap_write(dev->regmap[0], 0xae, 0x00); - ret = regmap_write(dev->regmap[2], 0x08, 0x1d); - ret = regmap_write(dev->regmap[0], 0xd9, 0xe3); + + switch (dev->ts_mode) { + case SERIAL_TS_MODE: + ret = regmap_write(dev->regmap[2], 0x08, 0x1d); + break; + case PARALLEL_TS_MODE: + ret = regmap_write(dev->regmap[2], 0x08, 0x00); + break; + default: + dev_dbg(&client->dev, "ts_mode error: %d\n", dev->ts_mode); + ret = -EINVAL; + goto err; + } + + switch (dev->ts_clock) { + case VARIABLE_TS_CLOCK: + ret = regmap_write(dev->regmap[0], 0xd9, 0xe3); + break; + case FIXED_TS_CLOCK: + ret = regmap_write(dev->regmap[0], 0xd9, 0xe1); + break; + default: + dev_dbg(&client->dev, "ts_clock error: %d\n", dev->ts_clock); + ret = -EINVAL; + goto err; + } /* Reset demod */ ret = regmap_write(dev->regmap[2], 0xf8, 0x9f); @@ -201,6 +225,7 @@ static int mn88472_read_status(struct dvb_frontend *fe, fe_status_t *status) struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; unsigned int utmp; + int lock = 0; *status = 0; @@ -211,21 +236,36 @@ static int mn88472_read_status(struct dvb_frontend *fe, fe_status_t *status) switch (c->delivery_system) { case SYS_DVBT: + ret = regmap_read(dev->regmap[0], 0x7F, &utmp); + if (ret) + goto err; + if ((utmp & 0xF) >= 0x09) + lock = 1; + break; case SYS_DVBT2: - /* FIXME: implement me */ - utmp = 0x08; /* DVB-C lock value */ + ret = regmap_read(dev->regmap[2], 0x92, &utmp); + if (ret) + goto err; + if ((utmp & 0xF) >= 0x07) + *status |= FE_HAS_SIGNAL; + if ((utmp & 0xF) >= 0x0a) + *status |= FE_HAS_CARRIER; + if ((utmp & 0xF) >= 0x0d) + *status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; break; case SYS_DVBC_ANNEX_A: ret = regmap_read(dev->regmap[1], 0x84, &utmp); if (ret) goto err; + if ((utmp & 0xF) >= 0x08) + lock = 1; break; default: ret = -EINVAL; goto err; } - if (utmp == 0x08) + if (lock) *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; @@ -242,6 +282,7 @@ static int mn88472_init(struct dvb_frontend *fe) int ret, len, remaining; const struct firmware *fw = NULL; u8 *fw_file = MN88472_FIRMWARE; + unsigned int tmp; dev_dbg(&client->dev, "\n"); @@ -257,6 +298,17 @@ static int mn88472_init(struct dvb_frontend *fe) if (ret) goto err; + /* check if firmware is already running */ + ret = regmap_read(dev->regmap[0], 0xf5, &tmp); + if (ret) + goto err; + + if (!(tmp & 0x1)) { + dev_info(&client->dev, "firmware already running\n"); + dev->warm = true; + return 0; + } + /* request the firmware, this will block and timeout */ ret = request_firmware(&fw, fw_file, &client->dev); if (ret) { @@ -270,7 +322,7 @@ static int mn88472_init(struct dvb_frontend *fe) ret = regmap_write(dev->regmap[0], 0xf5, 0x03); if (ret) - goto err; + goto firmware_release; for (remaining = fw->size; remaining > 0; remaining -= (dev->i2c_wr_max - 1)) { @@ -283,13 +335,27 @@ static int mn88472_init(struct dvb_frontend *fe) if (ret) { dev_err(&client->dev, "firmware download failed=%d\n", ret); - goto err; + goto firmware_release; } } + /* parity check of firmware */ + ret = regmap_read(dev->regmap[0], 0xf8, &tmp); + if (ret) { + dev_err(&client->dev, + "parity reg read failed=%d\n", ret); + goto err; + } + if (tmp & 0x10) { + dev_err(&client->dev, + "firmware parity check failed=0x%x\n", tmp); + goto err; + } + dev_err(&client->dev, "firmware parity check succeeded=0x%x\n", tmp); + ret = regmap_write(dev->regmap[0], 0xf5, 0x00); if (ret) - goto err; + goto firmware_release; release_firmware(fw); fw = NULL; @@ -298,10 +364,9 @@ static int mn88472_init(struct dvb_frontend *fe) dev->warm = true; return 0; +firmware_release: + release_firmware(fw); err: - if (fw) - release_firmware(fw); - dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } @@ -336,6 +401,8 @@ static struct dvb_frontend_ops mn88472_ops = { .delsys = {SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A}, .info = { .name = "Panasonic MN88472", + .symbol_rate_min = 1000000, + .symbol_rate_max = 7200000, .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | @@ -396,6 +463,8 @@ static int mn88472_probe(struct i2c_client *client, dev->i2c_wr_max = config->i2c_wr_max; dev->xtal = config->xtal; + dev->ts_mode = config->ts_mode; + dev->ts_clock = config->ts_clock; dev->client[0] = client; dev->regmap[0] = regmap_init_i2c(dev->client[0], ®map_config); if (IS_ERR(dev->regmap[0])) { diff --git a/drivers/staging/media/mn88472/mn88472_priv.h b/drivers/staging/media/mn88472/mn88472_priv.h index b12b731e2d4e..9ba8c8b3823e 100644 --- a/drivers/staging/media/mn88472/mn88472_priv.h +++ b/drivers/staging/media/mn88472/mn88472_priv.h @@ -32,6 +32,8 @@ struct mn88472_dev { fe_delivery_system_t delivery_system; bool warm; /* FW running */ u32 xtal; + int ts_mode; + int ts_clock; }; #endif diff --git a/drivers/staging/media/mn88473/mn88473.c b/drivers/staging/media/mn88473/mn88473.c index a333744b76b9..e909d62a086a 100644 --- a/drivers/staging/media/mn88473/mn88473.c +++ b/drivers/staging/media/mn88473/mn88473.c @@ -30,6 +30,7 @@ static int mn88473_set_frontend(struct dvb_frontend *fe) struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, i; u32 if_frequency; + u64 tmp; u8 delivery_system_val, if_val[3], bw_val[7]; dev_dbg(&client->dev, @@ -58,32 +59,13 @@ static int mn88473_set_frontend(struct dvb_frontend *fe) goto err; } - switch (c->delivery_system) { - case SYS_DVBT: - case SYS_DVBT2: - if (c->bandwidth_hz <= 6000000) { - /* IF 3570000 Hz, BW 6000000 Hz */ - memcpy(if_val, "\x24\x8e\x8a", 3); - memcpy(bw_val, "\xe9\x55\x55\x1c\x29\x1c\x29", 7); - } else if (c->bandwidth_hz <= 7000000) { - /* IF 4570000 Hz, BW 7000000 Hz */ - memcpy(if_val, "\x2e\xcb\xfb", 3); - memcpy(bw_val, "\xc8\x00\x00\x17\x0a\x17\x0a", 7); - } else if (c->bandwidth_hz <= 8000000) { - /* IF 4570000 Hz, BW 8000000 Hz */ - memcpy(if_val, "\x2e\xcb\xfb", 3); - memcpy(bw_val, "\xaf\x00\x00\x11\xec\x11\xec", 7); - } else { - ret = -EINVAL; - goto err; - } - break; - case SYS_DVBC_ANNEX_A: - /* IF 5070000 Hz, BW 8000000 Hz */ - memcpy(if_val, "\x33\xea\xb3", 3); + if (c->bandwidth_hz <= 6000000) { + memcpy(bw_val, "\xe9\x55\x55\x1c\x29\x1c\x29", 7); + } else if (c->bandwidth_hz <= 7000000) { + memcpy(bw_val, "\xc8\x00\x00\x17\x0a\x17\x0a", 7); + } else if (c->bandwidth_hz <= 8000000) { memcpy(bw_val, "\xaf\x00\x00\x11\xec\x11\xec", 7); - break; - default: + } else { ret = -EINVAL; goto err; } @@ -105,17 +87,12 @@ static int mn88473_set_frontend(struct dvb_frontend *fe) if_frequency = 0; } - switch (if_frequency) { - case 3570000: - case 4570000: - case 5070000: - break; - default: - dev_err(&client->dev, "IF frequency %d not supported\n", - if_frequency); - ret = -EINVAL; - goto err; - } + /* Calculate IF registers ( (1<<24)*IF / Xtal ) */ + tmp = div_u64(if_frequency * (u64)(1<<24) + (dev->xtal / 2), + dev->xtal); + if_val[0] = ((tmp >> 16) & 0xff); + if_val[1] = ((tmp >> 8) & 0xff); + if_val[2] = ((tmp >> 0) & 0xff); ret = regmap_write(dev->regmap[2], 0x05, 0x00); ret = regmap_write(dev->regmap[2], 0xfb, 0x13); @@ -190,7 +167,10 @@ static int mn88473_read_status(struct dvb_frontend *fe, fe_status_t *status) { struct i2c_client *client = fe->demodulator_priv; struct mn88473_dev *dev = i2c_get_clientdata(client); + struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; + unsigned int utmp; + int lock = 0; *status = 0; @@ -199,8 +179,51 @@ static int mn88473_read_status(struct dvb_frontend *fe, fe_status_t *status) goto err; } - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | - FE_HAS_SYNC | FE_HAS_LOCK; + switch (c->delivery_system) { + case SYS_DVBT: + ret = regmap_read(dev->regmap[0], 0x62, &utmp); + if (ret) + goto err; + if (!(utmp & 0xA0)) { + if ((utmp & 0xF) >= 0x03) + *status |= FE_HAS_SIGNAL; + if ((utmp & 0xF) >= 0x09) + lock = 1; + } + break; + case SYS_DVBT2: + ret = regmap_read(dev->regmap[2], 0x8B, &utmp); + if (ret) + goto err; + if (!(utmp & 0x40)) { + if ((utmp & 0xF) >= 0x07) + *status |= FE_HAS_SIGNAL; + if ((utmp & 0xF) >= 0x0a) + *status |= FE_HAS_CARRIER; + if ((utmp & 0xF) >= 0x0d) + *status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; + } + break; + case SYS_DVBC_ANNEX_A: + ret = regmap_read(dev->regmap[1], 0x85, &utmp); + if (ret) + goto err; + if (!(utmp & 0x40)) { + ret = regmap_read(dev->regmap[1], 0x89, &utmp); + if (ret) + goto err; + if (utmp & 0x01) + lock = 1; + } + break; + default: + ret = -EINVAL; + goto err; + } + + if (lock) + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | + FE_HAS_SYNC | FE_HAS_LOCK; return 0; err: @@ -215,11 +238,23 @@ static int mn88473_init(struct dvb_frontend *fe) int ret, len, remaining; const struct firmware *fw = NULL; u8 *fw_file = MN88473_FIRMWARE; + unsigned int tmp; dev_dbg(&client->dev, "\n"); - if (dev->warm) + /* set cold state by default */ + dev->warm = false; + + /* check if firmware is already running */ + ret = regmap_read(dev->regmap[0], 0xf5, &tmp); + if (ret) + goto err; + + if (!(tmp & 0x1)) { + dev_info(&client->dev, "firmware already running\n"); + dev->warm = true; return 0; + } /* request the firmware, this will block and timeout */ ret = request_firmware(&fw, fw_file, &client->dev); @@ -250,6 +285,20 @@ static int mn88473_init(struct dvb_frontend *fe) } } + /* parity check of firmware */ + ret = regmap_read(dev->regmap[0], 0xf8, &tmp); + if (ret) { + dev_err(&client->dev, + "parity reg read failed=%d\n", ret); + goto err; + } + if (tmp & 0x10) { + dev_err(&client->dev, + "firmware parity check failed=0x%x\n", tmp); + goto err; + } + dev_err(&client->dev, "firmware parity check succeeded=0x%x\n", tmp); + ret = regmap_write(dev->regmap[0], 0xf5, 0x00); if (ret) goto err; @@ -293,6 +342,8 @@ static struct dvb_frontend_ops mn88473_ops = { .delsys = {SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_AC}, .info = { .name = "Panasonic MN88473", + .symbol_rate_min = 1000000, + .symbol_rate_max = 7200000, .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | @@ -352,6 +403,10 @@ static int mn88473_probe(struct i2c_client *client, } dev->i2c_wr_max = config->i2c_wr_max; + if (!config->xtal) + dev->xtal = 25000000; + else + dev->xtal = config->xtal; dev->client[0] = client; dev->regmap[0] = regmap_init_i2c(dev->client[0], ®map_config); if (IS_ERR(dev->regmap[0])) { diff --git a/drivers/staging/media/mn88473/mn88473_priv.h b/drivers/staging/media/mn88473/mn88473_priv.h index 78af112fb41d..ef6f01323ac9 100644 --- a/drivers/staging/media/mn88473/mn88473_priv.h +++ b/drivers/staging/media/mn88473/mn88473_priv.h @@ -31,6 +31,7 @@ struct mn88473_dev { u16 i2c_wr_max; fe_delivery_system_t delivery_system; bool warm; /* FW running */ + u32 xtal; }; #endif diff --git a/drivers/staging/media/omap4iss/iss_csi2.c b/drivers/staging/media/omap4iss/iss_csi2.c index 2d96fb3eca53..d7ff7698a067 100644 --- a/drivers/staging/media/omap4iss/iss_csi2.c +++ b/drivers/staging/media/omap4iss/iss_csi2.c @@ -828,17 +828,17 @@ static const struct iss_video_operations csi2_issvideo_ops = { */ static struct v4l2_mbus_framefmt * -__csi2_get_format(struct iss_csi2_device *csi2, struct v4l2_subdev_fh *fh, +__csi2_get_format(struct iss_csi2_device *csi2, struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&csi2->subdev, cfg, pad); return &csi2->formats[pad]; } static void -csi2_try_format(struct iss_csi2_device *csi2, struct v4l2_subdev_fh *fh, +csi2_try_format(struct iss_csi2_device *csi2, struct v4l2_subdev_pad_config *cfg, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -868,7 +868,7 @@ csi2_try_format(struct iss_csi2_device *csi2, struct v4l2_subdev_fh *fh, * compression. */ pixelcode = fmt->code; - format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK, which); + format = __csi2_get_format(csi2, cfg, CSI2_PAD_SINK, which); memcpy(fmt, format, sizeof(*fmt)); /* @@ -889,12 +889,12 @@ csi2_try_format(struct iss_csi2_device *csi2, struct v4l2_subdev_fh *fh, /* * csi2_enum_mbus_code - Handle pixel format enumeration * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg : V4L2 subdev pad config * @code : pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ static int csi2_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd); @@ -907,8 +907,8 @@ static int csi2_enum_mbus_code(struct v4l2_subdev *sd, code->code = csi2_input_fmts[code->index]; } else { - format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK, - V4L2_SUBDEV_FORMAT_TRY); + format = __csi2_get_format(csi2, cfg, CSI2_PAD_SINK, + code->which); switch (code->index) { case 0: /* Passthrough sink pad code */ @@ -931,7 +931,7 @@ static int csi2_enum_mbus_code(struct v4l2_subdev *sd, } static int csi2_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd); @@ -943,7 +943,7 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = 1; format.height = 1; - csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + csi2_try_format(csi2, cfg, fse->pad, &format, fse->which); fse->min_width = format.width; fse->min_height = format.height; @@ -953,7 +953,7 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = -1; format.height = -1; - csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + csi2_try_format(csi2, cfg, fse->pad, &format, fse->which); fse->max_width = format.width; fse->max_height = format.height; @@ -963,17 +963,17 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd, /* * csi2_get_format - Handle get format by pads subdev method * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @fmt: pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ -static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which); + format = __csi2_get_format(csi2, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; @@ -984,29 +984,29 @@ static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * csi2_set_format - Handle set format by pads subdev method * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @fmt: pointer to v4l2 subdev format structure * return -EINVAL or zero on success */ -static int csi2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int csi2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which); + format = __csi2_get_format(csi2, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; - csi2_try_format(csi2, fh, fmt->pad, &fmt->format, fmt->which); + csi2_try_format(csi2, cfg, fmt->pad, &fmt->format, fmt->which); *format = fmt->format; /* Propagate the format from sink to source */ if (fmt->pad == CSI2_PAD_SINK) { - format = __csi2_get_format(csi2, fh, CSI2_PAD_SOURCE, + format = __csi2_get_format(csi2, cfg, CSI2_PAD_SOURCE, fmt->which); *format = fmt->format; - csi2_try_format(csi2, fh, CSI2_PAD_SOURCE, format, fmt->which); + csi2_try_format(csi2, cfg, CSI2_PAD_SOURCE, format, fmt->which); } return 0; @@ -1048,7 +1048,7 @@ static int csi2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; format.format.width = 4096; format.format.height = 4096; - csi2_set_format(sd, fh, &format); + csi2_set_format(sd, fh ? fh->pad : NULL, &format); return 0; } diff --git a/drivers/staging/media/omap4iss/iss_ipipe.c b/drivers/staging/media/omap4iss/iss_ipipe.c index a1a46ef8319b..eaa82da30f50 100644 --- a/drivers/staging/media/omap4iss/iss_ipipe.c +++ b/drivers/staging/media/omap4iss/iss_ipipe.c @@ -24,7 +24,7 @@ #include "iss_ipipe.h" static struct v4l2_mbus_framefmt * -__ipipe_get_format(struct iss_ipipe_device *ipipe, struct v4l2_subdev_fh *fh, +__ipipe_get_format(struct iss_ipipe_device *ipipe, struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which); static const unsigned int ipipe_fmts[] = { @@ -176,11 +176,11 @@ static int ipipe_set_stream(struct v4l2_subdev *sd, int enable) } static struct v4l2_mbus_framefmt * -__ipipe_get_format(struct iss_ipipe_device *ipipe, struct v4l2_subdev_fh *fh, +__ipipe_get_format(struct iss_ipipe_device *ipipe, struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&ipipe->subdev, cfg, pad); return &ipipe->formats[pad]; } @@ -188,12 +188,12 @@ __ipipe_get_format(struct iss_ipipe_device *ipipe, struct v4l2_subdev_fh *fh, /* * ipipe_try_format - Try video format on a pad * @ipipe: ISS IPIPE device - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @pad: Pad number * @fmt: Format */ static void -ipipe_try_format(struct iss_ipipe_device *ipipe, struct v4l2_subdev_fh *fh, +ipipe_try_format(struct iss_ipipe_device *ipipe, struct v4l2_subdev_pad_config *cfg, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -220,7 +220,7 @@ ipipe_try_format(struct iss_ipipe_device *ipipe, struct v4l2_subdev_fh *fh, break; case IPIPE_PAD_SOURCE_VP: - format = __ipipe_get_format(ipipe, fh, IPIPE_PAD_SINK, which); + format = __ipipe_get_format(ipipe, cfg, IPIPE_PAD_SINK, which); memcpy(fmt, format, sizeof(*fmt)); fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; @@ -236,12 +236,12 @@ ipipe_try_format(struct iss_ipipe_device *ipipe, struct v4l2_subdev_fh *fh, /* * ipipe_enum_mbus_code - Handle pixel format enumeration * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg : V4L2 subdev pad config * @code : pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ static int ipipe_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { switch (code->pad) { @@ -268,7 +268,7 @@ static int ipipe_enum_mbus_code(struct v4l2_subdev *sd, } static int ipipe_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd); @@ -280,7 +280,7 @@ static int ipipe_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = 1; format.height = 1; - ipipe_try_format(ipipe, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + ipipe_try_format(ipipe, cfg, fse->pad, &format, fse->which); fse->min_width = format.width; fse->min_height = format.height; @@ -290,7 +290,7 @@ static int ipipe_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = -1; format.height = -1; - ipipe_try_format(ipipe, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + ipipe_try_format(ipipe, cfg, fse->pad, &format, fse->which); fse->max_width = format.width; fse->max_height = format.height; @@ -300,19 +300,19 @@ static int ipipe_enum_frame_size(struct v4l2_subdev *sd, /* * ipipe_get_format - Retrieve the video format on a pad * @sd : ISP IPIPE V4L2 subdevice - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @fmt: Format * * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond * to the format type. */ -static int ipipe_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int ipipe_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __ipipe_get_format(ipipe, fh, fmt->pad, fmt->which); + format = __ipipe_get_format(ipipe, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; @@ -323,31 +323,31 @@ static int ipipe_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * ipipe_set_format - Set the video format on a pad * @sd : ISP IPIPE V4L2 subdevice - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @fmt: Format * * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond * to the format type. */ -static int ipipe_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int ipipe_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __ipipe_get_format(ipipe, fh, fmt->pad, fmt->which); + format = __ipipe_get_format(ipipe, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; - ipipe_try_format(ipipe, fh, fmt->pad, &fmt->format, fmt->which); + ipipe_try_format(ipipe, cfg, fmt->pad, &fmt->format, fmt->which); *format = fmt->format; /* Propagate the format from sink to source */ if (fmt->pad == IPIPE_PAD_SINK) { - format = __ipipe_get_format(ipipe, fh, IPIPE_PAD_SOURCE_VP, + format = __ipipe_get_format(ipipe, cfg, IPIPE_PAD_SOURCE_VP, fmt->which); *format = fmt->format; - ipipe_try_format(ipipe, fh, IPIPE_PAD_SOURCE_VP, format, + ipipe_try_format(ipipe, cfg, IPIPE_PAD_SOURCE_VP, format, fmt->which); } @@ -388,7 +388,7 @@ static int ipipe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; format.format.width = 4096; format.format.height = 4096; - ipipe_set_format(sd, fh, &format); + ipipe_set_format(sd, fh ? fh->pad : NULL, &format); return 0; } @@ -516,8 +516,6 @@ static int ipipe_init_entities(struct iss_ipipe_device *ipipe) void omap4iss_ipipe_unregister_entities(struct iss_ipipe_device *ipipe) { - media_entity_cleanup(&ipipe->subdev.entity); - v4l2_device_unregister_subdev(&ipipe->subdev); } @@ -566,5 +564,7 @@ int omap4iss_ipipe_init(struct iss_device *iss) */ void omap4iss_ipipe_cleanup(struct iss_device *iss) { - /* FIXME: are you sure there's nothing to do? */ + struct iss_ipipe_device *ipipe = &iss->ipipe; + + media_entity_cleanup(&ipipe->subdev.entity); } diff --git a/drivers/staging/media/omap4iss/iss_ipipeif.c b/drivers/staging/media/omap4iss/iss_ipipeif.c index 3943fae699ee..530ac8426b5b 100644 --- a/drivers/staging/media/omap4iss/iss_ipipeif.c +++ b/drivers/staging/media/omap4iss/iss_ipipeif.c @@ -361,24 +361,24 @@ static int ipipeif_set_stream(struct v4l2_subdev *sd, int enable) static struct v4l2_mbus_framefmt * __ipipeif_get_format(struct iss_ipipeif_device *ipipeif, - struct v4l2_subdev_fh *fh, unsigned int pad, + struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&ipipeif->subdev, cfg, pad); return &ipipeif->formats[pad]; } /* * ipipeif_try_format - Try video format on a pad * @ipipeif: ISS IPIPEIF device - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @pad: Pad number * @fmt: Format */ static void ipipeif_try_format(struct iss_ipipeif_device *ipipeif, - struct v4l2_subdev_fh *fh, unsigned int pad, + struct v4l2_subdev_pad_config *cfg, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -407,7 +407,7 @@ ipipeif_try_format(struct iss_ipipeif_device *ipipeif, break; case IPIPEIF_PAD_SOURCE_ISIF_SF: - format = __ipipeif_get_format(ipipeif, fh, IPIPEIF_PAD_SINK, + format = __ipipeif_get_format(ipipeif, cfg, IPIPEIF_PAD_SINK, which); memcpy(fmt, format, sizeof(*fmt)); @@ -422,7 +422,7 @@ ipipeif_try_format(struct iss_ipipeif_device *ipipeif, break; case IPIPEIF_PAD_SOURCE_VP: - format = __ipipeif_get_format(ipipeif, fh, IPIPEIF_PAD_SINK, + format = __ipipeif_get_format(ipipeif, cfg, IPIPEIF_PAD_SINK, which); memcpy(fmt, format, sizeof(*fmt)); @@ -441,12 +441,12 @@ ipipeif_try_format(struct iss_ipipeif_device *ipipeif, /* * ipipeif_enum_mbus_code - Handle pixel format enumeration * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg : V4L2 subdev pad config * @code : pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); @@ -466,8 +466,8 @@ static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd, if (code->index != 0) return -EINVAL; - format = __ipipeif_get_format(ipipeif, fh, IPIPEIF_PAD_SINK, - V4L2_SUBDEV_FORMAT_TRY); + format = __ipipeif_get_format(ipipeif, cfg, IPIPEIF_PAD_SINK, + code->which); code->code = format->code; break; @@ -480,7 +480,7 @@ static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd, } static int ipipeif_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); @@ -492,8 +492,7 @@ static int ipipeif_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = 1; format.height = 1; - ipipeif_try_format(ipipeif, fh, fse->pad, &format, - V4L2_SUBDEV_FORMAT_TRY); + ipipeif_try_format(ipipeif, cfg, fse->pad, &format, fse->which); fse->min_width = format.width; fse->min_height = format.height; @@ -503,8 +502,7 @@ static int ipipeif_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = -1; format.height = -1; - ipipeif_try_format(ipipeif, fh, fse->pad, &format, - V4L2_SUBDEV_FORMAT_TRY); + ipipeif_try_format(ipipeif, cfg, fse->pad, &format, fse->which); fse->max_width = format.width; fse->max_height = format.height; @@ -514,19 +512,19 @@ static int ipipeif_enum_frame_size(struct v4l2_subdev *sd, /* * ipipeif_get_format - Retrieve the video format on a pad * @sd : ISP IPIPEIF V4L2 subdevice - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @fmt: Format * * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond * to the format type. */ -static int ipipeif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int ipipeif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __ipipeif_get_format(ipipeif, fh, fmt->pad, fmt->which); + format = __ipipeif_get_format(ipipeif, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; @@ -537,39 +535,39 @@ static int ipipeif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * ipipeif_set_format - Set the video format on a pad * @sd : ISP IPIPEIF V4L2 subdevice - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @fmt: Format * * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond * to the format type. */ -static int ipipeif_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int ipipeif_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __ipipeif_get_format(ipipeif, fh, fmt->pad, fmt->which); + format = __ipipeif_get_format(ipipeif, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; - ipipeif_try_format(ipipeif, fh, fmt->pad, &fmt->format, fmt->which); + ipipeif_try_format(ipipeif, cfg, fmt->pad, &fmt->format, fmt->which); *format = fmt->format; /* Propagate the format from sink to source */ if (fmt->pad == IPIPEIF_PAD_SINK) { - format = __ipipeif_get_format(ipipeif, fh, + format = __ipipeif_get_format(ipipeif, cfg, IPIPEIF_PAD_SOURCE_ISIF_SF, fmt->which); *format = fmt->format; - ipipeif_try_format(ipipeif, fh, IPIPEIF_PAD_SOURCE_ISIF_SF, + ipipeif_try_format(ipipeif, cfg, IPIPEIF_PAD_SOURCE_ISIF_SF, format, fmt->which); - format = __ipipeif_get_format(ipipeif, fh, + format = __ipipeif_get_format(ipipeif, cfg, IPIPEIF_PAD_SOURCE_VP, fmt->which); *format = fmt->format; - ipipeif_try_format(ipipeif, fh, IPIPEIF_PAD_SOURCE_VP, format, + ipipeif_try_format(ipipeif, cfg, IPIPEIF_PAD_SOURCE_VP, format, fmt->which); } @@ -612,7 +610,7 @@ static int ipipeif_init_formats(struct v4l2_subdev *sd, format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; format.format.width = 4096; format.format.height = 4096; - ipipeif_set_format(sd, fh, &format); + ipipeif_set_format(sd, fh ? fh->pad : NULL, &format); return 0; } @@ -773,8 +771,6 @@ static int ipipeif_init_entities(struct iss_ipipeif_device *ipipeif) void omap4iss_ipipeif_unregister_entities(struct iss_ipipeif_device *ipipeif) { - media_entity_cleanup(&ipipeif->subdev.entity); - v4l2_device_unregister_subdev(&ipipeif->subdev); omap4iss_video_unregister(&ipipeif->video_out); } @@ -828,5 +824,7 @@ int omap4iss_ipipeif_init(struct iss_device *iss) */ void omap4iss_ipipeif_cleanup(struct iss_device *iss) { - /* FIXME: are you sure there's nothing to do? */ + struct iss_ipipeif_device *ipipeif = &iss->ipipeif; + + media_entity_cleanup(&ipipeif->subdev.entity); } diff --git a/drivers/staging/media/omap4iss/iss_resizer.c b/drivers/staging/media/omap4iss/iss_resizer.c index 3ab972818f1b..5f69012c4deb 100644 --- a/drivers/staging/media/omap4iss/iss_resizer.c +++ b/drivers/staging/media/omap4iss/iss_resizer.c @@ -420,24 +420,24 @@ static int resizer_set_stream(struct v4l2_subdev *sd, int enable) static struct v4l2_mbus_framefmt * __resizer_get_format(struct iss_resizer_device *resizer, - struct v4l2_subdev_fh *fh, unsigned int pad, + struct v4l2_subdev_pad_config *cfg, unsigned int pad, enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(fh, pad); + return v4l2_subdev_get_try_format(&resizer->subdev, cfg, pad); return &resizer->formats[pad]; } /* * resizer_try_format - Try video format on a pad * @resizer: ISS RESIZER device - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @pad: Pad number * @fmt: Format */ static void resizer_try_format(struct iss_resizer_device *resizer, - struct v4l2_subdev_fh *fh, unsigned int pad, + struct v4l2_subdev_pad_config *cfg, unsigned int pad, struct v4l2_mbus_framefmt *fmt, enum v4l2_subdev_format_whence which) { @@ -465,7 +465,7 @@ resizer_try_format(struct iss_resizer_device *resizer, case RESIZER_PAD_SOURCE_MEM: pixelcode = fmt->code; - format = __resizer_get_format(resizer, fh, RESIZER_PAD_SINK, + format = __resizer_get_format(resizer, cfg, RESIZER_PAD_SINK, which); memcpy(fmt, format, sizeof(*fmt)); @@ -492,12 +492,12 @@ resizer_try_format(struct iss_resizer_device *resizer, /* * resizer_enum_mbus_code - Handle pixel format enumeration * @sd : pointer to v4l2 subdev structure - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @code : pointer to v4l2_subdev_mbus_code_enum structure * return -EINVAL or zero on success */ static int resizer_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd); @@ -512,8 +512,8 @@ static int resizer_enum_mbus_code(struct v4l2_subdev *sd, break; case RESIZER_PAD_SOURCE_MEM: - format = __resizer_get_format(resizer, fh, RESIZER_PAD_SINK, - V4L2_SUBDEV_FORMAT_TRY); + format = __resizer_get_format(resizer, cfg, RESIZER_PAD_SINK, + code->which); if (code->index == 0) { code->code = format->code; @@ -542,7 +542,7 @@ static int resizer_enum_mbus_code(struct v4l2_subdev *sd, } static int resizer_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd); @@ -554,8 +554,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = 1; format.height = 1; - resizer_try_format(resizer, fh, fse->pad, &format, - V4L2_SUBDEV_FORMAT_TRY); + resizer_try_format(resizer, cfg, fse->pad, &format, fse->which); fse->min_width = format.width; fse->min_height = format.height; @@ -565,8 +564,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd, format.code = fse->code; format.width = -1; format.height = -1; - resizer_try_format(resizer, fh, fse->pad, &format, - V4L2_SUBDEV_FORMAT_TRY); + resizer_try_format(resizer, cfg, fse->pad, &format, fse->which); fse->max_width = format.width; fse->max_height = format.height; @@ -576,19 +574,19 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd, /* * resizer_get_format - Retrieve the video format on a pad * @sd : ISP RESIZER V4L2 subdevice - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @fmt: Format * * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond * to the format type. */ -static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __resizer_get_format(resizer, fh, fmt->pad, fmt->which); + format = __resizer_get_format(resizer, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; @@ -599,32 +597,32 @@ static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, /* * resizer_set_format - Set the video format on a pad * @sd : ISP RESIZER V4L2 subdevice - * @fh : V4L2 subdev file handle + * @cfg: V4L2 subdev pad config * @fmt: Format * * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond * to the format type. */ -static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, +static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *format; - format = __resizer_get_format(resizer, fh, fmt->pad, fmt->which); + format = __resizer_get_format(resizer, cfg, fmt->pad, fmt->which); if (format == NULL) return -EINVAL; - resizer_try_format(resizer, fh, fmt->pad, &fmt->format, fmt->which); + resizer_try_format(resizer, cfg, fmt->pad, &fmt->format, fmt->which); *format = fmt->format; /* Propagate the format from sink to source */ if (fmt->pad == RESIZER_PAD_SINK) { - format = __resizer_get_format(resizer, fh, + format = __resizer_get_format(resizer, cfg, RESIZER_PAD_SOURCE_MEM, fmt->which); *format = fmt->format; - resizer_try_format(resizer, fh, RESIZER_PAD_SOURCE_MEM, format, + resizer_try_format(resizer, cfg, RESIZER_PAD_SOURCE_MEM, format, fmt->which); } @@ -667,7 +665,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd, format.format.code = MEDIA_BUS_FMT_UYVY8_1X16; format.format.width = 4096; format.format.height = 4096; - resizer_set_format(sd, fh, &format); + resizer_set_format(sd, fh ? fh->pad : NULL, &format); return 0; } @@ -817,8 +815,6 @@ static int resizer_init_entities(struct iss_resizer_device *resizer) void omap4iss_resizer_unregister_entities(struct iss_resizer_device *resizer) { - media_entity_cleanup(&resizer->subdev.entity); - v4l2_device_unregister_subdev(&resizer->subdev); omap4iss_video_unregister(&resizer->video_out); } @@ -872,5 +868,7 @@ int omap4iss_resizer_init(struct iss_device *iss) */ void omap4iss_resizer_cleanup(struct iss_device *iss) { - /* FIXME: are you sure there's nothing to do? */ + struct iss_resizer_device *resizer = &iss->resizer; + + media_entity_cleanup(&resizer->subdev.entity); } diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c index 69550445a341..e949b6f179aa 100644 --- a/drivers/staging/media/omap4iss/iss_video.c +++ b/drivers/staging/media/omap4iss/iss_video.c @@ -171,14 +171,14 @@ static void iss_video_pix_to_mbus(const struct v4l2_pix_format *pix, mbus->width = pix->width; mbus->height = pix->height; - for (i = 0; i < ARRAY_SIZE(formats); ++i) { + /* Skip the last format in the loop so that it will be selected if no + * match is found. + */ + for (i = 0; i < ARRAY_SIZE(formats) - 1; ++i) { if (formats[i].pixelformat == pix->pixelformat) break; } - if (WARN_ON(i == ARRAY_SIZE(formats))) - return; - mbus->code = formats[i].code; mbus->colorspace = pix->colorspace; mbus->field = pix->field; diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index 76891adfba7a..cf0df8fbba89 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -222,7 +222,7 @@ uvc_function_ep0_complete(struct usb_ep *ep, struct usb_request *req) v4l2_event.type = UVC_EVENT_DATA; uvc_event->data.length = req->actual; memcpy(&uvc_event->data.data, req->buf, req->actual); - v4l2_event_queue(uvc->vdev, &v4l2_event); + v4l2_event_queue(&uvc->vdev, &v4l2_event); } } @@ -256,7 +256,7 @@ uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) memset(&v4l2_event, 0, sizeof(v4l2_event)); v4l2_event.type = UVC_EVENT_SETUP; memcpy(&uvc_event->req, ctrl, sizeof(uvc_event->req)); - v4l2_event_queue(uvc->vdev, &v4l2_event); + v4l2_event_queue(&uvc->vdev, &v4l2_event); return 0; } @@ -315,7 +315,7 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) memset(&v4l2_event, 0, sizeof(v4l2_event)); v4l2_event.type = UVC_EVENT_CONNECT; uvc_event->speed = cdev->gadget->speed; - v4l2_event_queue(uvc->vdev, &v4l2_event); + v4l2_event_queue(&uvc->vdev, &v4l2_event); uvc->state = UVC_STATE_CONNECTED; } @@ -343,7 +343,7 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) memset(&v4l2_event, 0, sizeof(v4l2_event)); v4l2_event.type = UVC_EVENT_STREAMOFF; - v4l2_event_queue(uvc->vdev, &v4l2_event); + v4l2_event_queue(&uvc->vdev, &v4l2_event); uvc->state = UVC_STATE_CONNECTED; return 0; @@ -370,7 +370,7 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) memset(&v4l2_event, 0, sizeof(v4l2_event)); v4l2_event.type = UVC_EVENT_STREAMON; - v4l2_event_queue(uvc->vdev, &v4l2_event); + v4l2_event_queue(&uvc->vdev, &v4l2_event); return USB_GADGET_DELAYED_STATUS; default: @@ -388,7 +388,7 @@ uvc_function_disable(struct usb_function *f) memset(&v4l2_event, 0, sizeof(v4l2_event)); v4l2_event.type = UVC_EVENT_DISCONNECT; - v4l2_event_queue(uvc->vdev, &v4l2_event); + v4l2_event_queue(&uvc->vdev, &v4l2_event); uvc->state = UVC_STATE_DISCONNECTED; @@ -435,24 +435,19 @@ static int uvc_register_video(struct uvc_device *uvc) { struct usb_composite_dev *cdev = uvc->func.config->cdev; - struct video_device *video; /* TODO reference counting. */ - video = video_device_alloc(); - if (video == NULL) - return -ENOMEM; + uvc->vdev.v4l2_dev = &uvc->v4l2_dev; + uvc->vdev.fops = &uvc_v4l2_fops; + uvc->vdev.ioctl_ops = &uvc_v4l2_ioctl_ops; + uvc->vdev.release = video_device_release_empty; + uvc->vdev.vfl_dir = VFL_DIR_TX; + uvc->vdev.lock = &uvc->video.mutex; + strlcpy(uvc->vdev.name, cdev->gadget->name, sizeof(uvc->vdev.name)); - video->v4l2_dev = &uvc->v4l2_dev; - video->fops = &uvc_v4l2_fops; - video->ioctl_ops = &uvc_v4l2_ioctl_ops; - video->release = video_device_release; - video->vfl_dir = VFL_DIR_TX; - strlcpy(video->name, cdev->gadget->name, sizeof(video->name)); + video_set_drvdata(&uvc->vdev, uvc); - uvc->vdev = video; - video_set_drvdata(video, uvc); - - return video_register_device(video, VFL_TYPE_GRABBER, -1); + return video_register_device(&uvc->vdev, VFL_TYPE_GRABBER, -1); } #define UVC_COPY_DESCRIPTOR(mem, dst, desc) \ @@ -765,8 +760,6 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) error: v4l2_device_unregister(&uvc->v4l2_dev); - if (uvc->vdev) - video_device_release(uvc->vdev); if (uvc->control_ep) uvc->control_ep->driver_data = NULL; @@ -897,7 +890,7 @@ static void uvc_unbind(struct usb_configuration *c, struct usb_function *f) INFO(cdev, "%s\n", __func__); - video_unregister_device(uvc->vdev); + video_unregister_device(&uvc->vdev); v4l2_device_unregister(&uvc->v4l2_dev); uvc->control_ep->driver_data = NULL; uvc->video.ep->driver_data = NULL; @@ -918,6 +911,7 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi) if (uvc == NULL) return ERR_PTR(-ENOMEM); + mutex_init(&uvc->video.mutex); uvc->state = UVC_STATE_DISCONNECTED; opts = fi_to_f_uvc_opts(fi); diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h index f67695cb28f8..ebe409b9e419 100644 --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h @@ -115,6 +115,7 @@ struct uvc_video unsigned int width; unsigned int height; unsigned int imagesize; + struct mutex mutex; /* protects frame parameters */ /* Requests */ unsigned int req_size; @@ -143,7 +144,7 @@ enum uvc_state struct uvc_device { - struct video_device *vdev; + struct video_device vdev; struct v4l2_device v4l2_dev; enum uvc_state state; struct usb_function func; diff --git a/drivers/usb/gadget/function/uvc_queue.c b/drivers/usb/gadget/function/uvc_queue.c index 8ea8b3b227b4..d617c39a0052 100644 --- a/drivers/usb/gadget/function/uvc_queue.c +++ b/drivers/usb/gadget/function/uvc_queue.c @@ -104,29 +104,16 @@ static void uvc_buffer_queue(struct vb2_buffer *vb) spin_unlock_irqrestore(&queue->irqlock, flags); } -static void uvc_wait_prepare(struct vb2_queue *vq) -{ - struct uvc_video_queue *queue = vb2_get_drv_priv(vq); - - mutex_unlock(&queue->mutex); -} - -static void uvc_wait_finish(struct vb2_queue *vq) -{ - struct uvc_video_queue *queue = vb2_get_drv_priv(vq); - - mutex_lock(&queue->mutex); -} - static struct vb2_ops uvc_queue_qops = { .queue_setup = uvc_queue_setup, .buf_prepare = uvc_buffer_prepare, .buf_queue = uvc_buffer_queue, - .wait_prepare = uvc_wait_prepare, - .wait_finish = uvc_wait_finish, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, }; -int uvcg_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type) +int uvcg_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, + struct mutex *lock) { int ret; @@ -135,6 +122,7 @@ int uvcg_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type) queue->queue.drv_priv = queue; queue->queue.buf_struct_size = sizeof(struct uvc_buffer); queue->queue.ops = &uvc_queue_qops; + queue->queue.lock = lock; queue->queue.mem_ops = &vb2_vmalloc_memops; queue->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC | V4L2_BUF_FLAG_TSTAMP_SRC_EOF; @@ -142,7 +130,6 @@ int uvcg_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type) if (ret) return ret; - mutex_init(&queue->mutex); spin_lock_init(&queue->irqlock); INIT_LIST_HEAD(&queue->irqqueue); queue->flags = 0; @@ -155,9 +142,7 @@ int uvcg_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type) */ void uvcg_free_buffers(struct uvc_video_queue *queue) { - mutex_lock(&queue->mutex); vb2_queue_release(&queue->queue); - mutex_unlock(&queue->mutex); } /* @@ -168,22 +153,14 @@ int uvcg_alloc_buffers(struct uvc_video_queue *queue, { int ret; - mutex_lock(&queue->mutex); ret = vb2_reqbufs(&queue->queue, rb); - mutex_unlock(&queue->mutex); return ret ? ret : rb->count; } int uvcg_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf) { - int ret; - - mutex_lock(&queue->mutex); - ret = vb2_querybuf(&queue->queue, buf); - mutex_unlock(&queue->mutex); - - return ret; + return vb2_querybuf(&queue->queue, buf); } int uvcg_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf) @@ -191,18 +168,14 @@ int uvcg_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf) unsigned long flags; int ret; - mutex_lock(&queue->mutex); ret = vb2_qbuf(&queue->queue, buf); if (ret < 0) - goto done; + return ret; spin_lock_irqsave(&queue->irqlock, flags); ret = (queue->flags & UVC_QUEUE_PAUSED) != 0; queue->flags &= ~UVC_QUEUE_PAUSED; spin_unlock_irqrestore(&queue->irqlock, flags); - -done: - mutex_unlock(&queue->mutex); return ret; } @@ -213,13 +186,7 @@ done: int uvcg_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf, int nonblocking) { - int ret; - - mutex_lock(&queue->mutex); - ret = vb2_dqbuf(&queue->queue, buf, nonblocking); - mutex_unlock(&queue->mutex); - - return ret; + return vb2_dqbuf(&queue->queue, buf, nonblocking); } /* @@ -231,24 +198,12 @@ int uvcg_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf, unsigned int uvcg_queue_poll(struct uvc_video_queue *queue, struct file *file, poll_table *wait) { - unsigned int ret; - - mutex_lock(&queue->mutex); - ret = vb2_poll(&queue->queue, file, wait); - mutex_unlock(&queue->mutex); - - return ret; + return vb2_poll(&queue->queue, file, wait); } int uvcg_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma) { - int ret; - - mutex_lock(&queue->mutex); - ret = vb2_mmap(&queue->queue, vma); - mutex_unlock(&queue->mutex); - - return ret; + return vb2_mmap(&queue->queue, vma); } #ifndef CONFIG_MMU @@ -260,12 +215,7 @@ int uvcg_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma) unsigned long uvcg_queue_get_unmapped_area(struct uvc_video_queue *queue, unsigned long pgoff) { - unsigned long ret; - - mutex_lock(&queue->mutex); - ret = vb2_get_unmapped_area(&queue->queue, 0, 0, pgoff, 0); - mutex_unlock(&queue->mutex); - return ret; + return vb2_get_unmapped_area(&queue->queue, 0, 0, pgoff, 0); } #endif @@ -327,18 +277,17 @@ int uvcg_queue_enable(struct uvc_video_queue *queue, int enable) unsigned long flags; int ret = 0; - mutex_lock(&queue->mutex); if (enable) { ret = vb2_streamon(&queue->queue, queue->queue.type); if (ret < 0) - goto done; + return ret; queue->sequence = 0; queue->buf_used = 0; } else { ret = vb2_streamoff(&queue->queue, queue->queue.type); if (ret < 0) - goto done; + return ret; spin_lock_irqsave(&queue->irqlock, flags); INIT_LIST_HEAD(&queue->irqqueue); @@ -353,8 +302,6 @@ int uvcg_queue_enable(struct uvc_video_queue *queue, int enable) spin_unlock_irqrestore(&queue->irqlock, flags); } -done: - mutex_unlock(&queue->mutex); return ret; } diff --git a/drivers/usb/gadget/function/uvc_queue.h b/drivers/usb/gadget/function/uvc_queue.h index 03919c724961..01ca9eab3481 100644 --- a/drivers/usb/gadget/function/uvc_queue.h +++ b/drivers/usb/gadget/function/uvc_queue.h @@ -41,7 +41,6 @@ struct uvc_buffer { struct uvc_video_queue { struct vb2_queue queue; - struct mutex mutex; /* Protects queue */ unsigned int flags; __u32 sequence; @@ -57,7 +56,8 @@ static inline int uvc_queue_streaming(struct uvc_video_queue *queue) return vb2_is_streaming(&queue->queue); } -int uvcg_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type); +int uvcg_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, + struct mutex *lock); void uvcg_free_buffers(struct uvc_video_queue *queue); diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c index 5aad7fededa5..cbd9bf020fb3 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -14,7 +14,6 @@ #include <linux/device.h> #include <linux/errno.h> #include <linux/list.h> -#include <linux/mutex.h> #include <linux/videodev2.h> #include <linux/vmalloc.h> #include <linux/wait.h> @@ -76,7 +75,8 @@ uvc_v4l2_querycap(struct file *file, void *fh, struct v4l2_capability *cap) strlcpy(cap->bus_info, dev_name(&cdev->gadget->dev), sizeof(cap->bus_info)); - cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; + cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -311,8 +311,10 @@ uvc_v4l2_release(struct file *file) uvc_function_disconnect(uvc); + mutex_lock(&video->mutex); uvcg_video_enable(video, 0); uvcg_free_buffers(&video->queue); + mutex_unlock(&video->mutex); file->private_data = NULL; v4l2_fh_del(&handle->vfh); @@ -356,7 +358,7 @@ struct v4l2_file_operations uvc_v4l2_fops = { .owner = THIS_MODULE, .open = uvc_v4l2_open, .release = uvc_v4l2_release, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, .mmap = uvc_v4l2_mmap, .poll = uvc_v4l2_poll, #ifndef CONFIG_MMU diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c index 9cb86bc1a9a5..8927358caf24 100644 --- a/drivers/usb/gadget/function/uvc_video.c +++ b/drivers/usb/gadget/function/uvc_video.c @@ -390,7 +390,8 @@ int uvcg_video_init(struct uvc_video *video) video->imagesize = 320 * 240 * 2; /* Initialize the video buffers queue. */ - uvcg_queue_init(&video->queue, V4L2_BUF_TYPE_VIDEO_OUTPUT); + uvcg_queue_init(&video->queue, V4L2_BUF_TYPE_VIDEO_OUTPUT, + &video->mutex); return 0; } diff --git a/include/dt-bindings/media/xilinx-vip.h b/include/dt-bindings/media/xilinx-vip.h new file mode 100644 index 000000000000..6298fec00685 --- /dev/null +++ b/include/dt-bindings/media/xilinx-vip.h @@ -0,0 +1,39 @@ +/* + * Xilinx Video IP Core + * + * Copyright (C) 2013-2015 Ideas on Board + * Copyright (C) 2013-2015 Xilinx, Inc. + * + * Contacts: Hyun Kwon <hyun.kwon@xilinx.com> + * Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __DT_BINDINGS_MEDIA_XILINX_VIP_H__ +#define __DT_BINDINGS_MEDIA_XILINX_VIP_H__ + +/* + * Video format codes as defined in "AXI4-Stream Video IP and System Design + * Guide". + */ +#define XVIP_VF_YUV_422 0 +#define XVIP_VF_YUV_444 1 +#define XVIP_VF_RBG 2 +#define XVIP_VF_YUV_420 3 +#define XVIP_VF_YUVA_422 4 +#define XVIP_VF_YUVA_444 5 +#define XVIP_VF_RGBA 6 +#define XVIP_VF_YUVA_420 7 +#define XVIP_VF_YUVD_422 8 +#define XVIP_VF_YUVD_444 9 +#define XVIP_VF_RGBD 10 +#define XVIP_VF_YUVD_420 11 +#define XVIP_VF_MONO_SENSOR 12 +#define XVIP_VF_CUSTOM2 13 +#define XVIP_VF_CUSTOM3 14 +#define XVIP_VF_CUSTOM4 15 + +#endif /* __DT_BINDINGS_MEDIA_XILINX_VIP_H__ */ diff --git a/include/linux/fixp-arith.h b/include/linux/fixp-arith.h index 3089d7382325..d4686fe1cac7 100644 --- a/include/linux/fixp-arith.h +++ b/include/linux/fixp-arith.h @@ -1,6 +1,8 @@ #ifndef _FIXP_ARITH_H #define _FIXP_ARITH_H +#include <linux/math64.h> + /* * Simplistic fixed-point arithmetics. * Hmm, I'm probably duplicating some code :( @@ -29,59 +31,126 @@ #include <linux/types.h> -/* The type representing fixed-point values */ -typedef s16 fixp_t; +static const s32 sin_table[] = { + 0x00000000, 0x023be165, 0x04779632, 0x06b2f1d2, 0x08edc7b6, 0x0b27eb5c, + 0x0d61304d, 0x0f996a26, 0x11d06c96, 0x14060b67, 0x163a1a7d, 0x186c6ddd, + 0x1a9cd9ac, 0x1ccb3236, 0x1ef74bf2, 0x2120fb82, 0x234815ba, 0x256c6f9e, + 0x278dde6e, 0x29ac379f, 0x2bc750e8, 0x2ddf003f, 0x2ff31bdd, 0x32037a44, + 0x340ff241, 0x36185aee, 0x381c8bb5, 0x3a1c5c56, 0x3c17a4e7, 0x3e0e3ddb, + 0x3fffffff, 0x41ecc483, 0x43d464fa, 0x45b6bb5d, 0x4793a20f, 0x496af3e1, + 0x4b3c8c11, 0x4d084650, 0x4ecdfec6, 0x508d9210, 0x5246dd48, 0x53f9be04, + 0x55a6125a, 0x574bb8e5, 0x58ea90c2, 0x5a827999, 0x5c135399, 0x5d9cff82, + 0x5f1f5ea0, 0x609a52d1, 0x620dbe8a, 0x637984d3, 0x64dd894f, 0x6639b039, + 0x678dde6d, 0x68d9f963, 0x6a1de735, 0x6b598ea1, 0x6c8cd70a, 0x6db7a879, + 0x6ed9eba0, 0x6ff389de, 0x71046d3c, 0x720c8074, 0x730baeec, 0x7401e4bf, + 0x74ef0ebb, 0x75d31a5f, 0x76adf5e5, 0x777f903b, 0x7847d908, 0x7906c0af, + 0x79bc384c, 0x7a6831b8, 0x7b0a9f8c, 0x7ba3751c, 0x7c32a67c, 0x7cb82884, + 0x7d33f0c8, 0x7da5f5a3, 0x7e0e2e31, 0x7e6c924f, 0x7ec11aa3, 0x7f0bc095, + 0x7f4c7e52, 0x7f834ecf, 0x7fb02dc4, 0x7fd317b3, 0x7fec09e1, 0x7ffb025e, + 0x7fffffff +}; -#define FRAC_N 8 -#define FRAC_MASK ((1<<FRAC_N)-1) +/** + * __fixp_sin32() returns the sin of an angle in degrees + * + * @degrees: angle, in degrees, from 0 to 360. + * + * The returned value ranges from -0x7fffffff to +0x7fffffff. + */ +static inline s32 __fixp_sin32(int degrees) +{ + s32 ret; + bool negative = false; -/* Not to be used directly. Use fixp_{cos,sin} */ -static const fixp_t cos_table[46] = { - 0x0100, 0x00FF, 0x00FF, 0x00FE, 0x00FD, 0x00FC, 0x00FA, 0x00F8, - 0x00F6, 0x00F3, 0x00F0, 0x00ED, 0x00E9, 0x00E6, 0x00E2, 0x00DD, - 0x00D9, 0x00D4, 0x00CF, 0x00C9, 0x00C4, 0x00BE, 0x00B8, 0x00B1, - 0x00AB, 0x00A4, 0x009D, 0x0096, 0x008F, 0x0087, 0x0080, 0x0078, - 0x0070, 0x0068, 0x005F, 0x0057, 0x004F, 0x0046, 0x003D, 0x0035, - 0x002C, 0x0023, 0x001A, 0x0011, 0x0008, 0x0000 -}; + if (degrees > 180) { + negative = true; + degrees -= 180; + } + if (degrees > 90) + degrees = 180 - degrees; + ret = sin_table[degrees]; -/* a: 123 -> 123.0 */ -static inline fixp_t fixp_new(s16 a) -{ - return a<<FRAC_N; + return negative ? -ret : ret; } -/* a: 0xFFFF -> -1.0 - 0x8000 -> 1.0 - 0x0000 -> 0.0 -*/ -static inline fixp_t fixp_new16(s16 a) +/** + * fixp_sin32() returns the sin of an angle in degrees + * + * @degrees: angle, in degrees. The angle can be positive or negative + * + * The returned value ranges from -0x7fffffff to +0x7fffffff. + */ +static inline s32 fixp_sin32(int degrees) { - return ((s32)a)>>(16-FRAC_N); + degrees = (degrees % 360 + 360) % 360; + + return __fixp_sin32(degrees); } -static inline fixp_t fixp_cos(unsigned int degrees) +/* cos(x) = sin(x + 90 degrees) */ +#define fixp_cos32(v) fixp_sin32((v) + 90) + +/* + * 16 bits variants + * + * The returned value ranges from -0x7fff to 0x7fff + */ + +#define fixp_sin16(v) (fixp_sin32(v) >> 16) +#define fixp_cos16(v) (fixp_cos32(v) >> 16) + +/** + * fixp_sin32_rad() - calculates the sin of an angle in radians + * + * @radians: angle, in radians + * @twopi: value to be used for 2*pi + * + * Provides a variant for the cases where just 360 + * values is not enough. This function uses linear + * interpolation to a wider range of values given by + * twopi var. + * + * Experimental tests gave a maximum difference of + * 0.000038 between the value calculated by sin() and + * the one produced by this function, when twopi is + * equal to 360000. That seems to be enough precision + * for practical purposes. + * + * Please notice that two high numbers for twopi could cause + * overflows, so the routine will not allow values of twopi + * bigger than 1^18. + */ +static inline s32 fixp_sin32_rad(u32 radians, u32 twopi) { - int quadrant = (degrees / 90) & 3; - unsigned int i = degrees % 90; + int degrees; + s32 v1, v2, dx, dy; + s64 tmp; - if (quadrant == 1 || quadrant == 3) - i = 90 - i; + /* + * Avoid too large values for twopi, as we don't want overflows. + */ + BUG_ON(twopi > 1 << 18); - i >>= 1; + degrees = (radians * 360) / twopi; + tmp = radians - (degrees * twopi) / 360; - return (quadrant == 1 || quadrant == 2)? -cos_table[i] : cos_table[i]; -} + degrees = (degrees % 360 + 360) % 360; + v1 = __fixp_sin32(degrees); -static inline fixp_t fixp_sin(unsigned int degrees) -{ - return -fixp_cos(degrees + 90); -} + v2 = fixp_sin32(degrees + 1); -static inline fixp_t fixp_mult(fixp_t a, fixp_t b) -{ - return ((s32)(a*b))>>FRAC_N; + dx = twopi / 360; + dy = v2 - v1; + + tmp *= dy; + + return v1 + div_s64(tmp, dx); } +/* cos(x) = sin(x + pi/2 radians) */ + +#define fixp_cos32_rad(rad, twopi) \ + fixp_sin32_rad(rad + twopi / 4, twopi) + #endif diff --git a/include/linux/kconfig.h b/include/linux/kconfig.h index be342b94c640..16cfb3448568 100644 --- a/include/linux/kconfig.h +++ b/include/linux/kconfig.h @@ -43,4 +43,13 @@ */ #define IS_MODULE(option) config_enabled(option##_MODULE) +/* + * IS_REACHABLE(CONFIG_FOO) evaluates to 1 if the currently compiled + * code can call a function defined in code compiled based on CONFIG_FOO. + * This is similar to IS_ENABLED(), but returns false when invoked from + * built-in code when CONFIG_FOO is set to 'm'. + */ +#define IS_REACHABLE(option) (config_enabled(option) || \ + (config_enabled(option##_MODULE) && config_enabled(MODULE))) + #endif /* __LINUX_KCONFIG_H */ diff --git a/include/media/adv7604.h b/include/media/adv7604.h index aa1c4477722d..9ecf353160c1 100644 --- a/include/media/adv7604.h +++ b/include/media/adv7604.h @@ -47,16 +47,16 @@ enum adv7604_bus_order { }; /* Input Color Space (IO register 0x02, [7:4]) */ -enum adv7604_inp_color_space { - ADV7604_INP_COLOR_SPACE_LIM_RGB = 0, - ADV7604_INP_COLOR_SPACE_FULL_RGB = 1, - ADV7604_INP_COLOR_SPACE_LIM_YCbCr_601 = 2, - ADV7604_INP_COLOR_SPACE_LIM_YCbCr_709 = 3, - ADV7604_INP_COLOR_SPACE_XVYCC_601 = 4, - ADV7604_INP_COLOR_SPACE_XVYCC_709 = 5, - ADV7604_INP_COLOR_SPACE_FULL_YCbCr_601 = 6, - ADV7604_INP_COLOR_SPACE_FULL_YCbCr_709 = 7, - ADV7604_INP_COLOR_SPACE_AUTO = 0xf, +enum adv76xx_inp_color_space { + ADV76XX_INP_COLOR_SPACE_LIM_RGB = 0, + ADV76XX_INP_COLOR_SPACE_FULL_RGB = 1, + ADV76XX_INP_COLOR_SPACE_LIM_YCbCr_601 = 2, + ADV76XX_INP_COLOR_SPACE_LIM_YCbCr_709 = 3, + ADV76XX_INP_COLOR_SPACE_XVYCC_601 = 4, + ADV76XX_INP_COLOR_SPACE_XVYCC_709 = 5, + ADV76XX_INP_COLOR_SPACE_FULL_YCbCr_601 = 6, + ADV76XX_INP_COLOR_SPACE_FULL_YCbCr_709 = 7, + ADV76XX_INP_COLOR_SPACE_AUTO = 0xf, }; /* Select output format (IO register 0x03, [4:2]) */ @@ -66,38 +66,39 @@ enum adv7604_op_format_mode_sel { ADV7604_OP_FORMAT_MODE2 = 0x08, }; -enum adv7604_drive_strength { - ADV7604_DR_STR_MEDIUM_LOW = 1, - ADV7604_DR_STR_MEDIUM_HIGH = 2, - ADV7604_DR_STR_HIGH = 3, +enum adv76xx_drive_strength { + ADV76XX_DR_STR_MEDIUM_LOW = 1, + ADV76XX_DR_STR_MEDIUM_HIGH = 2, + ADV76XX_DR_STR_HIGH = 3, }; -enum adv7604_int1_config { - ADV7604_INT1_CONFIG_OPEN_DRAIN, - ADV7604_INT1_CONFIG_ACTIVE_LOW, - ADV7604_INT1_CONFIG_ACTIVE_HIGH, - ADV7604_INT1_CONFIG_DISABLED, +/* INT1 Configuration (IO register 0x40, [1:0]) */ +enum adv76xx_int1_config { + ADV76XX_INT1_CONFIG_OPEN_DRAIN, + ADV76XX_INT1_CONFIG_ACTIVE_LOW, + ADV76XX_INT1_CONFIG_ACTIVE_HIGH, + ADV76XX_INT1_CONFIG_DISABLED, }; -enum adv7604_page { - ADV7604_PAGE_IO, +enum adv76xx_page { + ADV76XX_PAGE_IO, ADV7604_PAGE_AVLINK, - ADV7604_PAGE_CEC, - ADV7604_PAGE_INFOFRAME, + ADV76XX_PAGE_CEC, + ADV76XX_PAGE_INFOFRAME, ADV7604_PAGE_ESDP, ADV7604_PAGE_DPP, - ADV7604_PAGE_AFE, - ADV7604_PAGE_REP, - ADV7604_PAGE_EDID, - ADV7604_PAGE_HDMI, - ADV7604_PAGE_TEST, - ADV7604_PAGE_CP, + ADV76XX_PAGE_AFE, + ADV76XX_PAGE_REP, + ADV76XX_PAGE_EDID, + ADV76XX_PAGE_HDMI, + ADV76XX_PAGE_TEST, + ADV76XX_PAGE_CP, ADV7604_PAGE_VDP, - ADV7604_PAGE_MAX, + ADV76XX_PAGE_MAX, }; /* Platform dependent definition */ -struct adv7604_platform_data { +struct adv76xx_platform_data { /* DIS_PWRDNB: 1 if the PWRDNB pin is unused and unconnected */ unsigned disable_pwrdnb:1; @@ -116,7 +117,7 @@ struct adv7604_platform_data { enum adv7604_op_format_mode_sel op_format_mode_sel; /* Configuration of the INT1 pin */ - enum adv7604_int1_config int1_config; + enum adv76xx_int1_config int1_config; /* IO register 0x02 */ unsigned alt_gamma:1; @@ -134,9 +135,9 @@ struct adv7604_platform_data { unsigned inv_llc_pol:1; /* IO register 0x14 */ - enum adv7604_drive_strength dr_str_data; - enum adv7604_drive_strength dr_str_clk; - enum adv7604_drive_strength dr_str_sync; + enum adv76xx_drive_strength dr_str_data; + enum adv76xx_drive_strength dr_str_clk; + enum adv76xx_drive_strength dr_str_sync; /* IO register 0x30 */ unsigned output_bus_lsb_to_msb:1; @@ -145,11 +146,11 @@ struct adv7604_platform_data { unsigned hdmi_free_run_mode; /* i2c addresses: 0 == use default */ - u8 i2c_addresses[ADV7604_PAGE_MAX]; + u8 i2c_addresses[ADV76XX_PAGE_MAX]; }; -enum adv7604_pad { - ADV7604_PAD_HDMI_PORT_A = 0, +enum adv76xx_pad { + ADV76XX_PAD_HDMI_PORT_A = 0, ADV7604_PAD_HDMI_PORT_B = 1, ADV7604_PAD_HDMI_PORT_C = 2, ADV7604_PAD_HDMI_PORT_D = 3, @@ -158,7 +159,7 @@ enum adv7604_pad { /* The source pad is either 1 (ADV7611) or 6 (ADV7604) */ ADV7604_PAD_SOURCE = 6, ADV7611_PAD_SOURCE = 1, - ADV7604_PAD_MAX = 7, + ADV76XX_PAD_MAX = 7, }; #define V4L2_CID_ADV_RX_ANALOG_SAMPLING_PHASE (V4L2_CID_DV_CLASS_BASE + 0x1000) @@ -166,7 +167,7 @@ enum adv7604_pad { #define V4L2_CID_ADV_RX_FREE_RUN_COLOR (V4L2_CID_DV_CLASS_BASE + 0x1002) /* notify events */ -#define ADV7604_HOTPLUG 1 -#define ADV7604_FMT_CHANGE 2 +#define ADV76XX_HOTPLUG 1 +#define ADV76XX_FMT_CHANGE 2 #endif diff --git a/include/media/davinci/vpfe_capture.h b/include/media/davinci/vpfe_capture.h index 288772e6900a..28bcd71cdd26 100644 --- a/include/media/davinci/vpfe_capture.h +++ b/include/media/davinci/vpfe_capture.h @@ -102,7 +102,7 @@ struct vpfe_config { struct vpfe_device { /* V4l2 specific parameters */ /* Identifies video device for this channel */ - struct video_device *video_dev; + struct video_device video_dev; /* sub devices */ struct v4l2_subdev **sd; /* vpfe cfg */ diff --git a/include/media/media-entity.h b/include/media/media-entity.h index e00459185d20..0c003d817493 100644 --- a/include/media/media-entity.h +++ b/include/media/media-entity.h @@ -44,6 +44,15 @@ struct media_pad { unsigned long flags; /* Pad flags (MEDIA_PAD_FL_*) */ }; +/** + * struct media_entity_operations - Media entity operations + * @link_setup: Notify the entity of link changes. The operation can + * return an error, in which case link setup will be + * cancelled. Optional. + * @link_validate: Return whether a link is valid from the entity point of + * view. The media_entity_pipeline_start() function + * validates all links by calling this operation. Optional. + */ struct media_entity_operations { int (*link_setup)(struct media_entity *entity, const struct media_pad *local, @@ -87,17 +96,7 @@ struct media_entity { struct { u32 major; u32 minor; - } v4l; - struct { - u32 major; - u32 minor; - } fb; - struct { - u32 card; - u32 device; - u32 subdevice; - } alsa; - int dvb; + } dev; /* Sub-device specifications */ /* Nothing needed yet */ diff --git a/include/media/mt9p031.h b/include/media/mt9p031.h index b1e63f2b72bd..1ba361205af1 100644 --- a/include/media/mt9p031.h +++ b/include/media/mt9p031.h @@ -5,12 +5,10 @@ struct v4l2_subdev; /* * struct mt9p031_platform_data - MT9P031 platform data - * @reset: Chip reset GPIO (set to -1 if not used) * @ext_freq: Input clock frequency * @target_freq: Pixel clock frequency */ struct mt9p031_platform_data { - int reset; int ext_freq; int target_freq; }; diff --git a/include/media/omap3isp.h b/include/media/omap3isp.h index 398279dd1922..048f8f9117ef 100644 --- a/include/media/omap3isp.h +++ b/include/media/omap3isp.h @@ -45,7 +45,7 @@ enum { }; /** - * struct isp_parallel_platform_data - Parallel interface platform data + * struct isp_parallel_cfg - Parallel interface configuration * @data_lane_shift: Data lane shifter * ISP_LANE_SHIFT_0 - CAMEXT[13:0] -> CAM[13:0] * ISP_LANE_SHIFT_2 - CAMEXT[13:2] -> CAM[11:0] @@ -62,7 +62,7 @@ enum { * @data_pol: Data polarity * 0 - Normal, 1 - One's complement */ -struct isp_parallel_platform_data { +struct isp_parallel_cfg { unsigned int data_lane_shift:2; unsigned int clk_pol:1; unsigned int hs_pol:1; @@ -105,7 +105,7 @@ struct isp_csiphy_lanes_cfg { }; /** - * struct isp_ccp2_platform_data - CCP2 interface platform data + * struct isp_ccp2_cfg - CCP2 interface configuration * @strobe_clk_pol: Strobe/clock polarity * 0 - Non Inverted, 1 - Inverted * @crc: Enable the cyclic redundancy check @@ -117,7 +117,7 @@ struct isp_csiphy_lanes_cfg { * ISP_CCP2_PHY_DATA_STROBE - Data/strobe physical layer * @vpclk_div: Video port output clock control */ -struct isp_ccp2_platform_data { +struct isp_ccp2_cfg { unsigned int strobe_clk_pol:1; unsigned int crc:1; unsigned int ccp2_mode:1; @@ -127,39 +127,31 @@ struct isp_ccp2_platform_data { }; /** - * struct isp_csi2_platform_data - CSI2 interface platform data + * struct isp_csi2_cfg - CSI2 interface configuration * @crc: Enable the cyclic redundancy check - * @vpclk_div: Video port output clock control */ -struct isp_csi2_platform_data { +struct isp_csi2_cfg { unsigned crc:1; - unsigned vpclk_div:2; struct isp_csiphy_lanes_cfg lanecfg; }; -struct isp_subdev_i2c_board_info { - struct i2c_board_info *board_info; - int i2c_adapter_id; -}; - -struct isp_v4l2_subdevs_group { - struct isp_subdev_i2c_board_info *subdevs; +struct isp_bus_cfg { enum isp_interface_type interface; union { - struct isp_parallel_platform_data parallel; - struct isp_ccp2_platform_data ccp2; - struct isp_csi2_platform_data csi2; + struct isp_parallel_cfg parallel; + struct isp_ccp2_cfg ccp2; + struct isp_csi2_cfg csi2; } bus; /* gcc < 4.6.0 chokes on anonymous union initializers */ }; -struct isp_platform_xclk { - const char *dev_id; - const char *con_id; +struct isp_platform_subdev { + struct i2c_board_info *board_info; + int i2c_adapter_id; + struct isp_bus_cfg *bus; }; struct isp_platform_data { - struct isp_platform_xclk xclks[2]; - struct isp_v4l2_subdevs_group *subdevs; + struct isp_platform_subdev *subdevs; void (*set_constraints)(struct isp_device *isp, bool enable); }; diff --git a/include/media/ov2659.h b/include/media/ov2659.h new file mode 100644 index 000000000000..4216adc1ede2 --- /dev/null +++ b/include/media/ov2659.h @@ -0,0 +1,34 @@ +/* + * Omnivision OV2659 CMOS Image Sensor driver + * + * Copyright (C) 2015 Texas Instruments, Inc. + * + * Benoit Parrot <bparrot@ti.com> + * Lad, Prabhakar <prabhakar.csengg@gmail.com> + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef OV2659_H +#define OV2659_H + +/** + * struct ov2659_platform_data - ov2659 driver platform data + * @link_frequency: target pixel clock frequency + */ +struct ov2659_platform_data { + s64 link_frequency; +}; + +#endif /* OV2659_H */ diff --git a/include/media/saa7146_vv.h b/include/media/saa7146_vv.h index 944ecdf3530f..92766f77a5de 100644 --- a/include/media/saa7146_vv.h +++ b/include/media/saa7146_vv.h @@ -178,8 +178,8 @@ struct saa7146_use_ops { }; /* from saa7146_fops.c */ -int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev, char *name, int type); -int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev); +int saa7146_register_device(struct video_device *vid, struct saa7146_dev *dev, char *name, int type); +int saa7146_unregister_device(struct video_device *vid, struct saa7146_dev *dev); void saa7146_buffer_finish(struct saa7146_dev *dev, struct saa7146_dmaqueue *q, int state); void saa7146_buffer_next(struct saa7146_dev *dev, struct saa7146_dmaqueue *q,int vbi); int saa7146_buffer_queue(struct saa7146_dev *dev, struct saa7146_dmaqueue *q, struct saa7146_buf *buf); diff --git a/include/media/v4l2-clk.h b/include/media/v4l2-clk.h index 0b36cc138304..3ef6e3d5ed6c 100644 --- a/include/media/v4l2-clk.h +++ b/include/media/v4l2-clk.h @@ -22,14 +22,15 @@ struct module; struct device; +struct clk; struct v4l2_clk { struct list_head list; const struct v4l2_clk_ops *ops; const char *dev_id; - const char *id; int enable; struct mutex lock; /* Protect the enable count */ atomic_t use_count; + struct clk *clk; void *priv; }; @@ -43,7 +44,7 @@ struct v4l2_clk_ops { struct v4l2_clk *v4l2_clk_register(const struct v4l2_clk_ops *ops, const char *dev_name, - const char *name, void *priv); + void *priv); void v4l2_clk_unregister(struct v4l2_clk *clk); struct v4l2_clk *v4l2_clk_get(struct device *dev, const char *id); void v4l2_clk_put(struct v4l2_clk *clk); @@ -55,14 +56,13 @@ int v4l2_clk_set_rate(struct v4l2_clk *clk, unsigned long rate); struct module; struct v4l2_clk *__v4l2_clk_register_fixed(const char *dev_id, - const char *id, unsigned long rate, struct module *owner); + unsigned long rate, struct module *owner); void v4l2_clk_unregister_fixed(struct v4l2_clk *clk); static inline struct v4l2_clk *v4l2_clk_register_fixed(const char *dev_id, - const char *id, unsigned long rate) { - return __v4l2_clk_register_fixed(dev_id, id, rate, THIS_MODULE); + return __v4l2_clk_register_fixed(dev_id, rate, THIS_MODULE); } #define v4l2_clk_name_i2c(name, size, adap, client) snprintf(name, size, \ diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h index 3e4fddfc840c..acbcd2f5fe7f 100644 --- a/include/media/v4l2-dev.h +++ b/include/media/v4l2-dev.h @@ -65,7 +65,6 @@ struct v4l2_file_operations { ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); unsigned int (*poll) (struct file *, struct poll_table_struct *); - long (*ioctl) (struct file *, unsigned int, unsigned long); long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); #ifdef CONFIG_COMPAT long (*compat_ioctl32) (struct file *, unsigned int, unsigned long); diff --git a/include/media/v4l2-device.h b/include/media/v4l2-device.h index ffb69da3ce9e..9c581578783f 100644 --- a/include/media/v4l2-device.h +++ b/include/media/v4l2-device.h @@ -58,8 +58,6 @@ struct v4l2_device { struct v4l2_ctrl_handler *ctrl_handler; /* Device's priority state */ struct v4l2_prio_state prio; - /* BKL replacement mutex. Temporary solution only. */ - struct mutex ioctl_lock; /* Keep track of the references to this struct. */ struct kref ref; /* Release function that is called when the ref count goes to 0. */ diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index 8537983b9b22..8fbbd76d78e8 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -23,12 +23,6 @@ struct v4l2_ioctl_ops { /* VIDIOC_QUERYCAP handler */ int (*vidioc_querycap)(struct file *file, void *fh, struct v4l2_capability *cap); - /* Priority handling */ - int (*vidioc_g_priority) (struct file *file, void *fh, - enum v4l2_priority *p); - int (*vidioc_s_priority) (struct file *file, void *fh, - enum v4l2_priority p); - /* VIDIOC_ENUM_FMT handlers */ int (*vidioc_enum_fmt_vid_cap) (struct file *file, void *fh, struct v4l2_fmtdesc *f); diff --git a/include/media/v4l2-of.h b/include/media/v4l2-of.h index 70fa7b7b0487..f831c9c225b6 100644 --- a/include/media/v4l2-of.h +++ b/include/media/v4l2-of.h @@ -29,12 +29,15 @@ struct device_node; * @data_lanes: an array of physical data lane indexes * @clock_lane: physical lane index of the clock lane * @num_data_lanes: number of data lanes + * @lane_polarities: polarity of the lanes. The order is the same of + * the physical lanes. */ struct v4l2_of_bus_mipi_csi2 { unsigned int flags; unsigned char data_lanes[4]; unsigned char clock_lane; unsigned short num_data_lanes; + bool lane_polarities[5]; }; /** @@ -66,9 +69,26 @@ struct v4l2_of_endpoint { struct list_head head; }; +/** + * struct v4l2_of_link - a link between two endpoints + * @local_node: pointer to device_node of this endpoint + * @local_port: identifier of the port this endpoint belongs to + * @remote_node: pointer to device_node of the remote endpoint + * @remote_port: identifier of the port the remote endpoint belongs to + */ +struct v4l2_of_link { + struct device_node *local_node; + unsigned int local_port; + struct device_node *remote_node; + unsigned int remote_port; +}; + #ifdef CONFIG_OF int v4l2_of_parse_endpoint(const struct device_node *node, struct v4l2_of_endpoint *endpoint); +int v4l2_of_parse_link(const struct device_node *node, + struct v4l2_of_link *link); +void v4l2_of_put_link(struct v4l2_of_link *link); #else /* CONFIG_OF */ static inline int v4l2_of_parse_endpoint(const struct device_node *node, @@ -77,6 +97,16 @@ static inline int v4l2_of_parse_endpoint(const struct device_node *node, return -ENOSYS; } +static inline int v4l2_of_parse_link(const struct device_node *node, + struct v4l2_of_link *link) +{ + return -ENOSYS; +} + +static inline void v4l2_of_put_link(struct v4l2_of_link *link) +{ +} + #endif /* CONFIG_OF */ #endif /* _V4L2_OF_H */ diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 5beeb8744fd1..2f0a345a7fed 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -332,8 +332,6 @@ struct v4l2_subdev_video_ops { struct v4l2_subdev_frame_interval *interval); int (*s_frame_interval)(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *interval); - int (*enum_framesizes)(struct v4l2_subdev *sd, struct v4l2_frmsizeenum *fsize); - int (*enum_frameintervals)(struct v4l2_subdev *sd, struct v4l2_frmivalenum *fival); int (*s_dv_timings)(struct v4l2_subdev *sd, struct v4l2_dv_timings *timings); int (*g_dv_timings)(struct v4l2_subdev *sd, @@ -482,6 +480,18 @@ struct v4l2_subdev_ir_ops { struct v4l2_subdev_ir_parameters *params); }; +/* + * Used for storing subdev pad information. This structure only needs + * to be passed to the pad op if the 'which' field of the main argument + * is set to V4L2_SUBDEV_FORMAT_TRY. For V4L2_SUBDEV_FORMAT_ACTIVE it is + * safe to pass NULL. + */ +struct v4l2_subdev_pad_config { + struct v4l2_mbus_framefmt try_fmt; + struct v4l2_rect try_crop; + struct v4l2_rect try_compose; +}; + /** * struct v4l2_subdev_pad_ops - v4l2-subdev pad level operations * @get_frame_desc: get the current low level media bus frame parameters. @@ -489,21 +499,26 @@ struct v4l2_subdev_ir_ops { * may be adjusted by the subdev driver to device capabilities. */ struct v4l2_subdev_pad_ops { - int (*enum_mbus_code)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + int (*enum_mbus_code)(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code); int (*enum_frame_size)(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse); int (*enum_frame_interval)(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_interval_enum *fie); - int (*get_fmt)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + int (*get_fmt)(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format); - int (*set_fmt)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + int (*set_fmt)(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format); - int (*get_selection)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + int (*get_selection)(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel); - int (*set_selection)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + int (*set_selection)(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel); int (*get_edid)(struct v4l2_subdev *sd, struct v4l2_edid *edid); int (*set_edid)(struct v4l2_subdev *sd, struct v4l2_edid *edid); @@ -625,11 +640,7 @@ struct v4l2_subdev { struct v4l2_subdev_fh { struct v4l2_fh vfh; #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) - struct { - struct v4l2_mbus_framefmt try_fmt; - struct v4l2_rect try_crop; - struct v4l2_rect try_compose; - } *pad; + struct v4l2_subdev_pad_config *pad; #endif }; @@ -639,17 +650,17 @@ struct v4l2_subdev_fh { #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) #define __V4L2_SUBDEV_MK_GET_TRY(rtype, fun_name, field_name) \ static inline struct rtype * \ - v4l2_subdev_get_try_##fun_name(struct v4l2_subdev_fh *fh, \ - unsigned int pad) \ + fun_name(struct v4l2_subdev *sd, \ + struct v4l2_subdev_pad_config *cfg, \ + unsigned int pad) \ { \ - BUG_ON(pad >= vdev_to_v4l2_subdev( \ - fh->vfh.vdev)->entity.num_pads); \ - return &fh->pad[pad].field_name; \ + BUG_ON(pad >= sd->entity.num_pads); \ + return &cfg[pad].field_name; \ } -__V4L2_SUBDEV_MK_GET_TRY(v4l2_mbus_framefmt, format, try_fmt) -__V4L2_SUBDEV_MK_GET_TRY(v4l2_rect, crop, try_crop) -__V4L2_SUBDEV_MK_GET_TRY(v4l2_rect, compose, try_compose) +__V4L2_SUBDEV_MK_GET_TRY(v4l2_mbus_framefmt, v4l2_subdev_get_try_format, try_fmt) +__V4L2_SUBDEV_MK_GET_TRY(v4l2_rect, v4l2_subdev_get_try_crop, try_crop) +__V4L2_SUBDEV_MK_GET_TRY(v4l2_rect, v4l2_subdev_get_try_compose, try_compose) #endif extern const struct v4l2_file_operations v4l2_subdev_fops; diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index bd2cec2d6c3d..a5790fd5d125 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -134,17 +134,6 @@ enum vb2_io_modes { }; /** - * enum vb2_fileio_flags - flags for selecting a mode of the file io emulator, - * by default the 'streaming' style is used by the file io emulator - * @VB2_FILEIO_READ_ONCE: report EOF after reading the first buffer - * @VB2_FILEIO_WRITE_IMMEDIATELY: queue buffer after each write() call - */ -enum vb2_fileio_flags { - VB2_FILEIO_READ_ONCE = (1 << 0), - VB2_FILEIO_WRITE_IMMEDIATELY = (1 << 1), -}; - -/** * enum vb2_buffer_state - current video buffer state * @VB2_BUF_STATE_DEQUEUED: buffer under userspace control * @VB2_BUF_STATE_PREPARING: buffer is being prepared in videobuf @@ -346,7 +335,9 @@ struct v4l2_fh; * * @type: queue type (see V4L2_BUF_TYPE_* in linux/videodev2.h * @io_modes: supported io methods (see vb2_io_modes enum) - * @io_flags: additional io flags (see vb2_fileio_flags enum) + * @fileio_read_once: report EOF after reading the first buffer + * @fileio_write_immediately: queue buffer after each write() call + * @allow_zero_bytesused: allow bytesused == 0 to be passed to the driver * @lock: pointer to a mutex that protects the vb2_queue struct. The * driver can set this to a mutex to let the v4l2 core serialize * the queuing ioctls. If the driver wants to handle locking @@ -396,7 +387,10 @@ struct v4l2_fh; struct vb2_queue { enum v4l2_buf_type type; unsigned int io_modes; - unsigned int io_flags; + unsigned fileio_read_once:1; + unsigned fileio_write_immediately:1; + unsigned allow_zero_bytesused:1; + struct mutex *lock; struct v4l2_fh *owner; diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index 68ceb97c458c..d4cfc17cc414 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild @@ -446,5 +446,6 @@ header-y += wireless.h header-y += x25.h header-y += xattr.h header-y += xfrm.h +header-y += xilinx-v4l2-controls.h header-y += zorro.h header-y += zorro_ids.h diff --git a/include/uapi/linux/am437x-vpfe.h b/include/uapi/linux/am437x-vpfe.h index 9b03033f9cd6..d75774317b9b 100644 --- a/include/uapi/linux/am437x-vpfe.h +++ b/include/uapi/linux/am437x-vpfe.h @@ -21,6 +21,8 @@ #ifndef AM437X_VPFE_USER_H #define AM437X_VPFE_USER_H +#include <linux/videodev2.h> + enum vpfe_ccdc_data_size { VPFE_CCDC_DATA_16BITS = 0, VPFE_CCDC_DATA_15BITS, diff --git a/include/uapi/linux/media-bus-format.h b/include/uapi/linux/media-bus-format.h index 23b40908be30..d391893064a0 100644 --- a/include/uapi/linux/media-bus-format.h +++ b/include/uapi/linux/media-bus-format.h @@ -33,7 +33,7 @@ #define MEDIA_BUS_FMT_FIXED 0x0001 -/* RGB - next is 0x100e */ +/* RGB - next is 0x1010 */ #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE 0x1001 #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE 0x1002 #define MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE 0x1003 @@ -43,12 +43,14 @@ #define MEDIA_BUS_FMT_RGB565_2X8_BE 0x1007 #define MEDIA_BUS_FMT_RGB565_2X8_LE 0x1008 #define MEDIA_BUS_FMT_RGB666_1X18 0x1009 +#define MEDIA_BUS_FMT_RBG888_1X24 0x100e #define MEDIA_BUS_FMT_RGB888_1X24 0x100a #define MEDIA_BUS_FMT_RGB888_2X12_BE 0x100b #define MEDIA_BUS_FMT_RGB888_2X12_LE 0x100c #define MEDIA_BUS_FMT_ARGB8888_1X32 0x100d +#define MEDIA_BUS_FMT_RGB888_1X32_PADHI 0x100f -/* YUV (including grey) - next is 0x2024 */ +/* YUV (including grey) - next is 0x2025 */ #define MEDIA_BUS_FMT_Y8_1X8 0x2001 #define MEDIA_BUS_FMT_UV8_1X8 0x2015 #define MEDIA_BUS_FMT_UYVY8_1_5X8 0x2002 @@ -65,6 +67,10 @@ #define MEDIA_BUS_FMT_YUYV10_2X10 0x200b #define MEDIA_BUS_FMT_YVYU10_2X10 0x200c #define MEDIA_BUS_FMT_Y12_1X12 0x2013 +#define MEDIA_BUS_FMT_UYVY12_2X12 0x201c +#define MEDIA_BUS_FMT_VYUY12_2X12 0x201d +#define MEDIA_BUS_FMT_YUYV12_2X12 0x201e +#define MEDIA_BUS_FMT_YVYU12_2X12 0x201f #define MEDIA_BUS_FMT_UYVY8_1X16 0x200f #define MEDIA_BUS_FMT_VYUY8_1X16 0x2010 #define MEDIA_BUS_FMT_YUYV8_1X16 0x2011 @@ -74,16 +80,13 @@ #define MEDIA_BUS_FMT_VYUY10_1X20 0x201b #define MEDIA_BUS_FMT_YUYV10_1X20 0x200d #define MEDIA_BUS_FMT_YVYU10_1X20 0x200e -#define MEDIA_BUS_FMT_YUV10_1X30 0x2016 -#define MEDIA_BUS_FMT_AYUV8_1X32 0x2017 -#define MEDIA_BUS_FMT_UYVY12_2X12 0x201c -#define MEDIA_BUS_FMT_VYUY12_2X12 0x201d -#define MEDIA_BUS_FMT_YUYV12_2X12 0x201e -#define MEDIA_BUS_FMT_YVYU12_2X12 0x201f +#define MEDIA_BUS_FMT_VUY8_1X24 0x2024 #define MEDIA_BUS_FMT_UYVY12_1X24 0x2020 #define MEDIA_BUS_FMT_VYUY12_1X24 0x2021 #define MEDIA_BUS_FMT_YUYV12_1X24 0x2022 #define MEDIA_BUS_FMT_YVYU12_1X24 0x2023 +#define MEDIA_BUS_FMT_YUV10_1X30 0x2016 +#define MEDIA_BUS_FMT_AYUV8_1X32 0x2017 /* Bayer - next is 0x3019 */ #define MEDIA_BUS_FMT_SBGGR8_1X8 0x3001 diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h index d847c760e8f0..4e816be3de39 100644 --- a/include/uapi/linux/media.h +++ b/include/uapi/linux/media.h @@ -50,7 +50,14 @@ struct media_device_info { #define MEDIA_ENT_T_DEVNODE_V4L (MEDIA_ENT_T_DEVNODE + 1) #define MEDIA_ENT_T_DEVNODE_FB (MEDIA_ENT_T_DEVNODE + 2) #define MEDIA_ENT_T_DEVNODE_ALSA (MEDIA_ENT_T_DEVNODE + 3) -#define MEDIA_ENT_T_DEVNODE_DVB (MEDIA_ENT_T_DEVNODE + 4) +#define MEDIA_ENT_T_DEVNODE_DVB_FE (MEDIA_ENT_T_DEVNODE + 4) +#define MEDIA_ENT_T_DEVNODE_DVB_DEMUX (MEDIA_ENT_T_DEVNODE + 5) +#define MEDIA_ENT_T_DEVNODE_DVB_DVR (MEDIA_ENT_T_DEVNODE + 6) +#define MEDIA_ENT_T_DEVNODE_DVB_CA (MEDIA_ENT_T_DEVNODE + 7) +#define MEDIA_ENT_T_DEVNODE_DVB_NET (MEDIA_ENT_T_DEVNODE + 8) + +/* Legacy symbol. Use it to avoid userspace compilation breakages */ +#define MEDIA_ENT_T_DEVNODE_DVB MEDIA_ENT_T_DEVNODE_DVB_FE #define MEDIA_ENT_T_V4L2_SUBDEV (2 << MEDIA_ENT_TYPE_SHIFT) #define MEDIA_ENT_T_V4L2_SUBDEV_SENSOR (MEDIA_ENT_T_V4L2_SUBDEV + 1) @@ -59,6 +66,8 @@ struct media_device_info { /* A converter of analogue video to its digital representation. */ #define MEDIA_ENT_T_V4L2_SUBDEV_DECODER (MEDIA_ENT_T_V4L2_SUBDEV + 4) +#define MEDIA_ENT_T_V4L2_SUBDEV_TUNER (MEDIA_ENT_T_V4L2_SUBDEV + 5) + #define MEDIA_ENT_FL_DEFAULT (1 << 0) struct media_entity_desc { @@ -78,17 +87,48 @@ struct media_entity_desc { struct { __u32 major; __u32 minor; - } v4l; - struct { - __u32 major; - __u32 minor; - } fb; + } dev; + +#if 1 + /* + * TODO: this shouldn't have been added without + * actual drivers that use this. When the first real driver + * appears that sets this information, special attention + * should be given whether this information is 1) enough, and + * 2) can deal with udev rules that rename devices. The struct + * dev would not be sufficient for this since that does not + * contain the subdevice information. In addition, struct dev + * can only refer to a single device, and not to multiple (e.g. + * pcm and mixer devices). + * + * So for now mark this as a to do. + */ struct { __u32 card; __u32 device; __u32 subdevice; } alsa; +#endif + +#if 1 + /* + * DEPRECATED: previous node specifications. Kept just to + * avoid breaking compilation, but media_entity_desc.dev + * should be used instead. In particular, alsa and dvb + * fields below are wrong: for all devnodes, there should + * be just major/minor inside the struct, as this is enough + * to represent any devnode, no matter what type. + */ + struct { + __u32 major; + __u32 minor; + } v4l; + struct { + __u32 major; + __u32 minor; + } fb; int dvb; +#endif /* Sub-device specifications */ /* Nothing needed yet */ diff --git a/include/uapi/linux/v4l2-dv-timings.h b/include/uapi/linux/v4l2-dv-timings.h index 6c8f159e416e..c039f1d68a09 100644 --- a/include/uapi/linux/v4l2-dv-timings.h +++ b/include/uapi/linux/v4l2-dv-timings.h @@ -48,14 +48,15 @@ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(720, 480, 1, 0, \ 13500000, 19, 62, 57, 4, 3, 15, 4, 3, 16, \ - V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_HALF_LINE) \ + V4L2_DV_BT_STD_CEA861, \ + V4L2_DV_FL_HALF_LINE | V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_720X480P59_94 { \ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(720, 480, 0, 0, \ 27000000, 16, 62, 60, 9, 6, 30, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, 0) \ + V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \ } /* Note: these are the nominal timings, for HDMI links this format is typically @@ -64,14 +65,15 @@ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(720, 576, 1, 0, \ 13500000, 12, 63, 69, 2, 3, 19, 2, 3, 20, \ - V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_HALF_LINE) \ + V4L2_DV_BT_STD_CEA861, \ + V4L2_DV_FL_HALF_LINE | V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_720X576P50 { \ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(720, 576, 0, 0, \ 27000000, 12, 64, 68, 5, 5, 39, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, 0) \ + V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_1280X720P24 { \ @@ -88,7 +90,7 @@ V4L2_INIT_BT_TIMINGS(1280, 720, 0, \ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ 74250000, 2420, 40, 220, 5, 5, 20, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, 0) \ + V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_1280X720P30 { \ @@ -96,7 +98,8 @@ V4L2_INIT_BT_TIMINGS(1280, 720, 0, \ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ 74250000, 1760, 40, 220, 5, 5, 20, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_CAN_REDUCE_FPS) \ + V4L2_DV_BT_STD_CEA861, \ + V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_1280X720P50 { \ @@ -104,7 +107,7 @@ V4L2_INIT_BT_TIMINGS(1280, 720, 0, \ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ 74250000, 440, 40, 220, 5, 5, 20, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, 0) \ + V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_1280X720P60 { \ @@ -112,7 +115,8 @@ V4L2_INIT_BT_TIMINGS(1280, 720, 0, \ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ 74250000, 110, 40, 220, 5, 5, 20, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_CAN_REDUCE_FPS) \ + V4L2_DV_BT_STD_CEA861, \ + V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_1920X1080P24 { \ @@ -120,7 +124,8 @@ V4L2_INIT_BT_TIMINGS(1920, 1080, 0, \ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ 74250000, 638, 44, 148, 4, 5, 36, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_CAN_REDUCE_FPS) \ + V4L2_DV_BT_STD_CEA861, \ + V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_1920X1080P25 { \ @@ -128,7 +133,7 @@ V4L2_INIT_BT_TIMINGS(1920, 1080, 0, \ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ 74250000, 528, 44, 148, 4, 5, 36, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, 0) \ + V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_1920X1080P30 { \ @@ -136,7 +141,8 @@ V4L2_INIT_BT_TIMINGS(1920, 1080, 0, \ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ 74250000, 88, 44, 148, 4, 5, 36, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_CAN_REDUCE_FPS) \ + V4L2_DV_BT_STD_CEA861, \ + V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_1920X1080I50 { \ @@ -144,7 +150,8 @@ V4L2_INIT_BT_TIMINGS(1920, 1080, 1, \ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ 74250000, 528, 44, 148, 2, 5, 15, 2, 5, 16, \ - V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_HALF_LINE) \ + V4L2_DV_BT_STD_CEA861, \ + V4L2_DV_FL_HALF_LINE | V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_1920X1080P50 { \ @@ -152,7 +159,7 @@ V4L2_INIT_BT_TIMINGS(1920, 1080, 0, \ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ 148500000, 528, 44, 148, 4, 5, 36, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, 0) \ + V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_1920X1080I60 { \ @@ -161,7 +168,8 @@ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ 74250000, 88, 44, 148, 2, 5, 15, 2, 5, 16, \ V4L2_DV_BT_STD_CEA861, \ - V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_HALF_LINE) \ + V4L2_DV_FL_CAN_REDUCE_FPS | \ + V4L2_DV_FL_HALF_LINE | V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_1920X1080P60 { \ @@ -170,77 +178,83 @@ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \ 148500000, 88, 44, 148, 4, 5, 36, 0, 0, 0, \ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CEA861, \ - V4L2_DV_FL_CAN_REDUCE_FPS) \ + V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_3840X2160P24 { \ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(3840, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ 297000000, 1276, 88, 296, 8, 10, 72, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_CAN_REDUCE_FPS) \ + V4L2_DV_BT_STD_CEA861, \ + V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_3840X2160P25 { \ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(3840, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ 297000000, 1056, 88, 296, 8, 10, 72, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, 0) \ + V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_3840X2160P30 { \ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(3840, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ 297000000, 176, 88, 296, 8, 10, 72, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_CAN_REDUCE_FPS) \ + V4L2_DV_BT_STD_CEA861, \ + V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_3840X2160P50 { \ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(3840, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ 594000000, 1056, 88, 296, 8, 10, 72, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, 0) \ + V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_3840X2160P60 { \ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(3840, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ 594000000, 176, 88, 296, 8, 10, 72, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_CAN_REDUCE_FPS) \ + V4L2_DV_BT_STD_CEA861, \ + V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_4096X2160P24 { \ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(4096, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ 297000000, 1020, 88, 296, 8, 10, 72, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_CAN_REDUCE_FPS) \ + V4L2_DV_BT_STD_CEA861, \ + V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_4096X2160P25 { \ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(4096, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ 297000000, 968, 88, 128, 8, 10, 72, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, 0) \ + V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_4096X2160P30 { \ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(4096, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ 297000000, 88, 88, 128, 8, 10, 72, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_CAN_REDUCE_FPS) \ + V4L2_DV_BT_STD_CEA861, \ + V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_4096X2160P50 { \ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(4096, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ 594000000, 968, 88, 128, 8, 10, 72, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, 0) \ + V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_IS_CE_VIDEO) \ } #define V4L2_DV_BT_CEA_4096X2160P60 { \ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(4096, 2160, 0, V4L2_DV_HSYNC_POS_POL, \ 594000000, 88, 88, 128, 8, 10, 72, 0, 0, 0, \ - V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_CAN_REDUCE_FPS) \ + V4L2_DV_BT_STD_CEA861, \ + V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_IS_CE_VIDEO) \ } diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h index e0a7e3da498a..dbce2b554e02 100644 --- a/include/uapi/linux/v4l2-subdev.h +++ b/include/uapi/linux/v4l2-subdev.h @@ -69,12 +69,14 @@ struct v4l2_subdev_crop { * @pad: pad number, as reported by the media API * @index: format index during enumeration * @code: format code (MEDIA_BUS_FMT_ definitions) + * @which: format type (from enum v4l2_subdev_format_whence) */ struct v4l2_subdev_mbus_code_enum { __u32 pad; __u32 index; __u32 code; - __u32 reserved[9]; + __u32 which; + __u32 reserved[8]; }; /** @@ -82,6 +84,7 @@ struct v4l2_subdev_mbus_code_enum { * @pad: pad number, as reported by the media API * @index: format index during enumeration * @code: format code (MEDIA_BUS_FMT_ definitions) + * @which: format type (from enum v4l2_subdev_format_whence) */ struct v4l2_subdev_frame_size_enum { __u32 index; @@ -91,7 +94,8 @@ struct v4l2_subdev_frame_size_enum { __u32 max_width; __u32 min_height; __u32 max_height; - __u32 reserved[9]; + __u32 which; + __u32 reserved[8]; }; /** @@ -113,6 +117,7 @@ struct v4l2_subdev_frame_interval { * @width: frame width in pixels * @height: frame height in pixels * @interval: frame interval in seconds + * @which: format type (from enum v4l2_subdev_format_whence) */ struct v4l2_subdev_frame_interval_enum { __u32 index; @@ -121,7 +126,8 @@ struct v4l2_subdev_frame_interval_enum { __u32 width; __u32 height; struct v4l2_fract interval; - __u32 reserved[9]; + __u32 which; + __u32 reserved[8]; }; /** diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index fbdc3602ee27..fa376f7666ba 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -268,9 +268,10 @@ enum v4l2_ycbcr_encoding { enum v4l2_quantization { /* - * The default for R'G'B' quantization is always full range. For - * Y'CbCr the quantization is always limited range, except for - * SYCC, XV601, XV709 or JPEG: those are full range. + * The default for R'G'B' quantization is always full range, except + * for the BT2020 colorspace. For Y'CbCr the quantization is always + * limited range, except for COLORSPACE_JPEG, SYCC, XV601 or XV709: + * those are full range. */ V4L2_QUANTIZATION_DEFAULT = 0, V4L2_QUANTIZATION_FULL_RANGE = 1, @@ -1187,6 +1188,12 @@ struct v4l2_bt_timings { exactly the same number of half-lines. Whether half-lines can be detected or used depends on the hardware. */ #define V4L2_DV_FL_HALF_LINE (1 << 3) +/* If set, then this is a Consumer Electronics (CE) video format. Such formats + * differ from other formats (commonly called IT formats) in that if RGB + * encoding is used then by default the RGB values use limited range (i.e. + * use the range 16-235) as opposed to 0-255. All formats defined in CEA-861 + * except for the 640x480 format are CE formats. */ +#define V4L2_DV_FL_IS_CE_VIDEO (1 << 4) /* A few useful defines to calculate the total blanking and frame sizes */ #define V4L2_DV_BT_BLANKING_WIDTH(bt) \ @@ -1456,6 +1463,7 @@ struct v4l2_querymenu { #define V4L2_CTRL_FLAG_WRITE_ONLY 0x0040 #define V4L2_CTRL_FLAG_VOLATILE 0x0080 #define V4L2_CTRL_FLAG_HAS_PAYLOAD 0x0100 +#define V4L2_CTRL_FLAG_EXECUTE_ON_WRITE 0x0200 /* Query flags, to be ORed with the control ID */ #define V4L2_CTRL_FLAG_NEXT_CTRL 0x80000000 @@ -1841,8 +1849,8 @@ struct v4l2_mpeg_vbi_fmt_ivtv { */ struct v4l2_plane_pix_format { __u32 sizeimage; - __u16 bytesperline; - __u16 reserved[7]; + __u32 bytesperline; + __u16 reserved[6]; } __attribute__ ((packed)); /** diff --git a/include/uapi/linux/xilinx-v4l2-controls.h b/include/uapi/linux/xilinx-v4l2-controls.h new file mode 100644 index 000000000000..fb495b91e800 --- /dev/null +++ b/include/uapi/linux/xilinx-v4l2-controls.h @@ -0,0 +1,73 @@ +/* + * Xilinx Controls Header + * + * Copyright (C) 2013-2015 Ideas on Board + * Copyright (C) 2013-2015 Xilinx, Inc. + * + * Contacts: Hyun Kwon <hyun.kwon@xilinx.com> + * Laurent Pinchart <laurent.pinchart@ideasonboard.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __UAPI_XILINX_V4L2_CONTROLS_H__ +#define __UAPI_XILINX_V4L2_CONTROLS_H__ + +#include <linux/v4l2-controls.h> + +#define V4L2_CID_XILINX_OFFSET 0xc000 +#define V4L2_CID_XILINX_BASE (V4L2_CID_USER_BASE + V4L2_CID_XILINX_OFFSET) + +/* + * Private Controls for Xilinx Video IPs + */ + +/* + * Xilinx TPG Video IP + */ + +#define V4L2_CID_XILINX_TPG (V4L2_CID_USER_BASE + 0xc000) + +/* Draw cross hairs */ +#define V4L2_CID_XILINX_TPG_CROSS_HAIRS (V4L2_CID_XILINX_TPG + 1) +/* Enable a moving box */ +#define V4L2_CID_XILINX_TPG_MOVING_BOX (V4L2_CID_XILINX_TPG + 2) +/* Mask out a color component */ +#define V4L2_CID_XILINX_TPG_COLOR_MASK (V4L2_CID_XILINX_TPG + 3) +/* Enable a stuck pixel feature */ +#define V4L2_CID_XILINX_TPG_STUCK_PIXEL (V4L2_CID_XILINX_TPG + 4) +/* Enable a noisy output */ +#define V4L2_CID_XILINX_TPG_NOISE (V4L2_CID_XILINX_TPG + 5) +/* Enable the motion feature */ +#define V4L2_CID_XILINX_TPG_MOTION (V4L2_CID_XILINX_TPG + 6) +/* Configure the motion speed of moving patterns */ +#define V4L2_CID_XILINX_TPG_MOTION_SPEED (V4L2_CID_XILINX_TPG + 7) +/* The row of horizontal cross hair location */ +#define V4L2_CID_XILINX_TPG_CROSS_HAIR_ROW (V4L2_CID_XILINX_TPG + 8) +/* The colum of vertical cross hair location */ +#define V4L2_CID_XILINX_TPG_CROSS_HAIR_COLUMN (V4L2_CID_XILINX_TPG + 9) +/* Set starting point of sine wave for horizontal component */ +#define V4L2_CID_XILINX_TPG_ZPLATE_HOR_START (V4L2_CID_XILINX_TPG + 10) +/* Set speed of the horizontal component */ +#define V4L2_CID_XILINX_TPG_ZPLATE_HOR_SPEED (V4L2_CID_XILINX_TPG + 11) +/* Set starting point of sine wave for vertical component */ +#define V4L2_CID_XILINX_TPG_ZPLATE_VER_START (V4L2_CID_XILINX_TPG + 12) +/* Set speed of the vertical component */ +#define V4L2_CID_XILINX_TPG_ZPLATE_VER_SPEED (V4L2_CID_XILINX_TPG + 13) +/* Moving box size */ +#define V4L2_CID_XILINX_TPG_BOX_SIZE (V4L2_CID_XILINX_TPG + 14) +/* Moving box color */ +#define V4L2_CID_XILINX_TPG_BOX_COLOR (V4L2_CID_XILINX_TPG + 15) +/* Upper limit count of generated stuck pixels */ +#define V4L2_CID_XILINX_TPG_STUCK_PIXEL_THRESH (V4L2_CID_XILINX_TPG + 16) +/* Noise level */ +#define V4L2_CID_XILINX_TPG_NOISE_GAIN (V4L2_CID_XILINX_TPG + 17) + +#endif /* __UAPI_XILINX_V4L2_CONTROLS_H__ */ |