Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media

Pull media updates from Mauro Carvalho Chehab:
 - a new jpeg codec driver for Samsung Exynos (jpeg-hw-exynos4)
 - a new dvb frontend for ds2103 chipset (m88ds2103)
 - a new sensor driver for Samsung S5K5BAF UXGA (s5k5baf)
 - new drivers for R-Car VSP1
 - a new radio driver: radio-raremono
 - a new tuner driver for ts2022 chipset (m88ts2022)
 - the analog part of em28xx is now a separate module that only
   load/runs if the device is not a pure digital TV device
 - added a staging driver for bcm2048 radio devices
 - the omap 2 video driver (omap24xx) was moved to staging.  This driver
   is for an old hardware and uses a deprecated Kernel internal API.  If
   nobody cares enough to fix it, it would be removed on a couple Kernel
   releases
 - the sn9c102 driver was moved to staging.  This driver was replaced by
   gspca, and disabled on some distros, as almost all devices are known
   to work properly with gspca.  It should be removed from kernel on a
   couple Kernel releases
 - lots of driver fixes, improvements and cleanups

* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (421 commits)
  [media] media: v4l2-dev: fix video device index assignment
  [media] rc-core: reuse device numbers
  [media] em28xx-cards: properly initialize the device bitmap
  [media] Staging: media: Fix line length exceeding 80 characters in as102_drv.c
  [media] Staging: media: Fix line length exceeding 80 characters in as102_fe.c
  [media] Staging: media: Fix quoted string split across line in as102_fe.c
  [media] media: st-rc: Add reset support
  [media] m2m-deinterlace: fix allocated struct type
  [media] radio-usb-si4713: fix sparse non static symbol warnings
  [media] em28xx-audio: remove needless check before usb_free_coherent()
  [media] au0828: Fix sparse non static symbol warning
  Revert "[media] go7007-usb: only use go->dev after allocated"
  [media] em28xx-audio: provide an error code when URB submit fails
  [media] em28xx: fix check for audio only usb interfaces when changing the usb alternate setting
  [media] em28xx: fix usb alternate setting for analog and digital video endpoints > 0
  [media] em28xx: make 'em28xx_ctrl_ops' static
  em28xx-alsa: Fix error patch for init/fini
  [media] em28xx-audio: flush work at .fini
  [media] drxk: remove the option to load firmware asynchronously
  [media] em28xx: adjust period size at runtime
  ...
This commit is contained in:
Linus Torvalds 2014-01-31 09:31:14 -08:00
commit b399c46ea0
298 changed files with 29170 additions and 5133 deletions

View File

@ -2523,6 +2523,18 @@ that used it. It was originally scheduled for removal in 2.6.35.
</orderedlist>
</section>
<section>
<title>V4L2 in Linux 3.14</title>
<orderedlist>
<listitem>
<para> In struct <structname>v4l2_rect</structname>, the type
of <structfield>width</structfield> and <structfield>height</structfield>
fields changed from _s32 to _u32.
</para>
</listitem>
</orderedlist>
</section>
<section id="other">
<title>Relation of V4L2 to other Linux multimedia APIs</title>

View File

@ -3161,6 +3161,47 @@ V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_REF_PERIOD as a golden frame.</entry>
</entrytbl>
</row>
<row><entry></entry></row>
<row>
<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_VPX_MIN_QP</constant></entry>
<entry>integer</entry>
</row>
<row><entry spanname="descr">Minimum quantization parameter for VP8.</entry>
</row>
<row><entry></entry></row>
<row>
<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_VPX_MAX_QP</constant></entry>
<entry>integer</entry>
</row>
<row><entry spanname="descr">Maximum quantization parameter for VP8.</entry>
</row>
<row><entry></entry></row>
<row>
<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP</constant>&nbsp;</entry>
<entry>integer</entry>
</row>
<row><entry spanname="descr">Quantization parameter for an I frame for VP8.</entry>
</row>
<row><entry></entry></row>
<row>
<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP</constant>&nbsp;</entry>
<entry>integer</entry>
</row>
<row><entry spanname="descr">Quantization parameter for a P frame for VP8.</entry>
</row>
<row><entry></entry></row>
<row>
<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_VPX_PROFILE</constant>&nbsp;</entry>
<entry>integer</entry>
</row>
<row><entry spanname="descr">Select the desired profile for VPx encoder.
Acceptable values are 0, 1, 2 and 3 corresponding to encoder profiles 0, 1, 2 and 3.</entry>
</row>
<row><entry></entry></row>
</tbody>
</tgroup>

View File

@ -346,17 +346,14 @@ rectangle, in pixels.</entry>
rectangle, in pixels. Offsets increase to the right and down.</entry>
</row>
<row>
<entry>__s32</entry>
<entry>__u32</entry>
<entry><structfield>width</structfield></entry>
<entry>Width of the rectangle, in pixels.</entry>
</row>
<row>
<entry>__s32</entry>
<entry>__u32</entry>
<entry><structfield>height</structfield></entry>
<entry>Height of the rectangle, in pixels. Width and
height cannot be negative, the fields are signed for hysterical
reasons. <!-- video4linux-list@redhat.com on 22 Oct 2002 subject
"Re:[V4L][patches!] Re:v4l2/kernel-2.5" --></entry>
<entry>Height of the rectangle, in pixels.</entry>
</row>
</tbody>
</tgroup>

View File

@ -134,6 +134,15 @@
<entry>Output pad, relative to the entity. Output pads source data
and are origins of links.</entry>
</row>
<row>
<entry><constant>MEDIA_PAD_FL_MUST_CONNECT</constant></entry>
<entry>If this flag is set and the pad is linked to any other
pad, then at least one of those links must be enabled for the
entity to be able to stream. There could be temporary reasons
(e.g. device configuration dependent) for the pad to need
enabled links even when this flag isn't set; the absence of the
flag doesn't imply there is none.</entry>
</row>
</tbody>
</tgroup>
</table>

View File

@ -89,7 +89,7 @@
<constant>V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE</constant>.
</para>
<para>The following tables list existing packet RGB formats.</para>
<para>The following tables list existing packed RGB formats.</para>
<table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-rgb">
<title>RGB formats</title>
@ -615,7 +615,7 @@
</mediaobject>
</figure>
<para>The following table lists existing packet Bayer formats. The data
<para>The following table lists existing packed Bayer formats. The data
organization is given as an example for the first pixel only.</para>
<table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-bayer">
@ -1178,7 +1178,7 @@
U, Y, V, Y order will be named <constant>V4L2_MBUS_FMT_UYVY8_2X8</constant>.
</para>
<para><xref linkend="v4l2-mbus-pixelcode-yuv8"/> list existing packet YUV
<para><xref linkend="v4l2-mbus-pixelcode-yuv8"/> lists existing packed YUV
formats and describes the organization of each pixel data in each sample.
When a format pattern is split across multiple samples each of the samples
in the pattern is described.</para>
@ -2491,6 +2491,163 @@
</table>
</section>
<section>
<title>HSV/HSL Formats</title>
<para>Those formats transfer pixel data as RGB values in a cylindrical-coordinate
system using Hue-Saturation-Value or Hue-Saturation-Lightness components. The
format code is made of the following information.
<itemizedlist>
<listitem><para>The hue, saturation, value or lightness and optional alpha
components order code, as encoded in a pixel sample. The only currently
supported value is AHSV.
</para></listitem>
<listitem><para>The number of bits per component, for each component. The values
can be different for all components. The only currently supported value is 8888.
</para></listitem>
<listitem><para>The number of bus samples per pixel. Pixels that are wider than
the bus width must be transferred in multiple samples. The only currently
supported value is 1.</para></listitem>
<listitem><para>The bus width.</para></listitem>
<listitem><para>For formats where the total number of bits per pixel is smaller
than the number of bus samples per pixel times the bus width, a padding
value stating if the bytes are padded in their most high order bits
(PADHI) or low order bits (PADLO).</para></listitem>
<listitem><para>For formats where the number of bus samples per pixel is larger
than 1, an endianness value stating if the pixel is transferred MSB first
(BE) or LSB first (LE).</para></listitem>
</itemizedlist>
</para>
<para>The following table lists existing HSV/HSL formats.</para>
<table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-hsv">
<title>HSV/HSL formats</title>
<tgroup cols="27">
<colspec colname="id" align="left" />
<colspec colname="code" align="center"/>
<colspec colname="bit" />
<colspec colnum="4" colname="b31" align="center" />
<colspec colnum="5" colname="b20" align="center" />
<colspec colnum="6" colname="b29" align="center" />
<colspec colnum="7" colname="b28" align="center" />
<colspec colnum="8" colname="b27" align="center" />
<colspec colnum="9" colname="b26" align="center" />
<colspec colnum="10" colname="b25" align="center" />
<colspec colnum="11" colname="b24" align="center" />
<colspec colnum="12" colname="b23" align="center" />
<colspec colnum="13" colname="b22" align="center" />
<colspec colnum="14" colname="b21" align="center" />
<colspec colnum="15" colname="b20" align="center" />
<colspec colnum="16" colname="b19" align="center" />
<colspec colnum="17" colname="b18" align="center" />
<colspec colnum="18" colname="b17" align="center" />
<colspec colnum="19" colname="b16" align="center" />
<colspec colnum="20" colname="b15" align="center" />
<colspec colnum="21" colname="b14" align="center" />
<colspec colnum="22" colname="b13" align="center" />
<colspec colnum="23" colname="b12" align="center" />
<colspec colnum="24" colname="b11" align="center" />
<colspec colnum="25" colname="b10" align="center" />
<colspec colnum="26" colname="b09" align="center" />
<colspec colnum="27" colname="b08" align="center" />
<colspec colnum="28" colname="b07" align="center" />
<colspec colnum="29" colname="b06" align="center" />
<colspec colnum="30" colname="b05" align="center" />
<colspec colnum="31" colname="b04" align="center" />
<colspec colnum="32" colname="b03" align="center" />
<colspec colnum="33" colname="b02" align="center" />
<colspec colnum="34" colname="b01" align="center" />
<colspec colnum="35" colname="b00" align="center" />
<spanspec namest="b31" nameend="b00" spanname="b0" />
<thead>
<row>
<entry>Identifier</entry>
<entry>Code</entry>
<entry></entry>
<entry spanname="b0">Data organization</entry>
</row>
<row>
<entry></entry>
<entry></entry>
<entry>Bit</entry>
<entry>31</entry>
<entry>30</entry>
<entry>29</entry>
<entry>28</entry>
<entry>27</entry>
<entry>26</entry>
<entry>25</entry>
<entry>24</entry>
<entry>23</entry>
<entry>22</entry>
<entry>21</entry>
<entry>20</entry>
<entry>19</entry>
<entry>18</entry>
<entry>17</entry>
<entry>16</entry>
<entry>15</entry>
<entry>14</entry>
<entry>13</entry>
<entry>12</entry>
<entry>11</entry>
<entry>10</entry>
<entry>9</entry>
<entry>8</entry>
<entry>7</entry>
<entry>6</entry>
<entry>5</entry>
<entry>4</entry>
<entry>3</entry>
<entry>2</entry>
<entry>1</entry>
<entry>0</entry>
</row>
</thead>
<tbody valign="top">
<row id="V4L2-MBUS-FMT-AHSV8888-1X32">
<entry>V4L2_MBUS_FMT_AHSV8888_1X32</entry>
<entry>0x6001</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>h<subscript>7</subscript></entry>
<entry>h<subscript>6</subscript></entry>
<entry>h<subscript>5</subscript></entry>
<entry>h<subscript>4</subscript></entry>
<entry>h<subscript>3</subscript></entry>
<entry>h<subscript>2</subscript></entry>
<entry>h<subscript>1</subscript></entry>
<entry>h<subscript>0</subscript></entry>
<entry>s<subscript>7</subscript></entry>
<entry>s<subscript>6</subscript></entry>
<entry>s<subscript>5</subscript></entry>
<entry>s<subscript>4</subscript></entry>
<entry>s<subscript>3</subscript></entry>
<entry>s<subscript>2</subscript></entry>
<entry>s<subscript>1</subscript></entry>
<entry>s<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>
</section>
<section>
<title>JPEG Compressed Formats</title>

View File

@ -140,6 +140,14 @@ structs, ioctls) must be noted in more detail in the history chapter
(compat.xml), along with the possible impact on existing drivers and
applications. -->
<revision>
<revnumber>3.14</revnumber>
<date>2013-11-25</date>
<authorinitials>rr</authorinitials>
<revremark>Set width and height as unsigned on v4l2_rect.
</revremark>
</revision>
<revision>
<revnumber>3.11</revnumber>
<date>2013-05-26</date>
@ -501,7 +509,7 @@ and discussions on the V4L mailing list.</revremark>
</partinfo>
<title>Video for Linux Two API Specification</title>
<subtitle>Revision 3.11</subtitle>
<subtitle>Revision 3.14</subtitle>
<chapter id="common">
&sub-common;

View File

@ -133,18 +133,14 @@ rectangle, in pixels.</entry>
rectangle, in pixels.</entry>
</row>
<row>
<entry>__s32</entry>
<entry>__u32</entry>
<entry><structfield>width</structfield></entry>
<entry>Width of the rectangle, in pixels.</entry>
</row>
<row>
<entry>__s32</entry>
<entry>__u32</entry>
<entry><structfield>height</structfield></entry>
<entry>Height of the rectangle, in pixels. Width
and height cannot be negative, the fields are signed for
hysterical reasons. <!-- video4linux-list@redhat.com
on 22 Oct 2002 subject "Re:[V4L][patches!] Re:v4l2/kernel-2.5" -->
</entry>
<entry>Height of the rectangle, in pixels.</entry>
</row>
</tbody>
</tgroup>

View File

@ -59,7 +59,7 @@ buffers are filled (if there are any empty buffers in the incoming
queue) until <constant>VIDIOC_STREAMON</constant> has been called.
Accordingly the output hardware is disabled, no video signal is
produced until <constant>VIDIOC_STREAMON</constant> has been called.
The ioctl will succeed only when at least one output buffer is in the
The ioctl will succeed when at least one output buffer is in the
incoming queue.</para>
<para>The <constant>VIDIOC_STREAMOFF</constant> ioctl, apart of

View File

@ -95,7 +95,7 @@ to work with it.
f. u64 res_counter_uncharge_until
(struct res_counter *rc, struct res_counter *top,
unsinged long val)
unsigned long val)
Almost same as res_counter_uncharge() but propagation of uncharge
stops when rc == top. This is useful when kill a res_counter in

View File

@ -0,0 +1,11 @@
Samsung S5P/EXYNOS SoC series JPEG codec
Required properties:
- compatible : should be one of:
"samsung,s5pv210-jpeg", "samsung,exynos4210-jpeg";
- reg : address and length of the JPEG codec IP register set;
- interrupts : specifies the JPEG codec IP interrupt;
- clocks : should contain the JPEG codec IP gate clock specifier, from the
common clock bindings;
- clock-names : should contain "jpeg" entry.

View File

@ -0,0 +1,58 @@
Samsung S5K5BAF UXGA 1/5" 2M CMOS Image Sensor with embedded SoC ISP
--------------------------------------------------------------------
Required properties:
- compatible : "samsung,s5k5baf";
- reg : I2C slave address of the sensor;
- vdda-supply : analog power supply 2.8V (2.6V to 3.0V);
- vddreg-supply : regulator input power supply 1.8V (1.7V to 1.9V)
or 2.8V (2.6V to 3.0);
- vddio-supply : I/O power supply 1.8V (1.65V to 1.95V)
or 2.8V (2.5V to 3.1V);
- stbyn-gpios : GPIO connected to STDBYN pin;
- rstn-gpios : GPIO connected to RSTN pin;
- clocks : list of phandle and clock specifier pairs
according to common clock bindings for the
clocks described in clock-names;
- clock-names : should include "mclk" for the sensor's master clock;
Optional properties:
- clock-frequency : the frequency at which the "mclk" clock should be
configured to operate, in Hz; if this property is not
specified default 24 MHz value will be used.
The device node should contain one 'port' child node with one child 'endpoint'
node, according to the bindings defined in Documentation/devicetree/bindings/
media/video-interfaces.txt. The following are properties specific to those
nodes.
endpoint node
-------------
- data-lanes : (optional) specifies MIPI CSI-2 data lanes as covered in
video-interfaces.txt. If present it should be <1> - the device
supports only one data lane without re-mapping.
Example:
s5k5bafx@2d {
compatible = "samsung,s5k5baf";
reg = <0x2d>;
vdda-supply = <&cam_io_en_reg>;
vddreg-supply = <&vt_core_15v_reg>;
vddio-supply = <&vtcam_reg>;
stbyn-gpios = <&gpl2 0 1>;
rstn-gpios = <&gpl2 1 1>;
clock-names = "mclk";
clocks = <&clock_cam 0>;
clock-frequency = <24000000>;
port {
s5k5bafx_ep: endpoint {
remote-endpoint = <&csis1_ep>;
data-lanes = <1>;
};
};
};

View File

@ -0,0 +1,60 @@
OMAP4 ISS Driver
================
Introduction
------------
The OMAP44XX family of chips contains the Imaging SubSystem (a.k.a. ISS),
Which contains several components that can be categorized in 3 big groups:
- Interfaces (2 Interfaces: CSI2-A & CSI2-B/CCP2)
- ISP (Image Signal Processor)
- SIMCOP (Still Image Coprocessor)
For more information, please look in [1] for latest version of:
"OMAP4430 Multimedia Device Silicon Revision 2.x"
As of Revision AB, the ISS is described in detail in section 8.
This driver is supporting _only_ the CSI2-A/B interfaces for now.
It makes use of the Media Controller framework [2], and inherited most of the
code from OMAP3 ISP driver (found under drivers/media/platform/omap3isp/*),
except that it doesn't need an IOMMU now for ISS buffers memory mapping.
Supports usage of MMAP buffers only (for now).
Tested platforms
----------------
- OMAP4430SDP, w/ ES2.1 GP & SEVM4430-CAM-V1-0 (Contains IMX060 & OV5640, in
which only the last one is supported, outputting YUV422 frames).
- TI Blaze MDP, w/ OMAP4430 ES2.2 EMU (Contains 1 IMX060 & 2 OV5650 sensors, in
which only the OV5650 are supported, outputting RAW10 frames).
- PandaBoard, Rev. A2, w/ OMAP4430 ES2.1 GP & OV adapter board, tested with
following sensors:
* OV5640
* OV5650
- Tested on mainline kernel:
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=summary
Tag: v3.3 (commit c16fa4f2ad19908a47c63d8fa436a1178438c7e7)
File list
---------
drivers/staging/media/omap4iss/
include/media/omap4iss.h
References
----------
[1] http://focus.ti.com/general/docs/wtbu/wtbudocumentcenter.tsp?navigationId=12037&templateId=6123#62
[2] http://lwn.net/Articles/420485/
[3] http://www.spinics.net/lists/linux-media/msg44370.html
--
Author: Sergio Aguirre <sergio.a.aguirre@gmail.com>
Copyright (C) 2012, Texas Instruments

View File

@ -147,7 +147,7 @@ The drivers exposes following files:
--------------------------------------------------------------------
0x12 | readfreq | Current tuned frequency
--------------------------------------------------------------------
0x14 | freqoff | Singed frequency offset in units of
0x14 | freqoff | Signed frequency offset in units of
| | 2ppm
--------------------------------------------------------------------
0x15 | rssi | Signed value of RSSI in dBuV

View File

@ -5425,6 +5425,16 @@ W: http://www.tazenda.demon.co.uk/phil/linux-hp
S: Maintained
F: arch/m68k/hp300/
M88DS3103 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/dvb-frontends/m88ds3103*
M88RS2000 MEDIA DRIVER
M: Malcolm Priestley <tvboxspy@gmail.com>
L: linux-media@vger.kernel.org
@ -5433,6 +5443,16 @@ 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
@ -7471,6 +7491,13 @@ L: linux-media@vger.kernel.org
S: Supported
F: drivers/media/i2c/s5c73m3/*
SAMSUNG S5K5BAF CAMERA DRIVER
M: Kyungmin Park <kyungmin.park@samsung.com>
M: Andrzej Hajda <a.hajda@samsung.com>
L: linux-media@vger.kernel.org
S: Supported
F: drivers/media/i2c/s5k5baf.c
SAMSUNG SOC CLOCK DRIVERS
M: Tomasz Figa <t.figa@samsung.com>
S: Supported
@ -7774,7 +7801,7 @@ L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
W: http://linuxtv.org
S: Odd Fixes
F: drivers/media/radio/si4713-i2c.?
F: drivers/media/radio/si4713/si4713.?
SI4713 FM RADIO TRANSMITTER PLATFORM DRIVER
M: Eduardo Valentin <edubezval@gmail.com>
@ -7782,7 +7809,15 @@ L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
W: http://linuxtv.org
S: Odd Fixes
F: drivers/media/radio/radio-si4713.c
F: drivers/media/radio/si4713/radio-platform-si4713.c
SI4713 FM RADIO TRANSMITTER USB DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
W: http://linuxtv.org
S: Maintained
F: drivers/media/radio/si4713/radio-usb-si4713.c
SIANO DVB DRIVER
M: Mauro Carvalho Chehab <m.chehab@samsung.com>
@ -8634,6 +8669,14 @@ L: linux-xtensa@linux-xtensa.org
S: Maintained
F: arch/xtensa/
THANKO'S RAREMONO AM/FM/SW RADIO RECEIVER USB DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
W: http://linuxtv.org
S: Maintained
F: drivers/media/radio/radio-raremono.c
THERMAL
M: Zhang Rui <rui.zhang@intel.com>
M: Eduardo Valentin <eduardo.valentin@ti.com>
@ -9166,8 +9209,7 @@ L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
W: http://www.linux-projects.org
S: Maintained
F: Documentation/video4linux/sn9c102.txt
F: drivers/media/usb/sn9c102/
F: drivers/staging/media/sn9c102/
USB SUBSYSTEM
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

View File

@ -760,7 +760,14 @@ static struct regulator_init_data rx51_vintdig = {
},
};
static const char * const si4713_supply_names[] = {
"vio",
"vdd",
};
static struct si4713_platform_data rx51_si4713_i2c_data __initdata_or_module = {
.supplies = ARRAY_SIZE(si4713_supply_names),
.supply_names = si4713_supply_names,
.gpio_reset = RX51_FMTX_RESET_GPIO,
};

View File

@ -1025,7 +1025,9 @@ static struct adv7842_platform_data adv7842_data = {
.ain_sel = ADV7842_AIN10_11_12_NC_SYNC_4_1,
.prim_mode = ADV7842_PRIM_MODE_SDP,
.vid_std_select = ADV7842_SDP_VID_STD_CVBS_SD_4x1,
.inp_color_space = ADV7842_INP_COLOR_SPACE_AUTO,
.hdmi_free_run_enable = 1,
.sdp_free_run_auto = 1,
.llc_dll_phase = 0x10,
.i2c_sdp_io = 0x40,
.i2c_sdp = 0x41,
.i2c_cp = 0x42,

View File

@ -137,7 +137,7 @@ ENTRY(csum_partial)
ldi r25, 0
mv r10, r5
cmpi.c r5, 0x8
blt small_csumcpy /* < 8(singed) bytes to copy */
blt small_csumcpy /* < 8(signed) bytes to copy */
cmpi.c r5, 0x0
beq out
andri.c r25, src, 0x1 /* odd buffer? */

View File

@ -2118,6 +2118,7 @@ static const struct hid_device_id hid_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CIDC, 0x0103) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_RADIO_SI470X) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_RADIO_SI4713) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM109) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE) },

View File

@ -241,6 +241,8 @@
#define USB_VENDOR_ID_CYGNAL 0x10c4
#define USB_DEVICE_ID_CYGNAL_RADIO_SI470X 0x818a
#define USB_DEVICE_ID_CYGNAL_RADIO_SI4713 0x8244
#define USB_VENDOR_ID_CYPRESS 0x04b4
#define USB_DEVICE_ID_CYPRESS_MOUSE 0x0001
#define USB_DEVICE_ID_CYPRESS_HIDCOM 0x5500

View File

@ -172,6 +172,9 @@ comment "Media ancillary drivers (tuners, sensors, i2c, frontends)"
config MEDIA_SUBDRV_AUTOSELECT
bool "Autoselect ancillary drivers (tuners, sensors, i2c, frontends)"
depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_CAMERA_SUPPORT
depends on HAS_IOMEM
select I2C
select I2C_MUX
default y
help
By default, a media driver auto-selects all possible ancillary

View File

@ -239,6 +239,7 @@
#define USB_PID_AVERMEDIA_A835B_4835 0x4835
#define USB_PID_AVERMEDIA_1867 0x1867
#define USB_PID_AVERMEDIA_A867 0xa867
#define USB_PID_AVERMEDIA_H335 0x0335
#define USB_PID_AVERMEDIA_TWINSTAR 0x0825
#define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006
#define USB_PID_TECHNOTREND_CONNECT_S2400_8KEEPROM 0x3009
@ -317,6 +318,7 @@
#define USB_PID_WINFAST_DTV_DONGLE_H 0x60f6
#define USB_PID_WINFAST_DTV_DONGLE_STK7700P_2 0x6f01
#define USB_PID_WINFAST_DTV_DONGLE_GOLD 0x6029
#define USB_PID_WINFAST_DTV_DONGLE_MINID 0x6f0f
#define USB_PID_GENPIX_8PSK_REV_1_COLD 0x0200
#define USB_PID_GENPIX_8PSK_REV_1_WARM 0x0201
#define USB_PID_GENPIX_8PSK_REV_2 0x0202
@ -365,6 +367,7 @@
#define USB_PID_TERRATEC_DVBS2CI_V2 0x10ac
#define USB_PID_TECHNISAT_USB2_HDCI_V1 0x0001
#define USB_PID_TECHNISAT_USB2_HDCI_V2 0x0002
#define USB_PID_TECHNISAT_USB2_CABLESTAR_HDCI 0x0003
#define USB_PID_TECHNISAT_AIRSTAR_TELESTICK_2 0x0004
#define USB_PID_TECHNISAT_USB2_DVB_S2 0x0500
#define USB_PID_CPYTO_REDI_PC50A 0xa803

View File

@ -35,6 +35,13 @@ config DVB_STV6110x
help
A Silicon tuner that supports DVB-S and DVB-S2 modes
config DVB_M88DS3103
tristate "Montage M88DS3103"
depends on DVB_CORE && I2C && I2C_MUX
default m if !MEDIA_SUBDRV_AUTOSELECT
help
Say Y when you want to support this frontend.
comment "Multistandard (cable + terrestrial) frontends"
depends on DVB_CORE

View File

@ -85,6 +85,7 @@ obj-$(CONFIG_DVB_STV6110) += stv6110.o
obj-$(CONFIG_DVB_STV0900) += stv0900.o
obj-$(CONFIG_DVB_STV090x) += stv090x.o
obj-$(CONFIG_DVB_STV6110x) += stv6110x.o
obj-$(CONFIG_DVB_M88DS3103) += m88ds3103.o
obj-$(CONFIG_DVB_ISL6423) += isl6423.o
obj-$(CONFIG_DVB_EC100) += ec100.o
obj-$(CONFIG_DVB_HD29L2) += hd29l2.o

View File

@ -96,6 +96,8 @@ static int a8293_set_voltage(struct dvb_frontend *fe,
if (ret)
goto err;
usleep_range(1500, 50000);
return ret;
err:
dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);

View File

@ -135,15 +135,33 @@
enum cmds {
CMD_SET_VCO = 0x10,
CMD_TUNEREQUEST = 0x11,
CMD_MPEGCONFIG = 0x13,
CMD_TUNERINIT = 0x14,
CMD_LNBSEND = 0x21, /* Formerly CMD_SEND_DISEQC */
CMD_LNBDCLEVEL = 0x22,
CMD_SET_TONE = 0x23,
CMD_UPDFWVERS = 0x35,
CMD_TUNERSLEEP = 0x36,
CMD_SET_VCOFREQ = 0x10,
CMD_TUNEREQUEST = 0x11,
CMD_GLOBAL_MPEGCFG = 0x13,
CMD_MPEGCFG = 0x14,
CMD_TUNERINIT = 0x15,
CMD_GET_SRATE = 0x18,
CMD_SET_GOLDCODE = 0x19,
CMD_GET_AGCACC = 0x1a,
CMD_DEMODINIT = 0x1b,
CMD_GETCTLACC = 0x1c,
CMD_LNBCONFIG = 0x20,
CMD_LNBSEND = 0x21,
CMD_LNBDCLEVEL = 0x22,
CMD_LNBPCBCONFIG = 0x23,
CMD_LNBSENDTONEBST = 0x24,
CMD_LNBUPDREPLY = 0x25,
CMD_SET_GPIOMODE = 0x30,
CMD_SET_GPIOEN = 0x31,
CMD_SET_GPIODIR = 0x32,
CMD_SET_GPIOOUT = 0x33,
CMD_ENABLERSCORR = 0x34,
CMD_FWVERSION = 0x35,
CMD_SET_SLEEPMODE = 0x36,
CMD_BERCTRL = 0x3c,
CMD_EVENTCTRL = 0x3d,
};
static LIST_HEAD(hybrid_tuner_instance_list);
@ -619,8 +637,8 @@ static int cx24117_load_firmware(struct dvb_frontend *fe,
cx24117_writereg(state, 0xf7, 0x0c);
cx24117_writereg(state, 0xe0, 0x00);
/* CMD 1B */
cmd.args[0] = 0x1b;
/* Init demodulator */
cmd.args[0] = CMD_DEMODINIT;
cmd.args[1] = 0x00;
cmd.args[2] = 0x01;
cmd.args[3] = 0x00;
@ -629,8 +647,8 @@ static int cx24117_load_firmware(struct dvb_frontend *fe,
if (ret != 0)
goto error;
/* CMD 10 */
cmd.args[0] = CMD_SET_VCO;
/* Set VCO frequency */
cmd.args[0] = CMD_SET_VCOFREQ;
cmd.args[1] = 0x06;
cmd.args[2] = 0x2b;
cmd.args[3] = 0xd8;
@ -648,8 +666,8 @@ static int cx24117_load_firmware(struct dvb_frontend *fe,
if (ret != 0)
goto error;
/* CMD 15 */
cmd.args[0] = 0x15;
/* Tuner init */
cmd.args[0] = CMD_TUNERINIT;
cmd.args[1] = 0x00;
cmd.args[2] = 0x01;
cmd.args[3] = 0x00;
@ -667,8 +685,8 @@ static int cx24117_load_firmware(struct dvb_frontend *fe,
if (ret != 0)
goto error;
/* CMD 13 */
cmd.args[0] = CMD_MPEGCONFIG;
/* Global MPEG config */
cmd.args[0] = CMD_GLOBAL_MPEGCFG;
cmd.args[1] = 0x00;
cmd.args[2] = 0x00;
cmd.args[3] = 0x00;
@ -679,9 +697,9 @@ static int cx24117_load_firmware(struct dvb_frontend *fe,
if (ret != 0)
goto error;
/* CMD 14 */
/* MPEG config for each demod */
for (i = 0; i < 2; i++) {
cmd.args[0] = CMD_TUNERINIT;
cmd.args[0] = CMD_MPEGCFG;
cmd.args[1] = (u8) i;
cmd.args[2] = 0x00;
cmd.args[3] = 0x05;
@ -699,8 +717,8 @@ static int cx24117_load_firmware(struct dvb_frontend *fe,
cx24117_writereg(state, 0xcf, 0x00);
cx24117_writereg(state, 0xe5, 0x04);
/* Firmware CMD 35: Get firmware version */
cmd.args[0] = CMD_UPDFWVERS;
/* Get firmware version */
cmd.args[0] = CMD_FWVERSION;
cmd.len = 2;
for (i = 0; i < 4; i++) {
cmd.args[1] = i;
@ -779,8 +797,8 @@ static int cx24117_read_signal_strength(struct dvb_frontend *fe,
u8 reg = (state->demod == 0) ?
CX24117_REG_SSTATUS0 : CX24117_REG_SSTATUS1;
/* Firmware CMD 1A */
cmd.args[0] = 0x1a;
/* Read AGC accumulator register */
cmd.args[0] = CMD_GET_AGCACC;
cmd.args[1] = (u8) state->demod;
cmd.len = 2;
ret = cx24117_cmd_execute(fe, &cmd);
@ -899,22 +917,15 @@ static int cx24117_set_voltage(struct dvb_frontend *fe,
voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" :
"SEC_VOLTAGE_OFF");
/* CMD 32 */
cmd.args[0] = 0x32;
cmd.args[1] = reg;
cmd.args[2] = reg;
/* Prepare a set GPIO logic level CMD */
cmd.args[0] = CMD_SET_GPIOOUT;
cmd.args[2] = reg; /* mask */
cmd.len = 3;
ret = cx24117_cmd_execute(fe, &cmd);
if (ret)
return ret;
if ((voltage == SEC_VOLTAGE_13) ||
(voltage == SEC_VOLTAGE_18)) {
/* CMD 33 */
cmd.args[0] = 0x33;
/* power on LNB */
cmd.args[1] = reg;
cmd.args[2] = reg;
cmd.len = 3;
ret = cx24117_cmd_execute(fe, &cmd);
if (ret != 0)
return ret;
@ -926,22 +937,22 @@ static int cx24117_set_voltage(struct dvb_frontend *fe,
/* Wait for voltage/min repeat delay */
msleep(100);
/* CMD 22 - CMD_LNBDCLEVEL */
/* Set 13V/18V select pin */
cmd.args[0] = CMD_LNBDCLEVEL;
cmd.args[1] = state->demod ? 0 : 1;
cmd.args[2] = (voltage == SEC_VOLTAGE_18 ? 0x01 : 0x00);
cmd.len = 3;
ret = cx24117_cmd_execute(fe, &cmd);
/* Min delay time before DiSEqC send */
msleep(20);
} else {
cmd.args[0] = 0x33;
/* power off LNB */
cmd.args[1] = 0x00;
cmd.args[2] = reg;
cmd.len = 3;
ret = cx24117_cmd_execute(fe, &cmd);
}
return cx24117_cmd_execute(fe, &cmd);
return ret;
}
static int cx24117_set_tone(struct dvb_frontend *fe,
@ -968,8 +979,7 @@ static int cx24117_set_tone(struct dvb_frontend *fe,
msleep(20);
/* Set the tone */
/* CMD 23 - CMD_SET_TONE */
cmd.args[0] = CMD_SET_TONE;
cmd.args[0] = CMD_LNBPCBCONFIG;
cmd.args[1] = (state->demod ? 0 : 1);
cmd.args[2] = 0x00;
cmd.args[3] = 0x00;
@ -1231,8 +1241,8 @@ static int cx24117_initfe(struct dvb_frontend *fe)
mutex_lock(&state->priv->fe_lock);
/* Firmware CMD 36: Power config */
cmd.args[0] = CMD_TUNERSLEEP;
/* Set sleep mode off */
cmd.args[0] = CMD_SET_SLEEPMODE;
cmd.args[1] = (state->demod ? 1 : 0);
cmd.args[2] = 0;
cmd.len = 3;
@ -1244,8 +1254,8 @@ static int cx24117_initfe(struct dvb_frontend *fe)
if (ret != 0)
goto exit;
/* CMD 3C */
cmd.args[0] = 0x3c;
/* Set BER control */
cmd.args[0] = CMD_BERCTRL;
cmd.args[1] = (state->demod ? 1 : 0);
cmd.args[2] = 0x10;
cmd.args[3] = 0x10;
@ -1254,12 +1264,22 @@ static int cx24117_initfe(struct dvb_frontend *fe)
if (ret != 0)
goto exit;
/* CMD 34 */
cmd.args[0] = 0x34;
/* Set RS correction (enable/disable) */
cmd.args[0] = CMD_ENABLERSCORR;
cmd.args[1] = (state->demod ? 1 : 0);
cmd.args[2] = CX24117_OCC;
cmd.len = 3;
ret = cx24117_cmd_execute_nolock(fe, &cmd);
if (ret != 0)
goto exit;
/* Set GPIO direction */
/* Set as output - controls LNB power on/off */
cmd.args[0] = CMD_SET_GPIODIR;
cmd.args[1] = 0x30;
cmd.args[2] = 0x30;
cmd.len = 3;
ret = cx24117_cmd_execute_nolock(fe, &cmd);
exit:
mutex_unlock(&state->priv->fe_lock);
@ -1278,8 +1298,8 @@ static int cx24117_sleep(struct dvb_frontend *fe)
dev_dbg(&state->priv->i2c->dev, "%s() demod%d\n",
__func__, state->demod);
/* Firmware CMD 36: Power config */
cmd.args[0] = CMD_TUNERSLEEP;
/* Set sleep mode on */
cmd.args[0] = CMD_SET_SLEEPMODE;
cmd.args[1] = (state->demod ? 1 : 0);
cmd.args[2] = 1;
cmd.len = 3;
@ -1558,7 +1578,8 @@ static int cx24117_get_frontend(struct dvb_frontend *fe)
u8 buf[0x1f-4];
cmd.args[0] = 0x1c;
/* Read current tune parameters */
cmd.args[0] = CMD_GETCTLACC;
cmd.args[1] = (u8) state->demod;
cmd.len = 2;
ret = cx24117_cmd_execute(fe, &cmd);

View File

@ -11,6 +11,7 @@
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <asm/div64.h>
#include "dvb_math.h"
@ -118,6 +119,12 @@ struct dib8000_state {
u8 longest_intlv_layer;
u16 output_mode;
/* for DVBv5 stats */
s64 init_ucb;
unsigned long per_jiffies_stats;
unsigned long ber_jiffies_stats;
unsigned long ber_jiffies_stats_layer[3];
#ifdef DIB8000_AGC_FREEZE
u16 agc1_max;
u16 agc1_min;
@ -157,15 +164,10 @@ static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg)
return ret;
}
static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
static u16 __dib8000_read_word(struct dib8000_state *state, u16 reg)
{
u16 ret;
if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
dprintk("could not acquire lock");
return 0;
}
state->i2c_write_buffer[0] = reg >> 8;
state->i2c_write_buffer[1] = reg & 0xff;
@ -183,6 +185,21 @@ static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
dprintk("i2c read error on %d", reg);
ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
return ret;
}
static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
{
u16 ret;
if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
dprintk("could not acquire lock");
return 0;
}
ret = __dib8000_read_word(state, reg);
mutex_unlock(&state->i2c_buffer_lock);
return ret;
@ -192,8 +209,15 @@ static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
{
u16 rw[2];
rw[0] = dib8000_read_word(state, reg + 0);
rw[1] = dib8000_read_word(state, reg + 1);
if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
dprintk("could not acquire lock");
return 0;
}
rw[0] = __dib8000_read_word(state, reg + 0);
rw[1] = __dib8000_read_word(state, reg + 1);
mutex_unlock(&state->i2c_buffer_lock);
return ((rw[0] << 16) | (rw[1]));
}
@ -787,7 +811,7 @@ int dib8000_update_pll(struct dvb_frontend *fe,
dprintk("PLL: Update ratio (prediv: %d, ratio: %d)", state->cfg.pll->pll_prediv, ratio);
dib8000_write_word(state, 901, (state->cfg.pll->pll_prediv << 8) | (ratio << 0)); /* only the PLL ratio is updated. */
}
}
}
return 0;
}
@ -966,6 +990,45 @@ static u16 dib8000_identify(struct i2c_device *client)
return value;
}
static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 *unc);
static void dib8000_reset_stats(struct dvb_frontend *fe)
{
struct dib8000_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
u32 ucb;
memset(&c->strength, 0, sizeof(c->strength));
memset(&c->cnr, 0, sizeof(c->cnr));
memset(&c->post_bit_error, 0, sizeof(c->post_bit_error));
memset(&c->post_bit_count, 0, sizeof(c->post_bit_count));
memset(&c->block_error, 0, sizeof(c->block_error));
c->strength.len = 1;
c->cnr.len = 1;
c->block_error.len = 1;
c->block_count.len = 1;
c->post_bit_error.len = 1;
c->post_bit_count.len = 1;
c->strength.stat[0].scale = FE_SCALE_DECIBEL;
c->strength.stat[0].uvalue = 0;
c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
dib8000_read_unc_blocks(fe, &ucb);
state->init_ucb = -ucb;
state->ber_jiffies_stats = 0;
state->per_jiffies_stats = 0;
memset(&state->ber_jiffies_stats_layer, 0,
sizeof(state->ber_jiffies_stats_layer));
}
static int dib8000_reset(struct dvb_frontend *fe)
{
struct dib8000_state *state = fe->demodulator_priv;
@ -1071,6 +1134,8 @@ static int dib8000_reset(struct dvb_frontend *fe)
dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
dib8000_reset_stats(fe);
return 0;
}
@ -2445,7 +2510,8 @@ static int dib8000_autosearch_start(struct dvb_frontend *fe)
if (state->revision == 0x8090)
internal = dib8000_read32(state, 23) / 1000;
if (state->autosearch_state == AS_SEARCHING_FFT) {
if ((state->revision >= 0x8002) &&
(state->autosearch_state == AS_SEARCHING_FFT)) {
dib8000_write_word(state, 37, 0x0065); /* P_ctrl_pha_off_max default values */
dib8000_write_word(state, 116, 0x0000); /* P_ana_gain to 0 */
@ -2481,7 +2547,8 @@ static int dib8000_autosearch_start(struct dvb_frontend *fe)
dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (1 << 13)); /* P_restart_ccg = 1 */
dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (0 << 13)); /* P_restart_ccg = 0 */
dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x7ff) | (0 << 15) | (1 << 13)); /* P_restart_search = 0; */
} else if (state->autosearch_state == AS_SEARCHING_GUARD) {
} else if ((state->revision >= 0x8002) &&
(state->autosearch_state == AS_SEARCHING_GUARD)) {
c->transmission_mode = TRANSMISSION_MODE_8K;
c->guard_interval = GUARD_INTERVAL_1_8;
c->inversion = 0;
@ -2583,7 +2650,8 @@ static int dib8000_autosearch_irq(struct dvb_frontend *fe)
struct dib8000_state *state = fe->demodulator_priv;
u16 irq_pending = dib8000_read_word(state, 1284);
if (state->autosearch_state == AS_SEARCHING_FFT) {
if ((state->revision >= 0x8002) &&
(state->autosearch_state == AS_SEARCHING_FFT)) {
if (irq_pending & 0x1) {
dprintk("dib8000_autosearch_irq: max correlation result available");
return 3;
@ -2853,6 +2921,91 @@ static int dib8090p_init_sdram(struct dib8000_state *state)
return 0;
}
/**
* is_manual_mode - Check if TMCC should be used for parameters settings
* @c: struct dvb_frontend_properties
*
* By default, TMCC table should be used for parameter settings on most
* usercases. However, sometimes it is desirable to lock the demod to
* use the manual parameters.
*
* On manual mode, the current dib8000_tune state machine is very restrict:
* It requires that both per-layer and per-transponder parameters to be
* properly specified, otherwise the device won't lock.
*
* Check if all those conditions are properly satisfied before allowing
* the device to use the manual frequency lock mode.
*/
static int is_manual_mode(struct dtv_frontend_properties *c)
{
int i, n_segs = 0;
/* Use auto mode on DVB-T compat mode */
if (c->delivery_system != SYS_ISDBT)
return 0;
/*
* Transmission mode is only detected on auto mode, currently
*/
if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
dprintk("transmission mode auto");
return 0;
}
/*
* Guard interval is only detected on auto mode, currently
*/
if (c->guard_interval == GUARD_INTERVAL_AUTO) {
dprintk("guard interval auto");
return 0;
}
/*
* If no layer is enabled, assume auto mode, as at least one
* layer should be enabled
*/
if (!c->isdbt_layer_enabled) {
dprintk("no layer modulation specified");
return 0;
}
/*
* Check if the per-layer parameters aren't auto and
* disable a layer if segment count is 0 or invalid.
*/
for (i = 0; i < 3; i++) {
if (!(c->isdbt_layer_enabled & 1 << i))
continue;
if ((c->layer[i].segment_count > 13) ||
(c->layer[i].segment_count == 0)) {
c->isdbt_layer_enabled &= ~(1 << i);
continue;
}
n_segs += c->layer[i].segment_count;
if ((c->layer[i].modulation == QAM_AUTO) ||
(c->layer[i].fec == FEC_AUTO)) {
dprintk("layer %c has either modulation or FEC auto",
'A' + i);
return 0;
}
}
/*
* Userspace specified a wrong number of segments.
* fallback to auto mode.
*/
if (n_segs == 0 || n_segs > 13) {
dprintk("number of segments is invalid");
return 0;
}
/* Everything looks ok for manual mode */
return 1;
}
static int dib8000_tune(struct dvb_frontend *fe)
{
struct dib8000_state *state = fe->demodulator_priv;
@ -2878,40 +3031,19 @@ static int dib8000_tune(struct dvb_frontend *fe)
switch (*tune_state) {
case CT_DEMOD_START: /* 30 */
dib8000_reset_stats(fe);
if (state->revision == 0x8090)
dib8090p_init_sdram(state);
state->status = FE_STATUS_TUNE_PENDING;
if ((c->delivery_system != SYS_ISDBT) ||
(c->inversion == INVERSION_AUTO) ||
(c->transmission_mode == TRANSMISSION_MODE_AUTO) ||
(c->guard_interval == GUARD_INTERVAL_AUTO) ||
(((c->isdbt_layer_enabled & (1 << 0)) != 0) &&
(c->layer[0].segment_count != 0xff) &&
(c->layer[0].segment_count != 0) &&
((c->layer[0].modulation == QAM_AUTO) ||
(c->layer[0].fec == FEC_AUTO))) ||
(((c->isdbt_layer_enabled & (1 << 1)) != 0) &&
(c->layer[1].segment_count != 0xff) &&
(c->layer[1].segment_count != 0) &&
((c->layer[1].modulation == QAM_AUTO) ||
(c->layer[1].fec == FEC_AUTO))) ||
(((c->isdbt_layer_enabled & (1 << 2)) != 0) &&
(c->layer[2].segment_count != 0xff) &&
(c->layer[2].segment_count != 0) &&
((c->layer[2].modulation == QAM_AUTO) ||
(c->layer[2].fec == FEC_AUTO))) ||
(((c->layer[0].segment_count == 0) ||
((c->isdbt_layer_enabled & (1 << 0)) == 0)) &&
((c->layer[1].segment_count == 0) ||
((c->isdbt_layer_enabled & (2 << 0)) == 0)) &&
((c->layer[2].segment_count == 0) || ((c->isdbt_layer_enabled & (3 << 0)) == 0))))
state->channel_parameters_set = 0; /* auto search */
else
state->channel_parameters_set = 1; /* channel parameters are known */
state->channel_parameters_set = is_manual_mode(c);
dprintk("Tuning channel on %s search mode",
state->channel_parameters_set ? "manual" : "auto");
dib8000_viterbi_state(state, 0); /* force chan dec in restart */
/* Layer monit */
/* Layer monitor */
dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
dib8000_set_frequency_offset(state);
@ -3256,15 +3388,27 @@ static int dib8000_sleep(struct dvb_frontend *fe)
return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF);
}
static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat);
static int dib8000_get_frontend(struct dvb_frontend *fe)
{
struct dib8000_state *state = fe->demodulator_priv;
u16 i, val = 0;
fe_status_t stat;
fe_status_t stat = 0;
u8 index_frontend, sub_index_frontend;
fe->dtv_property_cache.bandwidth_hz = 6000000;
/*
* If called to early, get_frontend makes dib8000_tune to either
* not lock or not sync. This causes dvbv5-scan/dvbv5-zap to fail.
* So, let's just return if frontend 0 has not locked.
*/
dib8000_read_status(fe, &stat);
if (!(stat & FE_HAS_SYNC))
return 0;
dprintk("TMCC lock");
for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
if (stat&FE_HAS_SYNC) {
@ -3335,9 +3479,13 @@ static int dib8000_get_frontend(struct dvb_frontend *fe)
fe->dtv_property_cache.layer[i].segment_count = val & 0x0F;
dprintk("dib8000_get_frontend : Layer %d segments = %d ", i, fe->dtv_property_cache.layer[i].segment_count);
val = dib8000_read_word(state, 499 + i);
fe->dtv_property_cache.layer[i].interleaving = val & 0x3;
dprintk("dib8000_get_frontend : Layer %d time_intlv = %d ", i, fe->dtv_property_cache.layer[i].interleaving);
val = dib8000_read_word(state, 499 + i) & 0x3;
/* Interleaving can be 0, 1, 2 or 4 */
if (val == 3)
val = 4;
fe->dtv_property_cache.layer[i].interleaving = val;
dprintk("dib8000_get_frontend : Layer %d time_intlv = %d ",
i, fe->dtv_property_cache.layer[i].interleaving);
val = dib8000_read_word(state, 481 + i);
switch (val & 0x7) {
@ -3556,6 +3704,8 @@ static int dib8000_set_frontend(struct dvb_frontend *fe)
return 0;
}
static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat);
static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
{
struct dib8000_state *state = fe->demodulator_priv;
@ -3593,6 +3743,7 @@ static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
if (lock & 0x01)
*stat |= FE_HAS_VITERBI;
}
dib8000_get_stats(fe, *stat);
return 0;
}
@ -3699,6 +3850,357 @@ static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr)
return 0;
}
struct per_layer_regs {
u16 lock, ber, per;
};
static const struct per_layer_regs per_layer_regs[] = {
{ 554, 560, 562 },
{ 555, 576, 578 },
{ 556, 581, 583 },
};
struct linear_segments {
unsigned x;
signed y;
};
/*
* Table to estimate signal strength in dBm.
* This table was empirically determinated by measuring the signal
* strength generated by a DTA-2111 RF generator directly connected into
* a dib8076 device (a PixelView PV-D231U stick), using a good quality
* 3 meters RC6 cable and good RC6 connectors.
* The real value can actually be different on other devices, depending
* on several factors, like if LNA is enabled or not, if diversity is
* enabled, type of connectors, etc.
* Yet, it is better to use this measure in dB than a random non-linear
* percentage value, especially for antenna adjustments.
* On my tests, the precision of the measure using this table is about
* 0.5 dB, with sounds reasonable enough.
*/
static struct linear_segments strength_to_db_table[] = {
{ 55953, 108500 }, /* -22.5 dBm */
{ 55394, 108000 },
{ 53834, 107000 },
{ 52863, 106000 },
{ 52239, 105000 },
{ 52012, 104000 },
{ 51803, 103000 },
{ 51566, 102000 },
{ 51356, 101000 },
{ 51112, 100000 },
{ 50869, 99000 },
{ 50600, 98000 },
{ 50363, 97000 },
{ 50117, 96000 }, /* -35 dBm */
{ 49889, 95000 },
{ 49680, 94000 },
{ 49493, 93000 },
{ 49302, 92000 },
{ 48929, 91000 },
{ 48416, 90000 },
{ 48035, 89000 },
{ 47593, 88000 },
{ 47282, 87000 },
{ 46953, 86000 },
{ 46698, 85000 },
{ 45617, 84000 },
{ 44773, 83000 },
{ 43845, 82000 },
{ 43020, 81000 },
{ 42010, 80000 }, /* -51 dBm */
{ 0, 0 },
};
static u32 interpolate_value(u32 value, struct linear_segments *segments,
unsigned len)
{
u64 tmp64;
u32 dx;
s32 dy;
int i, ret;
if (value >= segments[0].x)
return segments[0].y;
if (value < segments[len-1].x)
return segments[len-1].y;
for (i = 1; i < len - 1; i++) {
/* If value is identical, no need to interpolate */
if (value == segments[i].x)
return segments[i].y;
if (value > segments[i].x)
break;
}
/* Linear interpolation between the two (x,y) points */
dy = segments[i - 1].y - segments[i].y;
dx = segments[i - 1].x - segments[i].x;
tmp64 = value - segments[i].x;
tmp64 *= dy;
do_div(tmp64, dx);
ret = segments[i].y + tmp64;
return ret;
}
static u32 dib8000_get_time_us(struct dvb_frontend *fe, int layer)
{
struct dib8000_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
int ini_layer, end_layer, i;
u64 time_us, tmp64;
u32 tmp, denom;
int guard, rate_num, rate_denum = 1, bits_per_symbol, nsegs;
int interleaving = 0, fft_div;
if (layer >= 0) {
ini_layer = layer;
end_layer = layer + 1;
} else {
ini_layer = 0;
end_layer = 3;
}
switch (c->guard_interval) {
case GUARD_INTERVAL_1_4:
guard = 4;
break;
case GUARD_INTERVAL_1_8:
guard = 8;
break;
case GUARD_INTERVAL_1_16:
guard = 16;
break;
default:
case GUARD_INTERVAL_1_32:
guard = 32;
break;
}
switch (c->transmission_mode) {
case TRANSMISSION_MODE_2K:
fft_div = 4;
break;
case TRANSMISSION_MODE_4K:
fft_div = 2;
break;
default:
case TRANSMISSION_MODE_8K:
fft_div = 1;
break;
}
denom = 0;
for (i = ini_layer; i < end_layer; i++) {
nsegs = c->layer[i].segment_count;
if (nsegs == 0 || nsegs > 13)
continue;
switch (c->layer[i].modulation) {
case DQPSK:
case QPSK:
bits_per_symbol = 2;
break;
case QAM_16:
bits_per_symbol = 4;
break;
default:
case QAM_64:
bits_per_symbol = 6;
break;
}
switch (c->layer[i].fec) {
case FEC_1_2:
rate_num = 1;
rate_denum = 2;
break;
case FEC_2_3:
rate_num = 2;
rate_denum = 3;
break;
case FEC_3_4:
rate_num = 3;
rate_denum = 4;
break;
case FEC_5_6:
rate_num = 5;
rate_denum = 6;
break;
default:
case FEC_7_8:
rate_num = 7;
rate_denum = 8;
break;
}
interleaving = c->layer[i].interleaving;
denom += bits_per_symbol * rate_num * fft_div * nsegs * 384;
}
/* If all goes wrong, wait for 1s for the next stats */
if (!denom)
return 0;
/* Estimate the period for the total bit rate */
time_us = rate_denum * (1008 * 1562500L);
tmp64 = time_us;
do_div(tmp64, guard);
time_us = time_us + tmp64;
time_us += denom / 2;
do_div(time_us, denom);
tmp = 1008 * 96 * interleaving;
time_us += tmp + tmp / guard;
return time_us;
}
static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat)
{
struct dib8000_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
int i;
int show_per_stats = 0;
u32 time_us = 0, snr, val;
u64 blocks;
s32 db;
u16 strength;
/* Get Signal strength */
dib8000_read_signal_strength(fe, &strength);
val = strength;
db = interpolate_value(val,
strength_to_db_table,
ARRAY_SIZE(strength_to_db_table)) - 131000;
c->strength.stat[0].svalue = db;
/* UCB/BER/CNR measures require lock */
if (!(stat & FE_HAS_LOCK)) {
c->cnr.len = 1;
c->block_count.len = 1;
c->block_error.len = 1;
c->post_bit_error.len = 1;
c->post_bit_count.len = 1;
c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
return 0;
}
/* Check if time for stats was elapsed */
if (time_after(jiffies, state->per_jiffies_stats)) {
state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000);
/* Get SNR */
snr = dib8000_get_snr(fe);
for (i = 1; i < MAX_NUMBER_OF_FRONTENDS; i++) {
if (state->fe[i])
snr += dib8000_get_snr(state->fe[i]);
}
snr = snr >> 16;
if (snr) {
snr = 10 * intlog10(snr);
snr = (1000L * snr) >> 24;
} else {
snr = 0;
}
c->cnr.stat[0].svalue = snr;
c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
/* Get UCB measures */
dib8000_read_unc_blocks(fe, &val);
if (val < state->init_ucb)
state->init_ucb += 0x100000000LL;
c->block_error.stat[0].scale = FE_SCALE_COUNTER;
c->block_error.stat[0].uvalue = val + state->init_ucb;
/* Estimate the number of packets based on bitrate */
if (!time_us)
time_us = dib8000_get_time_us(fe, -1);
if (time_us) {
blocks = 1250000ULL * 1000000ULL;
do_div(blocks, time_us * 8 * 204);
c->block_count.stat[0].scale = FE_SCALE_COUNTER;
c->block_count.stat[0].uvalue += blocks;
}
show_per_stats = 1;
}
/* Get post-BER measures */
if (time_after(jiffies, state->ber_jiffies_stats)) {
time_us = dib8000_get_time_us(fe, -1);
state->ber_jiffies_stats = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
dprintk("Next all layers stats available in %u us.", time_us);
dib8000_read_ber(fe, &val);
c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
c->post_bit_error.stat[0].uvalue += val;
c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
c->post_bit_count.stat[0].uvalue += 100000000;
}
if (state->revision < 0x8002)
return 0;
c->block_error.len = 4;
c->post_bit_error.len = 4;
c->post_bit_count.len = 4;
for (i = 0; i < 3; i++) {
unsigned nsegs = c->layer[i].segment_count;
if (nsegs == 0 || nsegs > 13)
continue;
time_us = 0;
if (time_after(jiffies, state->ber_jiffies_stats_layer[i])) {
time_us = dib8000_get_time_us(fe, i);
state->ber_jiffies_stats_layer[i] = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
dprintk("Next layer %c stats will be available in %u us\n",
'A' + i, time_us);
val = dib8000_read_word(state, per_layer_regs[i].ber);
c->post_bit_error.stat[1 + i].scale = FE_SCALE_COUNTER;
c->post_bit_error.stat[1 + i].uvalue += val;
c->post_bit_count.stat[1 + i].scale = FE_SCALE_COUNTER;
c->post_bit_count.stat[1 + i].uvalue += 100000000;
}
if (show_per_stats) {
val = dib8000_read_word(state, per_layer_regs[i].per);
c->block_error.stat[1 + i].scale = FE_SCALE_COUNTER;
c->block_error.stat[1 + i].uvalue += val;
if (!time_us)
time_us = dib8000_get_time_us(fe, i);
if (time_us) {
blocks = 1250000ULL * 1000000ULL;
do_div(blocks, time_us * 8 * 204);
c->block_count.stat[0].scale = FE_SCALE_COUNTER;
c->block_count.stat[0].uvalue += blocks;
}
}
}
return 0;
}
int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
{
struct dib8000_state *state = fe->demodulator_priv;

View File

@ -29,7 +29,6 @@
* A value of 0 (default) or lower indicates that
* the correct number of parameters will be
* automatically detected.
* @load_firmware_sync: Force the firmware load to be synchronous.
*
* On the *_gpio vars, bit 0 is UIO-1, bit 1 is UIO-2 and bit 2 is
* UIO-3.
@ -41,7 +40,6 @@ struct drxk_config {
bool parallel_ts;
bool dynamic_clk;
bool enable_merr_cfg;
bool load_firmware_sync;
bool antenna_dvbt;
u16 antenna_gpio;

View File

@ -6830,25 +6830,13 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config,
/* Load firmware and initialize DRX-K */
if (state->microcode_name) {
if (config->load_firmware_sync) {
const struct firmware *fw = NULL;
const struct firmware *fw = NULL;
status = request_firmware(&fw, state->microcode_name,
state->i2c->dev.parent);
if (status < 0)
fw = NULL;
load_firmware_cb(fw, state);
} else {
status = request_firmware_nowait(THIS_MODULE, 1,
state->microcode_name,
state->i2c->dev.parent,
GFP_KERNEL,
state, load_firmware_cb);
if (status < 0) {
pr_err("failed to request a firmware\n");
return NULL;
}
}
status = request_firmware(&fw, state->microcode_name,
state->i2c->dev.parent);
if (status < 0)
fw = NULL;
load_firmware_cb(fw, state);
} else if (init_drxk(state) < 0)
goto error;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,114 @@
/*
* Montage M88DS3103 demodulator 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 M88DS3103_H
#define M88DS3103_H
#include <linux/dvb/frontend.h>
struct m88ds3103_config {
/*
* I2C address
* Default: none, must set
* 0x68, ...
*/
u8 i2c_addr;
/*
* clock
* Default: none, must set
* 27000000
*/
u32 clock;
/*
* max bytes I2C provider is asked to write at once
* Default: none, must set
* 33, 65, ...
*/
u16 i2c_wr_max;
/*
* TS output mode
* Default: M88DS3103_TS_SERIAL
*/
#define M88DS3103_TS_SERIAL 0 /* TS output pin D0, normal */
#define M88DS3103_TS_SERIAL_D7 1 /* TS output pin D7 */
#define M88DS3103_TS_PARALLEL 2 /* 24 MHz, normal */
#define M88DS3103_TS_PARALLEL_12 3 /* 12 MHz */
#define M88DS3103_TS_PARALLEL_16 4 /* 16 MHz */
#define M88DS3103_TS_PARALLEL_19_2 5 /* 19.2 MHz */
#define M88DS3103_TS_CI 6 /* 6 MHz */
u8 ts_mode;
/*
* spectrum inversion
* Default: 0
*/
u8 spec_inv:1;
/*
* AGC polarity
* Default: 0
*/
u8 agc_inv:1;
/*
* clock output
* Default: M88DS3103_CLOCK_OUT_DISABLED
*/
#define M88DS3103_CLOCK_OUT_DISABLED 0
#define M88DS3103_CLOCK_OUT_ENABLED 1
#define M88DS3103_CLOCK_OUT_ENABLED_DIV2 2
u8 clock_out;
/*
* DiSEqC envelope mode
* Default: 0
*/
u8 envelope_mode:1;
/*
* AGC configuration
* Default: none, must set
*/
u8 agc;
};
/*
* Driver implements own I2C-adapter for tuner I2C access. That's since chip
* has I2C-gate control which closes gate automatically after I2C transfer.
* Using own I2C adapter we can workaround that.
*/
#if defined(CONFIG_DVB_M88DS3103) || \
(defined(CONFIG_DVB_M88DS3103_MODULE) && defined(MODULE))
extern struct dvb_frontend *m88ds3103_attach(
const struct m88ds3103_config *config,
struct i2c_adapter *i2c,
struct i2c_adapter **tuner_i2c);
#else
static inline struct dvb_frontend *m88ds3103_attach(
const struct m88ds3103_config *config,
struct i2c_adapter *i2c,
struct i2c_adapter **tuner_i2c)
{
pr_warn("%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif
#endif

View File

@ -0,0 +1,215 @@
/*
* Montage M88DS3103 demodulator 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 M88DS3103_PRIV_H
#define M88DS3103_PRIV_H
#include "dvb_frontend.h"
#include "m88ds3103.h"
#include "dvb_math.h"
#include <linux/firmware.h>
#include <linux/i2c-mux.h>
#define M88DS3103_FIRMWARE "dvb-demod-m88ds3103.fw"
#define M88DS3103_MCLK_KHZ 96000
struct m88ds3103_priv {
struct i2c_adapter *i2c;
/* mutex needed due to own tuner I2C adapter */
struct mutex i2c_mutex;
const struct m88ds3103_config *cfg;
struct dvb_frontend fe;
fe_delivery_system_t delivery_system;
fe_status_t fe_status;
bool warm; /* FW running */
struct i2c_adapter *i2c_adapter;
};
struct m88ds3103_reg_val {
u8 reg;
u8 val;
};
static const struct m88ds3103_reg_val m88ds3103_dvbs_init_reg_vals[] = {
{0x23, 0x07},
{0x08, 0x03},
{0x0c, 0x02},
{0x21, 0x54},
{0x25, 0x8a},
{0x27, 0x31},
{0x30, 0x08},
{0x31, 0x40},
{0x32, 0x32},
{0x35, 0xff},
{0x3a, 0x00},
{0x37, 0x10},
{0x38, 0x10},
{0x39, 0x02},
{0x42, 0x60},
{0x4a, 0x80},
{0x4b, 0x04},
{0x4d, 0x91},
{0x5d, 0xc8},
{0x50, 0x36},
{0x51, 0x36},
{0x52, 0x36},
{0x53, 0x36},
{0x56, 0x01},
{0x63, 0x0f},
{0x64, 0x30},
{0x65, 0x40},
{0x68, 0x26},
{0x69, 0x4c},
{0x70, 0x20},
{0x71, 0x70},
{0x72, 0x04},
{0x73, 0x00},
{0x70, 0x40},
{0x71, 0x70},
{0x72, 0x04},
{0x73, 0x00},
{0x70, 0x60},
{0x71, 0x70},
{0x72, 0x04},
{0x73, 0x00},
{0x70, 0x80},
{0x71, 0x70},
{0x72, 0x04},
{0x73, 0x00},
{0x70, 0xa0},
{0x71, 0x70},
{0x72, 0x04},
{0x73, 0x00},
{0x70, 0x1f},
{0x76, 0x38},
{0x77, 0xa6},
{0x78, 0x0c},
{0x79, 0x80},
{0x7f, 0x14},
{0x7c, 0x00},
{0xae, 0x82},
{0x80, 0x64},
{0x81, 0x66},
{0x82, 0x44},
{0x85, 0x04},
{0xcd, 0xf4},
{0x90, 0x33},
{0xa0, 0x44},
{0xc0, 0x08},
{0xc3, 0x10},
{0xc4, 0x08},
{0xc5, 0xf0},
{0xc6, 0xff},
{0xc7, 0x00},
{0xc8, 0x1a},
{0xc9, 0x80},
{0xe0, 0xf8},
{0xe6, 0x8b},
{0xd0, 0x40},
{0xf8, 0x20},
{0xfa, 0x0f},
{0x00, 0x00},
{0xbd, 0x01},
{0xb8, 0x00},
};
static const struct m88ds3103_reg_val m88ds3103_dvbs2_init_reg_vals[] = {
{0x23, 0x07},
{0x08, 0x07},
{0x0c, 0x02},
{0x21, 0x54},
{0x25, 0x8a},
{0x27, 0x31},
{0x30, 0x08},
{0x32, 0x32},
{0x35, 0xff},
{0x3a, 0x00},
{0x37, 0x10},
{0x38, 0x10},
{0x39, 0x02},
{0x42, 0x60},
{0x4a, 0x80},
{0x4b, 0x04},
{0x4d, 0x91},
{0x5d, 0xc8},
{0x50, 0x36},
{0x51, 0x36},
{0x52, 0x36},
{0x53, 0x36},
{0x56, 0x01},
{0x63, 0x0f},
{0x64, 0x10},
{0x65, 0x20},
{0x68, 0x46},
{0x69, 0xcd},
{0x70, 0x20},
{0x71, 0x70},
{0x72, 0x04},
{0x73, 0x00},
{0x70, 0x40},
{0x71, 0x70},
{0x72, 0x04},
{0x73, 0x00},
{0x70, 0x60},
{0x71, 0x70},
{0x72, 0x04},
{0x73, 0x00},
{0x70, 0x80},
{0x71, 0x70},
{0x72, 0x04},
{0x73, 0x00},
{0x70, 0xa0},
{0x71, 0x70},
{0x72, 0x04},
{0x73, 0x00},
{0x70, 0x1f},
{0x76, 0x38},
{0x77, 0xa6},
{0x78, 0x0c},
{0x79, 0x80},
{0x7f, 0x14},
{0x85, 0x08},
{0xcd, 0xf4},
{0x90, 0x33},
{0x86, 0x00},
{0x87, 0x0f},
{0x89, 0x00},
{0x8b, 0x44},
{0x8c, 0x66},
{0x9d, 0xc1},
{0x8a, 0x10},
{0xad, 0x40},
{0xa0, 0x44},
{0xc0, 0x08},
{0xc1, 0x10},
{0xc2, 0x08},
{0xc3, 0x10},
{0xc4, 0x08},
{0xc5, 0xf0},
{0xc6, 0xff},
{0xc7, 0x00},
{0xc8, 0x1a},
{0xc9, 0x80},
{0xca, 0x23},
{0xcb, 0x24},
{0xcc, 0xf4},
{0xce, 0x74},
{0x00, 0x00},
{0xbd, 0x01},
{0xb8, 0x00},
};
#endif

View File

@ -110,28 +110,94 @@ static u8 m88rs2000_readreg(struct m88rs2000_state *state, u8 reg)
return b1[0];
}
static u32 m88rs2000_get_mclk(struct dvb_frontend *fe)
{
struct m88rs2000_state *state = fe->demodulator_priv;
u32 mclk;
u8 reg;
/* Must not be 0x00 or 0xff */
reg = m88rs2000_readreg(state, 0x86);
if (!reg || reg == 0xff)
return 0;
reg /= 2;
reg += 1;
mclk = (u32)(reg * RS2000_FE_CRYSTAL_KHZ + 28 / 2) / 28;
return mclk;
}
static int m88rs2000_set_carrieroffset(struct dvb_frontend *fe, s16 offset)
{
struct m88rs2000_state *state = fe->demodulator_priv;
u32 mclk;
s32 tmp;
u8 reg;
int ret;
mclk = m88rs2000_get_mclk(fe);
if (!mclk)
return -EINVAL;
tmp = (offset * 4096 + (s32)mclk / 2) / (s32)mclk;
if (tmp < 0)
tmp += 4096;
/* Carrier Offset */
ret = m88rs2000_writereg(state, 0x9c, (u8)(tmp >> 4));
reg = m88rs2000_readreg(state, 0x9d);
reg &= 0xf;
reg |= (u8)(tmp & 0xf) << 4;
ret |= m88rs2000_writereg(state, 0x9d, reg);
return ret;
}
static int m88rs2000_set_symbolrate(struct dvb_frontend *fe, u32 srate)
{
struct m88rs2000_state *state = fe->demodulator_priv;
int ret;
u32 temp;
u64 temp;
u32 mclk;
u8 b[3];
if ((srate < 1000000) || (srate > 45000000))
return -EINVAL;
mclk = m88rs2000_get_mclk(fe);
if (!mclk)
return -EINVAL;
temp = srate / 1000;
temp *= 11831;
temp /= 68;
temp -= 3;
temp *= 1 << 24;
do_div(temp, mclk);
b[0] = (u8) (temp >> 16) & 0xff;
b[1] = (u8) (temp >> 8) & 0xff;
b[2] = (u8) temp & 0xff;
ret = m88rs2000_writereg(state, 0x93, b[2]);
ret |= m88rs2000_writereg(state, 0x94, b[1]);
ret |= m88rs2000_writereg(state, 0x95, b[0]);
if (srate > 10000000)
ret |= m88rs2000_writereg(state, 0xa0, 0x20);
else
ret |= m88rs2000_writereg(state, 0xa0, 0x60);
ret |= m88rs2000_writereg(state, 0xa1, 0xe0);
if (srate > 12000000)
ret |= m88rs2000_writereg(state, 0xa3, 0x20);
else if (srate > 2800000)
ret |= m88rs2000_writereg(state, 0xa3, 0x98);
else
ret |= m88rs2000_writereg(state, 0xa3, 0x90);
deb_info("m88rs2000: m88rs2000_set_symbolrate\n");
return ret;
}
@ -260,8 +326,6 @@ struct inittab m88rs2000_shutdown[] = {
};
struct inittab fe_reset[] = {
{DEMOD_WRITE, 0x00, 0x01},
{DEMOD_WRITE, 0xf1, 0xbf},
{DEMOD_WRITE, 0x00, 0x01},
{DEMOD_WRITE, 0x20, 0x81},
{DEMOD_WRITE, 0x21, 0x80},
@ -305,9 +369,6 @@ struct inittab fe_trigger[] = {
{DEMOD_WRITE, 0x9b, 0x64},
{DEMOD_WRITE, 0x9e, 0x00},
{DEMOD_WRITE, 0x9f, 0xf8},
{DEMOD_WRITE, 0xa0, 0x20},
{DEMOD_WRITE, 0xa1, 0xe0},
{DEMOD_WRITE, 0xa3, 0x38},
{DEMOD_WRITE, 0x98, 0xff},
{DEMOD_WRITE, 0xc0, 0x0f},
{DEMOD_WRITE, 0x89, 0x01},
@ -408,7 +469,7 @@ static int m88rs2000_read_status(struct dvb_frontend *fe, fe_status_t *status)
*status = 0;
if ((reg & 0x7) == 0x7) {
if ((reg & 0xee) == 0xee) {
*status = FE_HAS_CARRIER | FE_HAS_SIGNAL | FE_HAS_VITERBI
| FE_HAS_SYNC | FE_HAS_LOCK;
if (state->config->set_ts_params)
@ -480,34 +541,39 @@ static int m88rs2000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
static int m88rs2000_set_fec(struct m88rs2000_state *state,
fe_code_rate_t fec)
{
u16 fec_set;
u8 fec_set, reg;
int ret;
switch (fec) {
/* This is not confirmed kept for reference */
/* case FEC_1_2:
fec_set = 0x88;
case FEC_1_2:
fec_set = 0x8;
break;
case FEC_2_3:
fec_set = 0x68;
fec_set = 0x10;
break;
case FEC_3_4:
fec_set = 0x48;
fec_set = 0x20;
break;
case FEC_5_6:
fec_set = 0x28;
fec_set = 0x40;
break;
case FEC_7_8:
fec_set = 0x18;
break; */
fec_set = 0x80;
break;
case FEC_AUTO:
default:
fec_set = 0x08;
fec_set = 0x0;
}
m88rs2000_writereg(state, 0x76, fec_set);
return 0;
reg = m88rs2000_readreg(state, 0x70);
reg &= 0x7;
ret = m88rs2000_writereg(state, 0x70, reg | fec_set);
ret |= m88rs2000_writereg(state, 0x76, 0x8);
return ret;
}
static fe_code_rate_t m88rs2000_get_fec(struct m88rs2000_state *state)
{
u8 reg;
@ -515,18 +581,20 @@ static fe_code_rate_t m88rs2000_get_fec(struct m88rs2000_state *state)
reg = m88rs2000_readreg(state, 0x76);
m88rs2000_writereg(state, 0x9a, 0xb0);
reg &= 0xf0;
reg >>= 5;
switch (reg) {
case 0x88:
case 0x4:
return FEC_1_2;
case 0x68:
case 0x3:
return FEC_2_3;
case 0x48:
case 0x2:
return FEC_3_4;
case 0x28:
case 0x1:
return FEC_5_6;
case 0x18:
case 0x0:
return FEC_7_8;
case 0x08:
default:
break;
}
@ -540,9 +608,8 @@ static int m88rs2000_set_frontend(struct dvb_frontend *fe)
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
fe_status_t status;
int i, ret = 0;
s32 tmp;
u32 tuner_freq;
u16 offset = 0;
s16 offset = 0;
u8 reg;
state->no_lock_count = 0;
@ -567,38 +634,31 @@ static int m88rs2000_set_frontend(struct dvb_frontend *fe)
if (ret < 0)
return -ENODEV;
offset = tuner_freq - c->frequency;
offset = (s16)((s32)tuner_freq - c->frequency);
/* calculate offset assuming 96000kHz*/
tmp = offset;
tmp *= 65536;
/* default mclk value 96.4285 * 2 * 1000 = 192857 */
if (((c->frequency % 192857) >= (192857 - 3000)) ||
(c->frequency % 192857) <= 3000)
ret = m88rs2000_writereg(state, 0x86, 0xc2);
else
ret = m88rs2000_writereg(state, 0x86, 0xc6);
tmp = (2 * tmp + 96000) / (2 * 96000);
if (tmp < 0)
tmp += 65536;
offset = tmp & 0xffff;
ret = m88rs2000_writereg(state, 0x9a, 0x30);
/* Unknown usually 0xc6 sometimes 0xc1 */
reg = m88rs2000_readreg(state, 0x86);
ret |= m88rs2000_writereg(state, 0x86, reg);
/* Offset lower nibble always 0 */
ret |= m88rs2000_writereg(state, 0x9c, (offset >> 8));
ret |= m88rs2000_writereg(state, 0x9d, offset & 0xf0);
/* Reset Demod */
ret = m88rs2000_tab_set(state, fe_reset);
ret |= m88rs2000_set_carrieroffset(fe, offset);
if (ret < 0)
return -ENODEV;
/* Unknown */
reg = m88rs2000_readreg(state, 0x70);
ret = m88rs2000_writereg(state, 0x70, reg);
/* Reset demod by symbol rate */
if (c->symbol_rate > 27500000)
ret = m88rs2000_writereg(state, 0xf1, 0xa4);
else
ret = m88rs2000_writereg(state, 0xf1, 0xbf);
ret |= m88rs2000_tab_set(state, fe_reset);
if (ret < 0)
return -ENODEV;
/* Set FEC */
ret |= m88rs2000_set_fec(state, c->fec_inner);
ret = m88rs2000_set_fec(state, c->fec_inner);
ret |= m88rs2000_writereg(state, 0x85, 0x1);
ret |= m88rs2000_writereg(state, 0x8a, 0xbf);
ret |= m88rs2000_writereg(state, 0x8d, 0x1e);
@ -620,7 +680,7 @@ static int m88rs2000_set_frontend(struct dvb_frontend *fe)
for (i = 0; i < 25; i++) {
reg = m88rs2000_readreg(state, 0x8c);
if ((reg & 0x7) == 0x7) {
if ((reg & 0xee) == 0xee) {
status = FE_HAS_LOCK;
break;
}

View File

@ -53,6 +53,8 @@ static inline struct dvb_frontend *m88rs2000_attach(
}
#endif /* CONFIG_DVB_M88RS2000 */
#define RS2000_FE_CRYSTAL_KHZ 27000
enum {
DEMOD_WRITE = 0x1,
WRITE_DELAY = 0x10,

View File

@ -40,7 +40,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
/* Max transfer size done by I2C transfer functions */
#define MAX_XFER_SIZE 64
#define MAX_XFER_SIZE 256
#define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw"
#define NXT2004_DEFAULT_FIRMWARE "dvb-fe-nxt2004.fw"

View File

@ -555,14 +555,6 @@ config VIDEO_MT9V032
This is a Video4Linux2 sensor-level driver for the Micron
MT9V032 752x480 CMOS sensor.
config VIDEO_TCM825X
tristate "TCM825x camera sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_INT_DEVICE
depends on MEDIA_CAMERA_SUPPORT
---help---
This is a driver for the Toshiba TCM825x VGA camera sensor.
It is used for example in Nokia N800.
config VIDEO_SR030PC30
tristate "Siliconfile SR030PC30 sensor support"
depends on I2C && VIDEO_V4L2
@ -594,6 +586,13 @@ config VIDEO_S5K4ECGX
This is a V4L2 sensor-level driver for Samsung S5K4ECGX 5M
camera sensor with an embedded SoC image signal processor.
config VIDEO_S5K5BAF
tristate "Samsung S5K5BAF sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
---help---
This is a V4L2 sensor-level driver for Samsung S5K5BAF 2M
camera sensor with an embedded SoC image signal processor.
source "drivers/media/i2c/smiapp/Kconfig"
config VIDEO_S5C73M3
@ -655,6 +654,18 @@ config VIDEO_UPD64083
To compile this driver as a module, choose M here: the
module will be called upd64083.
comment "Audio/Video compression chips"
config VIDEO_SAA6752HS
tristate "Philips SAA6752HS MPEG-2 Audio/Video Encoder"
depends on VIDEO_V4L2 && I2C
---help---
Support for the Philips SAA6752HS MPEG-2 video and MPEG-audio/AC-3
audio encoder with multiplexer.
To compile this driver as a module, choose M here: the
module will be called saa6752hs.
comment "Miscellaneous helper chips"
config VIDEO_THS7303

View File

@ -19,6 +19,7 @@ obj-$(CONFIG_VIDEO_SAA717X) += saa717x.o
obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o
obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o
obj-$(CONFIG_VIDEO_SAA7191) += saa7191.o
obj-$(CONFIG_VIDEO_SAA6752HS) += saa6752hs.o
obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o
obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o
obj-$(CONFIG_VIDEO_ADV7180) += adv7180.o
@ -57,7 +58,6 @@ obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
obj-$(CONFIG_VIDEO_OV7640) += ov7640.o
obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
obj-$(CONFIG_VIDEO_OV9650) += ov9650.o
obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o
obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o
obj-$(CONFIG_VIDEO_MT9T001) += mt9t001.o
@ -67,6 +67,7 @@ obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o
obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o
obj-$(CONFIG_VIDEO_S5K6AA) += s5k6aa.o
obj-$(CONFIG_VIDEO_S5K4ECGX) += s5k4ecgx.o
obj-$(CONFIG_VIDEO_S5K5BAF) += s5k5baf.o
obj-$(CONFIG_VIDEO_S5C73M3) += s5c73m3/
obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o
obj-$(CONFIG_VIDEO_AS3645A) += as3645a.o

View File

@ -66,11 +66,6 @@ MODULE_LICENSE("GPL");
**********************************************************************
*/
struct i2c_reg_value {
u8 reg;
u8 value;
};
struct ad9389b_state_edid {
/* total number of blocks */
u32 blocks;
@ -143,14 +138,14 @@ static int ad9389b_wr(struct v4l2_subdev *sd, u8 reg, u8 val)
if (ret == 0)
return 0;
}
v4l2_err(sd, "I2C Write Problem\n");
v4l2_err(sd, "%s: failed reg 0x%x, val 0x%x\n", __func__, reg, val);
return ret;
}
/* To set specific bits in the register, a clear-mask is given (to be AND-ed),
and then the value-mask (to be OR-ed). */
static inline void ad9389b_wr_and_or(struct v4l2_subdev *sd, u8 reg,
u8 clr_mask, u8 val_mask)
u8 clr_mask, u8 val_mask)
{
ad9389b_wr(sd, reg, (ad9389b_rd(sd, reg) & clr_mask) | val_mask);
}
@ -321,12 +316,12 @@ static int ad9389b_s_ctrl(struct v4l2_ctrl *ctrl)
struct ad9389b_state *state = get_ad9389b_state(sd);
v4l2_dbg(1, debug, sd,
"%s: ctrl id: %d, ctrl->val %d\n", __func__, ctrl->id, ctrl->val);
"%s: ctrl id: %d, ctrl->val %d\n", __func__, ctrl->id, ctrl->val);
if (state->hdmi_mode_ctrl == ctrl) {
/* Set HDMI or DVI-D */
ad9389b_wr_and_or(sd, 0xaf, 0xfd,
ctrl->val == V4L2_DV_TX_MODE_HDMI ? 0x02 : 0x00);
ctrl->val == V4L2_DV_TX_MODE_HDMI ? 0x02 : 0x00);
return 0;
}
if (state->rgb_quantization_range_ctrl == ctrl)
@ -387,61 +382,57 @@ static int ad9389b_log_status(struct v4l2_subdev *sd)
v4l2_info(sd, "chip revision %d\n", state->chip_revision);
v4l2_info(sd, "power %s\n", state->power_on ? "on" : "off");
v4l2_info(sd, "%s hotplug, %s Rx Sense, %s EDID (%d block(s))\n",
(ad9389b_rd(sd, 0x42) & MASK_AD9389B_HPD_DETECT) ?
"detected" : "no",
(ad9389b_rd(sd, 0x42) & MASK_AD9389B_MSEN_DETECT) ?
"detected" : "no",
edid->segments ? "found" : "no", edid->blocks);
if (state->have_monitor) {
v4l2_info(sd, "%s output %s\n",
(ad9389b_rd(sd, 0xaf) & 0x02) ?
"HDMI" : "DVI-D",
(ad9389b_rd(sd, 0xa1) & 0x3c) ?
"disabled" : "enabled");
}
(ad9389b_rd(sd, 0x42) & MASK_AD9389B_HPD_DETECT) ?
"detected" : "no",
(ad9389b_rd(sd, 0x42) & MASK_AD9389B_MSEN_DETECT) ?
"detected" : "no",
edid->segments ? "found" : "no", edid->blocks);
v4l2_info(sd, "%s output %s\n",
(ad9389b_rd(sd, 0xaf) & 0x02) ?
"HDMI" : "DVI-D",
(ad9389b_rd(sd, 0xa1) & 0x3c) ?
"disabled" : "enabled");
v4l2_info(sd, "ad9389b: %s\n", (ad9389b_rd(sd, 0xb8) & 0x40) ?
"encrypted" : "no encryption");
"encrypted" : "no encryption");
v4l2_info(sd, "state: %s, error: %s, detect count: %u, msk/irq: %02x/%02x\n",
states[ad9389b_rd(sd, 0xc8) & 0xf],
errors[ad9389b_rd(sd, 0xc8) >> 4],
state->edid_detect_counter,
ad9389b_rd(sd, 0x94), ad9389b_rd(sd, 0x96));
states[ad9389b_rd(sd, 0xc8) & 0xf],
errors[ad9389b_rd(sd, 0xc8) >> 4],
state->edid_detect_counter,
ad9389b_rd(sd, 0x94), ad9389b_rd(sd, 0x96));
manual_gear = ad9389b_rd(sd, 0x98) & 0x80;
v4l2_info(sd, "ad9389b: RGB quantization: %s range\n",
ad9389b_rd(sd, 0x3b) & 0x01 ? "limited" : "full");
ad9389b_rd(sd, 0x3b) & 0x01 ? "limited" : "full");
v4l2_info(sd, "ad9389b: %s gear %d\n",
manual_gear ? "manual" : "automatic",
manual_gear ? ((ad9389b_rd(sd, 0x98) & 0x70) >> 4) :
((ad9389b_rd(sd, 0x9e) & 0x0e) >> 1));
if (state->have_monitor) {
if (ad9389b_rd(sd, 0xaf) & 0x02) {
/* HDMI only */
u8 manual_cts = ad9389b_rd(sd, 0x0a) & 0x80;
u32 N = (ad9389b_rd(sd, 0x01) & 0xf) << 16 |
ad9389b_rd(sd, 0x02) << 8 |
ad9389b_rd(sd, 0x03);
u8 vic_detect = ad9389b_rd(sd, 0x3e) >> 2;
u8 vic_sent = ad9389b_rd(sd, 0x3d) & 0x3f;
u32 CTS;
((ad9389b_rd(sd, 0x9e) & 0x0e) >> 1));
if (ad9389b_rd(sd, 0xaf) & 0x02) {
/* HDMI only */
u8 manual_cts = ad9389b_rd(sd, 0x0a) & 0x80;
u32 N = (ad9389b_rd(sd, 0x01) & 0xf) << 16 |
ad9389b_rd(sd, 0x02) << 8 |
ad9389b_rd(sd, 0x03);
u8 vic_detect = ad9389b_rd(sd, 0x3e) >> 2;
u8 vic_sent = ad9389b_rd(sd, 0x3d) & 0x3f;
u32 CTS;
if (manual_cts)
CTS = (ad9389b_rd(sd, 0x07) & 0xf) << 16 |
ad9389b_rd(sd, 0x08) << 8 |
ad9389b_rd(sd, 0x09);
else
CTS = (ad9389b_rd(sd, 0x04) & 0xf) << 16 |
ad9389b_rd(sd, 0x05) << 8 |
ad9389b_rd(sd, 0x06);
N = (ad9389b_rd(sd, 0x01) & 0xf) << 16 |
ad9389b_rd(sd, 0x02) << 8 |
ad9389b_rd(sd, 0x03);
if (manual_cts)
CTS = (ad9389b_rd(sd, 0x07) & 0xf) << 16 |
ad9389b_rd(sd, 0x08) << 8 |
ad9389b_rd(sd, 0x09);
else
CTS = (ad9389b_rd(sd, 0x04) & 0xf) << 16 |
ad9389b_rd(sd, 0x05) << 8 |
ad9389b_rd(sd, 0x06);
N = (ad9389b_rd(sd, 0x01) & 0xf) << 16 |
ad9389b_rd(sd, 0x02) << 8 |
ad9389b_rd(sd, 0x03);
v4l2_info(sd, "ad9389b: CTS %s mode: N %d, CTS %d\n",
manual_cts ? "manual" : "automatic", N, CTS);
v4l2_info(sd, "ad9389b: CTS %s mode: N %d, CTS %d\n",
manual_cts ? "manual" : "automatic", N, CTS);
v4l2_info(sd, "ad9389b: VIC: detected %d, sent %d\n",
vic_detect, vic_sent);
}
v4l2_info(sd, "ad9389b: VIC: detected %d, sent %d\n",
vic_detect, vic_sent);
}
if (state->dv_timings.type == V4L2_DV_BT_656_1120)
v4l2_print_dv_timings(sd->name, "timings: ",
@ -486,7 +477,7 @@ static int ad9389b_s_power(struct v4l2_subdev *sd, int on)
}
if (i > 1)
v4l2_dbg(1, debug, sd,
"needed %d retries to powerup the ad9389b\n", i);
"needed %d retries to powerup the ad9389b\n", i);
/* Select chip: AD9389B */
ad9389b_wr_and_or(sd, 0xba, 0xef, 0x10);
@ -556,14 +547,16 @@ static int ad9389b_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
irq_status = ad9389b_rd(sd, 0x96);
/* clear detected interrupts */
ad9389b_wr(sd, 0x96, irq_status);
/* enable interrupts */
ad9389b_set_isr(sd, true);
if (irq_status & (MASK_AD9389B_HPD_INT | MASK_AD9389B_MSEN_INT))
v4l2_dbg(1, debug, sd, "%s: irq_status 0x%x\n", __func__, irq_status);
if (irq_status & (MASK_AD9389B_HPD_INT))
ad9389b_check_monitor_present_status(sd);
if (irq_status & MASK_AD9389B_EDID_RDY_INT)
ad9389b_check_edid_status(sd);
/* enable interrupts */
ad9389b_set_isr(sd, true);
*handled = true;
return 0;
}
@ -599,7 +592,7 @@ static int ad9389b_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edi
if (edid->blocks + edid->start_block >= state->edid.segments * 2)
edid->blocks = state->edid.segments * 2 - edid->start_block;
memcpy(edid->edid, &state->edid.data[edid->start_block * 128],
128 * edid->blocks);
128 * edid->blocks);
return 0;
}
@ -612,8 +605,6 @@ static const struct v4l2_subdev_pad_ops ad9389b_pad_ops = {
/* Enable/disable ad9389b output */
static int ad9389b_s_stream(struct v4l2_subdev *sd, int enable)
{
struct ad9389b_state *state = get_ad9389b_state(sd);
v4l2_dbg(1, debug, sd, "%s: %sable\n", __func__, (enable ? "en" : "dis"));
ad9389b_wr_and_or(sd, 0xa1, ~0x3c, (enable ? 0 : 0x3c));
@ -621,7 +612,6 @@ static int ad9389b_s_stream(struct v4l2_subdev *sd, int enable)
ad9389b_check_monitor_present_status(sd);
} else {
ad9389b_s_power(sd, 0);
state->have_monitor = false;
}
return 0;
}
@ -686,14 +676,14 @@ static int ad9389b_g_dv_timings(struct v4l2_subdev *sd,
}
static int ad9389b_enum_dv_timings(struct v4l2_subdev *sd,
struct v4l2_enum_dv_timings *timings)
struct v4l2_enum_dv_timings *timings)
{
return v4l2_enum_dv_timings_cap(timings, &ad9389b_timings_cap,
NULL, NULL);
}
static int ad9389b_dv_timings_cap(struct v4l2_subdev *sd,
struct v4l2_dv_timings_cap *cap)
struct v4l2_dv_timings_cap *cap)
{
*cap = ad9389b_timings_cap;
return 0;
@ -724,15 +714,15 @@ static int ad9389b_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
u32 N;
switch (freq) {
case 32000: N = 4096; break;
case 44100: N = 6272; break;
case 48000: N = 6144; break;
case 88200: N = 12544; break;
case 96000: N = 12288; break;
case 32000: N = 4096; break;
case 44100: N = 6272; break;
case 48000: N = 6144; break;
case 88200: N = 12544; break;
case 96000: N = 12288; break;
case 176400: N = 25088; break;
case 192000: N = 24576; break;
default:
return -EINVAL;
return -EINVAL;
}
/* Set N (used with CTS to regenerate the audio clock) */
@ -748,15 +738,15 @@ static int ad9389b_s_i2s_clock_freq(struct v4l2_subdev *sd, u32 freq)
u32 i2s_sf;
switch (freq) {
case 32000: i2s_sf = 0x30; break;
case 44100: i2s_sf = 0x00; break;
case 48000: i2s_sf = 0x20; break;
case 88200: i2s_sf = 0x80; break;
case 96000: i2s_sf = 0xa0; break;
case 32000: i2s_sf = 0x30; break;
case 44100: i2s_sf = 0x00; break;
case 48000: i2s_sf = 0x20; break;
case 88200: i2s_sf = 0x80; break;
case 96000: i2s_sf = 0xa0; break;
case 176400: i2s_sf = 0xc0; break;
case 192000: i2s_sf = 0xe0; break;
default:
return -EINVAL;
return -EINVAL;
}
/* Set sampling frequency for I2S audio to 48 kHz */
@ -800,7 +790,7 @@ static const struct v4l2_subdev_ops ad9389b_ops = {
/* ----------------------------------------------------------------------- */
static void ad9389b_dbg_dump_edid(int lvl, int debug, struct v4l2_subdev *sd,
int segment, u8 *buf)
int segment, u8 *buf)
{
int i, j;
@ -826,8 +816,8 @@ static void ad9389b_dbg_dump_edid(int lvl, int debug, struct v4l2_subdev *sd,
static void ad9389b_edid_handler(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
struct ad9389b_state *state = container_of(dwork,
struct ad9389b_state, edid_handler);
struct ad9389b_state *state =
container_of(dwork, struct ad9389b_state, edid_handler);
struct v4l2_subdev *sd = &state->sd;
struct ad9389b_edid_detect ed;
@ -845,11 +835,10 @@ static void ad9389b_edid_handler(struct work_struct *work)
if (state->edid.read_retries) {
state->edid.read_retries--;
v4l2_dbg(1, debug, sd, "%s: edid read failed\n", __func__);
state->have_monitor = false;
ad9389b_s_power(sd, false);
ad9389b_s_power(sd, true);
queue_delayed_work(state->work_queue,
&state->edid_handler, EDID_DELAY);
&state->edid_handler, EDID_DELAY);
return;
}
}
@ -915,49 +904,35 @@ static void ad9389b_notify_monitor_detect(struct v4l2_subdev *sd)
v4l2_subdev_notify(sd, AD9389B_MONITOR_DETECT, (void *)&mdt);
}
static void ad9389b_check_monitor_present_status(struct v4l2_subdev *sd)
static void ad9389b_update_monitor_present_status(struct v4l2_subdev *sd)
{
struct ad9389b_state *state = get_ad9389b_state(sd);
/* read hotplug and rx-sense state */
u8 status = ad9389b_rd(sd, 0x42);
v4l2_dbg(1, debug, sd, "%s: status: 0x%x%s%s\n",
__func__,
status,
status & MASK_AD9389B_HPD_DETECT ? ", hotplug" : "",
status & MASK_AD9389B_MSEN_DETECT ? ", rx-sense" : "");
__func__,
status,
status & MASK_AD9389B_HPD_DETECT ? ", hotplug" : "",
status & MASK_AD9389B_MSEN_DETECT ? ", rx-sense" : "");
if ((status & MASK_AD9389B_HPD_DETECT) &&
((status & MASK_AD9389B_MSEN_DETECT) || state->edid.segments)) {
v4l2_dbg(1, debug, sd,
"%s: hotplug and (rx-sense or edid)\n", __func__);
if (!state->have_monitor) {
v4l2_dbg(1, debug, sd, "%s: monitor detected\n", __func__);
state->have_monitor = true;
ad9389b_set_isr(sd, true);
if (!ad9389b_s_power(sd, true)) {
v4l2_dbg(1, debug, sd,
"%s: monitor detected, powerup failed\n", __func__);
return;
}
ad9389b_setup(sd);
ad9389b_notify_monitor_detect(sd);
state->edid.read_retries = EDID_MAX_RETRIES;
queue_delayed_work(state->work_queue,
&state->edid_handler, EDID_DELAY);
}
} else if (status & MASK_AD9389B_HPD_DETECT) {
if (status & MASK_AD9389B_HPD_DETECT) {
v4l2_dbg(1, debug, sd, "%s: hotplug detected\n", __func__);
state->have_monitor = true;
if (!ad9389b_s_power(sd, true)) {
v4l2_dbg(1, debug, sd,
"%s: monitor detected, powerup failed\n", __func__);
return;
}
ad9389b_setup(sd);
ad9389b_notify_monitor_detect(sd);
state->edid.read_retries = EDID_MAX_RETRIES;
queue_delayed_work(state->work_queue,
&state->edid_handler, EDID_DELAY);
&state->edid_handler, EDID_DELAY);
} else if (!(status & MASK_AD9389B_HPD_DETECT)) {
v4l2_dbg(1, debug, sd, "%s: hotplug not detected\n", __func__);
if (state->have_monitor) {
v4l2_dbg(1, debug, sd, "%s: monitor not detected\n", __func__);
state->have_monitor = false;
ad9389b_notify_monitor_detect(sd);
}
state->have_monitor = false;
ad9389b_notify_monitor_detect(sd);
ad9389b_s_power(sd, false);
memset(&state->edid, 0, sizeof(struct ad9389b_state_edid));
}
@ -966,6 +941,35 @@ static void ad9389b_check_monitor_present_status(struct v4l2_subdev *sd)
v4l2_ctrl_s_ctrl(state->hotplug_ctrl, ad9389b_have_hotplug(sd) ? 0x1 : 0x0);
v4l2_ctrl_s_ctrl(state->rx_sense_ctrl, ad9389b_have_rx_sense(sd) ? 0x1 : 0x0);
v4l2_ctrl_s_ctrl(state->have_edid0_ctrl, state->edid.segments ? 0x1 : 0x0);
/* update with setting from ctrls */
ad9389b_s_ctrl(state->rgb_quantization_range_ctrl);
ad9389b_s_ctrl(state->hdmi_mode_ctrl);
}
static void ad9389b_check_monitor_present_status(struct v4l2_subdev *sd)
{
struct ad9389b_state *state = get_ad9389b_state(sd);
int retry = 0;
ad9389b_update_monitor_present_status(sd);
/*
* Rapid toggling of the hotplug may leave the chip powered off,
* even if we think it is on. In that case reset and power up again.
*/
while (state->power_on && (ad9389b_rd(sd, 0x41) & 0x40)) {
if (++retry > 5) {
v4l2_err(sd, "retried %d times, give up\n", retry);
return;
}
v4l2_dbg(1, debug, sd, "%s: reset and re-check status (%d)\n", __func__, retry);
ad9389b_notify_monitor_detect(sd);
cancel_delayed_work_sync(&state->edid_handler);
memset(&state->edid, 0, sizeof(struct ad9389b_state_edid));
ad9389b_s_power(sd, false);
ad9389b_update_monitor_present_status(sd);
}
}
static bool edid_block_verify_crc(u8 *edid_block)
@ -978,7 +982,7 @@ static bool edid_block_verify_crc(u8 *edid_block)
return sum == 0;
}
static bool edid_segment_verify_crc(struct v4l2_subdev *sd, u32 segment)
static bool edid_verify_crc(struct v4l2_subdev *sd, u32 segment)
{
struct ad9389b_state *state = get_ad9389b_state(sd);
u32 blocks = state->edid.blocks;
@ -992,6 +996,25 @@ static bool edid_segment_verify_crc(struct v4l2_subdev *sd, u32 segment)
return false;
}
static bool edid_verify_header(struct v4l2_subdev *sd, u32 segment)
{
static const u8 hdmi_header[] = {
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00
};
struct ad9389b_state *state = get_ad9389b_state(sd);
u8 *data = state->edid.data;
int i;
if (segment)
return true;
for (i = 0; i < ARRAY_SIZE(hdmi_header); i++)
if (data[i] != hdmi_header[i])
return false;
return true;
}
static bool ad9389b_check_edid_status(struct v4l2_subdev *sd)
{
struct ad9389b_state *state = get_ad9389b_state(sd);
@ -1000,7 +1023,7 @@ static bool ad9389b_check_edid_status(struct v4l2_subdev *sd)
u8 edidRdy = ad9389b_rd(sd, 0xc5);
v4l2_dbg(1, debug, sd, "%s: edid ready (retries: %d)\n",
__func__, EDID_MAX_RETRIES - state->edid.read_retries);
__func__, EDID_MAX_RETRIES - state->edid.read_retries);
if (!(edidRdy & MASK_AD9389B_EDID_RDY))
return false;
@ -1013,16 +1036,16 @@ static bool ad9389b_check_edid_status(struct v4l2_subdev *sd)
v4l2_dbg(1, debug, sd, "%s: got segment %d\n", __func__, segment);
ad9389b_edid_rd(sd, 256, &state->edid.data[segment * 256]);
ad9389b_dbg_dump_edid(2, debug, sd, segment,
&state->edid.data[segment * 256]);
&state->edid.data[segment * 256]);
if (segment == 0) {
state->edid.blocks = state->edid.data[0x7e] + 1;
v4l2_dbg(1, debug, sd, "%s: %d blocks in total\n",
__func__, state->edid.blocks);
__func__, state->edid.blocks);
}
if (!edid_segment_verify_crc(sd, segment)) {
if (!edid_verify_crc(sd, segment) ||
!edid_verify_header(sd, segment)) {
/* edid crc error, force reread of edid segment */
v4l2_err(sd, "%s: edid crc error\n", __func__);
state->have_monitor = false;
v4l2_err(sd, "%s: edid crc or header error\n", __func__);
ad9389b_s_power(sd, false);
ad9389b_s_power(sd, true);
return false;
@ -1032,12 +1055,12 @@ static bool ad9389b_check_edid_status(struct v4l2_subdev *sd)
if (((state->edid.data[0x7e] >> 1) + 1) > state->edid.segments) {
/* Request next EDID segment */
v4l2_dbg(1, debug, sd, "%s: request segment %d\n",
__func__, state->edid.segments);
__func__, state->edid.segments);
ad9389b_wr(sd, 0xc9, 0xf);
ad9389b_wr(sd, 0xc4, state->edid.segments);
state->edid.read_retries = EDID_MAX_RETRIES;
queue_delayed_work(state->work_queue,
&state->edid_handler, EDID_DELAY);
&state->edid_handler, EDID_DELAY);
return false;
}
@ -1081,7 +1104,7 @@ static int ad9389b_probe(struct i2c_client *client, const struct i2c_device_id *
return -EIO;
v4l_dbg(1, debug, client, "detecting ad9389b client on address 0x%x\n",
client->addr << 1);
client->addr << 1);
state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
if (!state)
@ -1140,7 +1163,7 @@ static int ad9389b_probe(struct i2c_client *client, const struct i2c_device_id *
goto err_entity;
}
v4l2_dbg(1, debug, sd, "reg 0x41 0x%x, chip version (reg 0x00) 0x%x\n",
ad9389b_rd(sd, 0x41), state->chip_revision);
ad9389b_rd(sd, 0x41), state->chip_revision);
state->edid_i2c_client = i2c_new_dummy(client->adapter, (0x7e>>1));
if (state->edid_i2c_client == NULL) {
@ -1163,7 +1186,7 @@ static int ad9389b_probe(struct i2c_client *client, const struct i2c_device_id *
ad9389b_set_isr(sd, true);
v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,
client->addr << 1, client->adapter->name);
client->addr << 1, client->adapter->name);
return 0;
err_unreg:

View File

@ -452,6 +452,29 @@ static int adv7511_log_status(struct v4l2_subdev *sd)
errors[adv7511_rd(sd, 0xc8) >> 4], state->edid_detect_counter,
adv7511_rd(sd, 0x94), adv7511_rd(sd, 0x96));
v4l2_info(sd, "RGB quantization: %s range\n", adv7511_rd(sd, 0x18) & 0x80 ? "limited" : "full");
if (adv7511_rd(sd, 0xaf) & 0x02) {
/* HDMI only */
u8 manual_cts = adv7511_rd(sd, 0x0a) & 0x80;
u32 N = (adv7511_rd(sd, 0x01) & 0xf) << 16 |
adv7511_rd(sd, 0x02) << 8 |
adv7511_rd(sd, 0x03);
u8 vic_detect = adv7511_rd(sd, 0x3e) >> 2;
u8 vic_sent = adv7511_rd(sd, 0x3d) & 0x3f;
u32 CTS;
if (manual_cts)
CTS = (adv7511_rd(sd, 0x07) & 0xf) << 16 |
adv7511_rd(sd, 0x08) << 8 |
adv7511_rd(sd, 0x09);
else
CTS = (adv7511_rd(sd, 0x04) & 0xf) << 16 |
adv7511_rd(sd, 0x05) << 8 |
adv7511_rd(sd, 0x06);
v4l2_info(sd, "CTS %s mode: N %d, CTS %d\n",
manual_cts ? "manual" : "automatic", N, CTS);
v4l2_info(sd, "VIC: detected %d, sent %d\n",
vic_detect, vic_sent);
}
if (state->dv_timings.type == V4L2_DV_BT_656_1120)
v4l2_print_dv_timings(sd->name, "timings: ",
&state->dv_timings, false);
@ -942,26 +965,38 @@ static void adv7511_check_monitor_present_status(struct v4l2_subdev *sd)
static bool edid_block_verify_crc(uint8_t *edid_block)
{
int i;
uint8_t sum = 0;
int i;
for (i = 0; i < 128; i++)
sum += *(edid_block + i);
return (sum == 0);
sum += edid_block[i];
return sum == 0;
}
static bool edid_segment_verify_crc(struct v4l2_subdev *sd, u32 segment)
static bool edid_verify_crc(struct v4l2_subdev *sd, u32 segment)
{
struct adv7511_state *state = get_adv7511_state(sd);
u32 blocks = state->edid.blocks;
uint8_t *data = state->edid.data;
if (edid_block_verify_crc(&data[segment * 256])) {
if ((segment + 1) * 2 <= blocks)
return edid_block_verify_crc(&data[segment * 256 + 128]);
if (!edid_block_verify_crc(&data[segment * 256]))
return false;
if ((segment + 1) * 2 <= blocks)
return edid_block_verify_crc(&data[segment * 256 + 128]);
return true;
}
static bool edid_verify_header(struct v4l2_subdev *sd, u32 segment)
{
static const u8 hdmi_header[] = {
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00
};
struct adv7511_state *state = get_adv7511_state(sd);
u8 *data = state->edid.data;
if (segment != 0)
return true;
}
return false;
return !memcmp(data, hdmi_header, sizeof(hdmi_header));
}
static bool adv7511_check_edid_status(struct v4l2_subdev *sd)
@ -990,9 +1025,10 @@ static bool adv7511_check_edid_status(struct v4l2_subdev *sd)
state->edid.blocks = state->edid.data[0x7e] + 1;
v4l2_dbg(1, debug, sd, "%s: %d blocks in total\n", __func__, state->edid.blocks);
}
if (!edid_segment_verify_crc(sd, segment)) {
if (!edid_verify_crc(sd, segment) ||
!edid_verify_header(sd, segment)) {
/* edid crc error, force reread of edid segment */
v4l2_dbg(1, debug, sd, "%s: edid crc error\n", __func__);
v4l2_err(sd, "%s: edid crc or header error\n", __func__);
state->have_monitor = false;
adv7511_s_power(sd, false);
adv7511_s_power(sd, true);
@ -1038,6 +1074,12 @@ static void adv7511_init_setup(struct v4l2_subdev *sd)
/* clear all interrupts */
adv7511_wr(sd, 0x96, 0xff);
/*
* Stop HPD from resetting a lot of registers.
* It might leave the chip in a partly un-initialized state,
* in particular with regards to hotplug bounces.
*/
adv7511_wr_and_or(sd, 0xd6, 0x3f, 0xc0);
memset(edid, 0, sizeof(struct adv7511_state_edid));
state->have_monitor = false;
adv7511_set_isr(sd, false);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -172,28 +172,28 @@ static int lm3560_flash_brt_ctrl(struct lm3560_flash *flash,
static int lm3560_get_ctrl(struct v4l2_ctrl *ctrl, enum lm3560_led_id led_no)
{
struct lm3560_flash *flash = to_lm3560_flash(ctrl, led_no);
int rval = -EINVAL;
mutex_lock(&flash->lock);
if (ctrl->id == V4L2_CID_FLASH_FAULT) {
int rval;
s32 fault = 0;
unsigned int reg_val;
rval = regmap_read(flash->regmap, REG_FLAG, &reg_val);
if (rval < 0)
return rval;
if (rval & FAULT_SHORT_CIRCUIT)
goto out;
if (reg_val & FAULT_SHORT_CIRCUIT)
fault |= V4L2_FLASH_FAULT_SHORT_CIRCUIT;
if (rval & FAULT_OVERTEMP)
if (reg_val & FAULT_OVERTEMP)
fault |= V4L2_FLASH_FAULT_OVER_TEMPERATURE;
if (rval & FAULT_TIMEOUT)
if (reg_val & FAULT_TIMEOUT)
fault |= V4L2_FLASH_FAULT_TIMEOUT;
ctrl->cur.val = fault;
return 0;
}
out:
mutex_unlock(&flash->lock);
return -EINVAL;
return rval;
}
static int lm3560_set_ctrl(struct v4l2_ctrl *ctrl, enum lm3560_led_id led_no)
@ -219,15 +219,19 @@ static int lm3560_set_ctrl(struct v4l2_ctrl *ctrl, enum lm3560_led_id led_no)
break;
case V4L2_CID_FLASH_STROBE:
if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH)
return -EBUSY;
if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) {
rval = -EBUSY;
goto err_out;
}
flash->led_mode = V4L2_FLASH_LED_MODE_FLASH;
rval = lm3560_mode_ctrl(flash);
break;
case V4L2_CID_FLASH_STROBE_STOP:
if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH)
return -EBUSY;
if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) {
rval = -EBUSY;
goto err_out;
}
flash->led_mode = V4L2_FLASH_LED_MODE_NONE;
rval = lm3560_mode_ctrl(flash);
break;
@ -247,8 +251,8 @@ static int lm3560_set_ctrl(struct v4l2_ctrl *ctrl, enum lm3560_led_id led_no)
break;
}
mutex_unlock(&flash->lock);
err_out:
mutex_unlock(&flash->lock);
return rval;
}
@ -444,14 +448,14 @@ static int lm3560_probe(struct i2c_client *client,
if (rval < 0)
return rval;
i2c_set_clientdata(client, flash);
return 0;
}
static int lm3560_remove(struct i2c_client *client)
{
struct v4l2_subdev *subdev = i2c_get_clientdata(client);
struct lm3560_flash *flash = container_of(subdev, struct lm3560_flash,
subdev_led[LM3560_LED_MAX]);
struct lm3560_flash *flash = i2c_get_clientdata(client);
unsigned int i;
for (i = LM3560_LED0; i < LM3560_LED_MAX; i++) {

View File

@ -459,13 +459,15 @@ static int mt9m032_set_pad_crop(struct v4l2_subdev *subdev,
MT9M032_COLUMN_START_MAX);
rect.top = clamp(ALIGN(crop->rect.top, 2), MT9M032_ROW_START_MIN,
MT9M032_ROW_START_MAX);
rect.width = clamp(ALIGN(crop->rect.width, 2), MT9M032_COLUMN_SIZE_MIN,
MT9M032_COLUMN_SIZE_MAX);
rect.height = clamp(ALIGN(crop->rect.height, 2), MT9M032_ROW_SIZE_MIN,
MT9M032_ROW_SIZE_MAX);
rect.width = clamp_t(unsigned int, ALIGN(crop->rect.width, 2),
MT9M032_COLUMN_SIZE_MIN, MT9M032_COLUMN_SIZE_MAX);
rect.height = clamp_t(unsigned int, ALIGN(crop->rect.height, 2),
MT9M032_ROW_SIZE_MIN, MT9M032_ROW_SIZE_MAX);
rect.width = min(rect.width, MT9M032_PIXEL_ARRAY_WIDTH - rect.left);
rect.height = min(rect.height, MT9M032_PIXEL_ARRAY_HEIGHT - rect.top);
rect.width = min_t(unsigned int, rect.width,
MT9M032_PIXEL_ARRAY_WIDTH - rect.left);
rect.height = min_t(unsigned int, rect.height,
MT9M032_PIXEL_ARRAY_HEIGHT - rect.top);
__crop = __mt9m032_get_pad_crop(sensor, fh, crop->which);

View File

@ -519,11 +519,13 @@ static int mt9p031_set_format(struct v4l2_subdev *subdev,
/* Clamp the width and height to avoid dividing by zero. */
width = clamp_t(unsigned int, ALIGN(format->format.width, 2),
max(__crop->width / 7, MT9P031_WINDOW_WIDTH_MIN),
max_t(unsigned int, __crop->width / 7,
MT9P031_WINDOW_WIDTH_MIN),
__crop->width);
height = clamp_t(unsigned int, ALIGN(format->format.height, 2),
max(__crop->height / 8, MT9P031_WINDOW_HEIGHT_MIN),
__crop->height);
max_t(unsigned int, __crop->height / 8,
MT9P031_WINDOW_HEIGHT_MIN),
__crop->height);
hratio = DIV_ROUND_CLOSEST(__crop->width, width);
vratio = DIV_ROUND_CLOSEST(__crop->height, height);
@ -565,15 +567,17 @@ static int mt9p031_set_crop(struct v4l2_subdev *subdev,
MT9P031_COLUMN_START_MAX);
rect.top = clamp(ALIGN(crop->rect.top, 2), MT9P031_ROW_START_MIN,
MT9P031_ROW_START_MAX);
rect.width = clamp(ALIGN(crop->rect.width, 2),
MT9P031_WINDOW_WIDTH_MIN,
MT9P031_WINDOW_WIDTH_MAX);
rect.height = clamp(ALIGN(crop->rect.height, 2),
MT9P031_WINDOW_HEIGHT_MIN,
MT9P031_WINDOW_HEIGHT_MAX);
rect.width = clamp_t(unsigned int, ALIGN(crop->rect.width, 2),
MT9P031_WINDOW_WIDTH_MIN,
MT9P031_WINDOW_WIDTH_MAX);
rect.height = clamp_t(unsigned int, ALIGN(crop->rect.height, 2),
MT9P031_WINDOW_HEIGHT_MIN,
MT9P031_WINDOW_HEIGHT_MAX);
rect.width = min(rect.width, MT9P031_PIXEL_ARRAY_WIDTH - rect.left);
rect.height = min(rect.height, MT9P031_PIXEL_ARRAY_HEIGHT - rect.top);
rect.width = min_t(unsigned int, rect.width,
MT9P031_PIXEL_ARRAY_WIDTH - rect.left);
rect.height = min_t(unsigned int, rect.height,
MT9P031_PIXEL_ARRAY_HEIGHT - rect.top);
__crop = __mt9p031_get_pad_crop(mt9p031, fh, crop->pad, crop->which);

View File

@ -291,10 +291,12 @@ static int mt9t001_set_format(struct v4l2_subdev *subdev,
/* Clamp the width and height to avoid dividing by zero. */
width = clamp_t(unsigned int, ALIGN(format->format.width, 2),
max(__crop->width / 8, MT9T001_WINDOW_HEIGHT_MIN + 1),
max_t(unsigned int, __crop->width / 8,
MT9T001_WINDOW_HEIGHT_MIN + 1),
__crop->width);
height = clamp_t(unsigned int, ALIGN(format->format.height, 2),
max(__crop->height / 8, MT9T001_WINDOW_HEIGHT_MIN + 1),
max_t(unsigned int, __crop->height / 8,
MT9T001_WINDOW_HEIGHT_MIN + 1),
__crop->height);
hratio = DIV_ROUND_CLOSEST(__crop->width, width);
@ -339,15 +341,17 @@ static int mt9t001_set_crop(struct v4l2_subdev *subdev,
rect.top = clamp(ALIGN(crop->rect.top, 2),
MT9T001_ROW_START_MIN,
MT9T001_ROW_START_MAX);
rect.width = clamp(ALIGN(crop->rect.width, 2),
MT9T001_WINDOW_WIDTH_MIN + 1,
MT9T001_WINDOW_WIDTH_MAX + 1);
rect.height = clamp(ALIGN(crop->rect.height, 2),
MT9T001_WINDOW_HEIGHT_MIN + 1,
MT9T001_WINDOW_HEIGHT_MAX + 1);
rect.width = clamp_t(unsigned int, ALIGN(crop->rect.width, 2),
MT9T001_WINDOW_WIDTH_MIN + 1,
MT9T001_WINDOW_WIDTH_MAX + 1);
rect.height = clamp_t(unsigned int, ALIGN(crop->rect.height, 2),
MT9T001_WINDOW_HEIGHT_MIN + 1,
MT9T001_WINDOW_HEIGHT_MAX + 1);
rect.width = min(rect.width, MT9T001_PIXEL_ARRAY_WIDTH - rect.left);
rect.height = min(rect.height, MT9T001_PIXEL_ARRAY_HEIGHT - rect.top);
rect.width = min_t(unsigned int, rect.width,
MT9T001_PIXEL_ARRAY_WIDTH - rect.left);
rect.height = min_t(unsigned int, rect.height,
MT9T001_PIXEL_ARRAY_HEIGHT - rect.top);
__crop = __mt9t001_get_pad_crop(mt9t001, fh, crop->pad, crop->which);

View File

@ -27,14 +27,16 @@
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
#define MT9V032_PIXEL_ARRAY_HEIGHT 492
#define MT9V032_PIXEL_ARRAY_WIDTH 782
/* The first four rows are black rows. The active area spans 753x481 pixels. */
#define MT9V032_PIXEL_ARRAY_HEIGHT 485
#define MT9V032_PIXEL_ARRAY_WIDTH 753
#define MT9V032_SYSCLK_FREQ_DEF 26600000
#define MT9V032_CHIP_VERSION 0x00
#define MT9V032_CHIP_ID_REV1 0x1311
#define MT9V032_CHIP_ID_REV3 0x1313
#define MT9V034_CHIP_ID_REV1 0X1324
#define MT9V032_COLUMN_START 0x01
#define MT9V032_COLUMN_START_MIN 1
#define MT9V032_COLUMN_START_DEF 1
@ -53,12 +55,15 @@
#define MT9V032_WINDOW_WIDTH_MAX 752
#define MT9V032_HORIZONTAL_BLANKING 0x05
#define MT9V032_HORIZONTAL_BLANKING_MIN 43
#define MT9V034_HORIZONTAL_BLANKING_MIN 61
#define MT9V032_HORIZONTAL_BLANKING_DEF 94
#define MT9V032_HORIZONTAL_BLANKING_MAX 1023
#define MT9V032_VERTICAL_BLANKING 0x06
#define MT9V032_VERTICAL_BLANKING_MIN 4
#define MT9V034_VERTICAL_BLANKING_MIN 2
#define MT9V032_VERTICAL_BLANKING_DEF 45
#define MT9V032_VERTICAL_BLANKING_MAX 3000
#define MT9V034_VERTICAL_BLANKING_MAX 32288
#define MT9V032_CHIP_CONTROL 0x07
#define MT9V032_CHIP_CONTROL_MASTER_MODE (1 << 3)
#define MT9V032_CHIP_CONTROL_DOUT_ENABLE (1 << 7)
@ -68,8 +73,10 @@
#define MT9V032_SHUTTER_WIDTH_CONTROL 0x0a
#define MT9V032_TOTAL_SHUTTER_WIDTH 0x0b
#define MT9V032_TOTAL_SHUTTER_WIDTH_MIN 1
#define MT9V034_TOTAL_SHUTTER_WIDTH_MIN 0
#define MT9V032_TOTAL_SHUTTER_WIDTH_DEF 480
#define MT9V032_TOTAL_SHUTTER_WIDTH_MAX 32767
#define MT9V034_TOTAL_SHUTTER_WIDTH_MAX 32765
#define MT9V032_RESET 0x0c
#define MT9V032_READ_MODE 0x0d
#define MT9V032_READ_MODE_ROW_BIN_MASK (3 << 0)
@ -81,6 +88,8 @@
#define MT9V032_READ_MODE_DARK_COLUMNS (1 << 6)
#define MT9V032_READ_MODE_DARK_ROWS (1 << 7)
#define MT9V032_PIXEL_OPERATION_MODE 0x0f
#define MT9V034_PIXEL_OPERATION_MODE_HDR (1 << 0)
#define MT9V034_PIXEL_OPERATION_MODE_COLOR (1 << 1)
#define MT9V032_PIXEL_OPERATION_MODE_COLOR (1 << 2)
#define MT9V032_PIXEL_OPERATION_MODE_HDR (1 << 6)
#define MT9V032_ANALOG_GAIN 0x35
@ -96,9 +105,12 @@
#define MT9V032_DARK_AVG_HIGH_THRESH_MASK (255 << 8)
#define MT9V032_DARK_AVG_HIGH_THRESH_SHIFT 8
#define MT9V032_ROW_NOISE_CORR_CONTROL 0x70
#define MT9V034_ROW_NOISE_CORR_ENABLE (1 << 0)
#define MT9V034_ROW_NOISE_CORR_USE_BLK_AVG (1 << 1)
#define MT9V032_ROW_NOISE_CORR_ENABLE (1 << 5)
#define MT9V032_ROW_NOISE_CORR_USE_BLK_AVG (1 << 7)
#define MT9V032_PIXEL_CLOCK 0x74
#define MT9V034_PIXEL_CLOCK 0x72
#define MT9V032_PIXEL_CLOCK_INV_LINE (1 << 0)
#define MT9V032_PIXEL_CLOCK_INV_FRAME (1 << 1)
#define MT9V032_PIXEL_CLOCK_XOR_LINE (1 << 2)
@ -120,12 +132,88 @@
#define MT9V032_AGC_ENABLE (1 << 1)
#define MT9V032_THERMAL_INFO 0xc1
enum mt9v032_model {
MT9V032_MODEL_V032_COLOR,
MT9V032_MODEL_V032_MONO,
MT9V032_MODEL_V034_COLOR,
MT9V032_MODEL_V034_MONO,
};
struct mt9v032_model_version {
unsigned int version;
const char *name;
};
struct mt9v032_model_data {
unsigned int min_row_time;
unsigned int min_hblank;
unsigned int min_vblank;
unsigned int max_vblank;
unsigned int min_shutter;
unsigned int max_shutter;
unsigned int pclk_reg;
};
struct mt9v032_model_info {
const struct mt9v032_model_data *data;
bool color;
};
static const struct mt9v032_model_version mt9v032_versions[] = {
{ MT9V032_CHIP_ID_REV1, "MT9V032 rev1/2" },
{ MT9V032_CHIP_ID_REV3, "MT9V032 rev3" },
{ MT9V034_CHIP_ID_REV1, "MT9V034 rev1" },
};
static const struct mt9v032_model_data mt9v032_model_data[] = {
{
/* MT9V032 revisions 1/2/3 */
.min_row_time = 660,
.min_hblank = MT9V032_HORIZONTAL_BLANKING_MIN,
.min_vblank = MT9V032_VERTICAL_BLANKING_MIN,
.max_vblank = MT9V032_VERTICAL_BLANKING_MAX,
.min_shutter = MT9V032_TOTAL_SHUTTER_WIDTH_MIN,
.max_shutter = MT9V032_TOTAL_SHUTTER_WIDTH_MAX,
.pclk_reg = MT9V032_PIXEL_CLOCK,
}, {
/* MT9V034 */
.min_row_time = 690,
.min_hblank = MT9V034_HORIZONTAL_BLANKING_MIN,
.min_vblank = MT9V034_VERTICAL_BLANKING_MIN,
.max_vblank = MT9V034_VERTICAL_BLANKING_MAX,
.min_shutter = MT9V034_TOTAL_SHUTTER_WIDTH_MIN,
.max_shutter = MT9V034_TOTAL_SHUTTER_WIDTH_MAX,
.pclk_reg = MT9V034_PIXEL_CLOCK,
},
};
static const struct mt9v032_model_info mt9v032_models[] = {
[MT9V032_MODEL_V032_COLOR] = {
.data = &mt9v032_model_data[0],
.color = true,
},
[MT9V032_MODEL_V032_MONO] = {
.data = &mt9v032_model_data[0],
.color = false,
},
[MT9V032_MODEL_V034_COLOR] = {
.data = &mt9v032_model_data[1],
.color = true,
},
[MT9V032_MODEL_V034_MONO] = {
.data = &mt9v032_model_data[1],
.color = false,
},
};
struct mt9v032 {
struct v4l2_subdev subdev;
struct media_pad pad;
struct v4l2_mbus_framefmt format;
struct v4l2_rect crop;
unsigned int hratio;
unsigned int vratio;
struct v4l2_ctrl_handler ctrls;
struct {
@ -139,6 +227,8 @@ struct mt9v032 {
struct clk *clk;
struct mt9v032_platform_data *pdata;
const struct mt9v032_model_info *model;
const struct mt9v032_model_version *version;
u32 sysclk;
u16 chip_control;
@ -210,13 +300,18 @@ mt9v032_update_hblank(struct mt9v032 *mt9v032)
{
struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
struct v4l2_rect *crop = &mt9v032->crop;
unsigned int min_hblank = mt9v032->model->data->min_hblank;
unsigned int hblank;
return mt9v032_write(client, MT9V032_HORIZONTAL_BLANKING,
max_t(s32, mt9v032->hblank, 660 - crop->width));
if (mt9v032->version->version == MT9V034_CHIP_ID_REV1)
min_hblank += (mt9v032->hratio - 1) * 10;
min_hblank = max_t(unsigned int, (int)mt9v032->model->data->min_row_time - crop->width,
(int)min_hblank);
hblank = max_t(unsigned int, mt9v032->hblank, min_hblank);
return mt9v032_write(client, MT9V032_HORIZONTAL_BLANKING, hblank);
}
#define EXT_CLK 25000000
static int mt9v032_power_on(struct mt9v032 *mt9v032)
{
struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
@ -259,7 +354,7 @@ static int __mt9v032_set_power(struct mt9v032 *mt9v032, bool on)
/* Configure the pixel clock polarity */
if (mt9v032->pdata && mt9v032->pdata->clk_pol) {
ret = mt9v032_write(client, MT9V032_PIXEL_CLOCK,
ret = mt9v032_write(client, mt9v032->model->data->pclk_reg,
MT9V032_PIXEL_CLOCK_INV_PXL_CLK);
if (ret < 0)
return ret;
@ -312,22 +407,20 @@ static int mt9v032_s_stream(struct v4l2_subdev *subdev, int enable)
| MT9V032_CHIP_CONTROL_SEQUENTIAL;
struct i2c_client *client = v4l2_get_subdevdata(subdev);
struct mt9v032 *mt9v032 = to_mt9v032(subdev);
struct v4l2_mbus_framefmt *format = &mt9v032->format;
struct v4l2_rect *crop = &mt9v032->crop;
unsigned int hratio;
unsigned int vratio;
unsigned int hbin;
unsigned int vbin;
int ret;
if (!enable)
return mt9v032_set_chip_control(mt9v032, mode, 0);
/* Configure the window size and row/column bin */
hratio = DIV_ROUND_CLOSEST(crop->width, format->width);
vratio = DIV_ROUND_CLOSEST(crop->height, format->height);
hbin = fls(mt9v032->hratio) - 1;
vbin = fls(mt9v032->vratio) - 1;
ret = mt9v032_write(client, MT9V032_READ_MODE,
(hratio - 1) << MT9V032_READ_MODE_ROW_BIN_SHIFT |
(vratio - 1) << MT9V032_READ_MODE_COLUMN_BIN_SHIFT);
hbin << MT9V032_READ_MODE_COLUMN_BIN_SHIFT |
vbin << MT9V032_READ_MODE_ROW_BIN_SHIFT);
if (ret < 0)
return ret;
@ -370,12 +463,12 @@ static int mt9v032_enum_frame_size(struct v4l2_subdev *subdev,
struct v4l2_subdev_fh *fh,
struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->index >= 8 || fse->code != V4L2_MBUS_FMT_SGRBG10_1X10)
if (fse->index >= 3 || fse->code != V4L2_MBUS_FMT_SGRBG10_1X10)
return -EINVAL;
fse->min_width = MT9V032_WINDOW_WIDTH_DEF / fse->index;
fse->min_width = MT9V032_WINDOW_WIDTH_DEF / (1 << fse->index);
fse->max_width = fse->min_width;
fse->min_height = MT9V032_WINDOW_HEIGHT_DEF / fse->index;
fse->min_height = MT9V032_WINDOW_HEIGHT_DEF / (1 << fse->index);
fse->max_height = fse->min_height;
return 0;
@ -392,18 +485,30 @@ static int mt9v032_get_format(struct v4l2_subdev *subdev,
return 0;
}
static void mt9v032_configure_pixel_rate(struct mt9v032 *mt9v032,
unsigned int hratio)
static void mt9v032_configure_pixel_rate(struct mt9v032 *mt9v032)
{
struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
int ret;
ret = v4l2_ctrl_s_ctrl_int64(mt9v032->pixel_rate,
mt9v032->sysclk / hratio);
mt9v032->sysclk / mt9v032->hratio);
if (ret < 0)
dev_warn(&client->dev, "failed to set pixel rate (%d)\n", ret);
}
static unsigned int mt9v032_calc_ratio(unsigned int input, unsigned int output)
{
/* Compute the power-of-two binning factor closest to the input size to
* output size ratio. Given that the output size is bounded by input/4
* and input, a generic implementation would be an ineffective luxury.
*/
if (output * 3 > input * 2)
return 1;
if (output * 3 > input)
return 2;
return 4;
}
static int mt9v032_set_format(struct v4l2_subdev *subdev,
struct v4l2_subdev_fh *fh,
struct v4l2_subdev_format *format)
@ -420,22 +525,28 @@ static int mt9v032_set_format(struct v4l2_subdev *subdev,
format->which);
/* Clamp the width and height to avoid dividing by zero. */
width = clamp_t(unsigned int, ALIGN(format->format.width, 2),
max(__crop->width / 8, MT9V032_WINDOW_WIDTH_MIN),
__crop->width);
height = clamp_t(unsigned int, ALIGN(format->format.height, 2),
max(__crop->height / 8, MT9V032_WINDOW_HEIGHT_MIN),
__crop->height);
width = clamp(ALIGN(format->format.width, 2),
max_t(unsigned int, __crop->width / 4,
MT9V032_WINDOW_WIDTH_MIN),
__crop->width);
height = clamp(ALIGN(format->format.height, 2),
max_t(unsigned int, __crop->height / 4,
MT9V032_WINDOW_HEIGHT_MIN),
__crop->height);
hratio = DIV_ROUND_CLOSEST(__crop->width, width);
vratio = DIV_ROUND_CLOSEST(__crop->height, height);
hratio = mt9v032_calc_ratio(__crop->width, width);
vratio = mt9v032_calc_ratio(__crop->height, height);
__format = __mt9v032_get_pad_format(mt9v032, fh, format->pad,
format->which);
__format->width = __crop->width / hratio;
__format->height = __crop->height / vratio;
if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
mt9v032_configure_pixel_rate(mt9v032, hratio);
if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
mt9v032->hratio = hratio;
mt9v032->vratio = vratio;
mt9v032_configure_pixel_rate(mt9v032);
}
format->format = *__format;
@ -471,15 +582,17 @@ static int mt9v032_set_crop(struct v4l2_subdev *subdev,
rect.top = clamp(ALIGN(crop->rect.top + 1, 2) - 1,
MT9V032_ROW_START_MIN,
MT9V032_ROW_START_MAX);
rect.width = clamp(ALIGN(crop->rect.width, 2),
MT9V032_WINDOW_WIDTH_MIN,
MT9V032_WINDOW_WIDTH_MAX);
rect.height = clamp(ALIGN(crop->rect.height, 2),
MT9V032_WINDOW_HEIGHT_MIN,
MT9V032_WINDOW_HEIGHT_MAX);
rect.width = clamp_t(unsigned int, ALIGN(crop->rect.width, 2),
MT9V032_WINDOW_WIDTH_MIN,
MT9V032_WINDOW_WIDTH_MAX);
rect.height = clamp_t(unsigned int, ALIGN(crop->rect.height, 2),
MT9V032_WINDOW_HEIGHT_MIN,
MT9V032_WINDOW_HEIGHT_MAX);
rect.width = min(rect.width, MT9V032_PIXEL_ARRAY_WIDTH - rect.left);
rect.height = min(rect.height, MT9V032_PIXEL_ARRAY_HEIGHT - rect.top);
rect.width = min_t(unsigned int,
rect.width, MT9V032_PIXEL_ARRAY_WIDTH - rect.left);
rect.height = min_t(unsigned int,
rect.height, MT9V032_PIXEL_ARRAY_HEIGHT - rect.top);
__crop = __mt9v032_get_pad_crop(mt9v032, fh, crop->pad, crop->which);
@ -491,8 +604,11 @@ static int mt9v032_set_crop(struct v4l2_subdev *subdev,
crop->which);
__format->width = rect.width;
__format->height = rect.height;
if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE)
mt9v032_configure_pixel_rate(mt9v032, 1);
if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
mt9v032->hratio = 1;
mt9v032->vratio = 1;
mt9v032_configure_pixel_rate(mt9v032);
}
}
*__crop = rect;
@ -641,7 +757,8 @@ static int mt9v032_registered(struct v4l2_subdev *subdev)
{
struct i2c_client *client = v4l2_get_subdevdata(subdev);
struct mt9v032 *mt9v032 = to_mt9v032(subdev);
s32 data;
unsigned int i;
s32 version;
int ret;
dev_info(&client->dev, "Probing MT9V032 at address 0x%02x\n",
@ -654,25 +771,38 @@ static int mt9v032_registered(struct v4l2_subdev *subdev)
}
/* Read and check the sensor version */
data = mt9v032_read(client, MT9V032_CHIP_VERSION);
if (data != MT9V032_CHIP_ID_REV1 && data != MT9V032_CHIP_ID_REV3) {
dev_err(&client->dev, "MT9V032 not detected, wrong version "
"0x%04x\n", data);
version = mt9v032_read(client, MT9V032_CHIP_VERSION);
if (version < 0) {
dev_err(&client->dev, "Failed reading chip version\n");
return version;
}
for (i = 0; i < ARRAY_SIZE(mt9v032_versions); ++i) {
if (mt9v032_versions[i].version == version) {
mt9v032->version = &mt9v032_versions[i];
break;
}
}
if (mt9v032->version == NULL) {
dev_err(&client->dev, "Unsupported chip version 0x%04x\n",
version);
return -ENODEV;
}
mt9v032_power_off(mt9v032);
dev_info(&client->dev, "MT9V032 detected at address 0x%02x\n",
client->addr);
dev_info(&client->dev, "%s detected at address 0x%02x\n",
mt9v032->version->name, client->addr);
mt9v032_configure_pixel_rate(mt9v032, 1);
mt9v032_configure_pixel_rate(mt9v032);
return ret;
}
static int mt9v032_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
{
struct mt9v032 *mt9v032 = to_mt9v032(subdev);
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *crop;
@ -683,7 +813,12 @@ static int mt9v032_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
crop->height = MT9V032_WINDOW_HEIGHT_DEF;
format = v4l2_subdev_get_try_format(fh, 0);
format->code = V4L2_MBUS_FMT_SGRBG10_1X10;
if (mt9v032->model->color)
format->code = V4L2_MBUS_FMT_SGRBG10_1X10;
else
format->code = V4L2_MBUS_FMT_Y10_1X10;
format->width = MT9V032_WINDOW_WIDTH_DEF;
format->height = MT9V032_WINDOW_HEIGHT_DEF;
format->field = V4L2_FIELD_NONE;
@ -755,6 +890,7 @@ static int mt9v032_probe(struct i2c_client *client,
mutex_init(&mt9v032->power_lock);
mt9v032->pdata = pdata;
mt9v032->model = (const void *)did->driver_data;
v4l2_ctrl_handler_init(&mt9v032->ctrls, 10);
@ -767,16 +903,16 @@ static int mt9v032_probe(struct i2c_client *client,
V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL, 0,
V4L2_EXPOSURE_AUTO);
v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
V4L2_CID_EXPOSURE, MT9V032_TOTAL_SHUTTER_WIDTH_MIN,
MT9V032_TOTAL_SHUTTER_WIDTH_MAX, 1,
V4L2_CID_EXPOSURE, mt9v032->model->data->min_shutter,
mt9v032->model->data->max_shutter, 1,
MT9V032_TOTAL_SHUTTER_WIDTH_DEF);
v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
V4L2_CID_HBLANK, MT9V032_HORIZONTAL_BLANKING_MIN,
V4L2_CID_HBLANK, mt9v032->model->data->min_hblank,
MT9V032_HORIZONTAL_BLANKING_MAX, 1,
MT9V032_HORIZONTAL_BLANKING_DEF);
v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
V4L2_CID_VBLANK, MT9V032_VERTICAL_BLANKING_MIN,
MT9V032_VERTICAL_BLANKING_MAX, 1,
V4L2_CID_VBLANK, mt9v032->model->data->min_vblank,
mt9v032->model->data->max_vblank, 1,
MT9V032_VERTICAL_BLANKING_DEF);
mt9v032->test_pattern = v4l2_ctrl_new_std_menu_items(&mt9v032->ctrls,
&mt9v032_ctrl_ops, V4L2_CID_TEST_PATTERN,
@ -819,12 +955,19 @@ static int mt9v032_probe(struct i2c_client *client,
mt9v032->crop.width = MT9V032_WINDOW_WIDTH_DEF;
mt9v032->crop.height = MT9V032_WINDOW_HEIGHT_DEF;
mt9v032->format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
if (mt9v032->model->color)
mt9v032->format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
else
mt9v032->format.code = V4L2_MBUS_FMT_Y10_1X10;
mt9v032->format.width = MT9V032_WINDOW_WIDTH_DEF;
mt9v032->format.height = MT9V032_WINDOW_HEIGHT_DEF;
mt9v032->format.field = V4L2_FIELD_NONE;
mt9v032->format.colorspace = V4L2_COLORSPACE_SRGB;
mt9v032->hratio = 1;
mt9v032->vratio = 1;
mt9v032->aec_agc = MT9V032_AEC_ENABLE | MT9V032_AGC_ENABLE;
mt9v032->hblank = MT9V032_HORIZONTAL_BLANKING_DEF;
mt9v032->sysclk = MT9V032_SYSCLK_FREQ_DEF;
@ -855,7 +998,10 @@ static int mt9v032_remove(struct i2c_client *client)
}
static const struct i2c_device_id mt9v032_id[] = {
{ "mt9v032", 0 },
{ "mt9v032", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V032_COLOR] },
{ "mt9v032m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V032_MONO] },
{ "mt9v034", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V034_COLOR] },
{ "mt9v034m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V034_MONO] },
{ }
};
MODULE_DEVICE_TABLE(i2c, mt9v032_id);

2045
drivers/media/i2c/s5k5baf.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -150,14 +150,14 @@ static inline struct saa6588 *to_saa6588(struct v4l2_subdev *sd)
/* ---------------------------------------------------------------------- */
static int block_to_user_buf(struct saa6588 *s, unsigned char __user *user_buf)
static bool block_from_buf(struct saa6588 *s, unsigned char *buf)
{
int i;
if (s->rd_index == s->wr_index) {
if (debug > 2)
dprintk(PREFIX "Read: buffer empty.\n");
return 0;
return false;
}
if (debug > 2) {
@ -166,8 +166,7 @@ static int block_to_user_buf(struct saa6588 *s, unsigned char __user *user_buf)
dprintk("0x%02x ", s->buffer[i]);
}
if (copy_to_user(user_buf, &s->buffer[s->rd_index], 3))
return -EFAULT;
memcpy(buf, &s->buffer[s->rd_index], 3);
s->rd_index += 3;
if (s->rd_index >= s->buf_size)
@ -177,22 +176,22 @@ static int block_to_user_buf(struct saa6588 *s, unsigned char __user *user_buf)
if (debug > 2)
dprintk("%d blocks total.\n", s->block_count);
return 1;
return true;
}
static void read_from_buf(struct saa6588 *s, struct saa6588_command *a)
{
unsigned long flags;
unsigned char __user *buf_ptr = a->buffer;
unsigned int i;
unsigned char buf[3];
unsigned long flags;
unsigned int rd_blocks;
unsigned int i;
a->result = 0;
if (!a->buffer)
return;
while (!s->data_available_for_read) {
while (!a->nonblocking && !s->data_available_for_read) {
int ret = wait_event_interruptible(s->read_queue,
s->data_available_for_read);
if (ret == -ERESTARTSYS) {
@ -201,24 +200,31 @@ static void read_from_buf(struct saa6588 *s, struct saa6588_command *a)
}
}
spin_lock_irqsave(&s->lock, flags);
rd_blocks = a->block_count;
spin_lock_irqsave(&s->lock, flags);
if (rd_blocks > s->block_count)
rd_blocks = s->block_count;
spin_unlock_irqrestore(&s->lock, flags);
if (!rd_blocks) {
spin_unlock_irqrestore(&s->lock, flags);
if (!rd_blocks)
return;
}
for (i = 0; i < rd_blocks; i++) {
if (block_to_user_buf(s, buf_ptr)) {
buf_ptr += 3;
a->result++;
} else
bool got_block;
spin_lock_irqsave(&s->lock, flags);
got_block = block_from_buf(s, buf);
spin_unlock_irqrestore(&s->lock, flags);
if (!got_block)
break;
if (copy_to_user(buf_ptr, buf, 3)) {
a->result = -EFAULT;
return;
}
buf_ptr += 3;
a->result += 3;
}
a->result *= 3;
spin_lock_irqsave(&s->lock, flags);
s->data_available_for_read = (s->block_count > 0);
spin_unlock_irqrestore(&s->lock, flags);
}
@ -394,14 +400,11 @@ static long saa6588_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
struct saa6588_command *a = arg;
switch (cmd) {
/* --- open() for /dev/radio --- */
case SAA6588_CMD_OPEN:
a->result = 0; /* return error if chip doesn't work ??? */
break;
/* --- close() for /dev/radio --- */
case SAA6588_CMD_CLOSE:
s->data_available_for_read = 1;
wake_up_interruptible(&s->read_queue);
s->data_available_for_read = 0;
a->result = 0;
break;
/* --- read() for /dev/radio --- */
@ -411,9 +414,8 @@ static long saa6588_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
/* --- poll() for /dev/radio --- */
case SAA6588_CMD_POLL:
a->result = 0;
if (s->data_available_for_read) {
if (s->data_available_for_read)
a->result |= POLLIN | POLLRDNORM;
}
poll_wait(a->instance, &s->read_queue, a->event_list);
break;

View File

@ -33,11 +33,11 @@
#include <linux/i2c.h>
#include <linux/types.h>
#include <linux/videodev2.h>
#include <linux/init.h>
#include <linux/crc32.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-common.h>
#include <linux/init.h>
#include <linux/crc32.h>
#define MPEG_VIDEO_TARGET_BITRATE_MAX 27000
#define MPEG_VIDEO_MAX_BITRATE_MAX 27000
@ -124,7 +124,7 @@ static inline struct saa6752hs_state *to_state(struct v4l2_subdev *sd)
/* ---------------------------------------------------------------------- */
static u8 PAT[] = {
static const u8 PAT[] = {
0xc2, /* i2c register */
0x00, /* table number for encoder */
@ -150,7 +150,7 @@ static u8 PAT[] = {
0x00, 0x00, 0x00, 0x00 /* CRC32 */
};
static u8 PMT[] = {
static const u8 PMT[] = {
0xc2, /* i2c register */
0x01, /* table number for encoder */
@ -179,7 +179,7 @@ static u8 PMT[] = {
0x00, 0x00, 0x00, 0x00 /* CRC32 */
};
static u8 PMT_AC3[] = {
static const u8 PMT_AC3[] = {
0xc2, /* i2c register */
0x01, /* table number for encoder(1) */
0x47, /* sync */
@ -212,7 +212,7 @@ static u8 PMT_AC3[] = {
0xED, 0xDE, 0x2D, 0xF3 /* CRC32 BE */
};
static struct saa6752hs_mpeg_params param_defaults =
static const struct saa6752hs_mpeg_params param_defaults =
{
.ts_pid_pmt = 16,
.ts_pid_video = 260,
@ -643,13 +643,6 @@ static const struct v4l2_ctrl_ops saa6752hs_ctrl_ops = {
static const struct v4l2_subdev_core_ops saa6752hs_core_ops = {
.init = saa6752hs_init,
.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
.g_ctrl = v4l2_subdev_g_ctrl,
.s_ctrl = v4l2_subdev_s_ctrl,
.queryctrl = v4l2_subdev_queryctrl,
.querymenu = v4l2_subdev_querymenu,
.s_std = saa6752hs_s_std,
};

View File

@ -399,7 +399,6 @@ static void smiapp_update_mbus_formats(struct smiapp_sensor *sensor)
BUG_ON(max(internal_csi_format_idx, csi_format_idx) + pixel_order
>= ARRAY_SIZE(smiapp_csi_data_formats));
BUG_ON(min(internal_csi_format_idx, csi_format_idx) < 0);
dev_dbg(&client->dev, "new pixel order %s\n",
pixel_order_str[pixel_order]);
@ -2028,8 +2027,8 @@ static int smiapp_set_crop(struct v4l2_subdev *subdev,
sel->r.width = min(sel->r.width, src_size->width);
sel->r.height = min(sel->r.height, src_size->height);
sel->r.left = min(sel->r.left, src_size->width - sel->r.width);
sel->r.top = min(sel->r.top, src_size->height - sel->r.height);
sel->r.left = min_t(int, sel->r.left, src_size->width - sel->r.width);
sel->r.top = min_t(int, sel->r.top, src_size->height - sel->r.height);
*crops[sel->pad] = sel->r;
@ -2121,8 +2120,8 @@ static int smiapp_set_selection(struct v4l2_subdev *subdev,
sel->r.left = max(0, sel->r.left & ~1);
sel->r.top = max(0, sel->r.top & ~1);
sel->r.width = max(0, SMIAPP_ALIGN_DIM(sel->r.width, sel->flags));
sel->r.height = max(0, SMIAPP_ALIGN_DIM(sel->r.height, sel->flags));
sel->r.width = SMIAPP_ALIGN_DIM(sel->r.width, sel->flags);
sel->r.height = SMIAPP_ALIGN_DIM(sel->r.height, sel->flags);
sel->r.width = max_t(unsigned int,
sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE],

View File

@ -208,8 +208,8 @@ struct mt9m111 {
struct mt9m111_context *ctx;
struct v4l2_rect rect; /* cropping rectangle */
struct v4l2_clk *clk;
int width; /* output */
int height; /* sizes */
unsigned int width; /* output */
unsigned int height; /* sizes */
struct mutex power_lock; /* lock to protect power_count */
int power_count;
const struct mt9m111_datafmt *fmt;

View File

@ -58,21 +58,17 @@ static int tvp5150_read(struct v4l2_subdev *sd, unsigned char addr)
struct i2c_client *c = v4l2_get_subdevdata(sd);
unsigned char buffer[1];
int rc;
struct i2c_msg msg[] = {
{ .addr = c->addr, .flags = 0,
.buf = &addr, .len = 1 },
{ .addr = c->addr, .flags = I2C_M_RD,
.buf = buffer, .len = 1 }
};
buffer[0] = addr;
rc = i2c_master_send(c, buffer, 1);
if (rc < 0) {
v4l2_err(sd, "i2c i/o error: rc == %d (should be 1)\n", rc);
return rc;
}
msleep(10);
rc = i2c_master_recv(c, buffer, 1);
if (rc < 0) {
v4l2_err(sd, "i2c i/o error: rc == %d (should be 1)\n", rc);
return rc;
rc = i2c_transfer(c->adapter, msg, 2);
if (rc < 0 || rc != 2) {
v4l2_err(sd, "i2c i/o error: rc == %d (should be 2)\n", rc);
return rc < 0 ? rc : -EIO;
}
v4l2_dbg(2, debug, sd, "tvp5150: read 0x%02x = 0x%02x\n", addr, buffer[0]);
@ -867,7 +863,7 @@ static int tvp5150_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a)
struct v4l2_rect rect = a->c;
struct tvp5150 *decoder = to_tvp5150(sd);
v4l2_std_id std;
int hmax;
unsigned int hmax;
v4l2_dbg(1, debug, sd, "%s left=%d, top=%d, width=%d, height=%d\n",
__func__, rect.left, rect.top, rect.width, rect.height);
@ -877,9 +873,9 @@ static int tvp5150_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a)
/* tvp5150 has some special limits */
rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT);
rect.width = clamp(rect.width,
TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect.left,
TVP5150_H_MAX - rect.left);
rect.width = clamp_t(unsigned int, rect.width,
TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect.left,
TVP5150_H_MAX - rect.left);
rect.top = clamp(rect.top, 0, TVP5150_MAX_CROP_TOP);
/* Calculate height based on current standard */
@ -893,9 +889,9 @@ static int tvp5150_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a)
else
hmax = TVP5150_V_MAX_OTHERS;
rect.height = clamp(rect.height,
hmax - TVP5150_MAX_CROP_TOP - rect.top,
hmax - rect.top);
rect.height = clamp_t(unsigned int, rect.height,
hmax - TVP5150_MAX_CROP_TOP - rect.top,
hmax - rect.top);
tvp5150_write(sd, TVP5150_VERT_BLANKING_START, rect.top);
tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP,

View File

@ -503,6 +503,7 @@ static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
return &container_of(ctrl->handler, struct vs6624, hdl)->sd;
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int vs6624_read(struct v4l2_subdev *sd, u16 index)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@ -515,6 +516,7 @@ static int vs6624_read(struct v4l2_subdev *sd, u16 index)
return buf[0];
}
#endif
static int vs6624_write(struct v4l2_subdev *sd, u16 index,
u8 value)

View File

@ -235,6 +235,8 @@ __must_check int media_entity_pipeline_start(struct media_entity *entity,
media_entity_graph_walk_start(&graph, entity);
while ((entity = media_entity_graph_walk_next(&graph))) {
DECLARE_BITMAP(active, entity->num_pads);
DECLARE_BITMAP(has_no_links, entity->num_pads);
unsigned int i;
entity->stream_count++;
@ -248,21 +250,46 @@ __must_check int media_entity_pipeline_start(struct media_entity *entity,
if (!entity->ops || !entity->ops->link_validate)
continue;
bitmap_zero(active, entity->num_pads);
bitmap_fill(has_no_links, entity->num_pads);
for (i = 0; i < entity->num_links; i++) {
struct media_link *link = &entity->links[i];
struct media_pad *pad = link->sink->entity == entity
? link->sink : link->source;
/* Is this pad part of an enabled link? */
if (!(link->flags & MEDIA_LNK_FL_ENABLED))
continue;
/* Mark that a pad is connected by a link. */
bitmap_clear(has_no_links, pad->index, 1);
/* Are we the sink or not? */
if (link->sink->entity != entity)
/*
* Pads that either do not need to connect or
* are connected through an enabled link are
* fine.
*/
if (!(pad->flags & MEDIA_PAD_FL_MUST_CONNECT) ||
link->flags & MEDIA_LNK_FL_ENABLED)
bitmap_set(active, pad->index, 1);
/*
* Link validation will only take place for
* sink ends of the link that are enabled.
*/
if (link->sink != pad ||
!(link->flags & MEDIA_LNK_FL_ENABLED))
continue;
ret = entity->ops->link_validate(link);
if (ret < 0 && ret != -ENOIOCTLCMD)
goto error;
}
/* Either no links or validated links are fine. */
bitmap_or(active, active, has_no_links, entity->num_pads);
if (!bitmap_full(active, entity->num_pads)) {
ret = -EPIPE;
goto error;
}
}
mutex_unlock(&mdev->graph_mutex);

View File

@ -1126,9 +1126,9 @@ bttv_crop_calc_limits(struct bttv_crop *c)
c->min_scaled_height = 32;
} else {
c->min_scaled_width =
(max(48, c->rect.width >> 4) + 3) & ~3;
(max_t(unsigned int, 48, c->rect.width >> 4) + 3) & ~3;
c->min_scaled_height =
max(32, c->rect.height >> 4);
max_t(unsigned int, 32, c->rect.height >> 4);
}
c->max_scaled_width = c->rect.width & ~3;
@ -2024,7 +2024,7 @@ limit_scaled_size_lock (struct bttv_fh * fh,
/* We cannot scale up. When the scaled image is larger
than crop.rect we adjust the crop.rect as required
by the V4L2 spec, hence cropcap.bounds are our limit. */
max_width = min(b->width, (__s32) MAX_HACTIVE);
max_width = min_t(unsigned int, b->width, MAX_HACTIVE);
max_height = b->height;
/* We cannot capture the same line as video and VBI data.
@ -3266,7 +3266,9 @@ static ssize_t radio_read(struct file *file, char __user *data,
struct bttv_fh *fh = file->private_data;
struct bttv *btv = fh->btv;
struct saa6588_command cmd;
cmd.block_count = count/3;
cmd.block_count = count / 3;
cmd.nonblocking = file->f_flags & O_NONBLOCK;
cmd.buffer = data;
cmd.instance = file;
cmd.result = -ENODEV;

View File

@ -327,13 +327,16 @@ void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv)
struct i2c_client *c;
u8 eedata[256];
memset(tv, 0, sizeof(*tv));
c = kzalloc(sizeof(*c), GFP_KERNEL);
if (!c)
return;
strlcpy(c->name, "cx18 tveeprom tmp", sizeof(c->name));
c->adapter = &cx->i2c_adap[0];
c->addr = 0xa0 >> 1;
memset(tv, 0, sizeof(*tv));
if (tveeprom_read(c, eedata, sizeof(eedata)))
goto ret;

View File

@ -618,7 +618,7 @@ static int snd_cx25821_pcm(struct cx25821_audio_dev *chip, int device,
* Only boards with eeprom and byte 1 at eeprom=1 have it
*/
static DEFINE_PCI_DEVICE_TABLE(cx25821_audio_pci_tbl) = {
static const struct pci_device_id cx25821_audio_pci_tbl[] = {
{0x14f1, 0x0920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0,}
};

View File

@ -1361,7 +1361,7 @@ static void cx25821_finidev(struct pci_dev *pci_dev)
kfree(dev);
}
static DEFINE_PCI_DEVICE_TABLE(cx25821_pci_tbl) = {
static const struct pci_device_id cx25821_pci_tbl[] = {
{
/* CX25821 Athena */
.vendor = 0x14f1,

View File

@ -931,9 +931,9 @@ error:
*/
static void cx88_audio_finidev(struct pci_dev *pci)
{
struct cx88_audio_dev *card = pci_get_drvdata(pci);
struct snd_card *card = pci_get_drvdata(pci);
snd_card_free((void *)card);
snd_card_free(card);
devno--;
}

View File

@ -6,6 +6,7 @@ config VIDEO_SAA7134
select VIDEO_TVEEPROM
select CRC32
select VIDEO_SAA6588 if MEDIA_SUBDRV_AUTOSELECT
select VIDEO_SAA6752HS if MEDIA_SUBDRV_AUTOSELECT
---help---
This is a video4linux driver for Philips SAA713x based
TV cards.

View File

@ -4,7 +4,7 @@ saa7134-y += saa7134-ts.o saa7134-tvaudio.o saa7134-vbi.o
saa7134-y += saa7134-video.o
saa7134-$(CONFIG_VIDEO_SAA7134_RC) += saa7134-input.o
obj-$(CONFIG_VIDEO_SAA7134) += saa6752hs.o saa7134.o saa7134-empress.o
obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o
obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o

View File

@ -751,6 +751,7 @@ static int saa7134_hwfini(struct saa7134_dev *dev)
saa7134_input_fini(dev);
saa7134_vbi_fini(dev);
saa7134_tvaudio_fini(dev);
saa7134_video_fini(dev);
return 0;
}
@ -802,7 +803,6 @@ static struct video_device *vdev_init(struct saa7134_dev *dev,
*vfd = *template;
vfd->v4l2_dev = &dev->v4l2_dev;
vfd->release = video_device_release;
vfd->debug = video_debug;
snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
dev->name, type, saa7134_boards[dev->board].name);
set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
@ -1008,13 +1008,13 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
/* load i2c helpers */
if (card_is_empress(dev)) {
struct v4l2_subdev *sd =
dev->empress_sd =
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
"saa6752hs",
saa7134_boards[dev->board].empress_addr, NULL);
if (sd)
sd->grp_id = GRP_EMPRESS;
if (dev->empress_sd)
dev->empress_sd->grp_id = GRP_EMPRESS;
}
if (saa7134_boards[dev->board].rds_addr) {
@ -1046,6 +1046,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
printk(KERN_INFO "%s: Overlay support disabled.\n", dev->name);
dev->video_dev = vdev_init(dev,&saa7134_video_template,"video");
dev->video_dev->ctrl_handler = &dev->ctrl_handler;
err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER,
video_nr[dev->nr]);
if (err < 0) {
@ -1057,6 +1058,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
dev->name, video_device_node_name(dev->video_dev));
dev->vbi_dev = vdev_init(dev, &saa7134_video_template, "vbi");
dev->vbi_dev->ctrl_handler = &dev->ctrl_handler;
err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI,
vbi_nr[dev->nr]);
@ -1067,6 +1069,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
if (card_has_radio(dev)) {
dev->radio_dev = vdev_init(dev,&saa7134_radio_template,"radio");
dev->radio_dev->ctrl_handler = &dev->radio_ctrl_handler;
err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO,
radio_nr[dev->nr]);
if (err < 0)

View File

@ -23,12 +23,12 @@
#include <linux/kernel.h>
#include <linux/delay.h>
#include <media/v4l2-common.h>
#include <media/v4l2-event.h>
#include "saa7134-reg.h"
#include "saa7134.h"
#include <media/saa6752hs.h>
#include <media/v4l2-common.h>
/* ------------------------------------------------------------------ */
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
@ -85,52 +85,54 @@ static int ts_open(struct file *file)
{
struct video_device *vdev = video_devdata(file);
struct saa7134_dev *dev = video_drvdata(file);
int err;
struct saa7134_fh *fh;
dprintk("open dev=%s\n", video_device_node_name(vdev));
err = -EBUSY;
if (!mutex_trylock(&dev->empress_tsq.vb_lock))
return err;
if (atomic_read(&dev->empress_users))
goto done;
/* allocate + initialize per filehandle data */
fh = kzalloc(sizeof(*fh), GFP_KERNEL);
if (NULL == fh)
return -ENOMEM;
v4l2_fh_init(&fh->fh, vdev);
file->private_data = fh;
fh->is_empress = true;
v4l2_fh_add(&fh->fh);
/* Unmute audio */
saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
saa_readb(SAA7134_AUDIO_MUTE_CTRL) & ~(1 << 6));
atomic_inc(&dev->empress_users);
file->private_data = dev;
err = 0;
done:
mutex_unlock(&dev->empress_tsq.vb_lock);
return err;
return 0;
}
static int ts_release(struct file *file)
{
struct saa7134_dev *dev = file->private_data;
struct saa7134_dev *dev = video_drvdata(file);
struct saa7134_fh *fh = file->private_data;
videobuf_stop(&dev->empress_tsq);
videobuf_mmap_free(&dev->empress_tsq);
if (res_check(fh, RESOURCE_EMPRESS)) {
videobuf_stop(&dev->empress_tsq);
videobuf_mmap_free(&dev->empress_tsq);
/* stop the encoder */
ts_reset_encoder(dev);
/* stop the encoder */
ts_reset_encoder(dev);
/* Mute audio */
saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6));
atomic_dec(&dev->empress_users);
/* Mute audio */
saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6));
}
v4l2_fh_del(&fh->fh);
v4l2_fh_exit(&fh->fh);
return 0;
}
static ssize_t
ts_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
{
struct saa7134_dev *dev = file->private_data;
struct saa7134_dev *dev = video_drvdata(file);
if (res_locked(dev, RESOURCE_EMPRESS))
return -EBUSY;
if (!dev->empress_started)
ts_init_encoder(dev);
@ -142,68 +144,27 @@ ts_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
static unsigned int
ts_poll(struct file *file, struct poll_table_struct *wait)
{
struct saa7134_dev *dev = file->private_data;
unsigned long req_events = poll_requested_events(wait);
struct saa7134_dev *dev = video_drvdata(file);
struct saa7134_fh *fh = file->private_data;
unsigned int rc = 0;
return videobuf_poll_stream(file, &dev->empress_tsq, wait);
if (v4l2_event_pending(&fh->fh))
rc = POLLPRI;
else if (req_events & POLLPRI)
poll_wait(file, &fh->fh.wait, wait);
return rc | videobuf_poll_stream(file, &dev->empress_tsq, wait);
}
static int
ts_mmap(struct file *file, struct vm_area_struct * vma)
{
struct saa7134_dev *dev = file->private_data;
struct saa7134_dev *dev = video_drvdata(file);
return videobuf_mmap_mapper(&dev->empress_tsq, vma);
}
/*
* This function is _not_ called directly, but from
* video_generic_ioctl (and maybe others). userspace
* copying is done already, arg is a kernel pointer.
*/
static int empress_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
struct saa7134_dev *dev = file->private_data;
strcpy(cap->driver, "saa7134");
strlcpy(cap->card, saa7134_boards[dev->board].name,
sizeof(cap->card));
sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
cap->capabilities =
V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING;
return 0;
}
static int empress_enum_input(struct file *file, void *priv,
struct v4l2_input *i)
{
if (i->index != 0)
return -EINVAL;
i->type = V4L2_INPUT_TYPE_CAMERA;
strcpy(i->name, "CCIR656");
return 0;
}
static int empress_g_input(struct file *file, void *priv, unsigned int *i)
{
*i = 0;
return 0;
}
static int empress_s_input(struct file *file, void *priv, unsigned int i)
{
if (i != 0)
return -EINVAL;
return 0;
}
static int empress_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
@ -219,7 +180,7 @@ static int empress_enum_fmt_vid_cap(struct file *file, void *priv,
static int empress_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct saa7134_dev *dev = file->private_data;
struct saa7134_dev *dev = video_drvdata(file);
struct v4l2_mbus_framefmt mbus_fmt;
saa_call_all(dev, video, g_mbus_fmt, &mbus_fmt);
@ -236,7 +197,7 @@ static int empress_g_fmt_vid_cap(struct file *file, void *priv,
static int empress_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct saa7134_dev *dev = file->private_data;
struct saa7134_dev *dev = video_drvdata(file);
struct v4l2_mbus_framefmt mbus_fmt;
v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
@ -254,7 +215,7 @@ static int empress_s_fmt_vid_cap(struct file *file, void *priv,
static int empress_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct saa7134_dev *dev = file->private_data;
struct saa7134_dev *dev = video_drvdata(file);
struct v4l2_mbus_framefmt mbus_fmt;
v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
@ -269,175 +230,6 @@ static int empress_try_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
static int empress_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *p)
{
struct saa7134_dev *dev = file->private_data;
return videobuf_reqbufs(&dev->empress_tsq, p);
}
static int empress_querybuf(struct file *file, void *priv,
struct v4l2_buffer *b)
{
struct saa7134_dev *dev = file->private_data;
return videobuf_querybuf(&dev->empress_tsq, b);
}
static int empress_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
{
struct saa7134_dev *dev = file->private_data;
return videobuf_qbuf(&dev->empress_tsq, b);
}
static int empress_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
{
struct saa7134_dev *dev = file->private_data;
return videobuf_dqbuf(&dev->empress_tsq, b,
file->f_flags & O_NONBLOCK);
}
static int empress_streamon(struct file *file, void *priv,
enum v4l2_buf_type type)
{
struct saa7134_dev *dev = file->private_data;
return videobuf_streamon(&dev->empress_tsq);
}
static int empress_streamoff(struct file *file, void *priv,
enum v4l2_buf_type type)
{
struct saa7134_dev *dev = file->private_data;
return videobuf_streamoff(&dev->empress_tsq);
}
static int empress_s_ext_ctrls(struct file *file, void *priv,
struct v4l2_ext_controls *ctrls)
{
struct saa7134_dev *dev = file->private_data;
int err;
/* count == 0 is abused in saa6752hs.c, so that special
case is handled here explicitly. */
if (ctrls->count == 0)
return 0;
if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
return -EINVAL;
err = saa_call_empress(dev, core, s_ext_ctrls, ctrls);
ts_init_encoder(dev);
return err;
}
static int empress_g_ext_ctrls(struct file *file, void *priv,
struct v4l2_ext_controls *ctrls)
{
struct saa7134_dev *dev = file->private_data;
if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
return -EINVAL;
return saa_call_empress(dev, core, g_ext_ctrls, ctrls);
}
static int empress_g_ctrl(struct file *file, void *priv,
struct v4l2_control *c)
{
struct saa7134_dev *dev = file->private_data;
return saa7134_g_ctrl_internal(dev, NULL, c);
}
static int empress_s_ctrl(struct file *file, void *priv,
struct v4l2_control *c)
{
struct saa7134_dev *dev = file->private_data;
return saa7134_s_ctrl_internal(dev, NULL, c);
}
static int empress_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *c)
{
/* Must be sorted from low to high control ID! */
static const u32 user_ctrls[] = {
V4L2_CID_USER_CLASS,
V4L2_CID_BRIGHTNESS,
V4L2_CID_CONTRAST,
V4L2_CID_SATURATION,
V4L2_CID_HUE,
V4L2_CID_AUDIO_VOLUME,
V4L2_CID_AUDIO_MUTE,
V4L2_CID_HFLIP,
0
};
/* Must be sorted from low to high control ID! */
static const u32 mpeg_ctrls[] = {
V4L2_CID_MPEG_CLASS,
V4L2_CID_MPEG_STREAM_TYPE,
V4L2_CID_MPEG_STREAM_PID_PMT,
V4L2_CID_MPEG_STREAM_PID_AUDIO,
V4L2_CID_MPEG_STREAM_PID_VIDEO,
V4L2_CID_MPEG_STREAM_PID_PCR,
V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
V4L2_CID_MPEG_AUDIO_ENCODING,
V4L2_CID_MPEG_AUDIO_L2_BITRATE,
V4L2_CID_MPEG_VIDEO_ENCODING,
V4L2_CID_MPEG_VIDEO_ASPECT,
V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
V4L2_CID_MPEG_VIDEO_BITRATE,
V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
0
};
static const u32 *ctrl_classes[] = {
user_ctrls,
mpeg_ctrls,
NULL
};
struct saa7134_dev *dev = file->private_data;
c->id = v4l2_ctrl_next(ctrl_classes, c->id);
if (c->id == 0)
return -EINVAL;
if (c->id == V4L2_CID_USER_CLASS || c->id == V4L2_CID_MPEG_CLASS)
return v4l2_ctrl_query_fill(c, 0, 0, 0, 0);
if (V4L2_CTRL_ID2CLASS(c->id) != V4L2_CTRL_CLASS_MPEG)
return saa7134_queryctrl(file, priv, c);
return saa_call_empress(dev, core, queryctrl, c);
}
static int empress_querymenu(struct file *file, void *priv,
struct v4l2_querymenu *c)
{
struct saa7134_dev *dev = file->private_data;
if (V4L2_CTRL_ID2CLASS(c->id) != V4L2_CTRL_CLASS_MPEG)
return -EINVAL;
return saa_call_empress(dev, core, querymenu, c);
}
static int empress_s_std(struct file *file, void *priv, v4l2_std_id id)
{
struct saa7134_dev *dev = file->private_data;
return saa7134_s_std_internal(dev, NULL, id);
}
static int empress_g_std(struct file *file, void *priv, v4l2_std_id *id)
{
struct saa7134_dev *dev = file->private_data;
*id = dev->tvnorm->id;
return 0;
}
static const struct v4l2_file_operations ts_fops =
{
.owner = THIS_MODULE,
@ -450,28 +242,29 @@ static const struct v4l2_file_operations ts_fops =
};
static const struct v4l2_ioctl_ops ts_ioctl_ops = {
.vidioc_querycap = empress_querycap,
.vidioc_querycap = saa7134_querycap,
.vidioc_enum_fmt_vid_cap = empress_enum_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = empress_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = empress_s_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = empress_g_fmt_vid_cap,
.vidioc_reqbufs = empress_reqbufs,
.vidioc_querybuf = empress_querybuf,
.vidioc_qbuf = empress_qbuf,
.vidioc_dqbuf = empress_dqbuf,
.vidioc_streamon = empress_streamon,
.vidioc_streamoff = empress_streamoff,
.vidioc_s_ext_ctrls = empress_s_ext_ctrls,
.vidioc_g_ext_ctrls = empress_g_ext_ctrls,
.vidioc_enum_input = empress_enum_input,
.vidioc_g_input = empress_g_input,
.vidioc_s_input = empress_s_input,
.vidioc_queryctrl = empress_queryctrl,
.vidioc_querymenu = empress_querymenu,
.vidioc_g_ctrl = empress_g_ctrl,
.vidioc_s_ctrl = empress_s_ctrl,
.vidioc_s_std = empress_s_std,
.vidioc_g_std = empress_g_std,
.vidioc_reqbufs = saa7134_reqbufs,
.vidioc_querybuf = saa7134_querybuf,
.vidioc_qbuf = saa7134_qbuf,
.vidioc_dqbuf = saa7134_dqbuf,
.vidioc_streamon = saa7134_streamon,
.vidioc_streamoff = saa7134_streamoff,
.vidioc_g_frequency = saa7134_g_frequency,
.vidioc_s_frequency = saa7134_s_frequency,
.vidioc_g_tuner = saa7134_g_tuner,
.vidioc_s_tuner = saa7134_s_tuner,
.vidioc_enum_input = saa7134_enum_input,
.vidioc_g_input = saa7134_g_input,
.vidioc_s_input = saa7134_s_input,
.vidioc_s_std = saa7134_s_std,
.vidioc_g_std = saa7134_g_std,
.vidioc_log_status = v4l2_ctrl_log_status,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
/* ----------------------------------------------------------- */
@ -501,9 +294,26 @@ static void empress_signal_change(struct saa7134_dev *dev)
schedule_work(&dev->empress_workqueue);
}
static bool empress_ctrl_filter(const struct v4l2_ctrl *ctrl)
{
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
case V4L2_CID_HUE:
case V4L2_CID_CONTRAST:
case V4L2_CID_SATURATION:
case V4L2_CID_AUDIO_MUTE:
case V4L2_CID_AUDIO_VOLUME:
case V4L2_CID_PRIVATE_INVERT:
case V4L2_CID_PRIVATE_AUTOMUTE:
return true;
default:
return false;
}
}
static int empress_init(struct saa7134_dev *dev)
{
struct v4l2_ctrl_handler *hdl = &dev->empress_ctrl_handler;
int err;
dprintk("%s: %s\n",dev->name,__func__);
@ -516,6 +326,16 @@ static int empress_init(struct saa7134_dev *dev)
snprintf(dev->empress_dev->name, sizeof(dev->empress_dev->name),
"%s empress (%s)", dev->name,
saa7134_boards[dev->board].name);
set_bit(V4L2_FL_USE_FH_PRIO, &dev->empress_dev->flags);
v4l2_ctrl_handler_init(hdl, 21);
v4l2_ctrl_add_handler(hdl, &dev->ctrl_handler, empress_ctrl_filter);
if (dev->empress_sd)
v4l2_ctrl_add_handler(hdl, dev->empress_sd->ctrl_handler, NULL);
if (hdl->error) {
video_device_release(dev->empress_dev);
return hdl->error;
}
dev->empress_dev->ctrl_handler = hdl;
INIT_WORK(&dev->empress_workqueue, empress_signal_update);
@ -551,6 +371,7 @@ static int empress_fini(struct saa7134_dev *dev)
return 0;
flush_work(&dev->empress_workqueue);
video_unregister_device(dev->empress_dev);
v4l2_ctrl_handler_free(&dev->empress_ctrl_handler);
dev->empress_dev = NULL;
return 0;
}

View File

@ -117,8 +117,7 @@ static int buffer_prepare(struct videobuf_queue *q,
struct videobuf_buffer *vb,
enum v4l2_field field)
{
struct saa7134_fh *fh = q->priv_data;
struct saa7134_dev *dev = fh->dev;
struct saa7134_dev *dev = q->priv_data;
struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
struct saa7134_tvnorm *norm = dev->tvnorm;
unsigned int lines, llength, size;
@ -141,7 +140,7 @@ static int buffer_prepare(struct videobuf_queue *q,
buf->vb.width = llength;
buf->vb.height = lines;
buf->vb.size = size;
buf->pt = &fh->pt_vbi;
buf->pt = &dev->pt_vbi;
err = videobuf_iolock(q,&buf->vb,NULL);
if (err)
@ -166,8 +165,7 @@ static int buffer_prepare(struct videobuf_queue *q,
static int
buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
{
struct saa7134_fh *fh = q->priv_data;
struct saa7134_dev *dev = fh->dev;
struct saa7134_dev *dev = q->priv_data;
int llength,lines;
lines = dev->tvnorm->vbi_v_stop_0 - dev->tvnorm->vbi_v_start_0 +1;
@ -181,8 +179,7 @@ buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
{
struct saa7134_fh *fh = q->priv_data;
struct saa7134_dev *dev = fh->dev;
struct saa7134_dev *dev = q->priv_data;
struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
saa7134_buffer_queue(dev,&dev->vbi_q,buf);

File diff suppressed because it is too large Load Diff

View File

@ -37,6 +37,7 @@
#include <media/v4l2-ioctl.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-ctrls.h>
#include <media/tuner.h>
#include <media/rc-core.h>
#include <media/ir-kbd-i2c.h>
@ -410,12 +411,18 @@ struct saa7134_board {
#define card(dev) (saa7134_boards[dev->board])
#define card_in(dev,n) (saa7134_boards[dev->board].inputs[n])
#define V4L2_CID_PRIVATE_INVERT (V4L2_CID_USER_SAA7134_BASE + 0)
#define V4L2_CID_PRIVATE_Y_ODD (V4L2_CID_USER_SAA7134_BASE + 1)
#define V4L2_CID_PRIVATE_Y_EVEN (V4L2_CID_USER_SAA7134_BASE + 2)
#define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_USER_SAA7134_BASE + 3)
/* ----------------------------------------------------------- */
/* device / file handle status */
#define RESOURCE_OVERLAY 1
#define RESOURCE_VIDEO 2
#define RESOURCE_VBI 4
#define RESOURCE_EMPRESS 8
#define INTERLACE_AUTO 0
#define INTERLACE_ON 1
@ -470,16 +477,8 @@ struct saa7134_dmaqueue {
/* video filehandle status */
struct saa7134_fh {
struct v4l2_fh fh;
struct saa7134_dev *dev;
bool is_empress;
unsigned int resources;
/* video capture */
struct videobuf_queue cap;
struct saa7134_pgtable pt_cap;
/* vbi capture */
struct videobuf_queue vbi;
struct saa7134_pgtable pt_vbi;
};
/* dmasound dsp status */
@ -589,7 +588,11 @@ struct saa7134_dev {
/* video+ts+vbi capture */
struct saa7134_dmaqueue video_q;
struct videobuf_queue cap;
struct saa7134_pgtable pt_cap;
struct saa7134_dmaqueue vbi_q;
struct videobuf_queue vbi;
struct saa7134_pgtable pt_vbi;
unsigned int video_fieldcount;
unsigned int vbi_fieldcount;
struct saa7134_format *fmt;
@ -599,6 +602,7 @@ struct saa7134_dev {
/* various v4l controls */
struct saa7134_tvnorm *tvnorm; /* video */
struct saa7134_tvaudio *tvaudio;
struct v4l2_ctrl_handler ctrl_handler;
unsigned int ctl_input;
int ctl_bright;
int ctl_contrast;
@ -626,6 +630,7 @@ struct saa7134_dev {
int last_carrier;
int nosignal;
unsigned int insuspend;
struct v4l2_ctrl_handler radio_ctrl_handler;
/* I2C keyboard data */
struct IR_i2c_init_data init_data;
@ -638,10 +643,11 @@ struct saa7134_dev {
/* SAA7134_MPEG_EMPRESS only */
struct video_device *empress_dev;
struct v4l2_subdev *empress_sd;
struct videobuf_queue empress_tsq;
atomic_t empress_users;
struct work_struct empress_workqueue;
int empress_started;
struct v4l2_ctrl_handler empress_ctrl_handler;
#if IS_ENABLED(CONFIG_VIDEO_SAA7134_DVB)
/* SAA7134_MPEG_DVB only */
@ -699,6 +705,16 @@ struct saa7134_dev {
_rc; \
})
static inline int res_check(struct saa7134_fh *fh, unsigned int bit)
{
return fh->resources & bit;
}
static inline int res_locked(struct saa7134_dev *dev, unsigned int bit)
{
return dev->resources & bit;
}
/* ----------------------------------------------------------- */
/* saa7134-core.c */
@ -761,10 +777,31 @@ extern unsigned int video_debug;
extern struct video_device saa7134_video_template;
extern struct video_device saa7134_radio_template;
int saa7134_s_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c);
int saa7134_g_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c);
int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c);
int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_std_id id);
int saa7134_s_std(struct file *file, void *priv, v4l2_std_id id);
int saa7134_g_std(struct file *file, void *priv, v4l2_std_id *id);
int saa7134_enum_input(struct file *file, void *priv, struct v4l2_input *i);
int saa7134_g_input(struct file *file, void *priv, unsigned int *i);
int saa7134_s_input(struct file *file, void *priv, unsigned int i);
int saa7134_querycap(struct file *file, void *priv,
struct v4l2_capability *cap);
int saa7134_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *t);
int saa7134_s_tuner(struct file *file, void *priv,
const struct v4l2_tuner *t);
int saa7134_g_frequency(struct file *file, void *priv,
struct v4l2_frequency *f);
int saa7134_s_frequency(struct file *file, void *priv,
const struct v4l2_frequency *f);
int saa7134_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *p);
int saa7134_querybuf(struct file *file, void *priv,
struct v4l2_buffer *b);
int saa7134_qbuf(struct file *file, void *priv, struct v4l2_buffer *b);
int saa7134_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b);
int saa7134_streamon(struct file *file, void *priv,
enum v4l2_buf_type type);
int saa7134_streamoff(struct file *file, void *priv,
enum v4l2_buf_type type);
int saa7134_videoport_init(struct saa7134_dev *dev);
void saa7134_set_tvnorm_hw(struct saa7134_dev *dev);
@ -773,6 +810,7 @@ int saa7134_video_init1(struct saa7134_dev *dev);
int saa7134_video_init2(struct saa7134_dev *dev);
void saa7134_irq_video_signalchange(struct saa7134_dev *dev);
void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status);
void saa7134_video_fini(struct saa7134_dev *dev);
/* ----------------------------------------------------------- */

View File

@ -1303,7 +1303,7 @@ static int sta2x11_vip_resume(struct pci_dev *pdev)
#endif
static DEFINE_PCI_DEVICE_TABLE(sta2x11_vip_pci_tbl) = {
static const struct pci_device_id sta2x11_vip_pci_tbl[] = {
{PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_VIP)},
{0,}
};

View File

@ -36,7 +36,8 @@ source "drivers/media/platform/blackfin/Kconfig"
config VIDEO_SH_VOU
tristate "SuperH VOU video output driver"
depends on MEDIA_CAMERA_SUPPORT
depends on VIDEO_DEV && ARCH_SHMOBILE && I2C
depends on VIDEO_DEV && I2C
depends on ARCH_SHMOBILE || COMPILE_TEST
select VIDEOBUF_DMA_CONTIG
help
Support for the Video Output Unit (VOU) on SuperH SoCs.
@ -90,13 +91,6 @@ config VIDEO_M32R_AR_M64278
To compile this driver as a module, choose M here: the
module will be called arv.
config VIDEO_OMAP2
tristate "OMAP2 Camera Capture Interface driver"
depends on VIDEO_DEV && ARCH_OMAP2 && VIDEO_V4L2_INT_DEVICE
select VIDEOBUF_DMA_SG
---help---
This is a v4l2 driver for the TI OMAP2 camera capture interface
config VIDEO_OMAP3
tristate "OMAP 3 Camera support"
depends on OMAP_IOVMM && VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3

View File

@ -2,8 +2,6 @@
# Makefile for the video capture/playback device drivers.
#
omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o
obj-$(CONFIG_VIDEO_VINO) += indycam.o
obj-$(CONFIG_VIDEO_VINO) += vino.o
@ -14,7 +12,6 @@ obj-$(CONFIG_VIDEO_VIA_CAMERA) += via-camera.o
obj-$(CONFIG_VIDEO_CAFE_CCIC) += marvell-ccic/
obj-$(CONFIG_VIDEO_MMP_CAMERA) += marvell-ccic/
obj-$(CONFIG_VIDEO_OMAP2) += omap2cam.o
obj-$(CONFIG_VIDEO_OMAP3) += omap3isp/
obj-$(CONFIG_VIDEO_VIU) += fsl-viu.o

View File

@ -347,7 +347,7 @@ static int vpbe_start_streaming(struct vb2_queue *vq, unsigned int count)
/* If buffer queue is empty, return error */
if (list_empty(&layer->dma_queue)) {
v4l2_err(&vpbe_dev->v4l2_dev, "buffer queue is empty\n");
return -EINVAL;
return -ENOBUFS;
}
/* Get the next frame from the buffer queue */
layer->next_frm = layer->cur_frm = list_entry(layer->dma_queue.next,

View File

@ -277,7 +277,7 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count)
if (list_empty(&common->dma_queue)) {
spin_unlock_irqrestore(&common->irqlock, flags);
vpif_dbg(1, debug, "buffer queue is empty\n");
return -EIO;
return -ENOBUFS;
}
/* Get the next frame from the buffer queue */

View File

@ -239,7 +239,7 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count)
if (list_empty(&common->dma_queue)) {
spin_unlock_irqrestore(&common->irqlock, flags);
vpif_err("buffer queue is empty\n");
return -EIO;
return -ENOBUFS;
}
/* Get the next frame from the buffer queue */

View File

@ -1,7 +1,7 @@
config VIDEO_SAMSUNG_EXYNOS4_IS
bool "Samsung S5P/EXYNOS4 SoC series Camera Subsystem driver"
depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && PM_RUNTIME
depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
depends on (PLAT_S5P || ARCH_EXYNOS)
help
Say Y here to enable camera host interface devices for

View File

@ -549,7 +549,7 @@ static int fimc_capture_release(struct file *file)
vc->streaming = false;
}
ret = vb2_fop_release(file);
ret = _vb2_fop_release(file, NULL);
if (close) {
clear_bit(ST_CAPT_BUSY, &fimc->state);

View File

@ -998,36 +998,39 @@ static int fimc_probe(struct platform_device *pdev)
ret = devm_request_irq(dev, res->start, fimc_irq_handler,
0, dev_name(dev), fimc);
if (ret) {
if (ret < 0) {
dev_err(dev, "failed to install irq (%d)\n", ret);
goto err_clk;
goto err_sclk;
}
ret = fimc_initialize_capture_subdev(fimc);
if (ret)
goto err_clk;
if (ret < 0)
goto err_sclk;
platform_set_drvdata(pdev, fimc);
pm_runtime_enable(dev);
ret = pm_runtime_get_sync(dev);
if (ret < 0)
goto err_sd;
if (!pm_runtime_enabled(dev)) {
ret = clk_enable(fimc->clock[CLK_GATE]);
if (ret < 0)
goto err_sd;
}
/* Initialize contiguous memory allocator */
fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev);
if (IS_ERR(fimc->alloc_ctx)) {
ret = PTR_ERR(fimc->alloc_ctx);
goto err_pm;
goto err_gclk;
}
dev_dbg(dev, "FIMC.%d registered successfully\n", fimc->id);
pm_runtime_put(dev);
return 0;
err_pm:
pm_runtime_put(dev);
err_gclk:
clk_disable(fimc->clock[CLK_GATE]);
err_sd:
fimc_unregister_capture_subdev(fimc);
err_clk:
err_sclk:
clk_disable(fimc->clock[CLK_BUS]);
fimc_clk_put(fimc);
return ret;

View File

@ -481,7 +481,6 @@ struct fimc_ctrls {
* @flags: additional flags for image conversion
* @state: flags to keep track of user configuration
* @fimc_dev: the FIMC device this context applies to
* @m2m_ctx: memory-to-memory device context
* @fh: v4l2 file handle
* @ctrls: v4l2 controls structure
*/
@ -502,7 +501,6 @@ struct fimc_ctx {
u32 flags;
u32 state;
struct fimc_dev *fimc_dev;
struct v4l2_m2m_ctx *m2m_ctx;
struct v4l2_fh fh;
struct fimc_ctrls ctrls;
};

View File

@ -33,47 +33,23 @@ void fimc_is_hw_set_intgr0_gd0(struct fimc_is *is)
mcuctl_write(INTGR0_INTGD(0), is, MCUCTL_REG_INTGR0);
}
int fimc_is_hw_wait_intsr0_intsd0(struct fimc_is *is)
{
unsigned int timeout = 2000;
u32 cfg, status;
cfg = mcuctl_read(is, MCUCTL_REG_INTSR0);
status = INTSR0_GET_INTSD(0, cfg);
while (status) {
cfg = mcuctl_read(is, MCUCTL_REG_INTSR0);
status = INTSR0_GET_INTSD(0, cfg);
if (timeout == 0) {
dev_warn(&is->pdev->dev, "%s timeout\n",
__func__);
return -ETIME;
}
timeout--;
udelay(1);
}
return 0;
}
int fimc_is_hw_wait_intmsr0_intmsd0(struct fimc_is *is)
{
unsigned int timeout = 2000;
u32 cfg, status;
cfg = mcuctl_read(is, MCUCTL_REG_INTMSR0);
status = INTMSR0_GET_INTMSD(0, cfg);
while (status) {
do {
cfg = mcuctl_read(is, MCUCTL_REG_INTMSR0);
status = INTMSR0_GET_INTMSD(0, cfg);
if (timeout == 0) {
if (--timeout == 0) {
dev_warn(&is->pdev->dev, "%s timeout\n",
__func__);
return -ETIME;
return -ETIMEDOUT;
}
timeout--;
udelay(1);
}
} while (status != 0);
return 0;
}

View File

@ -145,7 +145,6 @@ void fimc_is_fw_clear_irq2(struct fimc_is *is);
int fimc_is_hw_get_params(struct fimc_is *is, unsigned int num);
void fimc_is_hw_set_intgr0_gd0(struct fimc_is *is);
int fimc_is_hw_wait_intsr0_intsd0(struct fimc_is *is);
int fimc_is_hw_wait_intmsr0_intmsd0(struct fimc_is *is);
void fimc_is_hw_set_sensor_num(struct fimc_is *is);
void fimc_is_hw_stream_on(struct fimc_is *is);

View File

@ -781,6 +781,9 @@ static int fimc_is_debugfs_create(struct fimc_is *is)
return is->debugfs_entry == NULL ? -EIO : 0;
}
static int fimc_is_runtime_resume(struct device *dev);
static int fimc_is_runtime_suspend(struct device *dev);
static int fimc_is_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@ -835,14 +838,20 @@ static int fimc_is_probe(struct platform_device *pdev)
}
pm_runtime_enable(dev);
if (!pm_runtime_enabled(dev)) {
ret = fimc_is_runtime_resume(dev);
if (ret < 0)
goto err_irq;
}
ret = pm_runtime_get_sync(dev);
if (ret < 0)
goto err_irq;
goto err_pm;
is->alloc_ctx = vb2_dma_contig_init_ctx(dev);
if (IS_ERR(is->alloc_ctx)) {
ret = PTR_ERR(is->alloc_ctx);
goto err_irq;
goto err_pm;
}
/*
* Register FIMC-IS V4L2 subdevs to this driver. The video nodes
@ -867,10 +876,13 @@ static int fimc_is_probe(struct platform_device *pdev)
err_dfs:
fimc_is_debugfs_remove(is);
err_vb:
vb2_dma_contig_cleanup_ctx(is->alloc_ctx);
err_sd:
fimc_is_unregister_subdevs(is);
err_vb:
vb2_dma_contig_cleanup_ctx(is->alloc_ctx);
err_pm:
if (!pm_runtime_enabled(dev))
fimc_is_runtime_suspend(dev);
err_irq:
free_irq(is->irq, is);
err_clk:
@ -919,10 +931,13 @@ static int fimc_is_suspend(struct device *dev)
static int fimc_is_remove(struct platform_device *pdev)
{
struct fimc_is *is = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev;
struct fimc_is *is = dev_get_drvdata(dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);
if (!pm_runtime_status_suspended(dev))
fimc_is_runtime_suspend(dev);
free_irq(is->irq, is);
fimc_is_unregister_subdevs(is);
vb2_dma_contig_cleanup_ctx(is->alloc_ctx);

View File

@ -133,7 +133,7 @@ void flite_hw_set_source_format(struct fimc_lite *dev, struct flite_frame *f)
int i = ARRAY_SIZE(src_pixfmt_map);
u32 cfg;
while (--i >= 0) {
while (--i) {
if (src_pixfmt_map[i][0] == pixelcode)
break;
}
@ -240,7 +240,7 @@ static void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f)
u32 cfg = readl(dev->regs + FLITE_REG_CIODMAFMT);
int i = ARRAY_SIZE(pixcode);
while (--i >= 0)
while (--i)
if (pixcode[i][0] == f->fmt->mbus_code)
break;
cfg &= ~FLITE_REG_CIODMAFMT_YCBCR_ORDER_MASK;

View File

@ -546,7 +546,7 @@ static int fimc_lite_release(struct file *file)
mutex_unlock(&entity->parent->graph_mutex);
}
vb2_fop_release(file);
_vb2_fop_release(file, NULL);
pm_runtime_put(&fimc->pdev->dev);
clear_bit(ST_FLITE_SUSPENDED, &fimc->state);
@ -1549,38 +1549,40 @@ static int fimc_lite_probe(struct platform_device *pdev)
0, dev_name(dev), fimc);
if (ret) {
dev_err(dev, "Failed to install irq (%d)\n", ret);
goto err_clk;
goto err_clk_put;
}
/* The video node will be created within the subdev's registered() op */
ret = fimc_lite_create_capture_subdev(fimc);
if (ret)
goto err_clk;
goto err_clk_put;
platform_set_drvdata(pdev, fimc);
pm_runtime_enable(dev);
ret = pm_runtime_get_sync(dev);
if (ret < 0)
goto err_sd;
if (!pm_runtime_enabled(dev)) {
ret = clk_enable(fimc->clock);
if (ret < 0)
goto err_clk_put;
}
fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev);
if (IS_ERR(fimc->alloc_ctx)) {
ret = PTR_ERR(fimc->alloc_ctx);
goto err_pm;
goto err_clk_dis;
}
pm_runtime_put(dev);
fimc_lite_set_default_config(fimc);
dev_dbg(dev, "FIMC-LITE.%d registered successfully\n",
fimc->index);
return 0;
err_pm:
pm_runtime_put(dev);
err_clk_dis:
clk_disable(fimc->clock);
err_sd:
fimc_lite_unregister_capture_subdev(fimc);
err_clk:
err_clk_put:
fimc_lite_clk_put(fimc);
return ret;
}

View File

@ -44,17 +44,17 @@ void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state)
{
struct vb2_buffer *src_vb, *dst_vb;
if (!ctx || !ctx->m2m_ctx)
if (!ctx || !ctx->fh.m2m_ctx)
return;
src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
src_vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
dst_vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
if (src_vb && dst_vb) {
v4l2_m2m_buf_done(src_vb, vb_state);
v4l2_m2m_buf_done(dst_vb, vb_state);
v4l2_m2m_job_finish(ctx->fimc_dev->m2m.m2m_dev,
ctx->m2m_ctx);
ctx->fh.m2m_ctx);
}
}
@ -123,12 +123,12 @@ static void fimc_device_run(void *priv)
fimc_prepare_dma_offset(ctx, df);
}
src_vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
src_vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
ret = fimc_prepare_addr(ctx, src_vb, sf, &sf->paddr);
if (ret)
goto dma_unlock;
dst_vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
dst_vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
ret = fimc_prepare_addr(ctx, dst_vb, df, &df->paddr);
if (ret)
goto dma_unlock;
@ -219,31 +219,15 @@ static int fimc_buf_prepare(struct vb2_buffer *vb)
static void fimc_buf_queue(struct vb2_buffer *vb)
{
struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
dbg("ctx: %p, ctx->state: 0x%x", ctx, ctx->state);
if (ctx->m2m_ctx)
v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
}
static void fimc_lock(struct vb2_queue *vq)
{
struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
mutex_lock(&ctx->fimc_dev->lock);
}
static void fimc_unlock(struct vb2_queue *vq)
{
struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
mutex_unlock(&ctx->fimc_dev->lock);
v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
}
static struct vb2_ops fimc_qops = {
.queue_setup = fimc_queue_setup,
.buf_prepare = fimc_buf_prepare,
.buf_queue = fimc_buf_queue,
.wait_prepare = fimc_unlock,
.wait_finish = fimc_lock,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
.stop_streaming = stop_streaming,
.start_streaming = start_streaming,
};
@ -385,7 +369,7 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh,
if (ret)
return ret;
vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
if (vb2_is_busy(vq)) {
v4l2_err(&fimc->m2m.vfd, "queue (%d) busy\n", f->type);
@ -410,56 +394,6 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh,
return 0;
}
static int fimc_m2m_reqbufs(struct file *file, void *fh,
struct v4l2_requestbuffers *reqbufs)
{
struct fimc_ctx *ctx = fh_to_ctx(fh);
return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
}
static int fimc_m2m_querybuf(struct file *file, void *fh,
struct v4l2_buffer *buf)
{
struct fimc_ctx *ctx = fh_to_ctx(fh);
return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
}
static int fimc_m2m_qbuf(struct file *file, void *fh,
struct v4l2_buffer *buf)
{
struct fimc_ctx *ctx = fh_to_ctx(fh);
return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
}
static int fimc_m2m_dqbuf(struct file *file, void *fh,
struct v4l2_buffer *buf)
{
struct fimc_ctx *ctx = fh_to_ctx(fh);
return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
}
static int fimc_m2m_expbuf(struct file *file, void *fh,
struct v4l2_exportbuffer *eb)
{
struct fimc_ctx *ctx = fh_to_ctx(fh);
return v4l2_m2m_expbuf(file, ctx->m2m_ctx, eb);
}
static int fimc_m2m_streamon(struct file *file, void *fh,
enum v4l2_buf_type type)
{
struct fimc_ctx *ctx = fh_to_ctx(fh);
return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
}
static int fimc_m2m_streamoff(struct file *file, void *fh,
enum v4l2_buf_type type)
{
struct fimc_ctx *ctx = fh_to_ctx(fh);
return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
}
static int fimc_m2m_cropcap(struct file *file, void *fh,
struct v4l2_cropcap *cr)
{
@ -598,13 +532,13 @@ static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = {
.vidioc_try_fmt_vid_out_mplane = fimc_m2m_try_fmt_mplane,
.vidioc_s_fmt_vid_cap_mplane = fimc_m2m_s_fmt_mplane,
.vidioc_s_fmt_vid_out_mplane = fimc_m2m_s_fmt_mplane,
.vidioc_reqbufs = fimc_m2m_reqbufs,
.vidioc_querybuf = fimc_m2m_querybuf,
.vidioc_qbuf = fimc_m2m_qbuf,
.vidioc_dqbuf = fimc_m2m_dqbuf,
.vidioc_expbuf = fimc_m2m_expbuf,
.vidioc_streamon = fimc_m2m_streamon,
.vidioc_streamoff = fimc_m2m_streamoff,
.vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
.vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
.vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
.vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
.vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
.vidioc_streamon = v4l2_m2m_ioctl_streamon,
.vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
.vidioc_g_crop = fimc_m2m_g_crop,
.vidioc_s_crop = fimc_m2m_s_crop,
.vidioc_cropcap = fimc_m2m_cropcap
@ -624,6 +558,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
src_vq->mem_ops = &vb2_dma_contig_memops;
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
src_vq->lock = &ctx->fimc_dev->lock;
ret = vb2_queue_init(src_vq);
if (ret)
@ -636,6 +571,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->mem_ops = &vb2_dma_contig_memops;
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
dst_vq->lock = &ctx->fimc_dev->lock;
return vb2_queue_init(dst_vq);
}
@ -708,9 +644,9 @@ static int fimc_m2m_open(struct file *file)
ctx->out_path = FIMC_IO_DMA;
ctx->scaler.enabled = 1;
ctx->m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init);
if (IS_ERR(ctx->m2m_ctx)) {
ret = PTR_ERR(ctx->m2m_ctx);
ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init);
if (IS_ERR(ctx->fh.m2m_ctx)) {
ret = PTR_ERR(ctx->fh.m2m_ctx);
goto error_c;
}
@ -725,7 +661,7 @@ static int fimc_m2m_open(struct file *file)
return 0;
error_m2m_ctx:
v4l2_m2m_ctx_release(ctx->m2m_ctx);
v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
error_c:
fimc_ctrls_delete(ctx);
error_fh:
@ -747,7 +683,7 @@ static int fimc_m2m_release(struct file *file)
mutex_lock(&fimc->lock);
v4l2_m2m_ctx_release(ctx->m2m_ctx);
v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
fimc_ctrls_delete(ctx);
v4l2_fh_del(&ctx->fh);
v4l2_fh_exit(&ctx->fh);
@ -760,45 +696,13 @@ static int fimc_m2m_release(struct file *file)
return 0;
}
static unsigned int fimc_m2m_poll(struct file *file,
struct poll_table_struct *wait)
{
struct fimc_ctx *ctx = fh_to_ctx(file->private_data);
struct fimc_dev *fimc = ctx->fimc_dev;
int ret;
if (mutex_lock_interruptible(&fimc->lock))
return -ERESTARTSYS;
ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
mutex_unlock(&fimc->lock);
return ret;
}
static int fimc_m2m_mmap(struct file *file, struct vm_area_struct *vma)
{
struct fimc_ctx *ctx = fh_to_ctx(file->private_data);
struct fimc_dev *fimc = ctx->fimc_dev;
int ret;
if (mutex_lock_interruptible(&fimc->lock))
return -ERESTARTSYS;
ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
mutex_unlock(&fimc->lock);
return ret;
}
static const struct v4l2_file_operations fimc_m2m_fops = {
.owner = THIS_MODULE,
.open = fimc_m2m_open,
.release = fimc_m2m_release,
.poll = fimc_m2m_poll,
.poll = v4l2_m2m_fop_poll,
.unlocked_ioctl = video_ioctl2,
.mmap = fimc_m2m_mmap,
.mmap = v4l2_m2m_fop_mmap,
};
static struct v4l2_m2m_ops m2m_ops = {

View File

@ -91,7 +91,7 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
#define S5PCSIS_INTSRC_ODD_BEFORE (1 << 29)
#define S5PCSIS_INTSRC_ODD_AFTER (1 << 28)
#define S5PCSIS_INTSRC_ODD (0x3 << 28)
#define S5PCSIS_INTSRC_NON_IMAGE_DATA (0xff << 28)
#define S5PCSIS_INTSRC_NON_IMAGE_DATA (0xf << 28)
#define S5PCSIS_INTSRC_FRAME_START (1 << 27)
#define S5PCSIS_INTSRC_FRAME_END (1 << 26)
#define S5PCSIS_INTSRC_ERR_SOT_HS (0xf << 12)
@ -790,6 +790,7 @@ static int s5pcsis_parse_dt(struct platform_device *pdev,
#define s5pcsis_parse_dt(pdev, state) (-ENOSYS)
#endif
static int s5pcsis_pm_resume(struct device *dev, bool runtime);
static const struct of_device_id s5pcsis_of_match[];
static int s5pcsis_probe(struct platform_device *pdev)
@ -902,13 +903,21 @@ static int s5pcsis_probe(struct platform_device *pdev)
/* .. and a pointer to the subdev. */
platform_set_drvdata(pdev, &state->sd);
memcpy(state->events, s5pcsis_events, sizeof(state->events));
pm_runtime_enable(dev);
if (!pm_runtime_enabled(dev)) {
ret = s5pcsis_pm_resume(dev, true);
if (ret < 0)
goto e_m_ent;
}
dev_info(&pdev->dev, "lanes: %d, hs_settle: %d, wclk: %d, freq: %u\n",
state->num_lanes, state->hs_settle, state->wclk_ext,
state->clk_frequency);
return 0;
e_m_ent:
media_entity_cleanup(&state->sd.entity);
e_clkdis:
clk_disable(state->clock[CSIS_CLK_MUX]);
e_clkput:
@ -1014,7 +1023,7 @@ static int s5pcsis_remove(struct platform_device *pdev)
struct csis_state *state = sd_to_csis_state(sd);
pm_runtime_disable(&pdev->dev);
s5pcsis_pm_suspend(&pdev->dev, false);
s5pcsis_pm_suspend(&pdev->dev, true);
clk_disable(state->clock[CSIS_CLK_MUX]);
pm_runtime_set_suspended(&pdev->dev);
s5pcsis_clk_put(state);

View File

@ -918,7 +918,7 @@ static int deinterlace_open(struct file *file)
return ret;
}
ctx->xt = kzalloc(sizeof(struct dma_async_tx_descriptor) +
ctx->xt = kzalloc(sizeof(struct dma_interleaved_template) +
sizeof(struct data_chunk), GFP_KERNEL);
if (!ctx->xt) {
kfree(ctx);

View File

@ -177,8 +177,6 @@ struct m2mtest_ctx {
enum v4l2_colorspace colorspace;
struct v4l2_m2m_ctx *m2m_ctx;
/* Source and destination queue data */
struct m2mtest_q_data q_data[2];
};
@ -342,8 +340,8 @@ static int job_ready(void *priv)
{
struct m2mtest_ctx *ctx = priv;
if (v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) < ctx->translen
|| v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < ctx->translen) {
if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) < ctx->translen
|| v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) < ctx->translen) {
dprintk(ctx->dev, "Not enough buffers available\n");
return 0;
}
@ -359,21 +357,6 @@ static void job_abort(void *priv)
ctx->aborting = 1;
}
static void m2mtest_lock(void *priv)
{
struct m2mtest_ctx *ctx = priv;
struct m2mtest_dev *dev = ctx->dev;
mutex_lock(&dev->dev_mutex);
}
static void m2mtest_unlock(void *priv)
{
struct m2mtest_ctx *ctx = priv;
struct m2mtest_dev *dev = ctx->dev;
mutex_unlock(&dev->dev_mutex);
}
/* device_run() - prepares and starts the device
*
* This simulates all the immediate preparations required before starting
@ -386,8 +369,8 @@ static void device_run(void *priv)
struct m2mtest_dev *dev = ctx->dev;
struct vb2_buffer *src_buf, *dst_buf;
src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
device_process(ctx, src_buf, dst_buf);
@ -409,8 +392,8 @@ static void device_isr(unsigned long priv)
return;
}
src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
curr_ctx->num_processed++;
@ -423,7 +406,7 @@ static void device_isr(unsigned long priv)
|| curr_ctx->aborting) {
dprintk(curr_ctx->dev, "Finishing transaction\n");
curr_ctx->num_processed = 0;
v4l2_m2m_job_finish(m2mtest_dev->m2m_dev, curr_ctx->m2m_ctx);
v4l2_m2m_job_finish(m2mtest_dev->m2m_dev, curr_ctx->fh.m2m_ctx);
} else {
device_run(curr_ctx);
}
@ -491,7 +474,7 @@ static int vidioc_g_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f)
struct vb2_queue *vq;
struct m2mtest_q_data *q_data;
vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
if (!vq)
return -EINVAL;
@ -594,7 +577,7 @@ static int vidioc_s_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f)
struct m2mtest_q_data *q_data;
struct vb2_queue *vq;
vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
if (!vq)
return -EINVAL;
@ -648,52 +631,6 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
return ret;
}
static int vidioc_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *reqbufs)
{
struct m2mtest_ctx *ctx = file2ctx(file);
return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
}
static int vidioc_querybuf(struct file *file, void *priv,
struct v4l2_buffer *buf)
{
struct m2mtest_ctx *ctx = file2ctx(file);
return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
}
static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
{
struct m2mtest_ctx *ctx = file2ctx(file);
return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
}
static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
{
struct m2mtest_ctx *ctx = file2ctx(file);
return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
}
static int vidioc_streamon(struct file *file, void *priv,
enum v4l2_buf_type type)
{
struct m2mtest_ctx *ctx = file2ctx(file);
return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
}
static int vidioc_streamoff(struct file *file, void *priv,
enum v4l2_buf_type type)
{
struct m2mtest_ctx *ctx = file2ctx(file);
return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
}
static int m2mtest_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct m2mtest_ctx *ctx =
@ -748,14 +685,14 @@ static const struct v4l2_ioctl_ops m2mtest_ioctl_ops = {
.vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
.vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
.vidioc_reqbufs = vidioc_reqbufs,
.vidioc_querybuf = vidioc_querybuf,
.vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
.vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
.vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
.vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
.vidioc_qbuf = vidioc_qbuf,
.vidioc_dqbuf = vidioc_dqbuf,
.vidioc_streamon = v4l2_m2m_ioctl_streamon,
.vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
@ -818,27 +755,15 @@ static int m2mtest_buf_prepare(struct vb2_buffer *vb)
static void m2mtest_buf_queue(struct vb2_buffer *vb)
{
struct m2mtest_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
}
static void m2mtest_wait_prepare(struct vb2_queue *q)
{
struct m2mtest_ctx *ctx = vb2_get_drv_priv(q);
m2mtest_unlock(ctx);
}
static void m2mtest_wait_finish(struct vb2_queue *q)
{
struct m2mtest_ctx *ctx = vb2_get_drv_priv(q);
m2mtest_lock(ctx);
v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
}
static struct vb2_ops m2mtest_qops = {
.queue_setup = m2mtest_queue_setup,
.buf_prepare = m2mtest_buf_prepare,
.buf_queue = m2mtest_buf_queue,
.wait_prepare = m2mtest_wait_prepare,
.wait_finish = m2mtest_wait_finish,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
};
static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
@ -853,6 +778,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *ds
src_vq->ops = &m2mtest_qops;
src_vq->mem_ops = &vb2_vmalloc_memops;
src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
src_vq->lock = &ctx->dev->dev_mutex;
ret = vb2_queue_init(src_vq);
if (ret)
@ -865,6 +791,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *ds
dst_vq->ops = &m2mtest_qops;
dst_vq->mem_ops = &vb2_vmalloc_memops;
dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
dst_vq->lock = &ctx->dev->dev_mutex;
return vb2_queue_init(dst_vq);
}
@ -936,10 +863,10 @@ static int m2mtest_open(struct file *file)
ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC];
ctx->colorspace = V4L2_COLORSPACE_REC709;
ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
if (IS_ERR(ctx->m2m_ctx)) {
rc = PTR_ERR(ctx->m2m_ctx);
if (IS_ERR(ctx->fh.m2m_ctx)) {
rc = PTR_ERR(ctx->fh.m2m_ctx);
v4l2_ctrl_handler_free(hdl);
kfree(ctx);
@ -949,7 +876,8 @@ static int m2mtest_open(struct file *file)
v4l2_fh_add(&ctx->fh);
atomic_inc(&dev->num_inst);
dprintk(dev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx);
dprintk(dev, "Created instance: %p, m2m_ctx: %p\n",
ctx, ctx->fh.m2m_ctx);
open_unlock:
mutex_unlock(&dev->dev_mutex);
@ -967,7 +895,7 @@ static int m2mtest_release(struct file *file)
v4l2_fh_exit(&ctx->fh);
v4l2_ctrl_handler_free(&ctx->hdl);
mutex_lock(&dev->dev_mutex);
v4l2_m2m_ctx_release(ctx->m2m_ctx);
v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
mutex_unlock(&dev->dev_mutex);
kfree(ctx);
@ -976,34 +904,13 @@ static int m2mtest_release(struct file *file)
return 0;
}
static unsigned int m2mtest_poll(struct file *file,
struct poll_table_struct *wait)
{
struct m2mtest_ctx *ctx = file2ctx(file);
return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
}
static int m2mtest_mmap(struct file *file, struct vm_area_struct *vma)
{
struct m2mtest_dev *dev = video_drvdata(file);
struct m2mtest_ctx *ctx = file2ctx(file);
int res;
if (mutex_lock_interruptible(&dev->dev_mutex))
return -ERESTARTSYS;
res = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
mutex_unlock(&dev->dev_mutex);
return res;
}
static const struct v4l2_file_operations m2mtest_fops = {
.owner = THIS_MODULE,
.open = m2mtest_open,
.release = m2mtest_release,
.poll = m2mtest_poll,
.poll = v4l2_m2m_fop_poll,
.unlocked_ioctl = video_ioctl2,
.mmap = m2mtest_mmap,
.mmap = v4l2_m2m_fop_mmap,
};
static struct video_device m2mtest_videodev = {
@ -1019,8 +926,6 @@ static struct v4l2_m2m_ops m2m_ops = {
.device_run = device_run,
.job_ready = job_ready,
.job_abort = job_abort,
.lock = m2mtest_lock,
.unlock = m2mtest_unlock,
};
static int m2mtest_probe(struct platform_device *pdev)
@ -1133,4 +1038,3 @@ static int __init m2mtest_init(void)
module_init(m2mtest_init);
module_exit(m2mtest_exit);

View File

@ -873,15 +873,12 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe,
unsigned long flags;
int ret;
/* If the preview engine crashed it might not respond to read/write
* operations on the L4 bus. This would result in a bus fault and a
* kernel oops. Refuse to start streaming in that case. This check must
* be performed before the loop below to avoid starting entities if the
* pipeline won't start anyway (those entities would then likely fail to
* stop, making the problem worse).
/* Refuse to start streaming if an entity included in the pipeline has
* crashed. This check must be performed before the loop below to avoid
* starting entities if the pipeline won't start anyway (those entities
* would then likely fail to stop, making the problem worse).
*/
if ((pipe->entities & isp->crashed) &
(1U << isp->isp_prev.subdev.entity.id))
if (pipe->entities & isp->crashed)
return -EIO;
spin_lock_irqsave(&pipe->lock, flags);
@ -1014,13 +1011,23 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe)
else
ret = 0;
/* Handle stop failures. An entity that fails to stop can
* usually just be restarted. Flag the stop failure nonetheless
* to trigger an ISP reset the next time the device is released,
* just in case.
*
* The preview engine is a special case. A failure to stop can
* mean a hardware crash. When that happens the preview engine
* won't respond to read/write operations on the L4 bus anymore,
* resulting in a bus fault and a kernel oops next time it gets
* accessed. Mark it as crashed to prevent pipelines including
* it from being started.
*/
if (ret) {
dev_info(isp->dev, "Unable to stop %s\n", subdev->name);
/* If the entity failed to stopped, assume it has
* crashed. Mark it as such, the ISP will be reset when
* applications will release it.
*/
isp->crashed |= 1U << subdev->entity.id;
isp->stop_failure = true;
if (subdev == &isp->isp_prev.subdev)
isp->crashed |= 1U << subdev->entity.id;
failure = -ETIMEDOUT;
}
}
@ -1056,6 +1063,23 @@ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe,
return ret;
}
/*
* omap3isp_pipeline_cancel_stream - Cancel stream on a pipeline
* @pipe: ISP pipeline
*
* Cancelling a stream mark all buffers on all video nodes in the pipeline as
* erroneous and makes sure no new buffer can be queued. This function is called
* when a fatal error that prevents any further operation on the pipeline
* occurs.
*/
void omap3isp_pipeline_cancel_stream(struct isp_pipeline *pipe)
{
if (pipe->input)
omap3isp_video_cancel_stream(pipe->input);
if (pipe->output)
omap3isp_video_cancel_stream(pipe->output);
}
/*
* isp_pipeline_resume - Resume streaming on a pipeline
* @pipe: ISP pipeline
@ -1208,6 +1232,7 @@ static int isp_reset(struct isp_device *isp)
udelay(1);
}
isp->stop_failure = false;
isp->crashed = 0;
return 0;
}
@ -1619,7 +1644,7 @@ void omap3isp_put(struct isp_device *isp)
/* Reset the ISP if an entity has failed to stop. This is the
* only way to recover from such conditions.
*/
if (isp->crashed)
if (isp->crashed || isp->stop_failure)
isp_reset(isp);
isp_disable_clocks(isp);
}
@ -2130,28 +2155,13 @@ static int isp_map_mem_resource(struct platform_device *pdev,
/* request the mem region for the camera registers */
mem = platform_get_resource(pdev, IORESOURCE_MEM, res);
if (!mem) {
dev_err(isp->dev, "no mem resource?\n");
return -ENODEV;
}
if (!devm_request_mem_region(isp->dev, mem->start, resource_size(mem),
pdev->name)) {
dev_err(isp->dev,
"cannot reserve camera register I/O region\n");
return -ENODEV;
}
isp->mmio_base_phys[res] = mem->start;
isp->mmio_size[res] = resource_size(mem);
/* map the region */
isp->mmio_base[res] = devm_ioremap_nocache(isp->dev,
isp->mmio_base_phys[res],
isp->mmio_size[res]);
if (!isp->mmio_base[res]) {
dev_err(isp->dev, "cannot map camera register I/O region\n");
return -ENODEV;
}
isp->mmio_base[res] = devm_ioremap_resource(isp->dev, mem);
if (IS_ERR(isp->mmio_base[res]))
return PTR_ERR(isp->mmio_base[res]);
isp->mmio_base_phys[res] = mem->start;
return 0;
}

View File

@ -152,9 +152,9 @@ struct isp_xclk {
* regions.
* @mmio_base_phys: Array with physical L4 bus addresses for ISP register
* regions.
* @mmio_size: Array with ISP register regions size in bytes.
* @stat_lock: Spinlock for handling statistics
* @isp_mutex: Mutex for serializing requests to ISP.
* @stop_failure: Indicates that an entity failed to stop.
* @crashed: Bitmask of crashed entities (indexed by entity ID)
* @has_context: Context has been saved at least once and can be restored.
* @ref_count: Reference count for handling multiple ISP requests.
@ -188,11 +188,11 @@ struct isp_device {
void __iomem *mmio_base[OMAP3_ISP_IOMEM_LAST];
unsigned long mmio_base_phys[OMAP3_ISP_IOMEM_LAST];
resource_size_t mmio_size[OMAP3_ISP_IOMEM_LAST];
/* ISP Obj */
spinlock_t stat_lock; /* common lock for statistic drivers */
struct mutex isp_mutex; /* For handling ref_count field */
bool stop_failure;
u32 crashed;
int has_context;
int ref_count;
@ -238,6 +238,7 @@ int omap3isp_module_sync_is_stopping(wait_queue_head_t *wait,
int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe,
enum isp_pipeline_stream_state state);
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,

View File

@ -1516,6 +1516,8 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc)
if (ccdc_sbl_wait_idle(ccdc, 1000)) {
dev_info(isp->dev, "CCDC won't become idle!\n");
isp->crashed |= 1U << ccdc->subdev.entity.id;
omap3isp_pipeline_cancel_stream(pipe);
goto done;
}
@ -2484,7 +2486,8 @@ static int ccdc_init_entities(struct isp_ccdc_device *ccdc)
v4l2_set_subdevdata(sd, ccdc);
sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
pads[CCDC_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
pads[CCDC_PAD_SINK].flags = MEDIA_PAD_FL_SINK
| MEDIA_PAD_FL_MUST_CONNECT;
pads[CCDC_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE;
pads[CCDC_PAD_SOURCE_OF].flags = MEDIA_PAD_FL_SOURCE;

View File

@ -1076,7 +1076,8 @@ static int ccp2_init_entities(struct isp_ccp2_device *ccp2)
v4l2_set_subdevdata(sd, ccp2);
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
pads[CCP2_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
pads[CCP2_PAD_SINK].flags = MEDIA_PAD_FL_SINK
| MEDIA_PAD_FL_MUST_CONNECT;
pads[CCP2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
me->ops = &ccp2_media_ops;

View File

@ -1245,7 +1245,8 @@ static int csi2_init_entities(struct isp_csi2_device *csi2)
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
pads[CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
pads[CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
pads[CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK
| MEDIA_PAD_FL_MUST_CONNECT;
me->ops = &csi2_media_ops;
ret = media_entity_init(me, CSI2_PADS_NUM, pads, 0);

View File

@ -2283,7 +2283,8 @@ static int preview_init_entities(struct isp_prev_device *prev)
v4l2_ctrl_handler_setup(&prev->ctrls);
sd->ctrl_handler = &prev->ctrls;
pads[PREV_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
pads[PREV_PAD_SINK].flags = MEDIA_PAD_FL_SINK
| MEDIA_PAD_FL_MUST_CONNECT;
pads[PREV_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
me->ops = &preview_media_ops;

View File

@ -553,8 +553,10 @@ static void isp_video_buffer_query(struct isp_video_buffer *buf,
switch (buf->state) {
case ISP_BUF_STATE_ERROR:
vbuf->flags |= V4L2_BUF_FLAG_ERROR;
/* Fallthrough */
case ISP_BUF_STATE_DONE:
vbuf->flags |= V4L2_BUF_FLAG_DONE;
break;
case ISP_BUF_STATE_QUEUED:
case ISP_BUF_STATE_ACTIVE:
vbuf->flags |= V4L2_BUF_FLAG_QUEUED;

View File

@ -1532,6 +1532,20 @@ static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
return 0;
}
static int resizer_link_validate(struct v4l2_subdev *sd,
struct media_link *link,
struct v4l2_subdev_format *source_fmt,
struct v4l2_subdev_format *sink_fmt)
{
struct isp_res_device *res = v4l2_get_subdevdata(sd);
struct isp_pipeline *pipe = to_isp_pipeline(&sd->entity);
omap3isp_resizer_max_rate(res, &pipe->max_rate);
return v4l2_subdev_link_validate_default(sd, link,
source_fmt, sink_fmt);
}
/*
* resizer_init_formats - Initialize formats on all pads
* @sd: ISP resizer V4L2 subdevice
@ -1570,6 +1584,7 @@ static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = {
.set_fmt = resizer_set_format,
.get_selection = resizer_get_selection,
.set_selection = resizer_set_selection,
.link_validate = resizer_link_validate,
};
/* subdev operations */
@ -1701,7 +1716,8 @@ static int resizer_init_entities(struct isp_res_device *res)
v4l2_set_subdevdata(sd, res);
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
pads[RESZ_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
pads[RESZ_PAD_SINK].flags = MEDIA_PAD_FL_SINK
| MEDIA_PAD_FL_MUST_CONNECT;
pads[RESZ_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
me->ops = &resizer_media_ops;

View File

@ -1067,7 +1067,7 @@ static int isp_stat_init_entities(struct ispstat *stat, const char *name,
subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
v4l2_set_subdevdata(subdev, stat);
stat->pad.flags = MEDIA_PAD_FL_SINK;
stat->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
me->ops = NULL;
return media_entity_init(me, 1, &stat->pad, 0);

View File

@ -278,55 +278,6 @@ static int isp_video_get_graph_data(struct isp_video *video,
return 0;
}
/*
* Validate a pipeline by checking both ends of all links for format
* discrepancies.
*
* Compute the minimum time per frame value as the maximum of time per frame
* limits reported by every block in the pipeline.
*
* Return 0 if all formats match, or -EPIPE if at least one link is found with
* different formats on its two ends or if the pipeline doesn't start with a
* video source (either a subdev with no input pad, or a non-subdev entity).
*/
static int isp_video_validate_pipeline(struct isp_pipeline *pipe)
{
struct isp_device *isp = pipe->output->isp;
struct media_pad *pad;
struct v4l2_subdev *subdev;
subdev = isp_video_remote_subdev(pipe->output, NULL);
if (subdev == NULL)
return -EPIPE;
while (1) {
/* Retrieve the sink format */
pad = &subdev->entity.pads[0];
if (!(pad->flags & MEDIA_PAD_FL_SINK))
break;
/* Update the maximum frame rate */
if (subdev == &isp->isp_res.subdev)
omap3isp_resizer_max_rate(&isp->isp_res,
&pipe->max_rate);
/* Retrieve the source format. Return an error if no source
* entity can be found, and stop checking the pipeline if the
* source entity isn't a subdev.
*/
pad = media_entity_remote_pad(pad);
if (pad == NULL)
return -EPIPE;
if (media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
break;
subdev = media_entity_to_v4l2_subdev(pad->entity);
}
return 0;
}
static int
__isp_video_get_format(struct isp_video *video, struct v4l2_format *format)
{
@ -460,6 +411,15 @@ static int isp_video_buffer_prepare(struct isp_video_buffer *buf)
struct isp_video *video = vfh->video;
unsigned long addr;
/* Refuse to prepare the buffer is the video node has registered an
* error. We don't need to take any lock here as the operation is
* inherently racy. The authoritative check will be performed in the
* queue handler, which can't return an error, this check is just a best
* effort to notify userspace as early as possible.
*/
if (unlikely(video->error))
return -EIO;
addr = ispmmu_vmap(video->isp, buf->sglist, buf->sglen);
if (IS_ERR_VALUE(addr))
return -EIO;
@ -496,6 +456,12 @@ static void isp_video_buffer_queue(struct isp_video_buffer *buf)
unsigned int empty;
unsigned int start;
if (unlikely(video->error)) {
buf->state = ISP_BUF_STATE_ERROR;
wake_up(&buf->wait);
return;
}
empty = list_empty(&video->dmaqueue);
list_add_tail(&buffer->buffer.irqlist, &video->dmaqueue);
@ -617,6 +583,36 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video)
return to_isp_buffer(buf);
}
/*
* omap3isp_video_cancel_stream - Cancel stream on a video node
* @video: ISP video object
*
* Cancelling a stream mark all buffers on the video node as erroneous and makes
* sure no new buffer can be queued.
*/
void omap3isp_video_cancel_stream(struct isp_video *video)
{
struct isp_video_queue *queue = video->queue;
unsigned long flags;
spin_lock_irqsave(&queue->irqlock, flags);
while (!list_empty(&video->dmaqueue)) {
struct isp_video_buffer *buf;
buf = list_first_entry(&video->dmaqueue,
struct isp_video_buffer, irqlist);
list_del(&buf->irqlist);
buf->state = ISP_BUF_STATE_ERROR;
wake_up(&buf->wait);
}
video->error = true;
spin_unlock_irqrestore(&queue->irqlock, flags);
}
/*
* omap3isp_video_resume - Perform resume operation on the buffers
* @video: ISP video object
@ -1051,11 +1047,6 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
if (ret < 0)
goto err_check_format;
/* Validate the pipeline and update its state. */
ret = isp_video_validate_pipeline(pipe);
if (ret < 0)
goto err_check_format;
pipe->error = false;
spin_lock_irqsave(&pipe->lock, flags);
@ -1159,6 +1150,7 @@ isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
omap3isp_video_queue_streamoff(&vfh->queue);
video->queue = NULL;
video->streaming = 0;
video->error = false;
if (video->isp->pdata->set_constraints)
video->isp->pdata->set_constraints(video->isp, false);
@ -1332,11 +1324,13 @@ int omap3isp_video_init(struct isp_video *video, const char *name)
switch (video->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
direction = "output";
video->pad.flags = MEDIA_PAD_FL_SINK;
video->pad.flags = MEDIA_PAD_FL_SINK
| MEDIA_PAD_FL_MUST_CONNECT;
break;
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
direction = "input";
video->pad.flags = MEDIA_PAD_FL_SOURCE;
video->pad.flags = MEDIA_PAD_FL_SOURCE
| MEDIA_PAD_FL_MUST_CONNECT;
video->video.vfl_dir = VFL_DIR_TX;
break;

View File

@ -178,6 +178,7 @@ struct isp_video {
/* Pipeline state */
struct isp_pipeline pipe;
struct mutex stream_lock; /* pipeline and stream states */
bool error;
/* Video buffers queue */
struct isp_video_queue *queue;
@ -207,6 +208,7 @@ int omap3isp_video_register(struct isp_video *video,
struct v4l2_device *vdev);
void omap3isp_video_unregister(struct isp_video *video);
struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video);
void omap3isp_video_cancel_stream(struct isp_video *video);
void omap3isp_video_resume(struct isp_video *video, int continuous);
struct media_pad *omap3isp_video_remote_pad(struct isp_video *video);

View File

@ -136,10 +136,9 @@ static int g2d_buf_prepare(struct vb2_buffer *vb)
static void g2d_buf_queue(struct vb2_buffer *vb)
{
struct g2d_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
}
static struct vb2_ops g2d_qops = {
.queue_setup = g2d_queue_setup,
.buf_prepare = g2d_buf_prepare,
@ -159,6 +158,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
src_vq->mem_ops = &vb2_dma_contig_memops;
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
src_vq->lock = &ctx->dev->mutex;
ret = vb2_queue_init(src_vq);
if (ret)
@ -171,6 +171,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->mem_ops = &vb2_dma_contig_memops;
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
dst_vq->lock = &ctx->dev->mutex;
return vb2_queue_init(dst_vq);
}
@ -253,9 +254,9 @@ static int g2d_open(struct file *file)
kfree(ctx);
return -ERESTARTSYS;
}
ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
if (IS_ERR(ctx->m2m_ctx)) {
ret = PTR_ERR(ctx->m2m_ctx);
ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
if (IS_ERR(ctx->fh.m2m_ctx)) {
ret = PTR_ERR(ctx->fh.m2m_ctx);
mutex_unlock(&dev->mutex);
kfree(ctx);
return ret;
@ -324,7 +325,7 @@ static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f)
struct vb2_queue *vq;
struct g2d_frame *frm;
vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
if (!vq)
return -EINVAL;
frm = get_frame(ctx, f->type);
@ -384,7 +385,7 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f)
ret = vidioc_try_fmt(file, prv, f);
if (ret)
return ret;
vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
if (vb2_is_busy(vq)) {
v4l2_err(&dev->v4l2_dev, "queue (%d) bust\n", f->type);
return -EBUSY;
@ -410,72 +411,6 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f)
return 0;
}
static unsigned int g2d_poll(struct file *file, struct poll_table_struct *wait)
{
struct g2d_ctx *ctx = fh2ctx(file->private_data);
struct g2d_dev *dev = ctx->dev;
unsigned int res;
mutex_lock(&dev->mutex);
res = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
mutex_unlock(&dev->mutex);
return res;
}
static int g2d_mmap(struct file *file, struct vm_area_struct *vma)
{
struct g2d_ctx *ctx = fh2ctx(file->private_data);
struct g2d_dev *dev = ctx->dev;
int ret;
if (mutex_lock_interruptible(&dev->mutex))
return -ERESTARTSYS;
ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
mutex_unlock(&dev->mutex);
return ret;
}
static int vidioc_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *reqbufs)
{
struct g2d_ctx *ctx = priv;
return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
}
static int vidioc_querybuf(struct file *file, void *priv,
struct v4l2_buffer *buf)
{
struct g2d_ctx *ctx = priv;
return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
}
static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
{
struct g2d_ctx *ctx = priv;
return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
}
static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
{
struct g2d_ctx *ctx = priv;
return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
}
static int vidioc_streamon(struct file *file, void *priv,
enum v4l2_buf_type type)
{
struct g2d_ctx *ctx = priv;
return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
}
static int vidioc_streamoff(struct file *file, void *priv,
enum v4l2_buf_type type)
{
struct g2d_ctx *ctx = priv;
return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
}
static int vidioc_cropcap(struct file *file, void *priv,
struct v4l2_cropcap *cr)
{
@ -551,20 +486,6 @@ static int vidioc_s_crop(struct file *file, void *prv, const struct v4l2_crop *c
return 0;
}
static void g2d_lock(void *prv)
{
struct g2d_ctx *ctx = prv;
struct g2d_dev *dev = ctx->dev;
mutex_lock(&dev->mutex);
}
static void g2d_unlock(void *prv)
{
struct g2d_ctx *ctx = prv;
struct g2d_dev *dev = ctx->dev;
mutex_unlock(&dev->mutex);
}
static void job_abort(void *prv)
{
struct g2d_ctx *ctx = prv;
@ -589,8 +510,8 @@ static void device_run(void *prv)
dev->curr = ctx;
src = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
dst = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
clk_enable(dev->gate);
g2d_reset(dev);
@ -631,8 +552,8 @@ static irqreturn_t g2d_isr(int irq, void *prv)
BUG_ON(ctx == NULL);
src = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
dst = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
src = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
dst = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
BUG_ON(src == NULL);
BUG_ON(dst == NULL);
@ -642,7 +563,7 @@ static irqreturn_t g2d_isr(int irq, void *prv)
v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE);
v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE);
v4l2_m2m_job_finish(dev->m2m_dev, ctx->m2m_ctx);
v4l2_m2m_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx);
dev->curr = NULL;
wake_up(&dev->irq_queue);
@ -653,9 +574,9 @@ static const struct v4l2_file_operations g2d_fops = {
.owner = THIS_MODULE,
.open = g2d_open,
.release = g2d_release,
.poll = g2d_poll,
.poll = v4l2_m2m_fop_poll,
.unlocked_ioctl = video_ioctl2,
.mmap = g2d_mmap,
.mmap = v4l2_m2m_fop_mmap,
};
static const struct v4l2_ioctl_ops g2d_ioctl_ops = {
@ -671,14 +592,13 @@ static const struct v4l2_ioctl_ops g2d_ioctl_ops = {
.vidioc_try_fmt_vid_out = vidioc_try_fmt,
.vidioc_s_fmt_vid_out = vidioc_s_fmt,
.vidioc_reqbufs = vidioc_reqbufs,
.vidioc_querybuf = vidioc_querybuf,
.vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
.vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
.vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
.vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
.vidioc_qbuf = vidioc_qbuf,
.vidioc_dqbuf = vidioc_dqbuf,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
.vidioc_streamon = v4l2_m2m_ioctl_streamon,
.vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
.vidioc_g_crop = vidioc_g_crop,
.vidioc_s_crop = vidioc_s_crop,
@ -697,8 +617,6 @@ static struct video_device g2d_videodev = {
static struct v4l2_m2m_ops g2d_m2m_ops = {
.device_run = device_run,
.job_abort = job_abort,
.lock = g2d_lock,
.unlock = g2d_unlock,
};
static const struct of_device_id exynos_g2d_match[];

View File

@ -57,7 +57,6 @@ struct g2d_frame {
struct g2d_ctx {
struct v4l2_fh fh;
struct g2d_dev *dev;
struct v4l2_m2m_ctx *m2m_ctx;
struct g2d_frame in;
struct g2d_frame out;
struct v4l2_ctrl *ctrl_hflip;

View File

@ -1,2 +1,2 @@
s5p-jpeg-objs := jpeg-core.o
s5p-jpeg-objs := jpeg-core.o jpeg-hw-exynos4.o jpeg-hw-s5p.o
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += s5p-jpeg.o

File diff suppressed because it is too large Load Diff

View File

@ -13,6 +13,7 @@
#ifndef JPEG_CORE_H_
#define JPEG_CORE_H_
#include <linux/interrupt.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-ctrls.h>
@ -43,8 +44,45 @@
#define DHP 0xde
/* Flags that indicate a format can be used for capture/output */
#define MEM2MEM_CAPTURE (1 << 0)
#define MEM2MEM_OUTPUT (1 << 1)
#define SJPEG_FMT_FLAG_ENC_CAPTURE (1 << 0)
#define SJPEG_FMT_FLAG_ENC_OUTPUT (1 << 1)
#define SJPEG_FMT_FLAG_DEC_CAPTURE (1 << 2)
#define SJPEG_FMT_FLAG_DEC_OUTPUT (1 << 3)
#define SJPEG_FMT_FLAG_S5P (1 << 4)
#define SJPEG_FMT_FLAG_EXYNOS4 (1 << 5)
#define SJPEG_FMT_RGB (1 << 6)
#define SJPEG_FMT_NON_RGB (1 << 7)
#define S5P_JPEG_ENCODE 0
#define S5P_JPEG_DECODE 1
#define FMT_TYPE_OUTPUT 0
#define FMT_TYPE_CAPTURE 1
#define SJPEG_SUBSAMPLING_444 0x11
#define SJPEG_SUBSAMPLING_422 0x21
#define SJPEG_SUBSAMPLING_420 0x22
/* Version numbers */
#define SJPEG_S5P 1
#define SJPEG_EXYNOS4 2
enum exynos4_jpeg_result {
OK_ENC_OR_DEC,
ERR_PROT,
ERR_DEC_INVALID_FORMAT,
ERR_MULTI_SCAN,
ERR_FRAME,
ERR_UNKNOWN,
};
enum exynos4_jpeg_img_quality_level {
QUALITY_LEVEL_1 = 0, /* high */
QUALITY_LEVEL_2,
QUALITY_LEVEL_3,
QUALITY_LEVEL_4, /* low */
};
/**
* struct s5p_jpeg - JPEG IP abstraction
@ -71,9 +109,16 @@ struct s5p_jpeg {
void __iomem *regs;
unsigned int irq;
enum exynos4_jpeg_result irq_ret;
struct clk *clk;
struct device *dev;
void *alloc_ctx;
struct s5p_jpeg_variant *variant;
};
struct s5p_jpeg_variant {
unsigned int version;
irqreturn_t (*jpeg_irq)(int irq, void *priv);
};
/**
@ -84,16 +129,18 @@ struct s5p_jpeg {
* @colplanes: number of color planes (1 for packed formats)
* @h_align: horizontal alignment order (align to 2^h_align)
* @v_align: vertical alignment order (align to 2^v_align)
* @types: types of queue this format is applicable to
* @flags: flags describing format applicability
*/
struct s5p_jpeg_fmt {
char *name;
u32 fourcc;
int depth;
int colplanes;
int memplanes;
int h_align;
int v_align;
u32 types;
int subsampling;
u32 flags;
};
/**
@ -115,7 +162,6 @@ struct s5p_jpeg_q_data {
* @jpeg: JPEG IP device for this context
* @mode: compression (encode) operation or decompression (decode)
* @compr_quality: destination image quality in compression (encode) mode
* @m2m_ctx: mem2mem device context
* @out_q: source (output) queue information
* @cap_fmt: destination (capture) queue queue information
* @hdr_parsed: set if header has been parsed during decompression
@ -127,7 +173,6 @@ struct s5p_jpeg_ctx {
unsigned short compr_quality;
unsigned short restart_interval;
unsigned short subsampling;
struct v4l2_m2m_ctx *m2m_ctx;
struct s5p_jpeg_q_data out_q;
struct s5p_jpeg_q_data cap_q;
struct v4l2_fh fh;
@ -147,4 +192,16 @@ struct s5p_jpeg_buffer {
unsigned long data;
};
/**
* struct s5p_jpeg_addr - JPEG converter physical address set for DMA
* @y: luminance plane physical address
* @cb: Cb plane physical address
* @cr: Cr plane physical address
*/
struct s5p_jpeg_addr {
u32 y;
u32 cb;
u32 cr;
};
#endif /* JPEG_CORE_H */

Some files were not shown because too many files have changed in this diff Show More