diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-04 10:58:25 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-11-04 10:58:25 -0400 |
| commit | 1046a2c428bedd64c960dcfd0c57cc69a82fea2f (patch) | |
| tree | d34b83e0ac61b51305cece031f7ff49579e3fe76 | |
| parent | 46e85f5f1c2a1d106c1ec0fa2a06280276b8e052 (diff) | |
| parent | b3f4e1eba45eda5d1213810ef3bc53e5247df2df (diff) | |
Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (144 commits)
[media] saa7134.h: Suppress compiler warnings when CONFIG_VIDEO_SAA7134_RC is not set
[media] it913x [VER 1.07] Support for single ITE 9135 devices
[media] Support for Terratec G1
[media] cx25821: off by one in cx25821_vidioc_s_input()
[media] media: tea5764: reconcile Kconfig symbol and macro
[media] omap_vout: Add poll() support
[media] omap3isp: preview: Add crop support on the sink pad
[media] omap3isp: preview: Rename min/max input/output sizes defines
[media] omap3isp: preview: Remove horizontal averager support
[media] omap3isp: Report the ISP revision through the media controller API
[media] omap3isp: ccdc: remove redundant operation
[media] omap3isp: Fix memory leaks in initialization error paths
[media] omap3isp: Add missing mutex_destroy() calls
[media] omap3isp: Move *_init_entities() functions to the init/cleanup section
[media] omap3isp: Move media_entity_cleanup() from unregister() to cleanup()
[media] MFC: Change MFC firmware binary name
[media] vb2: add vb2_get_unmapped_area in vb2 core
[media] v4l: Add v4l2 subdev driver for S5K6AAFX sensor
[media] v4l: Add AUTO option for the V4L2_CID_POWER_LINE_FREQUENCY control
[media] media: ov6650: stylistic improvements
...
216 files changed, 10316 insertions, 3785 deletions
diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml index 91410b6e7e08..b68698f96e7f 100644 --- a/Documentation/DocBook/media/v4l/compat.xml +++ b/Documentation/DocBook/media/v4l/compat.xml | |||
| @@ -2486,6 +2486,9 @@ ioctls.</para> | |||
| 2486 | <listitem> | 2486 | <listitem> |
| 2487 | <para>Flash API. <xref linkend="flash-controls" /></para> | 2487 | <para>Flash API. <xref linkend="flash-controls" /></para> |
| 2488 | </listitem> | 2488 | </listitem> |
| 2489 | <listitem> | ||
| 2490 | <para>&VIDIOC-CREATE-BUFS; and &VIDIOC-PREPARE-BUF; ioctls.</para> | ||
| 2491 | </listitem> | ||
| 2489 | </itemizedlist> | 2492 | </itemizedlist> |
| 2490 | </section> | 2493 | </section> |
| 2491 | 2494 | ||
diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index 23fdf79f8cf3..3bc5ee8b2c74 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml | |||
| @@ -232,8 +232,9 @@ control is deprecated. New drivers and applications should use the | |||
| 232 | <entry>Enables a power line frequency filter to avoid | 232 | <entry>Enables a power line frequency filter to avoid |
| 233 | flicker. Possible values for <constant>enum v4l2_power_line_frequency</constant> are: | 233 | flicker. Possible values for <constant>enum v4l2_power_line_frequency</constant> are: |
| 234 | <constant>V4L2_CID_POWER_LINE_FREQUENCY_DISABLED</constant> (0), | 234 | <constant>V4L2_CID_POWER_LINE_FREQUENCY_DISABLED</constant> (0), |
| 235 | <constant>V4L2_CID_POWER_LINE_FREQUENCY_50HZ</constant> (1) and | 235 | <constant>V4L2_CID_POWER_LINE_FREQUENCY_50HZ</constant> (1), |
| 236 | <constant>V4L2_CID_POWER_LINE_FREQUENCY_60HZ</constant> (2).</entry> | 236 | <constant>V4L2_CID_POWER_LINE_FREQUENCY_60HZ</constant> (2) and |
| 237 | <constant>V4L2_CID_POWER_LINE_FREQUENCY_AUTO</constant> (3).</entry> | ||
| 237 | </row> | 238 | </row> |
| 238 | <row> | 239 | <row> |
| 239 | <entry><constant>V4L2_CID_HUE_AUTO</constant></entry> | 240 | <entry><constant>V4L2_CID_HUE_AUTO</constant></entry> |
diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml index c57d1ec6291c..3f47df1aa54a 100644 --- a/Documentation/DocBook/media/v4l/io.xml +++ b/Documentation/DocBook/media/v4l/io.xml | |||
| @@ -927,6 +927,33 @@ ioctl is called.</entry> | |||
| 927 | Applications set or clear this flag before calling the | 927 | Applications set or clear this flag before calling the |
| 928 | <constant>VIDIOC_QBUF</constant> ioctl.</entry> | 928 | <constant>VIDIOC_QBUF</constant> ioctl.</entry> |
| 929 | </row> | 929 | </row> |
| 930 | <row> | ||
| 931 | <entry><constant>V4L2_BUF_FLAG_PREPARED</constant></entry> | ||
| 932 | <entry>0x0400</entry> | ||
| 933 | <entry>The buffer has been prepared for I/O and can be queued by the | ||
| 934 | application. Drivers set or clear this flag when the | ||
| 935 | <link linkend="vidioc-querybuf">VIDIOC_QUERYBUF</link>, <link | ||
| 936 | linkend="vidioc-qbuf">VIDIOC_PREPARE_BUF</link>, <link | ||
| 937 | linkend="vidioc-qbuf">VIDIOC_QBUF</link> or <link | ||
| 938 | linkend="vidioc-qbuf">VIDIOC_DQBUF</link> ioctl is called.</entry> | ||
| 939 | </row> | ||
| 940 | <row> | ||
| 941 | <entry><constant>V4L2_BUF_FLAG_NO_CACHE_INVALIDATE</constant></entry> | ||
| 942 | <entry>0x0400</entry> | ||
| 943 | <entry>Caches do not have to be invalidated for this buffer. | ||
| 944 | Typically applications shall use this flag if the data captured in the buffer | ||
| 945 | is not going to be touched by the CPU, instead the buffer will, probably, be | ||
| 946 | passed on to a DMA-capable hardware unit for further processing or output. | ||
| 947 | </entry> | ||
| 948 | </row> | ||
| 949 | <row> | ||
| 950 | <entry><constant>V4L2_BUF_FLAG_NO_CACHE_CLEAN</constant></entry> | ||
| 951 | <entry>0x0800</entry> | ||
| 952 | <entry>Caches do not have to be cleaned for this buffer. | ||
| 953 | Typically applications shall use this flag for output buffers if the data | ||
| 954 | in this buffer has not been created by the CPU but by some DMA-capable unit, | ||
| 955 | in which case caches have not been used.</entry> | ||
| 956 | </row> | ||
| 930 | </tbody> | 957 | </tbody> |
| 931 | </tgroup> | 958 | </tgroup> |
| 932 | </table> | 959 | </table> |
diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml index 40132c277647..2ab365c10fb9 100644 --- a/Documentation/DocBook/media/v4l/v4l2.xml +++ b/Documentation/DocBook/media/v4l/v4l2.xml | |||
| @@ -469,6 +469,7 @@ and discussions on the V4L mailing list.</revremark> | |||
| 469 | &sub-close; | 469 | &sub-close; |
| 470 | &sub-ioctl; | 470 | &sub-ioctl; |
| 471 | <!-- All ioctls go here. --> | 471 | <!-- All ioctls go here. --> |
| 472 | &sub-create-bufs; | ||
| 472 | &sub-cropcap; | 473 | &sub-cropcap; |
| 473 | &sub-dbg-g-chip-ident; | 474 | &sub-dbg-g-chip-ident; |
| 474 | &sub-dbg-g-register; | 475 | &sub-dbg-g-register; |
| @@ -511,6 +512,7 @@ and discussions on the V4L mailing list.</revremark> | |||
| 511 | &sub-queryctrl; | 512 | &sub-queryctrl; |
| 512 | &sub-query-dv-preset; | 513 | &sub-query-dv-preset; |
| 513 | &sub-querystd; | 514 | &sub-querystd; |
| 515 | &sub-prepare-buf; | ||
| 514 | &sub-reqbufs; | 516 | &sub-reqbufs; |
| 515 | &sub-s-hw-freq-seek; | 517 | &sub-s-hw-freq-seek; |
| 516 | &sub-streamon; | 518 | &sub-streamon; |
diff --git a/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml new file mode 100644 index 000000000000..73ae8a6cd004 --- /dev/null +++ b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml | |||
| @@ -0,0 +1,139 @@ | |||
| 1 | <refentry id="vidioc-create-bufs"> | ||
| 2 | <refmeta> | ||
| 3 | <refentrytitle>ioctl VIDIOC_CREATE_BUFS</refentrytitle> | ||
| 4 | &manvol; | ||
| 5 | </refmeta> | ||
| 6 | |||
| 7 | <refnamediv> | ||
| 8 | <refname>VIDIOC_CREATE_BUFS</refname> | ||
| 9 | <refpurpose>Create buffers for Memory Mapped or User Pointer I/O</refpurpose> | ||
| 10 | </refnamediv> | ||
| 11 | |||
| 12 | <refsynopsisdiv> | ||
| 13 | <funcsynopsis> | ||
| 14 | <funcprototype> | ||
| 15 | <funcdef>int <function>ioctl</function></funcdef> | ||
| 16 | <paramdef>int <parameter>fd</parameter></paramdef> | ||
| 17 | <paramdef>int <parameter>request</parameter></paramdef> | ||
| 18 | <paramdef>struct v4l2_create_buffers *<parameter>argp</parameter></paramdef> | ||
| 19 | </funcprototype> | ||
| 20 | </funcsynopsis> | ||
| 21 | </refsynopsisdiv> | ||
| 22 | |||
| 23 | <refsect1> | ||
| 24 | <title>Arguments</title> | ||
| 25 | |||
| 26 | <variablelist> | ||
| 27 | <varlistentry> | ||
| 28 | <term><parameter>fd</parameter></term> | ||
| 29 | <listitem> | ||
| 30 | <para>&fd;</para> | ||
| 31 | </listitem> | ||
| 32 | </varlistentry> | ||
| 33 | <varlistentry> | ||
| 34 | <term><parameter>request</parameter></term> | ||
| 35 | <listitem> | ||
| 36 | <para>VIDIOC_CREATE_BUFS</para> | ||
| 37 | </listitem> | ||
| 38 | </varlistentry> | ||
| 39 | <varlistentry> | ||
| 40 | <term><parameter>argp</parameter></term> | ||
| 41 | <listitem> | ||
| 42 | <para></para> | ||
| 43 | </listitem> | ||
| 44 | </varlistentry> | ||
| 45 | </variablelist> | ||
| 46 | </refsect1> | ||
| 47 | |||
| 48 | <refsect1> | ||
| 49 | <title>Description</title> | ||
| 50 | |||
| 51 | <para>This ioctl is used to create buffers for <link linkend="mmap">memory | ||
| 52 | mapped</link> or <link linkend="userp">user pointer</link> | ||
| 53 | I/O. It can be used as an alternative or in addition to the | ||
| 54 | <constant>VIDIOC_REQBUFS</constant> ioctl, when a tighter control over buffers | ||
| 55 | is required. This ioctl can be called multiple times to create buffers of | ||
| 56 | different sizes.</para> | ||
| 57 | |||
| 58 | <para>To allocate device buffers applications initialize relevant fields of | ||
| 59 | the <structname>v4l2_create_buffers</structname> structure. They set the | ||
| 60 | <structfield>type</structfield> field in the | ||
| 61 | <structname>v4l2_format</structname> structure, embedded in this | ||
| 62 | structure, to the respective stream or buffer type. | ||
| 63 | <structfield>count</structfield> must be set to the number of required buffers. | ||
| 64 | <structfield>memory</structfield> specifies the required I/O method. The | ||
| 65 | <structfield>format</structfield> field shall typically be filled in using | ||
| 66 | either the <constant>VIDIOC_TRY_FMT</constant> or | ||
| 67 | <constant>VIDIOC_G_FMT</constant> ioctl(). Additionally, applications can adjust | ||
| 68 | <structfield>sizeimage</structfield> fields to fit their specific needs. The | ||
| 69 | <structfield>reserved</structfield> array must be zeroed.</para> | ||
| 70 | |||
| 71 | <para>When the ioctl is called with a pointer to this structure the driver | ||
| 72 | will attempt to allocate up to the requested number of buffers and store the | ||
| 73 | actual number allocated and the starting index in the | ||
| 74 | <structfield>count</structfield> and the <structfield>index</structfield> fields | ||
| 75 | respectively. On return <structfield>count</structfield> can be smaller than | ||
| 76 | the number requested. The driver may also increase buffer sizes if required, | ||
| 77 | however, it will not update <structfield>sizeimage</structfield> field values. | ||
| 78 | The user has to use <constant>VIDIOC_QUERYBUF</constant> to retrieve that | ||
| 79 | information.</para> | ||
| 80 | |||
| 81 | <table pgwide="1" frame="none" id="v4l2-create-buffers"> | ||
| 82 | <title>struct <structname>v4l2_create_buffers</structname></title> | ||
| 83 | <tgroup cols="3"> | ||
| 84 | &cs-str; | ||
| 85 | <tbody valign="top"> | ||
| 86 | <row> | ||
| 87 | <entry>__u32</entry> | ||
| 88 | <entry><structfield>index</structfield></entry> | ||
| 89 | <entry>The starting buffer index, returned by the driver.</entry> | ||
| 90 | </row> | ||
| 91 | <row> | ||
| 92 | <entry>__u32</entry> | ||
| 93 | <entry><structfield>count</structfield></entry> | ||
| 94 | <entry>The number of buffers requested or granted.</entry> | ||
| 95 | </row> | ||
| 96 | <row> | ||
| 97 | <entry>&v4l2-memory;</entry> | ||
| 98 | <entry><structfield>memory</structfield></entry> | ||
| 99 | <entry>Applications set this field to | ||
| 100 | <constant>V4L2_MEMORY_MMAP</constant> or | ||
| 101 | <constant>V4L2_MEMORY_USERPTR</constant>.</entry> | ||
| 102 | </row> | ||
| 103 | <row> | ||
| 104 | <entry>&v4l2-format;</entry> | ||
| 105 | <entry><structfield>format</structfield></entry> | ||
| 106 | <entry>Filled in by the application, preserved by the driver.</entry> | ||
| 107 | </row> | ||
| 108 | <row> | ||
| 109 | <entry>__u32</entry> | ||
| 110 | <entry><structfield>reserved</structfield>[8]</entry> | ||
| 111 | <entry>A place holder for future extensions.</entry> | ||
| 112 | </row> | ||
| 113 | </tbody> | ||
| 114 | </tgroup> | ||
| 115 | </table> | ||
| 116 | </refsect1> | ||
| 117 | |||
| 118 | <refsect1> | ||
| 119 | &return-value; | ||
| 120 | |||
| 121 | <variablelist> | ||
| 122 | <varlistentry> | ||
| 123 | <term><errorcode>ENOMEM</errorcode></term> | ||
| 124 | <listitem> | ||
| 125 | <para>No memory to allocate buffers for <link linkend="mmap">memory | ||
| 126 | mapped</link> I/O.</para> | ||
| 127 | </listitem> | ||
| 128 | </varlistentry> | ||
| 129 | <varlistentry> | ||
| 130 | <term><errorcode>EINVAL</errorcode></term> | ||
| 131 | <listitem> | ||
| 132 | <para>The buffer type (<structfield>type</structfield> field) or the | ||
| 133 | requested I/O method (<structfield>memory</structfield>) is not | ||
| 134 | supported.</para> | ||
| 135 | </listitem> | ||
| 136 | </varlistentry> | ||
| 137 | </variablelist> | ||
| 138 | </refsect1> | ||
| 139 | </refentry> | ||
diff --git a/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml new file mode 100644 index 000000000000..7bde698760e4 --- /dev/null +++ b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml | |||
| @@ -0,0 +1,88 @@ | |||
| 1 | <refentry id="vidioc-prepare-buf"> | ||
| 2 | <refmeta> | ||
| 3 | <refentrytitle>ioctl VIDIOC_PREPARE_BUF</refentrytitle> | ||
| 4 | &manvol; | ||
| 5 | </refmeta> | ||
| 6 | |||
| 7 | <refnamediv> | ||
| 8 | <refname>VIDIOC_PREPARE_BUF</refname> | ||
| 9 | <refpurpose>Prepare a buffer for I/O</refpurpose> | ||
| 10 | </refnamediv> | ||
| 11 | |||
| 12 | <refsynopsisdiv> | ||
| 13 | <funcsynopsis> | ||
| 14 | <funcprototype> | ||
| 15 | <funcdef>int <function>ioctl</function></funcdef> | ||
| 16 | <paramdef>int <parameter>fd</parameter></paramdef> | ||
| 17 | <paramdef>int <parameter>request</parameter></paramdef> | ||
| 18 | <paramdef>struct v4l2_buffer *<parameter>argp</parameter></paramdef> | ||
| 19 | </funcprototype> | ||
| 20 | </funcsynopsis> | ||
| 21 | </refsynopsisdiv> | ||
| 22 | |||
| 23 | <refsect1> | ||
| 24 | <title>Arguments</title> | ||
| 25 | |||
| 26 | <variablelist> | ||
| 27 | <varlistentry> | ||
| 28 | <term><parameter>fd</parameter></term> | ||
| 29 | <listitem> | ||
| 30 | <para>&fd;</para> | ||
| 31 | </listitem> | ||
| 32 | </varlistentry> | ||
| 33 | <varlistentry> | ||
| 34 | <term><parameter>request</parameter></term> | ||
| 35 | <listitem> | ||
| 36 | <para>VIDIOC_PREPARE_BUF</para> | ||
| 37 | </listitem> | ||
| 38 | </varlistentry> | ||
| 39 | <varlistentry> | ||
| 40 | <term><parameter>argp</parameter></term> | ||
| 41 | <listitem> | ||
| 42 | <para></para> | ||
| 43 | </listitem> | ||
| 44 | </varlistentry> | ||
| 45 | </variablelist> | ||
| 46 | </refsect1> | ||
| 47 | |||
| 48 | <refsect1> | ||
| 49 | <title>Description</title> | ||
| 50 | |||
| 51 | <para>Applications can optionally call the | ||
| 52 | <constant>VIDIOC_PREPARE_BUF</constant> ioctl to pass ownership of the buffer | ||
| 53 | to the driver before actually enqueuing it, using the | ||
| 54 | <constant>VIDIOC_QBUF</constant> ioctl, and to prepare it for future I/O. | ||
| 55 | Such preparations may include cache invalidation or cleaning. Performing them | ||
| 56 | in advance saves time during the actual I/O. In case such cache operations are | ||
| 57 | not required, the application can use one of | ||
| 58 | <constant>V4L2_BUF_FLAG_NO_CACHE_INVALIDATE</constant> and | ||
| 59 | <constant>V4L2_BUF_FLAG_NO_CACHE_CLEAN</constant> flags to skip the respective | ||
| 60 | step.</para> | ||
| 61 | |||
| 62 | <para>The <structname>v4l2_buffer</structname> structure is | ||
| 63 | specified in <xref linkend="buffer" />.</para> | ||
| 64 | </refsect1> | ||
| 65 | |||
| 66 | <refsect1> | ||
| 67 | &return-value; | ||
| 68 | |||
| 69 | <variablelist> | ||
| 70 | <varlistentry> | ||
| 71 | <term><errorcode>EBUSY</errorcode></term> | ||
| 72 | <listitem> | ||
| 73 | <para>File I/O is in progress.</para> | ||
| 74 | </listitem> | ||
| 75 | </varlistentry> | ||
| 76 | <varlistentry> | ||
| 77 | <term><errorcode>EINVAL</errorcode></term> | ||
| 78 | <listitem> | ||
| 79 | <para>The buffer <structfield>type</structfield> is not | ||
| 80 | supported, or the <structfield>index</structfield> is out of bounds, | ||
| 81 | or no buffers have been allocated yet, or the | ||
| 82 | <structfield>userptr</structfield> or | ||
| 83 | <structfield>length</structfield> are invalid.</para> | ||
| 84 | </listitem> | ||
| 85 | </varlistentry> | ||
| 86 | </variablelist> | ||
| 87 | </refsect1> | ||
| 88 | </refentry> | ||
diff --git a/arch/arm/mach-pxa/pcm990-baseboard.c b/arch/arm/mach-pxa/pcm990-baseboard.c index 9a9c539f6c01..6d38c6548b3d 100644 --- a/arch/arm/mach-pxa/pcm990-baseboard.c +++ b/arch/arm/mach-pxa/pcm990-baseboard.c | |||
| @@ -394,9 +394,9 @@ static int pcm990_camera_set_bus_param(struct soc_camera_link *link, | |||
| 394 | } | 394 | } |
| 395 | 395 | ||
| 396 | if (flags & SOCAM_DATAWIDTH_8) | 396 | if (flags & SOCAM_DATAWIDTH_8) |
| 397 | gpio_set_value(gpio_bus_switch, 1); | 397 | gpio_set_value_cansleep(gpio_bus_switch, 1); |
| 398 | else | 398 | else |
| 399 | gpio_set_value(gpio_bus_switch, 0); | 399 | gpio_set_value_cansleep(gpio_bus_switch, 0); |
| 400 | 400 | ||
| 401 | return 0; | 401 | return 0; |
| 402 | } | 402 | } |
diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index 5b7edadf4647..f9f66c20c9f1 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c | |||
| @@ -933,7 +933,7 @@ static struct platform_device ap4evb_camera = { | |||
| 933 | static struct sh_csi2_client_config csi2_clients[] = { | 933 | static struct sh_csi2_client_config csi2_clients[] = { |
| 934 | { | 934 | { |
| 935 | .phy = SH_CSI2_PHY_MAIN, | 935 | .phy = SH_CSI2_PHY_MAIN, |
| 936 | .lanes = 3, | 936 | .lanes = 0, /* default: 2 lanes */ |
| 937 | .channel = 0, | 937 | .channel = 0, |
| 938 | .pdev = &ap4evb_camera, | 938 | .pdev = &ap4evb_camera, |
| 939 | }, | 939 | }, |
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index 3689ad2e9156..682042306ea2 100644 --- a/arch/arm/mach-shmobile/board-mackerel.c +++ b/arch/arm/mach-shmobile/board-mackerel.c | |||
| @@ -1223,9 +1223,10 @@ static struct soc_camera_platform_info camera_info = { | |||
| 1223 | .width = 640, | 1223 | .width = 640, |
| 1224 | .height = 480, | 1224 | .height = 480, |
| 1225 | }, | 1225 | }, |
| 1226 | .bus_param = SOCAM_PCLK_SAMPLE_RISING | SOCAM_HSYNC_ACTIVE_HIGH | | 1226 | .mbus_param = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | |
| 1227 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_MASTER | SOCAM_DATAWIDTH_8 | | 1227 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | |
| 1228 | SOCAM_DATA_ACTIVE_HIGH, | 1228 | V4L2_MBUS_DATA_ACTIVE_HIGH, |
| 1229 | .mbus_type = V4L2_MBUS_PARALLEL, | ||
| 1229 | .set_capture = camera_set_capture, | 1230 | .set_capture = camera_set_capture, |
| 1230 | }; | 1231 | }; |
| 1231 | 1232 | ||
diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c index d36265758911..7030f4c8cf11 100644 --- a/arch/sh/boards/mach-ap325rxa/setup.c +++ b/arch/sh/boards/mach-ap325rxa/setup.c | |||
| @@ -345,9 +345,10 @@ static struct soc_camera_platform_info camera_info = { | |||
| 345 | .width = 640, | 345 | .width = 640, |
| 346 | .height = 480, | 346 | .height = 480, |
| 347 | }, | 347 | }, |
| 348 | .bus_param = SOCAM_PCLK_SAMPLE_RISING | SOCAM_HSYNC_ACTIVE_HIGH | | 348 | .mbus_param = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | |
| 349 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_MASTER | SOCAM_DATAWIDTH_8 | | 349 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | |
| 350 | SOCAM_DATA_ACTIVE_HIGH, | 350 | V4L2_MBUS_DATA_ACTIVE_HIGH, |
| 351 | .mbus_type = V4L2_MBUS_PARALLEL, | ||
| 351 | .set_capture = camera_set_capture, | 352 | .set_capture = camera_set_capture, |
| 352 | }; | 353 | }; |
| 353 | 354 | ||
| @@ -501,8 +502,7 @@ static struct i2c_board_info ap325rxa_i2c_camera[] = { | |||
| 501 | }; | 502 | }; |
| 502 | 503 | ||
| 503 | static struct ov772x_camera_info ov7725_info = { | 504 | static struct ov772x_camera_info ov7725_info = { |
| 504 | .flags = OV772X_FLAG_VFLIP | OV772X_FLAG_HFLIP | \ | 505 | .flags = OV772X_FLAG_VFLIP | OV772X_FLAG_HFLIP, |
| 505 | OV772X_FLAG_8BIT, | ||
| 506 | .edgectrl = OV772X_AUTO_EDGECTRL(0xf, 0), | 506 | .edgectrl = OV772X_AUTO_EDGECTRL(0xf, 0), |
| 507 | }; | 507 | }; |
| 508 | 508 | ||
diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c index 2d4c9c8c6664..e4c81195929c 100644 --- a/arch/sh/boards/mach-migor/setup.c +++ b/arch/sh/boards/mach-migor/setup.c | |||
| @@ -448,9 +448,7 @@ static struct i2c_board_info migor_i2c_camera[] = { | |||
| 448 | }, | 448 | }, |
| 449 | }; | 449 | }; |
| 450 | 450 | ||
| 451 | static struct ov772x_camera_info ov7725_info = { | 451 | static struct ov772x_camera_info ov7725_info; |
| 452 | .flags = OV772X_FLAG_8BIT, | ||
| 453 | }; | ||
| 454 | 452 | ||
| 455 | static struct soc_camera_link ov7725_link = { | 453 | static struct soc_camera_link ov7725_link = { |
| 456 | .power = ov7725_power, | 454 | .power = ov7725_power, |
diff --git a/drivers/dma/ipu/ipu_idmac.c b/drivers/dma/ipu/ipu_idmac.c index 6815905a772f..ddc2a1331822 100644 --- a/drivers/dma/ipu/ipu_idmac.c +++ b/drivers/dma/ipu/ipu_idmac.c | |||
| @@ -1307,6 +1307,7 @@ static irqreturn_t idmac_interrupt(int irq, void *dev_id) | |||
| 1307 | ipu_submit_buffer(ichan, descnew, sgnew, ichan->active_buffer) < 0) { | 1307 | ipu_submit_buffer(ichan, descnew, sgnew, ichan->active_buffer) < 0) { |
| 1308 | callback = descnew->txd.callback; | 1308 | callback = descnew->txd.callback; |
| 1309 | callback_param = descnew->txd.callback_param; | 1309 | callback_param = descnew->txd.callback_param; |
| 1310 | list_del_init(&descnew->list); | ||
| 1310 | spin_unlock(&ichan->lock); | 1311 | spin_unlock(&ichan->lock); |
| 1311 | if (callback) | 1312 | if (callback) |
| 1312 | callback(callback_param); | 1313 | callback(callback_param); |
| @@ -1428,39 +1429,58 @@ static int __idmac_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, | |||
| 1428 | { | 1429 | { |
| 1429 | struct idmac_channel *ichan = to_idmac_chan(chan); | 1430 | struct idmac_channel *ichan = to_idmac_chan(chan); |
| 1430 | struct idmac *idmac = to_idmac(chan->device); | 1431 | struct idmac *idmac = to_idmac(chan->device); |
| 1432 | struct ipu *ipu = to_ipu(idmac); | ||
| 1433 | struct list_head *list, *tmp; | ||
| 1431 | unsigned long flags; | 1434 | unsigned long flags; |
| 1432 | int i; | 1435 | int i; |
| 1433 | 1436 | ||
| 1434 | /* Only supports DMA_TERMINATE_ALL */ | 1437 | switch (cmd) { |
| 1435 | if (cmd != DMA_TERMINATE_ALL) | 1438 | case DMA_PAUSE: |
| 1436 | return -ENXIO; | 1439 | spin_lock_irqsave(&ipu->lock, flags); |
| 1440 | ipu_ic_disable_task(ipu, chan->chan_id); | ||
| 1437 | 1441 | ||
| 1438 | ipu_disable_channel(idmac, ichan, | 1442 | /* Return all descriptors into "prepared" state */ |
| 1439 | ichan->status >= IPU_CHANNEL_ENABLED); | 1443 | list_for_each_safe(list, tmp, &ichan->queue) |
| 1444 | list_del_init(list); | ||
| 1440 | 1445 | ||
| 1441 | tasklet_disable(&to_ipu(idmac)->tasklet); | 1446 | ichan->sg[0] = NULL; |
| 1447 | ichan->sg[1] = NULL; | ||
| 1442 | 1448 | ||
| 1443 | /* ichan->queue is modified in ISR, have to spinlock */ | 1449 | spin_unlock_irqrestore(&ipu->lock, flags); |
| 1444 | spin_lock_irqsave(&ichan->lock, flags); | ||
| 1445 | list_splice_init(&ichan->queue, &ichan->free_list); | ||
| 1446 | 1450 | ||
| 1447 | if (ichan->desc) | 1451 | ichan->status = IPU_CHANNEL_INITIALIZED; |
| 1448 | for (i = 0; i < ichan->n_tx_desc; i++) { | 1452 | break; |
| 1449 | struct idmac_tx_desc *desc = ichan->desc + i; | 1453 | case DMA_TERMINATE_ALL: |
| 1450 | if (list_empty(&desc->list)) | 1454 | ipu_disable_channel(idmac, ichan, |
| 1451 | /* Descriptor was prepared, but not submitted */ | 1455 | ichan->status >= IPU_CHANNEL_ENABLED); |
| 1452 | list_add(&desc->list, &ichan->free_list); | ||
| 1453 | 1456 | ||
| 1454 | async_tx_clear_ack(&desc->txd); | 1457 | tasklet_disable(&ipu->tasklet); |
| 1455 | } | ||
| 1456 | 1458 | ||
| 1457 | ichan->sg[0] = NULL; | 1459 | /* ichan->queue is modified in ISR, have to spinlock */ |
| 1458 | ichan->sg[1] = NULL; | 1460 | spin_lock_irqsave(&ichan->lock, flags); |
| 1459 | spin_unlock_irqrestore(&ichan->lock, flags); | 1461 | list_splice_init(&ichan->queue, &ichan->free_list); |
| 1460 | 1462 | ||
| 1461 | tasklet_enable(&to_ipu(idmac)->tasklet); | 1463 | if (ichan->desc) |
| 1464 | for (i = 0; i < ichan->n_tx_desc; i++) { | ||
| 1465 | struct idmac_tx_desc *desc = ichan->desc + i; | ||
| 1466 | if (list_empty(&desc->list)) | ||
| 1467 | /* Descriptor was prepared, but not submitted */ | ||
| 1468 | list_add(&desc->list, &ichan->free_list); | ||
| 1462 | 1469 | ||
| 1463 | ichan->status = IPU_CHANNEL_INITIALIZED; | 1470 | async_tx_clear_ack(&desc->txd); |
| 1471 | } | ||
| 1472 | |||
| 1473 | ichan->sg[0] = NULL; | ||
| 1474 | ichan->sg[1] = NULL; | ||
| 1475 | spin_unlock_irqrestore(&ichan->lock, flags); | ||
| 1476 | |||
| 1477 | tasklet_enable(&ipu->tasklet); | ||
| 1478 | |||
| 1479 | ichan->status = IPU_CHANNEL_INITIALIZED; | ||
| 1480 | break; | ||
| 1481 | default: | ||
| 1482 | return -ENOSYS; | ||
| 1483 | } | ||
| 1464 | 1484 | ||
| 1465 | return 0; | 1485 | return 0; |
| 1466 | } | 1486 | } |
| @@ -1663,7 +1683,6 @@ static void __exit ipu_idmac_exit(struct ipu *ipu) | |||
| 1663 | struct idmac_channel *ichan = ipu->channel + i; | 1683 | struct idmac_channel *ichan = ipu->channel + i; |
| 1664 | 1684 | ||
| 1665 | idmac_control(&ichan->dma_chan, DMA_TERMINATE_ALL, 0); | 1685 | idmac_control(&ichan->dma_chan, DMA_TERMINATE_ALL, 0); |
| 1666 | idmac_prep_slave_sg(&ichan->dma_chan, NULL, 0, DMA_NONE, 0); | ||
| 1667 | } | 1686 | } |
| 1668 | 1687 | ||
| 1669 | dma_async_device_unregister(&idmac->dma); | 1688 | dma_async_device_unregister(&idmac->dma); |
diff --git a/drivers/media/dvb/ddbridge/Makefile b/drivers/media/dvb/ddbridge/Makefile index cf7214edf65f..38019bafb862 100644 --- a/drivers/media/dvb/ddbridge/Makefile +++ b/drivers/media/dvb/ddbridge/Makefile | |||
| @@ -11,4 +11,4 @@ ccflags-y += -Idrivers/media/dvb/frontends/ | |||
| 11 | ccflags-y += -Idrivers/media/common/tuners/ | 11 | ccflags-y += -Idrivers/media/common/tuners/ |
| 12 | 12 | ||
| 13 | # For the staging CI driver cxd2099 | 13 | # For the staging CI driver cxd2099 |
| 14 | ccflags-y += -Idrivers/staging/cxd2099/ | 14 | ccflags-y += -Idrivers/staging/media/cxd2099/ |
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index 7d0710bb1978..26c8b9e57050 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile | |||
| @@ -102,6 +102,7 @@ obj-$(CONFIG_DVB_USB_IT913X) += dvb-usb-it913x.o | |||
| 102 | 102 | ||
| 103 | dvb-usb-mxl111sf-objs = mxl111sf.o mxl111sf-phy.o mxl111sf-i2c.o mxl111sf-gpio.o | 103 | dvb-usb-mxl111sf-objs = mxl111sf.o mxl111sf-phy.o mxl111sf-i2c.o mxl111sf-gpio.o |
| 104 | obj-$(CONFIG_DVB_USB_MXL111SF) += dvb-usb-mxl111sf.o | 104 | obj-$(CONFIG_DVB_USB_MXL111SF) += dvb-usb-mxl111sf.o |
| 105 | obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-demod.o | ||
| 105 | obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o | 106 | obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o |
| 106 | 107 | ||
| 107 | ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ | 108 | ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ |
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 2ad33ba92ba2..2d08c9b5128a 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h | |||
| @@ -37,6 +37,7 @@ | |||
| 37 | #define USB_VID_HAUPPAUGE 0x2040 | 37 | #define USB_VID_HAUPPAUGE 0x2040 |
| 38 | #define USB_VID_HYPER_PALTEK 0x1025 | 38 | #define USB_VID_HYPER_PALTEK 0x1025 |
| 39 | #define USB_VID_INTEL 0x8086 | 39 | #define USB_VID_INTEL 0x8086 |
| 40 | #define USB_VID_ITETECH 0x048d | ||
| 40 | #define USB_VID_KWORLD 0xeb2a | 41 | #define USB_VID_KWORLD 0xeb2a |
| 41 | #define USB_VID_KWORLD_2 0x1b80 | 42 | #define USB_VID_KWORLD_2 0x1b80 |
| 42 | #define USB_VID_KYE 0x0458 | 43 | #define USB_VID_KYE 0x0458 |
| @@ -126,6 +127,7 @@ | |||
| 126 | #define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0 | 127 | #define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0 |
| 127 | #define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1 | 128 | #define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1 |
| 128 | #define USB_PID_INTEL_CE9500 0x9500 | 129 | #define USB_PID_INTEL_CE9500 0x9500 |
| 130 | #define USB_PID_ITETECH_IT9135 0x9135 | ||
| 129 | #define USB_PID_KWORLD_399U 0xe399 | 131 | #define USB_PID_KWORLD_399U 0xe399 |
| 130 | #define USB_PID_KWORLD_399U_2 0xe400 | 132 | #define USB_PID_KWORLD_399U_2 0xe400 |
| 131 | #define USB_PID_KWORLD_395U 0xe396 | 133 | #define USB_PID_KWORLD_395U 0xe396 |
diff --git a/drivers/media/dvb/dvb-usb/it913x.c b/drivers/media/dvb/dvb-usb/it913x.c index f027a2c1c3e8..c46226187143 100644 --- a/drivers/media/dvb/dvb-usb/it913x.c +++ b/drivers/media/dvb/dvb-usb/it913x.c | |||
| @@ -60,6 +60,17 @@ struct it913x_state { | |||
| 60 | u8 id; | 60 | u8 id; |
| 61 | }; | 61 | }; |
| 62 | 62 | ||
| 63 | struct ite_config { | ||
| 64 | u8 chip_ver; | ||
| 65 | u16 chip_type; | ||
| 66 | u32 firmware; | ||
| 67 | u8 tuner_id_0; | ||
| 68 | u8 tuner_id_1; | ||
| 69 | u8 dual_mode; | ||
| 70 | }; | ||
| 71 | |||
| 72 | struct ite_config it913x_config; | ||
| 73 | |||
| 63 | static int it913x_bulk_write(struct usb_device *dev, | 74 | static int it913x_bulk_write(struct usb_device *dev, |
| 64 | u8 *snd, int len, u8 pipe) | 75 | u8 *snd, int len, u8 pipe) |
| 65 | { | 76 | { |
| @@ -191,18 +202,23 @@ static int it913x_read_reg(struct usb_device *udev, u32 reg) | |||
| 191 | static u32 it913x_query(struct usb_device *udev, u8 pro) | 202 | static u32 it913x_query(struct usb_device *udev, u8 pro) |
| 192 | { | 203 | { |
| 193 | int ret; | 204 | int ret; |
| 194 | u32 res = 0; | ||
| 195 | u8 data[4]; | 205 | u8 data[4]; |
| 196 | ret = it913x_io(udev, READ_LONG, pro, CMD_DEMOD_READ, | 206 | ret = it913x_io(udev, READ_LONG, pro, CMD_DEMOD_READ, |
| 197 | 0x1222, 0, &data[0], 1); | 207 | 0x1222, 0, &data[0], 3); |
| 198 | if (data[0] == 0x1) { | 208 | |
| 199 | ret = it913x_io(udev, READ_SHORT, pro, | 209 | it913x_config.chip_ver = data[0]; |
| 210 | it913x_config.chip_type = (u16)(data[2] << 8) + data[1]; | ||
| 211 | |||
| 212 | info("Chip Version=%02x Chip Type=%04x", it913x_config.chip_ver, | ||
| 213 | it913x_config.chip_type); | ||
| 214 | |||
| 215 | ret |= it913x_io(udev, READ_SHORT, pro, | ||
| 200 | CMD_QUERYINFO, 0, 0x1, &data[0], 4); | 216 | CMD_QUERYINFO, 0, 0x1, &data[0], 4); |
| 201 | res = (data[0] << 24) + (data[1] << 16) + | 217 | |
| 218 | it913x_config.firmware = (data[0] << 24) + (data[1] << 16) + | ||
| 202 | (data[2] << 8) + data[3]; | 219 | (data[2] << 8) + data[3]; |
| 203 | } | ||
| 204 | 220 | ||
| 205 | return (ret < 0) ? 0 : res; | 221 | return (ret < 0) ? 0 : it913x_config.firmware; |
| 206 | } | 222 | } |
| 207 | 223 | ||
| 208 | static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) | 224 | static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) |
| @@ -336,26 +352,35 @@ static int it913x_identify_state(struct usb_device *udev, | |||
| 336 | int *cold) | 352 | int *cold) |
| 337 | { | 353 | { |
| 338 | int ret = 0, firm_no; | 354 | int ret = 0, firm_no; |
| 339 | u8 reg, adap, ep, tun0, tun1; | 355 | u8 reg, remote; |
| 340 | 356 | ||
| 341 | firm_no = it913x_return_status(udev); | 357 | firm_no = it913x_return_status(udev); |
| 342 | 358 | ||
| 343 | ep = it913x_read_reg(udev, 0x49ac); | 359 | /* checnk for dual mode */ |
| 344 | adap = it913x_read_reg(udev, 0x49c5); | 360 | it913x_config.dual_mode = it913x_read_reg(udev, 0x49c5); |
| 345 | tun0 = it913x_read_reg(udev, 0x49d0); | 361 | |
| 346 | info("No. Adapters=%x Endpoints=%x Tuner Type=%x", adap, ep, tun0); | 362 | /* TODO different remotes */ |
| 363 | remote = it913x_read_reg(udev, 0x49ac); /* Remote */ | ||
| 364 | if (remote == 0) | ||
| 365 | props->rc.core.rc_codes = NULL; | ||
| 366 | |||
| 367 | /* TODO at the moment tuner_id is always assigned to 0x38 */ | ||
| 368 | it913x_config.tuner_id_0 = it913x_read_reg(udev, 0x49d0); | ||
| 369 | |||
| 370 | info("Dual mode=%x Remote=%x Tuner Type=%x", it913x_config.dual_mode | ||
| 371 | , remote, it913x_config.tuner_id_0); | ||
| 347 | 372 | ||
| 348 | if (firm_no > 0) { | 373 | if (firm_no > 0) { |
| 349 | *cold = 0; | 374 | *cold = 0; |
| 350 | return 0; | 375 | return 0; |
| 351 | } | 376 | } |
| 352 | 377 | ||
| 353 | if (adap > 2) { | 378 | if (it913x_config.dual_mode) { |
| 354 | tun1 = it913x_read_reg(udev, 0x49e0); | 379 | it913x_config.tuner_id_1 = it913x_read_reg(udev, 0x49e0); |
| 355 | ret = it913x_wr_reg(udev, DEV_0, GPIOH1_EN, 0x1); | 380 | ret = it913x_wr_reg(udev, DEV_0, GPIOH1_EN, 0x1); |
| 356 | ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_ON, 0x1); | 381 | ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_ON, 0x1); |
| 357 | ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_O, 0x1); | 382 | ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_O, 0x1); |
| 358 | msleep(50); /* Delay noticed reset cycle ? */ | 383 | msleep(50); |
| 359 | ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_O, 0x0); | 384 | ret |= it913x_wr_reg(udev, DEV_0, GPIOH1_O, 0x0); |
| 360 | msleep(50); | 385 | msleep(50); |
| 361 | reg = it913x_read_reg(udev, GPIOH1_O); | 386 | reg = it913x_read_reg(udev, GPIOH1_O); |
| @@ -366,14 +391,19 @@ static int it913x_identify_state(struct usb_device *udev, | |||
| 366 | ret = it913x_wr_reg(udev, DEV_0, | 391 | ret = it913x_wr_reg(udev, DEV_0, |
| 367 | GPIOH1_O, 0x0); | 392 | GPIOH1_O, 0x0); |
| 368 | } | 393 | } |
| 394 | props->num_adapters = 2; | ||
| 369 | } else | 395 | } else |
| 370 | props->num_adapters = 1; | 396 | props->num_adapters = 1; |
| 371 | 397 | ||
| 372 | reg = it913x_read_reg(udev, IO_MUX_POWER_CLK); | 398 | reg = it913x_read_reg(udev, IO_MUX_POWER_CLK); |
| 373 | 399 | ||
| 374 | ret |= it913x_wr_reg(udev, DEV_0, 0x4bfb, CHIP2_I2C_ADDR); | 400 | if (it913x_config.dual_mode) { |
| 375 | 401 | ret |= it913x_wr_reg(udev, DEV_0, 0x4bfb, CHIP2_I2C_ADDR); | |
| 376 | ret |= it913x_wr_reg(udev, DEV_0, CLK_O_EN, 0x1); | 402 | ret |= it913x_wr_reg(udev, DEV_0, CLK_O_EN, 0x1); |
| 403 | } else { | ||
| 404 | ret |= it913x_wr_reg(udev, DEV_0, 0x4bfb, 0x0); | ||
| 405 | ret |= it913x_wr_reg(udev, DEV_0, CLK_O_EN, 0x0); | ||
| 406 | } | ||
| 377 | 407 | ||
| 378 | *cold = 1; | 408 | *cold = 1; |
| 379 | 409 | ||
| @@ -403,13 +433,11 @@ static int it913x_download_firmware(struct usb_device *udev, | |||
| 403 | const struct firmware *fw) | 433 | const struct firmware *fw) |
| 404 | { | 434 | { |
| 405 | int ret = 0, i; | 435 | int ret = 0, i; |
| 406 | u8 packet_size, dlen, tun1; | 436 | u8 packet_size, dlen; |
| 407 | u8 *fw_data; | 437 | u8 *fw_data; |
| 408 | 438 | ||
| 409 | packet_size = 0x29; | 439 | packet_size = 0x29; |
| 410 | 440 | ||
| 411 | tun1 = it913x_read_reg(udev, 0x49e0); | ||
| 412 | |||
| 413 | ret = it913x_wr_reg(udev, DEV_0, I2C_CLK, I2C_CLK_100); | 441 | ret = it913x_wr_reg(udev, DEV_0, I2C_CLK, I2C_CLK_100); |
| 414 | 442 | ||
| 415 | info("FRM Starting Firmware Download"); | 443 | info("FRM Starting Firmware Download"); |
| @@ -444,11 +472,12 @@ static int it913x_download_firmware(struct usb_device *udev, | |||
| 444 | ret |= it913x_wr_reg(udev, DEV_0, I2C_CLK, I2C_CLK_400); | 472 | ret |= it913x_wr_reg(udev, DEV_0, I2C_CLK, I2C_CLK_400); |
| 445 | 473 | ||
| 446 | /* Tuner function */ | 474 | /* Tuner function */ |
| 447 | ret |= it913x_wr_reg(udev, DEV_0_DMOD , 0xec4c, 0xa0); | 475 | if (it913x_config.dual_mode) |
| 476 | ret |= it913x_wr_reg(udev, DEV_0_DMOD , 0xec4c, 0xa0); | ||
| 448 | 477 | ||
| 449 | ret |= it913x_wr_reg(udev, DEV_0, PADODPU, 0x0); | 478 | ret |= it913x_wr_reg(udev, DEV_0, PADODPU, 0x0); |
| 450 | ret |= it913x_wr_reg(udev, DEV_0, AGC_O_D, 0x0); | 479 | ret |= it913x_wr_reg(udev, DEV_0, AGC_O_D, 0x0); |
| 451 | if (tun1 > 0) { | 480 | if (it913x_config.dual_mode) { |
| 452 | ret |= it913x_wr_reg(udev, DEV_1, PADODPU, 0x0); | 481 | ret |= it913x_wr_reg(udev, DEV_1, PADODPU, 0x0); |
| 453 | ret |= it913x_wr_reg(udev, DEV_1, AGC_O_D, 0x0); | 482 | ret |= it913x_wr_reg(udev, DEV_1, AGC_O_D, 0x0); |
| 454 | } | 483 | } |
| @@ -475,9 +504,28 @@ static int it913x_frontend_attach(struct dvb_usb_adapter *adap) | |||
| 475 | u8 adf = it913x_read_reg(udev, IO_MUX_POWER_CLK); | 504 | u8 adf = it913x_read_reg(udev, IO_MUX_POWER_CLK); |
| 476 | u8 adap_addr = I2C_BASE_ADDR + (adap->id << 5); | 505 | u8 adap_addr = I2C_BASE_ADDR + (adap->id << 5); |
| 477 | u16 ep_size = adap->props.fe[0].stream.u.bulk.buffersize; | 506 | u16 ep_size = adap->props.fe[0].stream.u.bulk.buffersize; |
| 507 | u8 tuner_id, tuner_type; | ||
| 508 | |||
| 509 | if (adap->id == 0) | ||
| 510 | tuner_id = it913x_config.tuner_id_0; | ||
| 511 | else | ||
| 512 | tuner_id = it913x_config.tuner_id_1; | ||
| 513 | |||
| 514 | /* TODO we always use IT9137 possible references here*/ | ||
| 515 | /* Documentation suggests don't care */ | ||
| 516 | switch (tuner_id) { | ||
| 517 | case 0x51: | ||
| 518 | case 0x52: | ||
| 519 | case 0x60: | ||
| 520 | case 0x61: | ||
| 521 | case 0x62: | ||
| 522 | default: | ||
| 523 | case 0x38: | ||
| 524 | tuner_type = IT9137; | ||
| 525 | } | ||
| 478 | 526 | ||
| 479 | adap->fe_adap[0].fe = dvb_attach(it913x_fe_attach, | 527 | adap->fe_adap[0].fe = dvb_attach(it913x_fe_attach, |
| 480 | &adap->dev->i2c_adap, adap_addr, adf, IT9137); | 528 | &adap->dev->i2c_adap, adap_addr, adf, tuner_type); |
| 481 | 529 | ||
| 482 | if (adap->id == 0 && adap->fe_adap[0].fe) { | 530 | if (adap->id == 0 && adap->fe_adap[0].fe) { |
| 483 | ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2_SW_RST, 0x1); | 531 | ret = it913x_wr_reg(udev, DEV_0_DMOD, MP2_SW_RST, 0x1); |
| @@ -533,6 +581,7 @@ static int it913x_probe(struct usb_interface *intf, | |||
| 533 | 581 | ||
| 534 | static struct usb_device_id it913x_table[] = { | 582 | static struct usb_device_id it913x_table[] = { |
| 535 | { USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB499_2T_T09) }, | 583 | { USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB499_2T_T09) }, |
| 584 | { USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135) }, | ||
| 536 | {} /* Terminating entry */ | 585 | {} /* Terminating entry */ |
| 537 | }; | 586 | }; |
| 538 | 587 | ||
| @@ -608,12 +657,14 @@ static struct dvb_usb_device_properties it913x_properties = { | |||
| 608 | .rc_codes = RC_MAP_KWORLD_315U, | 657 | .rc_codes = RC_MAP_KWORLD_315U, |
| 609 | }, | 658 | }, |
| 610 | .i2c_algo = &it913x_i2c_algo, | 659 | .i2c_algo = &it913x_i2c_algo, |
| 611 | .num_device_descs = 1, | 660 | .num_device_descs = 2, |
| 612 | .devices = { | 661 | .devices = { |
| 613 | { "Kworld UB499-2T T09(IT9137)", | 662 | { "Kworld UB499-2T T09(IT9137)", |
| 614 | { &it913x_table[0], NULL }, | 663 | { &it913x_table[0], NULL }, |
| 615 | }, | 664 | }, |
| 616 | 665 | { "ITE 9135 Generic", | |
| 666 | { &it913x_table[1], NULL }, | ||
| 667 | }, | ||
| 617 | } | 668 | } |
| 618 | }; | 669 | }; |
| 619 | 670 | ||
| @@ -647,5 +698,5 @@ module_exit(it913x_module_exit); | |||
| 647 | 698 | ||
| 648 | MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>"); | 699 | MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>"); |
| 649 | MODULE_DESCRIPTION("it913x USB 2 Driver"); | 700 | MODULE_DESCRIPTION("it913x USB 2 Driver"); |
| 650 | MODULE_VERSION("1.06"); | 701 | MODULE_VERSION("1.07"); |
| 651 | MODULE_LICENSE("GPL"); | 702 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-demod.c b/drivers/media/dvb/dvb-usb/mxl111sf-demod.c new file mode 100644 index 000000000000..d1f58371c711 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/mxl111sf-demod.c | |||
| @@ -0,0 +1,614 @@ | |||
| 1 | /* | ||
| 2 | * mxl111sf-demod.c - driver for the MaxLinear MXL111SF DVB-T demodulator | ||
| 3 | * | ||
| 4 | * Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include "mxl111sf-demod.h" | ||
| 22 | #include "mxl111sf-reg.h" | ||
| 23 | |||
| 24 | /* debug */ | ||
| 25 | static int mxl111sf_demod_debug; | ||
| 26 | module_param_named(debug, mxl111sf_demod_debug, int, 0644); | ||
| 27 | MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."); | ||
| 28 | |||
| 29 | #define mxl_dbg(fmt, arg...) \ | ||
| 30 | if (mxl111sf_demod_debug) \ | ||
| 31 | mxl_printk(KERN_DEBUG, fmt, ##arg) | ||
| 32 | |||
| 33 | /* ------------------------------------------------------------------------ */ | ||
| 34 | |||
| 35 | struct mxl111sf_demod_state { | ||
| 36 | struct mxl111sf_state *mxl_state; | ||
| 37 | |||
| 38 | struct mxl111sf_demod_config *cfg; | ||
| 39 | |||
| 40 | struct dvb_frontend fe; | ||
| 41 | }; | ||
| 42 | |||
| 43 | /* ------------------------------------------------------------------------ */ | ||
| 44 | |||
| 45 | static int mxl111sf_demod_read_reg(struct mxl111sf_demod_state *state, | ||
| 46 | u8 addr, u8 *data) | ||
| 47 | { | ||
| 48 | return (state->cfg->read_reg) ? | ||
| 49 | state->cfg->read_reg(state->mxl_state, addr, data) : | ||
| 50 | -EINVAL; | ||
| 51 | } | ||
| 52 | |||
| 53 | static int mxl111sf_demod_write_reg(struct mxl111sf_demod_state *state, | ||
| 54 | u8 addr, u8 data) | ||
| 55 | { | ||
| 56 | return (state->cfg->write_reg) ? | ||
| 57 | state->cfg->write_reg(state->mxl_state, addr, data) : | ||
| 58 | -EINVAL; | ||
| 59 | } | ||
| 60 | |||
| 61 | static | ||
| 62 | int mxl111sf_demod_program_regs(struct mxl111sf_demod_state *state, | ||
| 63 | struct mxl111sf_reg_ctrl_info *ctrl_reg_info) | ||
| 64 | { | ||
| 65 | return (state->cfg->program_regs) ? | ||
| 66 | state->cfg->program_regs(state->mxl_state, ctrl_reg_info) : | ||
| 67 | -EINVAL; | ||
| 68 | } | ||
| 69 | |||
| 70 | /* ------------------------------------------------------------------------ */ | ||
| 71 | /* TPS */ | ||
| 72 | |||
| 73 | static | ||
| 74 | int mxl1x1sf_demod_get_tps_code_rate(struct mxl111sf_demod_state *state, | ||
| 75 | fe_code_rate_t *code_rate) | ||
| 76 | { | ||
| 77 | u8 val; | ||
| 78 | int ret = mxl111sf_demod_read_reg(state, V6_CODE_RATE_TPS_REG, &val); | ||
| 79 | /* bit<2:0> - 000:1/2, 001:2/3, 010:3/4, 011:5/6, 100:7/8 */ | ||
| 80 | if (mxl_fail(ret)) | ||
| 81 | goto fail; | ||
| 82 | |||
| 83 | switch (val & V6_CODE_RATE_TPS_MASK) { | ||
| 84 | case 0: | ||
| 85 | *code_rate = FEC_1_2; | ||
| 86 | break; | ||
| 87 | case 1: | ||
| 88 | *code_rate = FEC_2_3; | ||
| 89 | break; | ||
| 90 | case 2: | ||
| 91 | *code_rate = FEC_3_4; | ||
| 92 | break; | ||
| 93 | case 3: | ||
| 94 | *code_rate = FEC_5_6; | ||
| 95 | break; | ||
| 96 | case 4: | ||
| 97 | *code_rate = FEC_7_8; | ||
| 98 | break; | ||
| 99 | } | ||
| 100 | fail: | ||
| 101 | return ret; | ||
| 102 | } | ||
| 103 | |||
| 104 | static | ||
| 105 | int mxl1x1sf_demod_get_tps_constellation(struct mxl111sf_demod_state *state, | ||
| 106 | fe_modulation_t *constellation) | ||
| 107 | { | ||
| 108 | u8 val; | ||
| 109 | int ret = mxl111sf_demod_read_reg(state, V6_MODORDER_TPS_REG, &val); | ||
| 110 | /* Constellation, 00 : QPSK, 01 : 16QAM, 10:64QAM */ | ||
| 111 | if (mxl_fail(ret)) | ||
| 112 | goto fail; | ||
| 113 | |||
| 114 | switch ((val & V6_PARAM_CONSTELLATION_MASK) >> 4) { | ||
| 115 | case 0: | ||
| 116 | *constellation = QPSK; | ||
| 117 | break; | ||
| 118 | case 1: | ||
| 119 | *constellation = QAM_16; | ||
| 120 | break; | ||
| 121 | case 2: | ||
| 122 | *constellation = QAM_64; | ||
| 123 | break; | ||
| 124 | } | ||
| 125 | fail: | ||
| 126 | return ret; | ||
| 127 | } | ||
| 128 | |||
| 129 | static | ||
| 130 | int mxl1x1sf_demod_get_tps_guard_fft_mode(struct mxl111sf_demod_state *state, | ||
| 131 | fe_transmit_mode_t *fft_mode) | ||
| 132 | { | ||
| 133 | u8 val; | ||
| 134 | int ret = mxl111sf_demod_read_reg(state, V6_MODE_TPS_REG, &val); | ||
| 135 | /* FFT Mode, 00:2K, 01:8K, 10:4K */ | ||
| 136 | if (mxl_fail(ret)) | ||
| 137 | goto fail; | ||
| 138 | |||
| 139 | switch ((val & V6_PARAM_FFT_MODE_MASK) >> 2) { | ||
| 140 | case 0: | ||
| 141 | *fft_mode = TRANSMISSION_MODE_2K; | ||
| 142 | break; | ||
| 143 | case 1: | ||
| 144 | *fft_mode = TRANSMISSION_MODE_8K; | ||
| 145 | break; | ||
| 146 | case 2: | ||
| 147 | *fft_mode = TRANSMISSION_MODE_4K; | ||
| 148 | break; | ||
| 149 | } | ||
| 150 | fail: | ||
| 151 | return ret; | ||
| 152 | } | ||
| 153 | |||
| 154 | static | ||
| 155 | int mxl1x1sf_demod_get_tps_guard_interval(struct mxl111sf_demod_state *state, | ||
| 156 | fe_guard_interval_t *guard) | ||
| 157 | { | ||
| 158 | u8 val; | ||
| 159 | int ret = mxl111sf_demod_read_reg(state, V6_CP_TPS_REG, &val); | ||
| 160 | /* 00:1/32, 01:1/16, 10:1/8, 11:1/4 */ | ||
| 161 | if (mxl_fail(ret)) | ||
| 162 | goto fail; | ||
| 163 | |||
| 164 | switch ((val & V6_PARAM_GI_MASK) >> 4) { | ||
| 165 | case 0: | ||
| 166 | *guard = GUARD_INTERVAL_1_32; | ||
| 167 | break; | ||
| 168 | case 1: | ||
| 169 | *guard = GUARD_INTERVAL_1_16; | ||
| 170 | break; | ||
| 171 | case 2: | ||
| 172 | *guard = GUARD_INTERVAL_1_8; | ||
| 173 | break; | ||
| 174 | case 3: | ||
| 175 | *guard = GUARD_INTERVAL_1_4; | ||
| 176 | break; | ||
| 177 | } | ||
| 178 | fail: | ||
| 179 | return ret; | ||
| 180 | } | ||
| 181 | |||
| 182 | static | ||
| 183 | int mxl1x1sf_demod_get_tps_hierarchy(struct mxl111sf_demod_state *state, | ||
| 184 | fe_hierarchy_t *hierarchy) | ||
| 185 | { | ||
| 186 | u8 val; | ||
| 187 | int ret = mxl111sf_demod_read_reg(state, V6_TPS_HIERACHY_REG, &val); | ||
| 188 | /* bit<6:4> - 000:Non hierarchy, 001:1, 010:2, 011:4 */ | ||
| 189 | if (mxl_fail(ret)) | ||
| 190 | goto fail; | ||
| 191 | |||
| 192 | switch ((val & V6_TPS_HIERARCHY_INFO_MASK) >> 6) { | ||
| 193 | case 0: | ||
| 194 | *hierarchy = HIERARCHY_NONE; | ||
| 195 | break; | ||
| 196 | case 1: | ||
| 197 | *hierarchy = HIERARCHY_1; | ||
| 198 | break; | ||
| 199 | case 2: | ||
| 200 | *hierarchy = HIERARCHY_2; | ||
| 201 | break; | ||
| 202 | case 3: | ||
| 203 | *hierarchy = HIERARCHY_4; | ||
| 204 | break; | ||
| 205 | } | ||
| 206 | fail: | ||
| 207 | return ret; | ||
| 208 | } | ||
| 209 | |||
| 210 | /* ------------------------------------------------------------------------ */ | ||
| 211 | /* LOCKS */ | ||
| 212 | |||
| 213 | static | ||
| 214 | int mxl1x1sf_demod_get_sync_lock_status(struct mxl111sf_demod_state *state, | ||
| 215 | int *sync_lock) | ||
| 216 | { | ||
| 217 | u8 val = 0; | ||
| 218 | int ret = mxl111sf_demod_read_reg(state, V6_SYNC_LOCK_REG, &val); | ||
| 219 | if (mxl_fail(ret)) | ||
| 220 | goto fail; | ||
| 221 | *sync_lock = (val & SYNC_LOCK_MASK) >> 4; | ||
| 222 | fail: | ||
| 223 | return ret; | ||
| 224 | } | ||
| 225 | |||
| 226 | static | ||
| 227 | int mxl1x1sf_demod_get_rs_lock_status(struct mxl111sf_demod_state *state, | ||
| 228 | int *rs_lock) | ||
| 229 | { | ||
| 230 | u8 val = 0; | ||
| 231 | int ret = mxl111sf_demod_read_reg(state, V6_RS_LOCK_DET_REG, &val); | ||
| 232 | if (mxl_fail(ret)) | ||
| 233 | goto fail; | ||
| 234 | *rs_lock = (val & RS_LOCK_DET_MASK) >> 3; | ||
| 235 | fail: | ||
| 236 | return ret; | ||
| 237 | } | ||
| 238 | |||
| 239 | static | ||
| 240 | int mxl1x1sf_demod_get_tps_lock_status(struct mxl111sf_demod_state *state, | ||
| 241 | int *tps_lock) | ||
| 242 | { | ||
| 243 | u8 val = 0; | ||
| 244 | int ret = mxl111sf_demod_read_reg(state, V6_TPS_LOCK_REG, &val); | ||
| 245 | if (mxl_fail(ret)) | ||
| 246 | goto fail; | ||
| 247 | *tps_lock = (val & V6_PARAM_TPS_LOCK_MASK) >> 6; | ||
| 248 | fail: | ||
| 249 | return ret; | ||
| 250 | } | ||
| 251 | |||
| 252 | static | ||
| 253 | int mxl1x1sf_demod_get_fec_lock_status(struct mxl111sf_demod_state *state, | ||
| 254 | int *fec_lock) | ||
| 255 | { | ||
| 256 | u8 val = 0; | ||
| 257 | int ret = mxl111sf_demod_read_reg(state, V6_IRQ_STATUS_REG, &val); | ||
| 258 | if (mxl_fail(ret)) | ||
| 259 | goto fail; | ||
| 260 | *fec_lock = (val & IRQ_MASK_FEC_LOCK) >> 4; | ||
| 261 | fail: | ||
| 262 | return ret; | ||
| 263 | } | ||
| 264 | |||
| 265 | #if 0 | ||
| 266 | static | ||
| 267 | int mxl1x1sf_demod_get_cp_lock_status(struct mxl111sf_demod_state *state, | ||
| 268 | int *cp_lock) | ||
| 269 | { | ||
| 270 | u8 val = 0; | ||
| 271 | int ret = mxl111sf_demod_read_reg(state, V6_CP_LOCK_DET_REG, &val); | ||
| 272 | if (mxl_fail(ret)) | ||
| 273 | goto fail; | ||
| 274 | *cp_lock = (val & V6_CP_LOCK_DET_MASK) >> 2; | ||
| 275 | fail: | ||
| 276 | return ret; | ||
| 277 | } | ||
| 278 | #endif | ||
| 279 | |||
| 280 | static int mxl1x1sf_demod_reset_irq_status(struct mxl111sf_demod_state *state) | ||
| 281 | { | ||
| 282 | return mxl111sf_demod_write_reg(state, 0x0e, 0xff); | ||
| 283 | } | ||
| 284 | |||
| 285 | /* ------------------------------------------------------------------------ */ | ||
| 286 | |||
| 287 | static int mxl111sf_demod_set_frontend(struct dvb_frontend *fe, | ||
| 288 | struct dvb_frontend_parameters *param) | ||
| 289 | { | ||
| 290 | struct mxl111sf_demod_state *state = fe->demodulator_priv; | ||
| 291 | int ret = 0; | ||
| 292 | |||
| 293 | struct mxl111sf_reg_ctrl_info phy_pll_patch[] = { | ||
| 294 | {0x00, 0xff, 0x01}, /* change page to 1 */ | ||
| 295 | {0x40, 0xff, 0x05}, | ||
| 296 | {0x40, 0xff, 0x01}, | ||
| 297 | {0x41, 0xff, 0xca}, | ||
| 298 | {0x41, 0xff, 0xc0}, | ||
| 299 | {0x00, 0xff, 0x00}, /* change page to 0 */ | ||
| 300 | {0, 0, 0} | ||
| 301 | }; | ||
| 302 | |||
| 303 | mxl_dbg("()"); | ||
| 304 | |||
| 305 | if (fe->ops.tuner_ops.set_params) { | ||
| 306 | ret = fe->ops.tuner_ops.set_params(fe, param); | ||
| 307 | if (mxl_fail(ret)) | ||
| 308 | goto fail; | ||
| 309 | msleep(50); | ||
| 310 | } | ||
| 311 | ret = mxl111sf_demod_program_regs(state, phy_pll_patch); | ||
| 312 | mxl_fail(ret); | ||
| 313 | msleep(50); | ||
| 314 | ret = mxl1x1sf_demod_reset_irq_status(state); | ||
| 315 | mxl_fail(ret); | ||
| 316 | msleep(100); | ||
| 317 | fail: | ||
| 318 | return ret; | ||
| 319 | } | ||
| 320 | |||
| 321 | /* ------------------------------------------------------------------------ */ | ||
| 322 | |||
| 323 | #if 0 | ||
| 324 | /* resets TS Packet error count */ | ||
| 325 | /* After setting 7th bit of V5_PER_COUNT_RESET_REG, it should be reset to 0. */ | ||
| 326 | static | ||
| 327 | int mxl1x1sf_demod_reset_packet_error_count(struct mxl111sf_demod_state *state) | ||
| 328 | { | ||
| 329 | struct mxl111sf_reg_ctrl_info reset_per_count[] = { | ||
| 330 | {0x20, 0x01, 0x01}, | ||
| 331 | {0x20, 0x01, 0x00}, | ||
| 332 | {0, 0, 0} | ||
| 333 | }; | ||
| 334 | return mxl111sf_demod_program_regs(state, reset_per_count); | ||
| 335 | } | ||
| 336 | #endif | ||
| 337 | |||
| 338 | /* returns TS Packet error count */ | ||
| 339 | /* PER Count = FEC_PER_COUNT * (2 ** (FEC_PER_SCALE * 4)) */ | ||
| 340 | static int mxl111sf_demod_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) | ||
| 341 | { | ||
| 342 | struct mxl111sf_demod_state *state = fe->demodulator_priv; | ||
| 343 | u32 fec_per_count, fec_per_scale; | ||
| 344 | u8 val; | ||
| 345 | int ret; | ||
| 346 | |||
| 347 | *ucblocks = 0; | ||
| 348 | |||
| 349 | /* FEC_PER_COUNT Register */ | ||
| 350 | ret = mxl111sf_demod_read_reg(state, V6_FEC_PER_COUNT_REG, &val); | ||
| 351 | if (mxl_fail(ret)) | ||
| 352 | goto fail; | ||
| 353 | |||
| 354 | fec_per_count = val; | ||
| 355 | |||
| 356 | /* FEC_PER_SCALE Register */ | ||
| 357 | ret = mxl111sf_demod_read_reg(state, V6_FEC_PER_SCALE_REG, &val); | ||
| 358 | if (mxl_fail(ret)) | ||
| 359 | goto fail; | ||
| 360 | |||
| 361 | val &= V6_FEC_PER_SCALE_MASK; | ||
| 362 | val *= 4; | ||
| 363 | |||
| 364 | fec_per_scale = 1 << val; | ||
| 365 | |||
| 366 | fec_per_count *= fec_per_scale; | ||
| 367 | |||
| 368 | *ucblocks = fec_per_count; | ||
| 369 | fail: | ||
| 370 | return ret; | ||
| 371 | } | ||
| 372 | |||
| 373 | #ifdef MXL111SF_DEMOD_ENABLE_CALCULATIONS | ||
| 374 | /* FIXME: leaving this enabled breaks the build on some architectures, | ||
| 375 | * and we shouldn't have any floating point math in the kernel, anyway. | ||
| 376 | * | ||
| 377 | * These macros need to be re-written, but it's harmless to simply | ||
| 378 | * return zero for now. */ | ||
| 379 | #define CALCULATE_BER(avg_errors, count) \ | ||
| 380 | ((u32)(avg_errors * 4)/(count*64*188*8)) | ||
| 381 | #define CALCULATE_SNR(data) \ | ||
| 382 | ((u32)((10 * (u32)data / 64) - 2.5)) | ||
| 383 | #else | ||
| 384 | #define CALCULATE_BER(avg_errors, count) 0 | ||
| 385 | #define CALCULATE_SNR(data) 0 | ||
| 386 | #endif | ||
| 387 | |||
| 388 | static int mxl111sf_demod_read_ber(struct dvb_frontend *fe, u32 *ber) | ||
| 389 | { | ||
| 390 | struct mxl111sf_demod_state *state = fe->demodulator_priv; | ||
| 391 | u8 val1, val2, val3; | ||
| 392 | int ret; | ||
| 393 | |||
| 394 | *ber = 0; | ||
| 395 | |||
| 396 | ret = mxl111sf_demod_read_reg(state, V6_RS_AVG_ERRORS_LSB_REG, &val1); | ||
| 397 | if (mxl_fail(ret)) | ||
| 398 | goto fail; | ||
| 399 | ret = mxl111sf_demod_read_reg(state, V6_RS_AVG_ERRORS_MSB_REG, &val2); | ||
| 400 | if (mxl_fail(ret)) | ||
| 401 | goto fail; | ||
| 402 | ret = mxl111sf_demod_read_reg(state, V6_N_ACCUMULATE_REG, &val3); | ||
| 403 | if (mxl_fail(ret)) | ||
| 404 | goto fail; | ||
| 405 | |||
| 406 | *ber = CALCULATE_BER((val1 | (val2 << 8)), val3); | ||
| 407 | fail: | ||
| 408 | return ret; | ||
| 409 | } | ||
| 410 | |||
| 411 | static int mxl111sf_demod_calc_snr(struct mxl111sf_demod_state *state, | ||
| 412 | u16 *snr) | ||
| 413 | { | ||
| 414 | u8 val1, val2; | ||
| 415 | int ret; | ||
| 416 | |||
| 417 | *snr = 0; | ||
| 418 | |||
| 419 | ret = mxl111sf_demod_read_reg(state, V6_SNR_RB_LSB_REG, &val1); | ||
| 420 | if (mxl_fail(ret)) | ||
| 421 | goto fail; | ||
| 422 | ret = mxl111sf_demod_read_reg(state, V6_SNR_RB_MSB_REG, &val2); | ||
| 423 | if (mxl_fail(ret)) | ||
| 424 | goto fail; | ||
| 425 | |||
| 426 | *snr = CALCULATE_SNR(val1 | ((val2 & 0x03) << 8)); | ||
| 427 | fail: | ||
| 428 | return ret; | ||
| 429 | } | ||
| 430 | |||
| 431 | static int mxl111sf_demod_read_snr(struct dvb_frontend *fe, u16 *snr) | ||
| 432 | { | ||
| 433 | struct mxl111sf_demod_state *state = fe->demodulator_priv; | ||
| 434 | |||
| 435 | int ret = mxl111sf_demod_calc_snr(state, snr); | ||
| 436 | if (mxl_fail(ret)) | ||
| 437 | goto fail; | ||
| 438 | |||
| 439 | *snr /= 10; /* 0.1 dB */ | ||
| 440 | fail: | ||
| 441 | return ret; | ||
| 442 | } | ||
| 443 | |||
| 444 | static int mxl111sf_demod_read_status(struct dvb_frontend *fe, | ||
| 445 | fe_status_t *status) | ||
| 446 | { | ||
| 447 | struct mxl111sf_demod_state *state = fe->demodulator_priv; | ||
| 448 | int ret, locked, cr_lock, sync_lock, fec_lock; | ||
| 449 | |||
| 450 | *status = 0; | ||
| 451 | |||
| 452 | ret = mxl1x1sf_demod_get_rs_lock_status(state, &locked); | ||
| 453 | if (mxl_fail(ret)) | ||
| 454 | goto fail; | ||
| 455 | ret = mxl1x1sf_demod_get_tps_lock_status(state, &cr_lock); | ||
| 456 | if (mxl_fail(ret)) | ||
| 457 | goto fail; | ||
| 458 | ret = mxl1x1sf_demod_get_sync_lock_status(state, &sync_lock); | ||
| 459 | if (mxl_fail(ret)) | ||
| 460 | goto fail; | ||
| 461 | ret = mxl1x1sf_demod_get_fec_lock_status(state, &fec_lock); | ||
| 462 | if (mxl_fail(ret)) | ||
| 463 | goto fail; | ||
| 464 | |||
| 465 | if (locked) | ||
| 466 | *status |= FE_HAS_SIGNAL; | ||
| 467 | if (cr_lock) | ||
| 468 | *status |= FE_HAS_CARRIER; | ||
| 469 | if (sync_lock) | ||
| 470 | *status |= FE_HAS_SYNC; | ||
| 471 | if (fec_lock) /* false positives? */ | ||
| 472 | *status |= FE_HAS_VITERBI; | ||
| 473 | |||
| 474 | if ((locked) && (cr_lock) && (sync_lock)) | ||
| 475 | *status |= FE_HAS_LOCK; | ||
| 476 | fail: | ||
| 477 | return ret; | ||
| 478 | } | ||
| 479 | |||
| 480 | static int mxl111sf_demod_read_signal_strength(struct dvb_frontend *fe, | ||
| 481 | u16 *signal_strength) | ||
| 482 | { | ||
| 483 | struct mxl111sf_demod_state *state = fe->demodulator_priv; | ||
| 484 | fe_modulation_t constellation; | ||
| 485 | u16 snr; | ||
| 486 | |||
| 487 | mxl111sf_demod_calc_snr(state, &snr); | ||
| 488 | mxl1x1sf_demod_get_tps_constellation(state, &constellation); | ||
| 489 | |||
| 490 | switch (constellation) { | ||
| 491 | case QPSK: | ||
| 492 | *signal_strength = (snr >= 1300) ? | ||
| 493 | min(65535, snr * 44) : snr * 38; | ||
| 494 | break; | ||
| 495 | case QAM_16: | ||
| 496 | *signal_strength = (snr >= 1500) ? | ||
| 497 | min(65535, snr * 38) : snr * 33; | ||
| 498 | break; | ||
| 499 | case QAM_64: | ||
| 500 | *signal_strength = (snr >= 2000) ? | ||
| 501 | min(65535, snr * 29) : snr * 25; | ||
| 502 | break; | ||
| 503 | default: | ||
| 504 | *signal_strength = 0; | ||
| 505 | return -EINVAL; | ||
| 506 | } | ||
| 507 | |||
| 508 | return 0; | ||
| 509 | } | ||
| 510 | |||
| 511 | static int mxl111sf_demod_get_frontend(struct dvb_frontend *fe, | ||
| 512 | struct dvb_frontend_parameters *p) | ||
| 513 | { | ||
| 514 | struct mxl111sf_demod_state *state = fe->demodulator_priv; | ||
| 515 | |||
| 516 | mxl_dbg("()"); | ||
| 517 | #if 0 | ||
| 518 | p->inversion = /* FIXME */ ? INVERSION_ON : INVERSION_OFF; | ||
| 519 | #endif | ||
| 520 | if (fe->ops.tuner_ops.get_bandwidth) | ||
| 521 | fe->ops.tuner_ops.get_bandwidth(fe, &p->u.ofdm.bandwidth); | ||
| 522 | if (fe->ops.tuner_ops.get_frequency) | ||
| 523 | fe->ops.tuner_ops.get_frequency(fe, &p->frequency); | ||
| 524 | mxl1x1sf_demod_get_tps_code_rate(state, &p->u.ofdm.code_rate_HP); | ||
| 525 | mxl1x1sf_demod_get_tps_code_rate(state, &p->u.ofdm.code_rate_LP); | ||
| 526 | mxl1x1sf_demod_get_tps_constellation(state, &p->u.ofdm.constellation); | ||
| 527 | mxl1x1sf_demod_get_tps_guard_fft_mode(state, | ||
| 528 | &p->u.ofdm.transmission_mode); | ||
| 529 | mxl1x1sf_demod_get_tps_guard_interval(state, | ||
| 530 | &p->u.ofdm.guard_interval); | ||
| 531 | mxl1x1sf_demod_get_tps_hierarchy(state, | ||
| 532 | &p->u.ofdm.hierarchy_information); | ||
| 533 | |||
| 534 | return 0; | ||
| 535 | } | ||
| 536 | |||
| 537 | static | ||
| 538 | int mxl111sf_demod_get_tune_settings(struct dvb_frontend *fe, | ||
| 539 | struct dvb_frontend_tune_settings *tune) | ||
| 540 | { | ||
| 541 | tune->min_delay_ms = 1000; | ||
| 542 | return 0; | ||
| 543 | } | ||
| 544 | |||
| 545 | static void mxl111sf_demod_release(struct dvb_frontend *fe) | ||
| 546 | { | ||
| 547 | struct mxl111sf_demod_state *state = fe->demodulator_priv; | ||
| 548 | mxl_dbg("()"); | ||
| 549 | kfree(state); | ||
| 550 | fe->demodulator_priv = NULL; | ||
| 551 | } | ||
| 552 | |||
| 553 | static struct dvb_frontend_ops mxl111sf_demod_ops = { | ||
| 554 | |||
| 555 | .info = { | ||
| 556 | .name = "MaxLinear MxL111SF DVB-T demodulator", | ||
| 557 | .type = FE_OFDM, | ||
| 558 | .frequency_min = 177000000, | ||
| 559 | .frequency_max = 858000000, | ||
| 560 | .frequency_stepsize = 166666, | ||
| 561 | .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | | ||
| 562 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | | ||
| 563 | FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | | ||
| 564 | FE_CAN_QAM_AUTO | | ||
| 565 | FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | | ||
| 566 | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER | ||
| 567 | }, | ||
| 568 | .release = mxl111sf_demod_release, | ||
| 569 | #if 0 | ||
| 570 | .init = mxl111sf_init, | ||
| 571 | .i2c_gate_ctrl = mxl111sf_i2c_gate_ctrl, | ||
| 572 | #endif | ||
| 573 | .set_frontend = mxl111sf_demod_set_frontend, | ||
| 574 | .get_frontend = mxl111sf_demod_get_frontend, | ||
| 575 | .get_tune_settings = mxl111sf_demod_get_tune_settings, | ||
| 576 | .read_status = mxl111sf_demod_read_status, | ||
| 577 | .read_signal_strength = mxl111sf_demod_read_signal_strength, | ||
| 578 | .read_ber = mxl111sf_demod_read_ber, | ||
| 579 | .read_snr = mxl111sf_demod_read_snr, | ||
| 580 | .read_ucblocks = mxl111sf_demod_read_ucblocks, | ||
| 581 | }; | ||
| 582 | |||
| 583 | struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state, | ||
| 584 | struct mxl111sf_demod_config *cfg) | ||
| 585 | { | ||
| 586 | struct mxl111sf_demod_state *state = NULL; | ||
| 587 | |||
| 588 | mxl_dbg("()"); | ||
| 589 | |||
| 590 | state = kzalloc(sizeof(struct mxl111sf_demod_state), GFP_KERNEL); | ||
| 591 | if (state == NULL) | ||
| 592 | return NULL; | ||
| 593 | |||
| 594 | state->mxl_state = mxl_state; | ||
| 595 | state->cfg = cfg; | ||
| 596 | |||
| 597 | memcpy(&state->fe.ops, &mxl111sf_demod_ops, | ||
| 598 | sizeof(struct dvb_frontend_ops)); | ||
| 599 | |||
| 600 | state->fe.demodulator_priv = state; | ||
| 601 | return &state->fe; | ||
| 602 | } | ||
| 603 | EXPORT_SYMBOL_GPL(mxl111sf_demod_attach); | ||
| 604 | |||
| 605 | MODULE_DESCRIPTION("MaxLinear MxL111SF DVB-T demodulator driver"); | ||
| 606 | MODULE_AUTHOR("Michael Krufky <mkrufky@kernellabs.com>"); | ||
| 607 | MODULE_LICENSE("GPL"); | ||
| 608 | MODULE_VERSION("0.1"); | ||
| 609 | |||
| 610 | /* | ||
| 611 | * Local variables: | ||
| 612 | * c-basic-offset: 8 | ||
| 613 | * End: | ||
| 614 | */ | ||
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-demod.h b/drivers/media/dvb/dvb-usb/mxl111sf-demod.h new file mode 100644 index 000000000000..432706ae5274 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/mxl111sf-demod.h | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | /* | ||
| 2 | * mxl111sf-demod.h - driver for the MaxLinear MXL111SF DVB-T demodulator | ||
| 3 | * | ||
| 4 | * Copyright (C) 2010 Michael Krufky <mkrufky@kernellabs.com> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #ifndef __MXL111SF_DEMOD_H__ | ||
| 22 | #define __MXL111SF_DEMOD_H__ | ||
| 23 | |||
| 24 | #include "dvb_frontend.h" | ||
| 25 | #include "mxl111sf.h" | ||
| 26 | |||
| 27 | struct mxl111sf_demod_config { | ||
| 28 | int (*read_reg)(struct mxl111sf_state *state, u8 addr, u8 *data); | ||
| 29 | int (*write_reg)(struct mxl111sf_state *state, u8 addr, u8 data); | ||
| 30 | int (*program_regs)(struct mxl111sf_state *state, | ||
| 31 | struct mxl111sf_reg_ctrl_info *ctrl_reg_info); | ||
| 32 | }; | ||
| 33 | |||
| 34 | #if defined(CONFIG_DVB_USB_MXL111SF) || \ | ||
| 35 | (defined(CONFIG_DVB_USB_MXL111SF_MODULE) && defined(MODULE)) | ||
| 36 | extern | ||
| 37 | struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state, | ||
| 38 | struct mxl111sf_demod_config *cfg); | ||
| 39 | #else | ||
| 40 | static inline | ||
| 41 | struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state, | ||
| 42 | struct mxl111sf_demod_config *cfg) | ||
| 43 | { | ||
| 44 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
| 45 | return NULL; | ||
| 46 | } | ||
| 47 | #endif /* CONFIG_DVB_USB_MXL111SF */ | ||
| 48 | |||
| 49 | #endif /* __MXL111SF_DEMOD_H__ */ | ||
| 50 | |||
| 51 | /* | ||
| 52 | * Local variables: | ||
| 53 | * c-basic-offset: 8 | ||
| 54 | * End: | ||
| 55 | */ | ||
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.c b/drivers/media/dvb/dvb-usb/mxl111sf.c index 546ba5915a5b..b5c98da5d9e2 100644 --- a/drivers/media/dvb/dvb-usb/mxl111sf.c +++ b/drivers/media/dvb/dvb-usb/mxl111sf.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include "mxl111sf-i2c.h" | 17 | #include "mxl111sf-i2c.h" |
| 18 | #include "mxl111sf-gpio.h" | 18 | #include "mxl111sf-gpio.h" |
| 19 | 19 | ||
| 20 | #include "mxl111sf-demod.h" | ||
| 20 | #include "mxl111sf-tuner.h" | 21 | #include "mxl111sf-tuner.h" |
| 21 | 22 | ||
| 22 | #include "lgdt3305.h" | 23 | #include "lgdt3305.h" |
| @@ -362,6 +363,22 @@ static int mxl111sf_ep6_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) | |||
| 362 | return ret; | 363 | return ret; |
| 363 | } | 364 | } |
| 364 | 365 | ||
| 366 | static int mxl111sf_ep4_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) | ||
| 367 | { | ||
| 368 | struct dvb_usb_device *d = adap->dev; | ||
| 369 | struct mxl111sf_state *state = d->priv; | ||
| 370 | int ret = 0; | ||
| 371 | |||
| 372 | deb_info("%s(%d)\n", __func__, onoff); | ||
| 373 | |||
| 374 | if (onoff) { | ||
| 375 | ret = mxl111sf_enable_usb_output(state); | ||
| 376 | mxl_fail(ret); | ||
| 377 | } | ||
| 378 | |||
| 379 | return ret; | ||
| 380 | } | ||
| 381 | |||
| 365 | /* ------------------------------------------------------------------------ */ | 382 | /* ------------------------------------------------------------------------ */ |
| 366 | 383 | ||
| 367 | static struct lgdt3305_config hauppauge_lgdt3305_config = { | 384 | static struct lgdt3305_config hauppauge_lgdt3305_config = { |
| @@ -438,6 +455,70 @@ fail: | |||
| 438 | return ret; | 455 | return ret; |
| 439 | } | 456 | } |
| 440 | 457 | ||
| 458 | static struct mxl111sf_demod_config mxl_demod_config = { | ||
| 459 | .read_reg = mxl111sf_read_reg, | ||
| 460 | .write_reg = mxl111sf_write_reg, | ||
| 461 | .program_regs = mxl111sf_ctrl_program_regs, | ||
| 462 | }; | ||
| 463 | |||
| 464 | static int mxl111sf_attach_demod(struct dvb_usb_adapter *adap) | ||
| 465 | { | ||
| 466 | struct dvb_usb_device *d = adap->dev; | ||
| 467 | struct mxl111sf_state *state = d->priv; | ||
| 468 | int fe_id = adap->num_frontends_initialized; | ||
| 469 | struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv; | ||
| 470 | int ret; | ||
| 471 | |||
| 472 | deb_adv("%s()\n", __func__); | ||
| 473 | |||
| 474 | /* save a pointer to the dvb_usb_device in device state */ | ||
| 475 | state->d = d; | ||
| 476 | adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 1 : 2; | ||
| 477 | state->alt_mode = adap_state->alt_mode; | ||
| 478 | |||
| 479 | if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0) | ||
| 480 | err("set interface failed"); | ||
| 481 | |||
| 482 | state->gpio_mode = MXL111SF_GPIO_MOD_DVBT; | ||
| 483 | adap_state->gpio_mode = state->gpio_mode; | ||
| 484 | adap_state->device_mode = MXL_SOC_MODE; | ||
| 485 | adap_state->ep6_clockphase = 1; | ||
| 486 | |||
| 487 | ret = mxl1x1sf_soft_reset(state); | ||
| 488 | if (mxl_fail(ret)) | ||
| 489 | goto fail; | ||
| 490 | ret = mxl111sf_init_tuner_demod(state); | ||
| 491 | if (mxl_fail(ret)) | ||
| 492 | goto fail; | ||
| 493 | |||
| 494 | ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode); | ||
| 495 | if (mxl_fail(ret)) | ||
| 496 | goto fail; | ||
| 497 | |||
| 498 | ret = mxl111sf_enable_usb_output(state); | ||
| 499 | if (mxl_fail(ret)) | ||
| 500 | goto fail; | ||
| 501 | ret = mxl1x1sf_top_master_ctrl(state, 1); | ||
| 502 | if (mxl_fail(ret)) | ||
| 503 | goto fail; | ||
| 504 | |||
| 505 | /* dont care if this fails */ | ||
| 506 | mxl111sf_init_port_expander(state); | ||
| 507 | |||
| 508 | adap->fe_adap[fe_id].fe = dvb_attach(mxl111sf_demod_attach, state, | ||
| 509 | &mxl_demod_config); | ||
| 510 | if (adap->fe_adap[fe_id].fe) { | ||
| 511 | adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init; | ||
| 512 | adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init; | ||
| 513 | adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep; | ||
| 514 | adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep; | ||
| 515 | return 0; | ||
| 516 | } | ||
| 517 | ret = -EIO; | ||
| 518 | fail: | ||
| 519 | return ret; | ||
| 520 | } | ||
| 521 | |||
| 441 | static inline int mxl111sf_set_ant_path(struct mxl111sf_state *state, | 522 | static inline int mxl111sf_set_ant_path(struct mxl111sf_state *state, |
| 442 | int antpath) | 523 | int antpath) |
| 443 | { | 524 | { |
| @@ -567,7 +648,8 @@ struct i2c_algorithm mxl111sf_i2c_algo = { | |||
| 567 | #endif | 648 | #endif |
| 568 | }; | 649 | }; |
| 569 | 650 | ||
| 570 | /* DVB USB Driver stuff */ | 651 | static struct dvb_usb_device_properties mxl111sf_dvbt_bulk_properties; |
| 652 | static struct dvb_usb_device_properties mxl111sf_dvbt_isoc_properties; | ||
| 571 | static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties; | 653 | static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties; |
| 572 | static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties; | 654 | static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties; |
| 573 | 655 | ||
| @@ -580,9 +662,15 @@ static int mxl111sf_probe(struct usb_interface *intf, | |||
| 580 | 662 | ||
| 581 | if (((dvb_usb_mxl111sf_isoc) && | 663 | if (((dvb_usb_mxl111sf_isoc) && |
| 582 | (0 == dvb_usb_device_init(intf, | 664 | (0 == dvb_usb_device_init(intf, |
| 665 | &mxl111sf_dvbt_isoc_properties, | ||
| 666 | THIS_MODULE, &d, adapter_nr) || | ||
| 667 | 0 == dvb_usb_device_init(intf, | ||
| 583 | &mxl111sf_atsc_isoc_properties, | 668 | &mxl111sf_atsc_isoc_properties, |
| 584 | THIS_MODULE, &d, adapter_nr))) || | 669 | THIS_MODULE, &d, adapter_nr))) || |
| 585 | 0 == dvb_usb_device_init(intf, | 670 | 0 == dvb_usb_device_init(intf, |
| 671 | &mxl111sf_dvbt_bulk_properties, | ||
| 672 | THIS_MODULE, &d, adapter_nr) || | ||
| 673 | 0 == dvb_usb_device_init(intf, | ||
| 586 | &mxl111sf_atsc_bulk_properties, | 674 | &mxl111sf_atsc_bulk_properties, |
| 587 | THIS_MODULE, &d, adapter_nr) || 0) { | 675 | THIS_MODULE, &d, adapter_nr) || 0) { |
| 588 | 676 | ||
| @@ -669,6 +757,36 @@ static struct usb_device_id mxl111sf_table[] = { | |||
| 669 | MODULE_DEVICE_TABLE(usb, mxl111sf_table); | 757 | MODULE_DEVICE_TABLE(usb, mxl111sf_table); |
| 670 | 758 | ||
| 671 | 759 | ||
| 760 | #define MXL111SF_EP4_BULK_STREAMING_CONFIG \ | ||
| 761 | .streaming_ctrl = mxl111sf_ep4_streaming_ctrl, \ | ||
| 762 | .stream = { \ | ||
| 763 | .type = USB_BULK, \ | ||
| 764 | .count = 5, \ | ||
| 765 | .endpoint = 0x04, \ | ||
| 766 | .u = { \ | ||
| 767 | .bulk = { \ | ||
| 768 | .buffersize = 8192, \ | ||
| 769 | } \ | ||
| 770 | } \ | ||
| 771 | } | ||
| 772 | |||
| 773 | /* FIXME: works for v6 but not v8 silicon */ | ||
| 774 | #define MXL111SF_EP4_ISOC_STREAMING_CONFIG \ | ||
| 775 | .streaming_ctrl = mxl111sf_ep4_streaming_ctrl, \ | ||
| 776 | .stream = { \ | ||
| 777 | .type = USB_ISOC, \ | ||
| 778 | .count = 5, \ | ||
| 779 | .endpoint = 0x04, \ | ||
| 780 | .u = { \ | ||
| 781 | .isoc = { \ | ||
| 782 | .framesperurb = 96, \ | ||
| 783 | /* FIXME: v6 SILICON: */ \ | ||
| 784 | .framesize = 564, \ | ||
| 785 | .interval = 1, \ | ||
| 786 | } \ | ||
| 787 | } \ | ||
| 788 | } | ||
| 789 | |||
| 672 | #define MXL111SF_EP6_BULK_STREAMING_CONFIG \ | 790 | #define MXL111SF_EP6_BULK_STREAMING_CONFIG \ |
| 673 | .streaming_ctrl = mxl111sf_ep6_streaming_ctrl, \ | 791 | .streaming_ctrl = mxl111sf_ep6_streaming_ctrl, \ |
| 674 | .stream = { \ | 792 | .stream = { \ |
| @@ -712,7 +830,7 @@ MODULE_DEVICE_TABLE(usb, mxl111sf_table); | |||
| 712 | .generic_bulk_ctrl_endpoint_response = MXL_EP1_REG_READ, \ | 830 | .generic_bulk_ctrl_endpoint_response = MXL_EP1_REG_READ, \ |
| 713 | .size_of_priv = sizeof(struct mxl111sf_state) | 831 | .size_of_priv = sizeof(struct mxl111sf_state) |
| 714 | 832 | ||
| 715 | static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties = { | 833 | static struct dvb_usb_device_properties mxl111sf_dvbt_bulk_properties = { |
| 716 | MXL111SF_DEFAULT_DEVICE_PROPERTIES, | 834 | MXL111SF_DEFAULT_DEVICE_PROPERTIES, |
| 717 | 835 | ||
| 718 | .num_adapters = 1, | 836 | .num_adapters = 1, |
| @@ -723,10 +841,106 @@ static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties = { | |||
| 723 | .fe = {{ | 841 | .fe = {{ |
| 724 | .size_of_priv = sizeof(struct mxl111sf_adap_state), | 842 | .size_of_priv = sizeof(struct mxl111sf_adap_state), |
| 725 | 843 | ||
| 844 | .frontend_attach = mxl111sf_attach_demod, | ||
| 845 | .tuner_attach = mxl111sf_attach_tuner, | ||
| 846 | |||
| 847 | MXL111SF_EP4_BULK_STREAMING_CONFIG, | ||
| 848 | } }, | ||
| 849 | }, | ||
| 850 | }, | ||
| 851 | .num_device_descs = 4, | ||
| 852 | .devices = { | ||
| 853 | { "Hauppauge 126xxx DVBT (bulk)", | ||
| 854 | { NULL }, | ||
| 855 | { &mxl111sf_table[4], &mxl111sf_table[8], | ||
| 856 | NULL }, | ||
| 857 | }, | ||
| 858 | { "Hauppauge 117xxx DVBT (bulk)", | ||
| 859 | { NULL }, | ||
| 860 | { &mxl111sf_table[15], &mxl111sf_table[18], | ||
| 861 | NULL }, | ||
| 862 | }, | ||
| 863 | { "Hauppauge 138xxx DVBT (bulk)", | ||
| 864 | { NULL }, | ||
| 865 | { &mxl111sf_table[20], &mxl111sf_table[22], | ||
| 866 | &mxl111sf_table[24], &mxl111sf_table[26], | ||
| 867 | NULL }, | ||
| 868 | }, | ||
| 869 | { "Hauppauge 126xxx (tp-bulk)", | ||
| 870 | { NULL }, | ||
| 871 | { &mxl111sf_table[28], &mxl111sf_table[30], | ||
| 872 | NULL }, | ||
| 873 | }, | ||
| 874 | } | ||
| 875 | }; | ||
| 876 | |||
| 877 | static struct dvb_usb_device_properties mxl111sf_dvbt_isoc_properties = { | ||
| 878 | MXL111SF_DEFAULT_DEVICE_PROPERTIES, | ||
| 879 | |||
| 880 | .num_adapters = 1, | ||
| 881 | .adapter = { | ||
| 882 | { | ||
| 883 | .fe_ioctl_override = mxl111sf_fe_ioctl_override, | ||
| 884 | .num_frontends = 1, | ||
| 885 | .fe = {{ | ||
| 886 | .size_of_priv = sizeof(struct mxl111sf_adap_state), | ||
| 887 | |||
| 888 | .frontend_attach = mxl111sf_attach_demod, | ||
| 889 | .tuner_attach = mxl111sf_attach_tuner, | ||
| 890 | |||
| 891 | MXL111SF_EP4_ISOC_STREAMING_CONFIG, | ||
| 892 | } }, | ||
| 893 | }, | ||
| 894 | }, | ||
| 895 | .num_device_descs = 4, | ||
| 896 | .devices = { | ||
| 897 | { "Hauppauge 126xxx DVBT (isoc)", | ||
| 898 | { NULL }, | ||
| 899 | { &mxl111sf_table[4], &mxl111sf_table[8], | ||
| 900 | NULL }, | ||
| 901 | }, | ||
| 902 | { "Hauppauge 117xxx DVBT (isoc)", | ||
| 903 | { NULL }, | ||
| 904 | { &mxl111sf_table[15], &mxl111sf_table[18], | ||
| 905 | NULL }, | ||
| 906 | }, | ||
| 907 | { "Hauppauge 138xxx DVBT (isoc)", | ||
| 908 | { NULL }, | ||
| 909 | { &mxl111sf_table[20], &mxl111sf_table[22], | ||
| 910 | &mxl111sf_table[24], &mxl111sf_table[26], | ||
| 911 | NULL }, | ||
| 912 | }, | ||
| 913 | { "Hauppauge 126xxx (tp-isoc)", | ||
| 914 | { NULL }, | ||
| 915 | { &mxl111sf_table[28], &mxl111sf_table[30], | ||
| 916 | NULL }, | ||
| 917 | }, | ||
| 918 | } | ||
| 919 | }; | ||
| 920 | |||
| 921 | static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties = { | ||
| 922 | MXL111SF_DEFAULT_DEVICE_PROPERTIES, | ||
| 923 | |||
| 924 | .num_adapters = 1, | ||
| 925 | .adapter = { | ||
| 926 | { | ||
| 927 | .fe_ioctl_override = mxl111sf_fe_ioctl_override, | ||
| 928 | .num_frontends = 2, | ||
| 929 | .fe = {{ | ||
| 930 | .size_of_priv = sizeof(struct mxl111sf_adap_state), | ||
| 931 | |||
| 726 | .frontend_attach = mxl111sf_lgdt3305_frontend_attach, | 932 | .frontend_attach = mxl111sf_lgdt3305_frontend_attach, |
| 727 | .tuner_attach = mxl111sf_attach_tuner, | 933 | .tuner_attach = mxl111sf_attach_tuner, |
| 728 | 934 | ||
| 729 | MXL111SF_EP6_BULK_STREAMING_CONFIG, | 935 | MXL111SF_EP6_BULK_STREAMING_CONFIG, |
| 936 | }, | ||
| 937 | { | ||
| 938 | .size_of_priv = sizeof(struct mxl111sf_adap_state), | ||
| 939 | |||
| 940 | .frontend_attach = mxl111sf_attach_demod, | ||
| 941 | .tuner_attach = mxl111sf_attach_tuner, | ||
| 942 | |||
| 943 | MXL111SF_EP4_BULK_STREAMING_CONFIG, | ||
| 730 | }}, | 944 | }}, |
| 731 | }, | 945 | }, |
| 732 | }, | 946 | }, |
| @@ -776,7 +990,7 @@ static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties = { | |||
| 776 | .adapter = { | 990 | .adapter = { |
| 777 | { | 991 | { |
| 778 | .fe_ioctl_override = mxl111sf_fe_ioctl_override, | 992 | .fe_ioctl_override = mxl111sf_fe_ioctl_override, |
| 779 | .num_frontends = 1, | 993 | .num_frontends = 2, |
| 780 | .fe = {{ | 994 | .fe = {{ |
| 781 | .size_of_priv = sizeof(struct mxl111sf_adap_state), | 995 | .size_of_priv = sizeof(struct mxl111sf_adap_state), |
| 782 | 996 | ||
| @@ -784,6 +998,14 @@ static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties = { | |||
| 784 | .tuner_attach = mxl111sf_attach_tuner, | 998 | .tuner_attach = mxl111sf_attach_tuner, |
| 785 | 999 | ||
| 786 | MXL111SF_EP6_ISOC_STREAMING_CONFIG, | 1000 | MXL111SF_EP6_ISOC_STREAMING_CONFIG, |
| 1001 | }, | ||
| 1002 | { | ||
| 1003 | .size_of_priv = sizeof(struct mxl111sf_adap_state), | ||
| 1004 | |||
| 1005 | .frontend_attach = mxl111sf_attach_demod, | ||
| 1006 | .tuner_attach = mxl111sf_attach_tuner, | ||
| 1007 | |||
| 1008 | MXL111SF_EP4_ISOC_STREAMING_CONFIG, | ||
| 787 | }}, | 1009 | }}, |
| 788 | }, | 1010 | }, |
| 789 | }, | 1011 | }, |
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.h b/drivers/media/dvb/dvb-usb/mxl111sf.h index 5a2c7bb386cd..364d89f826bd 100644 --- a/drivers/media/dvb/dvb-usb/mxl111sf.h +++ b/drivers/media/dvb/dvb-usb/mxl111sf.h | |||
| @@ -133,7 +133,7 @@ extern int dvb_usb_mxl111sf_debug; | |||
| 133 | /* The following allows the mxl_fail() macro defined below to work | 133 | /* The following allows the mxl_fail() macro defined below to work |
| 134 | * in externel modules, such as mxl111sf-tuner.ko, even though | 134 | * in externel modules, such as mxl111sf-tuner.ko, even though |
| 135 | * dvb_usb_mxl111sf_debug is not defined within those modules */ | 135 | * dvb_usb_mxl111sf_debug is not defined within those modules */ |
| 136 | #ifdef __MXL111SF_TUNER_H__ | 136 | #if (defined(__MXL111SF_TUNER_H__)) || (defined(__MXL111SF_DEMOD_H__)) |
| 137 | #define MXL_ADV_DEBUG_ENABLED MXL_ADV_DBG | 137 | #define MXL_ADV_DEBUG_ENABLED MXL_ADV_DBG |
| 138 | #else | 138 | #else |
| 139 | #define MXL_ADV_DEBUG_ENABLED dvb_usb_mxl111sf_debug | 139 | #define MXL_ADV_DEBUG_ENABLED dvb_usb_mxl111sf_debug |
diff --git a/drivers/media/dvb/ngene/Makefile b/drivers/media/dvb/ngene/Makefile index 89873615e683..13ebeffb705f 100644 --- a/drivers/media/dvb/ngene/Makefile +++ b/drivers/media/dvb/ngene/Makefile | |||
| @@ -11,4 +11,4 @@ ccflags-y += -Idrivers/media/dvb/frontends/ | |||
| 11 | ccflags-y += -Idrivers/media/common/tuners/ | 11 | ccflags-y += -Idrivers/media/common/tuners/ |
| 12 | 12 | ||
| 13 | # For the staging CI driver cxd2099 | 13 | # For the staging CI driver cxd2099 |
| 14 | ccflags-y += -Idrivers/staging/cxd2099/ | 14 | ccflags-y += -Idrivers/staging/media/cxd2099/ |
diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c index 95ddcc4845d3..db20904d01f0 100644 --- a/drivers/media/radio/radio-tea5764.c +++ b/drivers/media/radio/radio-tea5764.c | |||
| @@ -128,8 +128,10 @@ struct tea5764_write_regs { | |||
| 128 | u16 rdsbbl; /* PAUSEDET & RDSBBL */ | 128 | u16 rdsbbl; /* PAUSEDET & RDSBBL */ |
| 129 | } __attribute__ ((packed)); | 129 | } __attribute__ ((packed)); |
| 130 | 130 | ||
| 131 | #ifndef RADIO_TEA5764_XTAL | 131 | #ifdef CONFIG_RADIO_TEA5764_XTAL |
| 132 | #define RADIO_TEA5764_XTAL 1 | 132 | #define RADIO_TEA5764_XTAL 1 |
| 133 | #else | ||
| 134 | #define RADIO_TEA5764_XTAL 0 | ||
| 133 | #endif | 135 | #endif |
| 134 | 136 | ||
| 135 | static int radio_nr = -1; | 137 | static int radio_nr = -1; |
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index d285c8c92819..b303a3f8a9f8 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig | |||
| @@ -517,6 +517,13 @@ config VIDEO_NOON010PC30 | |||
| 517 | 517 | ||
| 518 | source "drivers/media/video/m5mols/Kconfig" | 518 | source "drivers/media/video/m5mols/Kconfig" |
| 519 | 519 | ||
| 520 | config VIDEO_S5K6AA | ||
| 521 | tristate "Samsung S5K6AAFX sensor support" | ||
| 522 | depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API | ||
| 523 | ---help--- | ||
| 524 | This is a V4L2 sensor-level driver for Samsung S5K6AA(FX) 1.3M | ||
| 525 | camera sensor with an embedded SoC image signal processor. | ||
| 526 | |||
| 520 | comment "Flash devices" | 527 | comment "Flash devices" |
| 521 | 528 | ||
| 522 | config VIDEO_ADP1653 | 529 | config VIDEO_ADP1653 |
| @@ -736,6 +743,8 @@ source "drivers/media/video/cx88/Kconfig" | |||
| 736 | 743 | ||
| 737 | source "drivers/media/video/cx23885/Kconfig" | 744 | source "drivers/media/video/cx23885/Kconfig" |
| 738 | 745 | ||
| 746 | source "drivers/media/video/cx25821/Kconfig" | ||
| 747 | |||
| 739 | source "drivers/media/video/au0828/Kconfig" | 748 | source "drivers/media/video/au0828/Kconfig" |
| 740 | 749 | ||
| 741 | source "drivers/media/video/ivtv/Kconfig" | 750 | source "drivers/media/video/ivtv/Kconfig" |
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 11fff97e7196..117f9c4b4cb9 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile | |||
| @@ -72,6 +72,7 @@ obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o | |||
| 72 | obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o | 72 | obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o |
| 73 | obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o | 73 | obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o |
| 74 | obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/ | 74 | obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/ |
| 75 | obj-$(CONFIG_VIDEO_S5K6AA) += s5k6aa.o | ||
| 75 | obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o | 76 | obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o |
| 76 | 77 | ||
| 77 | obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o | 78 | obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o |
| @@ -104,6 +105,7 @@ obj-$(CONFIG_VIDEO_CX88) += cx88/ | |||
| 104 | obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ | 105 | obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ |
| 105 | obj-$(CONFIG_VIDEO_TLG2300) += tlg2300/ | 106 | obj-$(CONFIG_VIDEO_TLG2300) += tlg2300/ |
| 106 | obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/ | 107 | obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/ |
| 108 | obj-$(CONFIG_VIDEO_CX25821) += cx25821/ | ||
| 107 | obj-$(CONFIG_VIDEO_USBVISION) += usbvision/ | 109 | obj-$(CONFIG_VIDEO_USBVISION) += usbvision/ |
| 108 | obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/ | 110 | obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/ |
| 109 | obj-$(CONFIG_VIDEO_CPIA2) += cpia2/ | 111 | obj-$(CONFIG_VIDEO_CPIA2) += cpia2/ |
diff --git a/drivers/media/video/atmel-isi.c b/drivers/media/video/atmel-isi.c index 774715d2f84f..8c775c59e120 100644 --- a/drivers/media/video/atmel-isi.c +++ b/drivers/media/video/atmel-isi.c | |||
| @@ -94,6 +94,7 @@ struct atmel_isi { | |||
| 94 | unsigned int irq; | 94 | unsigned int irq; |
| 95 | 95 | ||
| 96 | struct isi_platform_data *pdata; | 96 | struct isi_platform_data *pdata; |
| 97 | u16 width_flags; /* max 12 bits */ | ||
| 97 | 98 | ||
| 98 | struct list_head video_buffer_list; | 99 | struct list_head video_buffer_list; |
| 99 | struct frame_buffer *active; | 100 | struct frame_buffer *active; |
| @@ -248,9 +249,9 @@ static int atmel_isi_wait_status(struct atmel_isi *isi, int wait_reset) | |||
| 248 | /* ------------------------------------------------------------------ | 249 | /* ------------------------------------------------------------------ |
| 249 | Videobuf operations | 250 | Videobuf operations |
| 250 | ------------------------------------------------------------------*/ | 251 | ------------------------------------------------------------------*/ |
| 251 | static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, | 252 | static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, |
| 252 | unsigned int *nplanes, unsigned int sizes[], | 253 | unsigned int *nbuffers, unsigned int *nplanes, |
| 253 | void *alloc_ctxs[]) | 254 | unsigned int sizes[], void *alloc_ctxs[]) |
| 254 | { | 255 | { |
| 255 | struct soc_camera_device *icd = soc_camera_from_vb2q(vq); | 256 | struct soc_camera_device *icd = soc_camera_from_vb2q(vq); |
| 256 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 257 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
| @@ -647,50 +648,42 @@ static bool isi_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt) | |||
| 647 | fmt->packing == SOC_MBUS_PACKING_EXTEND16); | 648 | fmt->packing == SOC_MBUS_PACKING_EXTEND16); |
| 648 | } | 649 | } |
| 649 | 650 | ||
| 650 | static unsigned long make_bus_param(struct atmel_isi *isi) | 651 | #define ISI_BUS_PARAM (V4L2_MBUS_MASTER | \ |
| 651 | { | 652 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | \ |
| 652 | unsigned long flags; | 653 | V4L2_MBUS_HSYNC_ACTIVE_LOW | \ |
| 653 | /* | 654 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | \ |
| 654 | * Platform specified synchronization and pixel clock polarities are | 655 | V4L2_MBUS_VSYNC_ACTIVE_LOW | \ |
| 655 | * only a recommendation and are only used during probing. Atmel ISI | 656 | V4L2_MBUS_PCLK_SAMPLE_RISING | \ |
| 656 | * camera interface only works in master mode, i.e., uses HSYNC and | 657 | V4L2_MBUS_PCLK_SAMPLE_FALLING | \ |
| 657 | * VSYNC signals from the sensor | 658 | V4L2_MBUS_DATA_ACTIVE_HIGH) |
| 658 | */ | ||
| 659 | flags = SOCAM_MASTER | | ||
| 660 | SOCAM_HSYNC_ACTIVE_HIGH | | ||
| 661 | SOCAM_HSYNC_ACTIVE_LOW | | ||
| 662 | SOCAM_VSYNC_ACTIVE_HIGH | | ||
| 663 | SOCAM_VSYNC_ACTIVE_LOW | | ||
| 664 | SOCAM_PCLK_SAMPLE_RISING | | ||
| 665 | SOCAM_PCLK_SAMPLE_FALLING | | ||
| 666 | SOCAM_DATA_ACTIVE_HIGH; | ||
| 667 | |||
| 668 | if (isi->pdata->data_width_flags & ISI_DATAWIDTH_10) | ||
| 669 | flags |= SOCAM_DATAWIDTH_10; | ||
| 670 | |||
| 671 | if (isi->pdata->data_width_flags & ISI_DATAWIDTH_8) | ||
| 672 | flags |= SOCAM_DATAWIDTH_8; | ||
| 673 | |||
| 674 | if (flags & SOCAM_DATAWIDTH_MASK) | ||
| 675 | return flags; | ||
| 676 | |||
| 677 | return 0; | ||
| 678 | } | ||
| 679 | 659 | ||
| 680 | static int isi_camera_try_bus_param(struct soc_camera_device *icd, | 660 | static int isi_camera_try_bus_param(struct soc_camera_device *icd, |
| 681 | unsigned char buswidth) | 661 | unsigned char buswidth) |
| 682 | { | 662 | { |
| 663 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
| 683 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 664 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
| 684 | struct atmel_isi *isi = ici->priv; | 665 | struct atmel_isi *isi = ici->priv; |
| 685 | unsigned long camera_flags; | 666 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; |
| 667 | unsigned long common_flags; | ||
| 686 | int ret; | 668 | int ret; |
| 687 | 669 | ||
| 688 | camera_flags = icd->ops->query_bus_param(icd); | 670 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); |
| 689 | ret = soc_camera_bus_param_compatible(camera_flags, | 671 | if (!ret) { |
| 690 | make_bus_param(isi)); | 672 | common_flags = soc_mbus_config_compatible(&cfg, |
| 691 | if (!ret) | 673 | ISI_BUS_PARAM); |
| 692 | return -EINVAL; | 674 | if (!common_flags) { |
| 693 | return 0; | 675 | dev_warn(icd->parent, |
| 676 | "Flags incompatible: camera 0x%x, host 0x%x\n", | ||
| 677 | cfg.flags, ISI_BUS_PARAM); | ||
| 678 | return -EINVAL; | ||
| 679 | } | ||
| 680 | } else if (ret != -ENOIOCTLCMD) { | ||
| 681 | return ret; | ||
| 682 | } | ||
| 683 | |||
| 684 | if ((1 << (buswidth - 1)) & isi->width_flags) | ||
| 685 | return 0; | ||
| 686 | return -EINVAL; | ||
| 694 | } | 687 | } |
| 695 | 688 | ||
| 696 | 689 | ||
| @@ -812,59 +805,71 @@ static int isi_camera_querycap(struct soc_camera_host *ici, | |||
| 812 | 805 | ||
| 813 | static int isi_camera_set_bus_param(struct soc_camera_device *icd, u32 pixfmt) | 806 | static int isi_camera_set_bus_param(struct soc_camera_device *icd, u32 pixfmt) |
| 814 | { | 807 | { |
| 808 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
| 815 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 809 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
| 816 | struct atmel_isi *isi = ici->priv; | 810 | struct atmel_isi *isi = ici->priv; |
| 817 | unsigned long bus_flags, camera_flags, common_flags; | 811 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; |
| 812 | unsigned long common_flags; | ||
| 818 | int ret; | 813 | int ret; |
| 819 | u32 cfg1 = 0; | 814 | u32 cfg1 = 0; |
| 820 | 815 | ||
| 821 | camera_flags = icd->ops->query_bus_param(icd); | 816 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); |
| 822 | 817 | if (!ret) { | |
| 823 | bus_flags = make_bus_param(isi); | 818 | common_flags = soc_mbus_config_compatible(&cfg, |
| 824 | common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags); | 819 | ISI_BUS_PARAM); |
| 825 | dev_dbg(icd->parent, "Flags cam: 0x%lx host: 0x%lx common: 0x%lx\n", | 820 | if (!common_flags) { |
| 826 | camera_flags, bus_flags, common_flags); | 821 | dev_warn(icd->parent, |
| 827 | if (!common_flags) | 822 | "Flags incompatible: camera 0x%x, host 0x%x\n", |
| 828 | return -EINVAL; | 823 | cfg.flags, ISI_BUS_PARAM); |
| 824 | return -EINVAL; | ||
| 825 | } | ||
| 826 | } else if (ret != -ENOIOCTLCMD) { | ||
| 827 | return ret; | ||
| 828 | } else { | ||
| 829 | common_flags = ISI_BUS_PARAM; | ||
| 830 | } | ||
| 831 | dev_dbg(icd->parent, "Flags cam: 0x%x host: 0x%x common: 0x%lx\n", | ||
| 832 | cfg.flags, ISI_BUS_PARAM, common_flags); | ||
| 829 | 833 | ||
| 830 | /* Make choises, based on platform preferences */ | 834 | /* Make choises, based on platform preferences */ |
| 831 | if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && | 835 | if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && |
| 832 | (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { | 836 | (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { |
| 833 | if (isi->pdata->hsync_act_low) | 837 | if (isi->pdata->hsync_act_low) |
| 834 | common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; | 838 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; |
| 835 | else | 839 | else |
| 836 | common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; | 840 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; |
| 837 | } | 841 | } |
| 838 | 842 | ||
| 839 | if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && | 843 | if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && |
| 840 | (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { | 844 | (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { |
| 841 | if (isi->pdata->vsync_act_low) | 845 | if (isi->pdata->vsync_act_low) |
| 842 | common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; | 846 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; |
| 843 | else | 847 | else |
| 844 | common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; | 848 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; |
| 845 | } | 849 | } |
| 846 | 850 | ||
| 847 | if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && | 851 | if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && |
| 848 | (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { | 852 | (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { |
| 849 | if (isi->pdata->pclk_act_falling) | 853 | if (isi->pdata->pclk_act_falling) |
| 850 | common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; | 854 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; |
| 851 | else | 855 | else |
| 852 | common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; | 856 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; |
| 853 | } | 857 | } |
| 854 | 858 | ||
| 855 | ret = icd->ops->set_bus_param(icd, common_flags); | 859 | cfg.flags = common_flags; |
| 856 | if (ret < 0) { | 860 | ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); |
| 857 | dev_dbg(icd->parent, "Camera set_bus_param(%lx) returned %d\n", | 861 | if (ret < 0 && ret != -ENOIOCTLCMD) { |
| 862 | dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n", | ||
| 858 | common_flags, ret); | 863 | common_flags, ret); |
| 859 | return ret; | 864 | return ret; |
| 860 | } | 865 | } |
| 861 | 866 | ||
| 862 | /* set bus param for ISI */ | 867 | /* set bus param for ISI */ |
| 863 | if (common_flags & SOCAM_HSYNC_ACTIVE_LOW) | 868 | if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) |
| 864 | cfg1 |= ISI_CFG1_HSYNC_POL_ACTIVE_LOW; | 869 | cfg1 |= ISI_CFG1_HSYNC_POL_ACTIVE_LOW; |
| 865 | if (common_flags & SOCAM_VSYNC_ACTIVE_LOW) | 870 | if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) |
| 866 | cfg1 |= ISI_CFG1_VSYNC_POL_ACTIVE_LOW; | 871 | cfg1 |= ISI_CFG1_VSYNC_POL_ACTIVE_LOW; |
| 867 | if (common_flags & SOCAM_PCLK_SAMPLE_FALLING) | 872 | if (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) |
| 868 | cfg1 |= ISI_CFG1_PIXCLK_POL_ACTIVE_FALLING; | 873 | cfg1 |= ISI_CFG1_PIXCLK_POL_ACTIVE_FALLING; |
| 869 | 874 | ||
| 870 | if (isi->pdata->has_emb_sync) | 875 | if (isi->pdata->has_emb_sync) |
| @@ -983,6 +988,11 @@ static int __devinit atmel_isi_probe(struct platform_device *pdev) | |||
| 983 | goto err_ioremap; | 988 | goto err_ioremap; |
| 984 | } | 989 | } |
| 985 | 990 | ||
| 991 | if (pdata->data_width_flags & ISI_DATAWIDTH_8) | ||
| 992 | isi->width_flags = 1 << 7; | ||
| 993 | if (pdata->data_width_flags & ISI_DATAWIDTH_10) | ||
| 994 | isi->width_flags |= 1 << 9; | ||
| 995 | |||
| 986 | isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); | 996 | isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); |
| 987 | 997 | ||
| 988 | irq = platform_get_irq(pdev, 0); | 998 | irq = platform_get_irq(pdev, 0); |
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index 9e2f870f4258..c6ff32a6137c 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c | |||
| @@ -1085,6 +1085,8 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev, | |||
| 1085 | setup.addr = ADDR_UNSET; | 1085 | setup.addr = ADDR_UNSET; |
| 1086 | setup.type = cx->options.tuner; | 1086 | setup.type = cx->options.tuner; |
| 1087 | setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ | 1087 | setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ |
| 1088 | if (cx->options.radio > 0) | ||
| 1089 | setup.mode_mask |= T_RADIO; | ||
| 1088 | setup.tuner_callback = (setup.type == TUNER_XC2028) ? | 1090 | setup.tuner_callback = (setup.type == TUNER_XC2028) ? |
| 1089 | cx18_reset_tuner_gpio : NULL; | 1091 | cx18_reset_tuner_gpio : NULL; |
| 1090 | cx18_call_all(cx, tuner, s_type_addr, &setup); | 1092 | cx18_call_all(cx, tuner, s_type_addr, &setup); |
diff --git a/drivers/staging/cx25821/Kconfig b/drivers/media/video/cx25821/Kconfig index 5f6b54213713..5f6b54213713 100644 --- a/drivers/staging/cx25821/Kconfig +++ b/drivers/media/video/cx25821/Kconfig | |||
diff --git a/drivers/staging/cx25821/Makefile b/drivers/media/video/cx25821/Makefile index aedde18c68f9..aedde18c68f9 100644 --- a/drivers/staging/cx25821/Makefile +++ b/drivers/media/video/cx25821/Makefile | |||
diff --git a/drivers/staging/cx25821/cx25821-alsa.c b/drivers/media/video/cx25821/cx25821-alsa.c index 09e99de5fd21..09e99de5fd21 100644 --- a/drivers/staging/cx25821/cx25821-alsa.c +++ b/drivers/media/video/cx25821/cx25821-alsa.c | |||
diff --git a/drivers/staging/cx25821/cx25821-audio-upstream.c b/drivers/media/video/cx25821/cx25821-audio-upstream.c index c20d6dece154..c20d6dece154 100644 --- a/drivers/staging/cx25821/cx25821-audio-upstream.c +++ b/drivers/media/video/cx25821/cx25821-audio-upstream.c | |||
diff --git a/drivers/staging/cx25821/cx25821-audio-upstream.h b/drivers/media/video/cx25821/cx25821-audio-upstream.h index af2ae7c5815a..af2ae7c5815a 100644 --- a/drivers/staging/cx25821/cx25821-audio-upstream.h +++ b/drivers/media/video/cx25821/cx25821-audio-upstream.h | |||
diff --git a/drivers/staging/cx25821/cx25821-audio.h b/drivers/media/video/cx25821/cx25821-audio.h index 8eb55b7b88cb..8eb55b7b88cb 100644 --- a/drivers/staging/cx25821/cx25821-audio.h +++ b/drivers/media/video/cx25821/cx25821-audio.h | |||
diff --git a/drivers/staging/cx25821/cx25821-biffuncs.h b/drivers/media/video/cx25821/cx25821-biffuncs.h index 9326a7c729ec..9326a7c729ec 100644 --- a/drivers/staging/cx25821/cx25821-biffuncs.h +++ b/drivers/media/video/cx25821/cx25821-biffuncs.h | |||
diff --git a/drivers/staging/cx25821/cx25821-cards.c b/drivers/media/video/cx25821/cx25821-cards.c index 6ace60313b49..6ace60313b49 100644 --- a/drivers/staging/cx25821/cx25821-cards.c +++ b/drivers/media/video/cx25821/cx25821-cards.c | |||
diff --git a/drivers/staging/cx25821/cx25821-core.c b/drivers/media/video/cx25821/cx25821-core.c index a7fa38f9594e..a7fa38f9594e 100644 --- a/drivers/staging/cx25821/cx25821-core.c +++ b/drivers/media/video/cx25821/cx25821-core.c | |||
diff --git a/drivers/staging/cx25821/cx25821-gpio.c b/drivers/media/video/cx25821/cx25821-gpio.c index 29e43b03c85e..29e43b03c85e 100644 --- a/drivers/staging/cx25821/cx25821-gpio.c +++ b/drivers/media/video/cx25821/cx25821-gpio.c | |||
diff --git a/drivers/staging/cx25821/cx25821-i2c.c b/drivers/media/video/cx25821/cx25821-i2c.c index 4d3d0ce40785..4d3d0ce40785 100644 --- a/drivers/staging/cx25821/cx25821-i2c.c +++ b/drivers/media/video/cx25821/cx25821-i2c.c | |||
diff --git a/drivers/staging/cx25821/cx25821-medusa-defines.h b/drivers/media/video/cx25821/cx25821-medusa-defines.h index 60d197f57556..60d197f57556 100644 --- a/drivers/staging/cx25821/cx25821-medusa-defines.h +++ b/drivers/media/video/cx25821/cx25821-medusa-defines.h | |||
diff --git a/drivers/staging/cx25821/cx25821-medusa-reg.h b/drivers/media/video/cx25821/cx25821-medusa-reg.h index 1c1c228352d1..1c1c228352d1 100644 --- a/drivers/staging/cx25821/cx25821-medusa-reg.h +++ b/drivers/media/video/cx25821/cx25821-medusa-reg.h | |||
diff --git a/drivers/staging/cx25821/cx25821-medusa-video.c b/drivers/media/video/cx25821/cx25821-medusa-video.c index fc780d0908dc..fc780d0908dc 100644 --- a/drivers/staging/cx25821/cx25821-medusa-video.c +++ b/drivers/media/video/cx25821/cx25821-medusa-video.c | |||
diff --git a/drivers/staging/cx25821/cx25821-medusa-video.h b/drivers/media/video/cx25821/cx25821-medusa-video.h index 6175e0961855..6175e0961855 100644 --- a/drivers/staging/cx25821/cx25821-medusa-video.h +++ b/drivers/media/video/cx25821/cx25821-medusa-video.h | |||
diff --git a/drivers/staging/cx25821/cx25821-reg.h b/drivers/media/video/cx25821/cx25821-reg.h index a3fc25a4dc0b..a3fc25a4dc0b 100644 --- a/drivers/staging/cx25821/cx25821-reg.h +++ b/drivers/media/video/cx25821/cx25821-reg.h | |||
diff --git a/drivers/staging/cx25821/cx25821-sram.h b/drivers/media/video/cx25821/cx25821-sram.h index 5f05d153bc4d..5f05d153bc4d 100644 --- a/drivers/staging/cx25821/cx25821-sram.h +++ b/drivers/media/video/cx25821/cx25821-sram.h | |||
diff --git a/drivers/staging/cx25821/cx25821-video-upstream-ch2.c b/drivers/media/video/cx25821/cx25821-video-upstream-ch2.c index 2a724ddfa53f..2a724ddfa53f 100644 --- a/drivers/staging/cx25821/cx25821-video-upstream-ch2.c +++ b/drivers/media/video/cx25821/cx25821-video-upstream-ch2.c | |||
diff --git a/drivers/staging/cx25821/cx25821-video-upstream-ch2.h b/drivers/media/video/cx25821/cx25821-video-upstream-ch2.h index d42dab59b663..d42dab59b663 100644 --- a/drivers/staging/cx25821/cx25821-video-upstream-ch2.h +++ b/drivers/media/video/cx25821/cx25821-video-upstream-ch2.h | |||
diff --git a/drivers/staging/cx25821/cx25821-video-upstream.c b/drivers/media/video/cx25821/cx25821-video-upstream.c index c0b80068f468..c0b80068f468 100644 --- a/drivers/staging/cx25821/cx25821-video-upstream.c +++ b/drivers/media/video/cx25821/cx25821-video-upstream.c | |||
diff --git a/drivers/staging/cx25821/cx25821-video-upstream.h b/drivers/media/video/cx25821/cx25821-video-upstream.h index 268ec8aa6a61..268ec8aa6a61 100644 --- a/drivers/staging/cx25821/cx25821-video-upstream.h +++ b/drivers/media/video/cx25821/cx25821-video-upstream.h | |||
diff --git a/drivers/staging/cx25821/cx25821-video.c b/drivers/media/video/cx25821/cx25821-video.c index 084fc0899e13..4d6907cda75b 100644 --- a/drivers/staging/cx25821/cx25821-video.c +++ b/drivers/media/video/cx25821/cx25821-video.c | |||
| @@ -1312,7 +1312,7 @@ int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i) | |||
| 1312 | return err; | 1312 | return err; |
| 1313 | } | 1313 | } |
| 1314 | 1314 | ||
| 1315 | if (i > 2) { | 1315 | if (i >= CX25821_NR_INPUT) { |
| 1316 | dprintk(1, "%s(): -EINVAL\n", __func__); | 1316 | dprintk(1, "%s(): -EINVAL\n", __func__); |
| 1317 | return -EINVAL; | 1317 | return -EINVAL; |
| 1318 | } | 1318 | } |
diff --git a/drivers/staging/cx25821/cx25821-video.h b/drivers/media/video/cx25821/cx25821-video.h index d0d9538ca5b3..d0d9538ca5b3 100644 --- a/drivers/staging/cx25821/cx25821-video.h +++ b/drivers/media/video/cx25821/cx25821-video.h | |||
diff --git a/drivers/staging/cx25821/cx25821.h b/drivers/media/video/cx25821/cx25821.h index db2615b2bac3..2d2d00932823 100644 --- a/drivers/staging/cx25821/cx25821.h +++ b/drivers/media/video/cx25821/cx25821.h | |||
| @@ -98,6 +98,7 @@ | |||
| 98 | #define CX25821_BOARD_CONEXANT_ATHENA10 1 | 98 | #define CX25821_BOARD_CONEXANT_ATHENA10 1 |
| 99 | #define MAX_VID_CHANNEL_NUM 12 | 99 | #define MAX_VID_CHANNEL_NUM 12 |
| 100 | #define VID_CHANNEL_NUM 8 | 100 | #define VID_CHANNEL_NUM 8 |
| 101 | #define CX25821_NR_INPUT 2 | ||
| 101 | 102 | ||
| 102 | struct cx25821_fmt { | 103 | struct cx25821_fmt { |
| 103 | char *name; | 104 | char *name; |
| @@ -196,7 +197,7 @@ struct cx25821_board { | |||
| 196 | unsigned char radio_addr; | 197 | unsigned char radio_addr; |
| 197 | 198 | ||
| 198 | u32 clk_freq; | 199 | u32 clk_freq; |
| 199 | struct cx25821_input input[2]; | 200 | struct cx25821_input input[CX25821_NR_INPUT]; |
| 200 | }; | 201 | }; |
| 201 | 202 | ||
| 202 | struct cx25821_subid { | 203 | struct cx25821_subid { |
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 4240f0b720fa..9b747c266afa 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c | |||
| @@ -1923,6 +1923,8 @@ struct usb_device_id em28xx_id_table[] = { | |||
| 1923 | .driver_info = EM2860_BOARD_TERRATEC_AV350 }, | 1923 | .driver_info = EM2860_BOARD_TERRATEC_AV350 }, |
| 1924 | { USB_DEVICE(0x0ccd, 0x0096), | 1924 | { USB_DEVICE(0x0ccd, 0x0096), |
| 1925 | .driver_info = EM2860_BOARD_TERRATEC_GRABBY }, | 1925 | .driver_info = EM2860_BOARD_TERRATEC_GRABBY }, |
| 1926 | { USB_DEVICE(0x0ccd, 0x10AF), | ||
| 1927 | .driver_info = EM2860_BOARD_TERRATEC_GRABBY }, | ||
| 1926 | { USB_DEVICE(0x0fd9, 0x0033), | 1928 | { USB_DEVICE(0x0fd9, 0x0033), |
| 1927 | .driver_info = EM2860_BOARD_ELGATO_VIDEO_CAPTURE}, | 1929 | .driver_info = EM2860_BOARD_ELGATO_VIDEO_CAPTURE}, |
| 1928 | { USB_DEVICE(0x185b, 0x2870), | 1930 | { USB_DEVICE(0x185b, 0x2870), |
diff --git a/drivers/media/video/imx074.c b/drivers/media/video/imx074.c index 0382ea752e6f..8775e262bb6e 100644 --- a/drivers/media/video/imx074.c +++ b/drivers/media/video/imx074.c | |||
| @@ -12,11 +12,11 @@ | |||
| 12 | 12 | ||
| 13 | #include <linux/delay.h> | 13 | #include <linux/delay.h> |
| 14 | #include <linux/i2c.h> | 14 | #include <linux/i2c.h> |
| 15 | #include <linux/v4l2-mediabus.h> | ||
| 15 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
| 16 | #include <linux/videodev2.h> | 17 | #include <linux/videodev2.h> |
| 17 | 18 | ||
| 18 | #include <media/soc_camera.h> | 19 | #include <media/soc_camera.h> |
| 19 | #include <media/soc_mediabus.h> | ||
| 20 | #include <media/v4l2-subdev.h> | 20 | #include <media/v4l2-subdev.h> |
| 21 | #include <media/v4l2-chip-ident.h> | 21 | #include <media/v4l2-chip-ident.h> |
| 22 | 22 | ||
| @@ -267,6 +267,17 @@ static int imx074_g_chip_ident(struct v4l2_subdev *sd, | |||
| 267 | return 0; | 267 | return 0; |
| 268 | } | 268 | } |
| 269 | 269 | ||
| 270 | static int imx074_g_mbus_config(struct v4l2_subdev *sd, | ||
| 271 | struct v4l2_mbus_config *cfg) | ||
| 272 | { | ||
| 273 | cfg->type = V4L2_MBUS_CSI2; | ||
| 274 | cfg->flags = V4L2_MBUS_CSI2_2_LANE | | ||
| 275 | V4L2_MBUS_CSI2_CHANNEL_0 | | ||
| 276 | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; | ||
| 277 | |||
| 278 | return 0; | ||
| 279 | } | ||
| 280 | |||
| 270 | static struct v4l2_subdev_video_ops imx074_subdev_video_ops = { | 281 | static struct v4l2_subdev_video_ops imx074_subdev_video_ops = { |
| 271 | .s_stream = imx074_s_stream, | 282 | .s_stream = imx074_s_stream, |
| 272 | .s_mbus_fmt = imx074_s_fmt, | 283 | .s_mbus_fmt = imx074_s_fmt, |
| @@ -275,6 +286,7 @@ static struct v4l2_subdev_video_ops imx074_subdev_video_ops = { | |||
| 275 | .enum_mbus_fmt = imx074_enum_fmt, | 286 | .enum_mbus_fmt = imx074_enum_fmt, |
| 276 | .g_crop = imx074_g_crop, | 287 | .g_crop = imx074_g_crop, |
| 277 | .cropcap = imx074_cropcap, | 288 | .cropcap = imx074_cropcap, |
| 289 | .g_mbus_config = imx074_g_mbus_config, | ||
| 278 | }; | 290 | }; |
| 279 | 291 | ||
| 280 | static struct v4l2_subdev_core_ops imx074_subdev_core_ops = { | 292 | static struct v4l2_subdev_core_ops imx074_subdev_core_ops = { |
| @@ -286,28 +298,7 @@ static struct v4l2_subdev_ops imx074_subdev_ops = { | |||
| 286 | .video = &imx074_subdev_video_ops, | 298 | .video = &imx074_subdev_video_ops, |
| 287 | }; | 299 | }; |
| 288 | 300 | ||
| 289 | /* | 301 | static int imx074_video_probe(struct i2c_client *client) |
| 290 | * We have to provide soc-camera operations, but we don't have anything to say | ||
| 291 | * there. The MIPI CSI2 driver will provide .query_bus_param and .set_bus_param | ||
| 292 | */ | ||
| 293 | static unsigned long imx074_query_bus_param(struct soc_camera_device *icd) | ||
| 294 | { | ||
| 295 | return 0; | ||
| 296 | } | ||
| 297 | |||
| 298 | static int imx074_set_bus_param(struct soc_camera_device *icd, | ||
| 299 | unsigned long flags) | ||
| 300 | { | ||
| 301 | return -EINVAL; | ||
| 302 | } | ||
| 303 | |||
| 304 | static struct soc_camera_ops imx074_ops = { | ||
| 305 | .query_bus_param = imx074_query_bus_param, | ||
| 306 | .set_bus_param = imx074_set_bus_param, | ||
| 307 | }; | ||
| 308 | |||
| 309 | static int imx074_video_probe(struct soc_camera_device *icd, | ||
| 310 | struct i2c_client *client) | ||
| 311 | { | 302 | { |
| 312 | int ret; | 303 | int ret; |
| 313 | u16 id; | 304 | u16 id; |
| @@ -417,17 +408,10 @@ static int imx074_probe(struct i2c_client *client, | |||
| 417 | const struct i2c_device_id *did) | 408 | const struct i2c_device_id *did) |
| 418 | { | 409 | { |
| 419 | struct imx074 *priv; | 410 | struct imx074 *priv; |
| 420 | struct soc_camera_device *icd = client->dev.platform_data; | ||
| 421 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 411 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
| 422 | struct soc_camera_link *icl; | 412 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
| 423 | int ret; | 413 | int ret; |
| 424 | 414 | ||
| 425 | if (!icd) { | ||
| 426 | dev_err(&client->dev, "IMX074: missing soc-camera data!\n"); | ||
| 427 | return -EINVAL; | ||
| 428 | } | ||
| 429 | |||
| 430 | icl = to_soc_camera_link(icd); | ||
| 431 | if (!icl) { | 415 | if (!icl) { |
| 432 | dev_err(&client->dev, "IMX074: missing platform data!\n"); | 416 | dev_err(&client->dev, "IMX074: missing platform data!\n"); |
| 433 | return -EINVAL; | 417 | return -EINVAL; |
| @@ -445,12 +429,10 @@ static int imx074_probe(struct i2c_client *client, | |||
| 445 | 429 | ||
| 446 | v4l2_i2c_subdev_init(&priv->subdev, client, &imx074_subdev_ops); | 430 | v4l2_i2c_subdev_init(&priv->subdev, client, &imx074_subdev_ops); |
| 447 | 431 | ||
| 448 | icd->ops = &imx074_ops; | ||
| 449 | priv->fmt = &imx074_colour_fmts[0]; | 432 | priv->fmt = &imx074_colour_fmts[0]; |
| 450 | 433 | ||
| 451 | ret = imx074_video_probe(icd, client); | 434 | ret = imx074_video_probe(client); |
| 452 | if (ret < 0) { | 435 | if (ret < 0) { |
| 453 | icd->ops = NULL; | ||
| 454 | kfree(priv); | 436 | kfree(priv); |
| 455 | return ret; | 437 | return ret; |
| 456 | } | 438 | } |
| @@ -461,10 +443,8 @@ static int imx074_probe(struct i2c_client *client, | |||
| 461 | static int imx074_remove(struct i2c_client *client) | 443 | static int imx074_remove(struct i2c_client *client) |
| 462 | { | 444 | { |
| 463 | struct imx074 *priv = to_imx074(client); | 445 | struct imx074 *priv = to_imx074(client); |
| 464 | struct soc_camera_device *icd = client->dev.platform_data; | 446 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
| 465 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
| 466 | 447 | ||
| 467 | icd->ops = NULL; | ||
| 468 | if (icl->free_bus) | 448 | if (icl->free_bus) |
| 469 | icl->free_bus(icl); | 449 | icl->free_bus(icl); |
| 470 | kfree(priv); | 450 | kfree(priv); |
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 0fb75524484d..41108a9a195e 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c | |||
| @@ -1180,6 +1180,8 @@ static int __devinit ivtv_probe(struct pci_dev *pdev, | |||
| 1180 | setup.addr = ADDR_UNSET; | 1180 | setup.addr = ADDR_UNSET; |
| 1181 | setup.type = itv->options.tuner; | 1181 | setup.type = itv->options.tuner; |
| 1182 | setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ | 1182 | setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ |
| 1183 | if (itv->options.radio > 0) | ||
| 1184 | setup.mode_mask |= T_RADIO; | ||
| 1183 | setup.tuner_callback = (setup.type == TUNER_XC2028) ? | 1185 | setup.tuner_callback = (setup.type == TUNER_XC2028) ? |
| 1184 | ivtv_reset_tuner_gpio : NULL; | 1186 | ivtv_reset_tuner_gpio : NULL; |
| 1185 | ivtv_call_all(itv, tuner, s_type_addr, &setup); | 1187 | ivtv_call_all(itv, tuner, s_type_addr, &setup); |
diff --git a/drivers/media/video/marvell-ccic/mcam-core.c b/drivers/media/video/marvell-ccic/mcam-core.c index 1141b976dff4..80ec64d2d6d8 100644 --- a/drivers/media/video/marvell-ccic/mcam-core.c +++ b/drivers/media/video/marvell-ccic/mcam-core.c | |||
| @@ -883,7 +883,8 @@ static int mcam_read_setup(struct mcam_camera *cam) | |||
| 883 | * Videobuf2 interface code. | 883 | * Videobuf2 interface code. |
| 884 | */ | 884 | */ |
| 885 | 885 | ||
| 886 | static int mcam_vb_queue_setup(struct vb2_queue *vq, unsigned int *nbufs, | 886 | static int mcam_vb_queue_setup(struct vb2_queue *vq, |
| 887 | const struct v4l2_format *fmt, unsigned int *nbufs, | ||
| 887 | unsigned int *num_planes, unsigned int sizes[], | 888 | unsigned int *num_planes, unsigned int sizes[], |
| 888 | void *alloc_ctxs[]) | 889 | void *alloc_ctxs[]) |
| 889 | { | 890 | { |
diff --git a/drivers/media/video/mem2mem_testdev.c b/drivers/media/video/mem2mem_testdev.c index 9594b52f8605..12897e8a3314 100644 --- a/drivers/media/video/mem2mem_testdev.c +++ b/drivers/media/video/mem2mem_testdev.c | |||
| @@ -738,9 +738,10 @@ static const struct v4l2_ioctl_ops m2mtest_ioctl_ops = { | |||
| 738 | * Queue operations | 738 | * Queue operations |
| 739 | */ | 739 | */ |
| 740 | 740 | ||
| 741 | static int m2mtest_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, | 741 | static int m2mtest_queue_setup(struct vb2_queue *vq, |
| 742 | unsigned int *nplanes, unsigned int sizes[], | 742 | const struct v4l2_format *fmt, |
| 743 | void *alloc_ctxs[]) | 743 | unsigned int *nbuffers, unsigned int *nplanes, |
| 744 | unsigned int sizes[], void *alloc_ctxs[]) | ||
| 744 | { | 745 | { |
| 745 | struct m2mtest_ctx *ctx = vb2_get_drv_priv(vq); | 746 | struct m2mtest_ctx *ctx = vb2_get_drv_priv(vq); |
| 746 | struct m2mtest_q_data *q_data; | 747 | struct m2mtest_q_data *q_data; |
diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index 4da9cca939c1..63ae5c61c9bf 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c | |||
| @@ -13,9 +13,11 @@ | |||
| 13 | #include <linux/i2c.h> | 13 | #include <linux/i2c.h> |
| 14 | #include <linux/log2.h> | 14 | #include <linux/log2.h> |
| 15 | 15 | ||
| 16 | #include <media/soc_camera.h> | ||
| 17 | #include <media/soc_mediabus.h> | ||
| 16 | #include <media/v4l2-subdev.h> | 18 | #include <media/v4l2-subdev.h> |
| 17 | #include <media/v4l2-chip-ident.h> | 19 | #include <media/v4l2-chip-ident.h> |
| 18 | #include <media/soc_camera.h> | 20 | #include <media/v4l2-ctrls.h> |
| 19 | 21 | ||
| 20 | /* | 22 | /* |
| 21 | * mt9m001 i2c address 0x5d | 23 | * mt9m001 i2c address 0x5d |
| @@ -84,15 +86,19 @@ static const struct mt9m001_datafmt mt9m001_monochrome_fmts[] = { | |||
| 84 | 86 | ||
| 85 | struct mt9m001 { | 87 | struct mt9m001 { |
| 86 | struct v4l2_subdev subdev; | 88 | struct v4l2_subdev subdev; |
| 89 | struct v4l2_ctrl_handler hdl; | ||
| 90 | struct { | ||
| 91 | /* exposure/auto-exposure cluster */ | ||
| 92 | struct v4l2_ctrl *autoexposure; | ||
| 93 | struct v4l2_ctrl *exposure; | ||
| 94 | }; | ||
| 87 | struct v4l2_rect rect; /* Sensor window */ | 95 | struct v4l2_rect rect; /* Sensor window */ |
| 88 | const struct mt9m001_datafmt *fmt; | 96 | const struct mt9m001_datafmt *fmt; |
| 89 | const struct mt9m001_datafmt *fmts; | 97 | const struct mt9m001_datafmt *fmts; |
| 90 | int num_fmts; | 98 | int num_fmts; |
| 91 | int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */ | 99 | int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */ |
| 92 | unsigned int gain; | 100 | unsigned int total_h; |
| 93 | unsigned int exposure; | ||
| 94 | unsigned short y_skip_top; /* Lines to skip at the top */ | 101 | unsigned short y_skip_top; /* Lines to skip at the top */ |
| 95 | unsigned char autoexposure; | ||
| 96 | }; | 102 | }; |
| 97 | 103 | ||
| 98 | static struct mt9m001 *to_mt9m001(const struct i2c_client *client) | 104 | static struct mt9m001 *to_mt9m001(const struct i2c_client *client) |
| @@ -165,54 +171,13 @@ static int mt9m001_s_stream(struct v4l2_subdev *sd, int enable) | |||
| 165 | return 0; | 171 | return 0; |
| 166 | } | 172 | } |
| 167 | 173 | ||
| 168 | static int mt9m001_set_bus_param(struct soc_camera_device *icd, | ||
| 169 | unsigned long flags) | ||
| 170 | { | ||
| 171 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
| 172 | unsigned long width_flag = flags & SOCAM_DATAWIDTH_MASK; | ||
| 173 | |||
| 174 | /* Only one width bit may be set */ | ||
| 175 | if (!is_power_of_2(width_flag)) | ||
| 176 | return -EINVAL; | ||
| 177 | |||
| 178 | if (icl->set_bus_param) | ||
| 179 | return icl->set_bus_param(icl, width_flag); | ||
| 180 | |||
| 181 | /* | ||
| 182 | * Without board specific bus width settings we only support the | ||
| 183 | * sensors native bus width | ||
| 184 | */ | ||
| 185 | if (width_flag == SOCAM_DATAWIDTH_10) | ||
| 186 | return 0; | ||
| 187 | |||
| 188 | return -EINVAL; | ||
| 189 | } | ||
| 190 | |||
| 191 | static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd) | ||
| 192 | { | ||
| 193 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
| 194 | /* MT9M001 has all capture_format parameters fixed */ | ||
| 195 | unsigned long flags = SOCAM_PCLK_SAMPLE_FALLING | | ||
| 196 | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | | ||
| 197 | SOCAM_DATA_ACTIVE_HIGH | SOCAM_MASTER; | ||
| 198 | |||
| 199 | if (icl->query_bus_param) | ||
| 200 | flags |= icl->query_bus_param(icl) & SOCAM_DATAWIDTH_MASK; | ||
| 201 | else | ||
| 202 | flags |= SOCAM_DATAWIDTH_10; | ||
| 203 | |||
| 204 | return soc_camera_apply_sensor_flags(icl, flags); | ||
| 205 | } | ||
| 206 | |||
| 207 | static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 174 | static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) |
| 208 | { | 175 | { |
| 209 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 176 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 210 | struct mt9m001 *mt9m001 = to_mt9m001(client); | 177 | struct mt9m001 *mt9m001 = to_mt9m001(client); |
| 211 | struct v4l2_rect rect = a->c; | 178 | struct v4l2_rect rect = a->c; |
| 212 | struct soc_camera_device *icd = client->dev.platform_data; | ||
| 213 | int ret; | 179 | int ret; |
| 214 | const u16 hblank = 9, vblank = 25; | 180 | const u16 hblank = 9, vblank = 25; |
| 215 | unsigned int total_h; | ||
| 216 | 181 | ||
| 217 | if (mt9m001->fmts == mt9m001_colour_fmts) | 182 | if (mt9m001->fmts == mt9m001_colour_fmts) |
| 218 | /* | 183 | /* |
| @@ -231,7 +196,7 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
| 231 | soc_camera_limit_side(&rect.top, &rect.height, | 196 | soc_camera_limit_side(&rect.top, &rect.height, |
| 232 | MT9M001_ROW_SKIP, MT9M001_MIN_HEIGHT, MT9M001_MAX_HEIGHT); | 197 | MT9M001_ROW_SKIP, MT9M001_MIN_HEIGHT, MT9M001_MAX_HEIGHT); |
| 233 | 198 | ||
| 234 | total_h = rect.height + mt9m001->y_skip_top + vblank; | 199 | mt9m001->total_h = rect.height + mt9m001->y_skip_top + vblank; |
| 235 | 200 | ||
| 236 | /* Blanking and start values - default... */ | 201 | /* Blanking and start values - default... */ |
| 237 | ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank); | 202 | ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank); |
| @@ -240,7 +205,7 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
| 240 | 205 | ||
| 241 | /* | 206 | /* |
| 242 | * The caller provides a supported format, as verified per | 207 | * The caller provides a supported format, as verified per |
| 243 | * call to icd->try_fmt() | 208 | * call to .try_mbus_fmt() |
| 244 | */ | 209 | */ |
| 245 | if (!ret) | 210 | if (!ret) |
| 246 | ret = reg_write(client, MT9M001_COLUMN_START, rect.left); | 211 | ret = reg_write(client, MT9M001_COLUMN_START, rect.left); |
| @@ -251,17 +216,8 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
| 251 | if (!ret) | 216 | if (!ret) |
| 252 | ret = reg_write(client, MT9M001_WINDOW_HEIGHT, | 217 | ret = reg_write(client, MT9M001_WINDOW_HEIGHT, |
| 253 | rect.height + mt9m001->y_skip_top - 1); | 218 | rect.height + mt9m001->y_skip_top - 1); |
| 254 | if (!ret && mt9m001->autoexposure) { | 219 | if (!ret && v4l2_ctrl_g_ctrl(mt9m001->autoexposure) == V4L2_EXPOSURE_AUTO) |
| 255 | ret = reg_write(client, MT9M001_SHUTTER_WIDTH, total_h); | 220 | ret = reg_write(client, MT9M001_SHUTTER_WIDTH, mt9m001->total_h); |
| 256 | if (!ret) { | ||
| 257 | const struct v4l2_queryctrl *qctrl = | ||
| 258 | soc_camera_find_qctrl(icd->ops, | ||
| 259 | V4L2_CID_EXPOSURE); | ||
| 260 | mt9m001->exposure = (524 + (total_h - 1) * | ||
| 261 | (qctrl->maximum - qctrl->minimum)) / | ||
| 262 | 1048 + qctrl->minimum; | ||
| 263 | } | ||
| 264 | } | ||
| 265 | 221 | ||
| 266 | if (!ret) | 222 | if (!ret) |
| 267 | mt9m001->rect = rect; | 223 | mt9m001->rect = rect; |
| @@ -421,107 +377,48 @@ static int mt9m001_s_register(struct v4l2_subdev *sd, | |||
| 421 | } | 377 | } |
| 422 | #endif | 378 | #endif |
| 423 | 379 | ||
| 424 | static const struct v4l2_queryctrl mt9m001_controls[] = { | 380 | static int mt9m001_g_volatile_ctrl(struct v4l2_ctrl *ctrl) |
| 425 | { | ||
| 426 | .id = V4L2_CID_VFLIP, | ||
| 427 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 428 | .name = "Flip Vertically", | ||
| 429 | .minimum = 0, | ||
| 430 | .maximum = 1, | ||
| 431 | .step = 1, | ||
| 432 | .default_value = 0, | ||
| 433 | }, { | ||
| 434 | .id = V4L2_CID_GAIN, | ||
| 435 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 436 | .name = "Gain", | ||
| 437 | .minimum = 0, | ||
| 438 | .maximum = 127, | ||
| 439 | .step = 1, | ||
| 440 | .default_value = 64, | ||
| 441 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
| 442 | }, { | ||
| 443 | .id = V4L2_CID_EXPOSURE, | ||
| 444 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 445 | .name = "Exposure", | ||
| 446 | .minimum = 1, | ||
| 447 | .maximum = 255, | ||
| 448 | .step = 1, | ||
| 449 | .default_value = 255, | ||
| 450 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
| 451 | }, { | ||
| 452 | .id = V4L2_CID_EXPOSURE_AUTO, | ||
| 453 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 454 | .name = "Automatic Exposure", | ||
| 455 | .minimum = 0, | ||
| 456 | .maximum = 1, | ||
| 457 | .step = 1, | ||
| 458 | .default_value = 1, | ||
| 459 | } | ||
| 460 | }; | ||
| 461 | |||
| 462 | static struct soc_camera_ops mt9m001_ops = { | ||
| 463 | .set_bus_param = mt9m001_set_bus_param, | ||
| 464 | .query_bus_param = mt9m001_query_bus_param, | ||
| 465 | .controls = mt9m001_controls, | ||
| 466 | .num_controls = ARRAY_SIZE(mt9m001_controls), | ||
| 467 | }; | ||
| 468 | |||
| 469 | static int mt9m001_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
| 470 | { | 381 | { |
| 471 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 382 | struct mt9m001 *mt9m001 = container_of(ctrl->handler, |
| 472 | struct mt9m001 *mt9m001 = to_mt9m001(client); | 383 | struct mt9m001, hdl); |
| 473 | int data; | 384 | s32 min, max; |
| 474 | 385 | ||
| 475 | switch (ctrl->id) { | 386 | switch (ctrl->id) { |
| 476 | case V4L2_CID_VFLIP: | ||
| 477 | data = reg_read(client, MT9M001_READ_OPTIONS2); | ||
| 478 | if (data < 0) | ||
| 479 | return -EIO; | ||
| 480 | ctrl->value = !!(data & 0x8000); | ||
| 481 | break; | ||
| 482 | case V4L2_CID_EXPOSURE_AUTO: | 387 | case V4L2_CID_EXPOSURE_AUTO: |
| 483 | ctrl->value = mt9m001->autoexposure; | 388 | min = mt9m001->exposure->minimum; |
| 484 | break; | 389 | max = mt9m001->exposure->maximum; |
| 485 | case V4L2_CID_GAIN: | 390 | mt9m001->exposure->val = |
| 486 | ctrl->value = mt9m001->gain; | 391 | (524 + (mt9m001->total_h - 1) * (max - min)) / 1048 + min; |
| 487 | break; | ||
| 488 | case V4L2_CID_EXPOSURE: | ||
| 489 | ctrl->value = mt9m001->exposure; | ||
| 490 | break; | 392 | break; |
| 491 | } | 393 | } |
| 492 | return 0; | 394 | return 0; |
| 493 | } | 395 | } |
| 494 | 396 | ||
| 495 | static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 397 | static int mt9m001_s_ctrl(struct v4l2_ctrl *ctrl) |
| 496 | { | 398 | { |
| 399 | struct mt9m001 *mt9m001 = container_of(ctrl->handler, | ||
| 400 | struct mt9m001, hdl); | ||
| 401 | struct v4l2_subdev *sd = &mt9m001->subdev; | ||
| 497 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 402 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 498 | struct mt9m001 *mt9m001 = to_mt9m001(client); | 403 | struct v4l2_ctrl *exp = mt9m001->exposure; |
| 499 | struct soc_camera_device *icd = client->dev.platform_data; | ||
| 500 | const struct v4l2_queryctrl *qctrl; | ||
| 501 | int data; | 404 | int data; |
| 502 | 405 | ||
| 503 | qctrl = soc_camera_find_qctrl(&mt9m001_ops, ctrl->id); | ||
| 504 | |||
| 505 | if (!qctrl) | ||
| 506 | return -EINVAL; | ||
| 507 | |||
| 508 | switch (ctrl->id) { | 406 | switch (ctrl->id) { |
| 509 | case V4L2_CID_VFLIP: | 407 | case V4L2_CID_VFLIP: |
| 510 | if (ctrl->value) | 408 | if (ctrl->val) |
| 511 | data = reg_set(client, MT9M001_READ_OPTIONS2, 0x8000); | 409 | data = reg_set(client, MT9M001_READ_OPTIONS2, 0x8000); |
| 512 | else | 410 | else |
| 513 | data = reg_clear(client, MT9M001_READ_OPTIONS2, 0x8000); | 411 | data = reg_clear(client, MT9M001_READ_OPTIONS2, 0x8000); |
| 514 | if (data < 0) | 412 | if (data < 0) |
| 515 | return -EIO; | 413 | return -EIO; |
| 516 | break; | 414 | return 0; |
| 415 | |||
| 517 | case V4L2_CID_GAIN: | 416 | case V4L2_CID_GAIN: |
| 518 | if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) | ||
| 519 | return -EINVAL; | ||
| 520 | /* See Datasheet Table 7, Gain settings. */ | 417 | /* See Datasheet Table 7, Gain settings. */ |
| 521 | if (ctrl->value <= qctrl->default_value) { | 418 | if (ctrl->val <= ctrl->default_value) { |
| 522 | /* Pack it into 0..1 step 0.125, register values 0..8 */ | 419 | /* Pack it into 0..1 step 0.125, register values 0..8 */ |
| 523 | unsigned long range = qctrl->default_value - qctrl->minimum; | 420 | unsigned long range = ctrl->default_value - ctrl->minimum; |
| 524 | data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range; | 421 | data = ((ctrl->val - ctrl->minimum) * 8 + range / 2) / range; |
| 525 | 422 | ||
| 526 | dev_dbg(&client->dev, "Setting gain %d\n", data); | 423 | dev_dbg(&client->dev, "Setting gain %d\n", data); |
| 527 | data = reg_write(client, MT9M001_GLOBAL_GAIN, data); | 424 | data = reg_write(client, MT9M001_GLOBAL_GAIN, data); |
| @@ -530,8 +427,8 @@ static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
| 530 | } else { | 427 | } else { |
| 531 | /* Pack it into 1.125..15 variable step, register values 9..67 */ | 428 | /* Pack it into 1.125..15 variable step, register values 9..67 */ |
| 532 | /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */ | 429 | /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */ |
| 533 | unsigned long range = qctrl->maximum - qctrl->default_value - 1; | 430 | unsigned long range = ctrl->maximum - ctrl->default_value - 1; |
| 534 | unsigned long gain = ((ctrl->value - qctrl->default_value - 1) * | 431 | unsigned long gain = ((ctrl->val - ctrl->default_value - 1) * |
| 535 | 111 + range / 2) / range + 9; | 432 | 111 + range / 2) / range + 9; |
| 536 | 433 | ||
| 537 | if (gain <= 32) | 434 | if (gain <= 32) |
| @@ -547,66 +444,44 @@ static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
| 547 | if (data < 0) | 444 | if (data < 0) |
| 548 | return -EIO; | 445 | return -EIO; |
| 549 | } | 446 | } |
| 447 | return 0; | ||
| 550 | 448 | ||
| 551 | /* Success */ | 449 | case V4L2_CID_EXPOSURE_AUTO: |
| 552 | mt9m001->gain = ctrl->value; | 450 | if (ctrl->val == V4L2_EXPOSURE_MANUAL) { |
| 553 | break; | 451 | unsigned long range = exp->maximum - exp->minimum; |
| 554 | case V4L2_CID_EXPOSURE: | 452 | unsigned long shutter = ((exp->val - exp->minimum) * 1048 + |
| 555 | /* mt9m001 has maximum == default */ | ||
| 556 | if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) | ||
| 557 | return -EINVAL; | ||
| 558 | else { | ||
| 559 | unsigned long range = qctrl->maximum - qctrl->minimum; | ||
| 560 | unsigned long shutter = ((ctrl->value - qctrl->minimum) * 1048 + | ||
| 561 | range / 2) / range + 1; | 453 | range / 2) / range + 1; |
| 562 | 454 | ||
| 563 | dev_dbg(&client->dev, | 455 | dev_dbg(&client->dev, |
| 564 | "Setting shutter width from %d to %lu\n", | 456 | "Setting shutter width from %d to %lu\n", |
| 565 | reg_read(client, MT9M001_SHUTTER_WIDTH), | 457 | reg_read(client, MT9M001_SHUTTER_WIDTH), shutter); |
| 566 | shutter); | ||
| 567 | if (reg_write(client, MT9M001_SHUTTER_WIDTH, shutter) < 0) | 458 | if (reg_write(client, MT9M001_SHUTTER_WIDTH, shutter) < 0) |
| 568 | return -EIO; | 459 | return -EIO; |
| 569 | mt9m001->exposure = ctrl->value; | 460 | } else { |
| 570 | mt9m001->autoexposure = 0; | ||
| 571 | } | ||
| 572 | break; | ||
| 573 | case V4L2_CID_EXPOSURE_AUTO: | ||
| 574 | if (ctrl->value) { | ||
| 575 | const u16 vblank = 25; | 461 | const u16 vblank = 25; |
| 576 | unsigned int total_h = mt9m001->rect.height + | 462 | |
| 463 | mt9m001->total_h = mt9m001->rect.height + | ||
| 577 | mt9m001->y_skip_top + vblank; | 464 | mt9m001->y_skip_top + vblank; |
| 578 | if (reg_write(client, MT9M001_SHUTTER_WIDTH, | 465 | if (reg_write(client, MT9M001_SHUTTER_WIDTH, mt9m001->total_h) < 0) |
| 579 | total_h) < 0) | ||
| 580 | return -EIO; | 466 | return -EIO; |
| 581 | qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); | 467 | } |
| 582 | mt9m001->exposure = (524 + (total_h - 1) * | 468 | return 0; |
| 583 | (qctrl->maximum - qctrl->minimum)) / | ||
| 584 | 1048 + qctrl->minimum; | ||
| 585 | mt9m001->autoexposure = 1; | ||
| 586 | } else | ||
| 587 | mt9m001->autoexposure = 0; | ||
| 588 | break; | ||
| 589 | } | 469 | } |
| 590 | return 0; | 470 | return -EINVAL; |
| 591 | } | 471 | } |
| 592 | 472 | ||
| 593 | /* | 473 | /* |
| 594 | * Interface active, can use i2c. If it fails, it can indeed mean, that | 474 | * Interface active, can use i2c. If it fails, it can indeed mean, that |
| 595 | * this wasn't our capture interface, so, we wait for the right one | 475 | * this wasn't our capture interface, so, we wait for the right one |
| 596 | */ | 476 | */ |
| 597 | static int mt9m001_video_probe(struct soc_camera_device *icd, | 477 | static int mt9m001_video_probe(struct soc_camera_link *icl, |
| 598 | struct i2c_client *client) | 478 | struct i2c_client *client) |
| 599 | { | 479 | { |
| 600 | struct mt9m001 *mt9m001 = to_mt9m001(client); | 480 | struct mt9m001 *mt9m001 = to_mt9m001(client); |
| 601 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
| 602 | s32 data; | 481 | s32 data; |
| 603 | unsigned long flags; | 482 | unsigned long flags; |
| 604 | int ret; | 483 | int ret; |
| 605 | 484 | ||
| 606 | /* We must have a parent by now. And it cannot be a wrong one. */ | ||
| 607 | BUG_ON(!icd->parent || | ||
| 608 | to_soc_camera_host(icd->parent)->nr != icd->iface); | ||
| 609 | |||
| 610 | /* Enable the chip */ | 485 | /* Enable the chip */ |
| 611 | data = reg_write(client, MT9M001_CHIP_ENABLE, 1); | 486 | data = reg_write(client, MT9M001_CHIP_ENABLE, 1); |
| 612 | dev_dbg(&client->dev, "write: %d\n", data); | 487 | dev_dbg(&client->dev, "write: %d\n", data); |
| @@ -661,18 +536,11 @@ static int mt9m001_video_probe(struct soc_camera_device *icd, | |||
| 661 | dev_err(&client->dev, "Failed to initialise the camera\n"); | 536 | dev_err(&client->dev, "Failed to initialise the camera\n"); |
| 662 | 537 | ||
| 663 | /* mt9m001_init() has reset the chip, returning registers to defaults */ | 538 | /* mt9m001_init() has reset the chip, returning registers to defaults */ |
| 664 | mt9m001->gain = 64; | 539 | return v4l2_ctrl_handler_setup(&mt9m001->hdl); |
| 665 | mt9m001->exposure = 255; | ||
| 666 | |||
| 667 | return ret; | ||
| 668 | } | 540 | } |
| 669 | 541 | ||
| 670 | static void mt9m001_video_remove(struct soc_camera_device *icd) | 542 | static void mt9m001_video_remove(struct soc_camera_link *icl) |
| 671 | { | 543 | { |
| 672 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
| 673 | |||
| 674 | dev_dbg(icd->pdev, "Video removed: %p, %p\n", | ||
| 675 | icd->parent, icd->vdev); | ||
| 676 | if (icl->free_bus) | 544 | if (icl->free_bus) |
| 677 | icl->free_bus(icl); | 545 | icl->free_bus(icl); |
| 678 | } | 546 | } |
| @@ -687,9 +555,12 @@ static int mt9m001_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) | |||
| 687 | return 0; | 555 | return 0; |
| 688 | } | 556 | } |
| 689 | 557 | ||
| 558 | static const struct v4l2_ctrl_ops mt9m001_ctrl_ops = { | ||
| 559 | .g_volatile_ctrl = mt9m001_g_volatile_ctrl, | ||
| 560 | .s_ctrl = mt9m001_s_ctrl, | ||
| 561 | }; | ||
| 562 | |||
| 690 | static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = { | 563 | static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = { |
| 691 | .g_ctrl = mt9m001_g_ctrl, | ||
| 692 | .s_ctrl = mt9m001_s_ctrl, | ||
| 693 | .g_chip_ident = mt9m001_g_chip_ident, | 564 | .g_chip_ident = mt9m001_g_chip_ident, |
| 694 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 565 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
| 695 | .g_register = mt9m001_g_register, | 566 | .g_register = mt9m001_g_register, |
| @@ -710,6 +581,40 @@ static int mt9m001_enum_fmt(struct v4l2_subdev *sd, unsigned int index, | |||
| 710 | return 0; | 581 | return 0; |
| 711 | } | 582 | } |
| 712 | 583 | ||
| 584 | static int mt9m001_g_mbus_config(struct v4l2_subdev *sd, | ||
| 585 | struct v4l2_mbus_config *cfg) | ||
| 586 | { | ||
| 587 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 588 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
| 589 | |||
| 590 | /* MT9M001 has all capture_format parameters fixed */ | ||
| 591 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_FALLING | | ||
| 592 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | | ||
| 593 | V4L2_MBUS_DATA_ACTIVE_HIGH | V4L2_MBUS_MASTER; | ||
| 594 | cfg->type = V4L2_MBUS_PARALLEL; | ||
| 595 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | ||
| 596 | |||
| 597 | return 0; | ||
| 598 | } | ||
| 599 | |||
| 600 | static int mt9m001_s_mbus_config(struct v4l2_subdev *sd, | ||
| 601 | const struct v4l2_mbus_config *cfg) | ||
| 602 | { | ||
| 603 | const struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 604 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
| 605 | struct mt9m001 *mt9m001 = to_mt9m001(client); | ||
| 606 | unsigned int bps = soc_mbus_get_fmtdesc(mt9m001->fmt->code)->bits_per_sample; | ||
| 607 | |||
| 608 | if (icl->set_bus_param) | ||
| 609 | return icl->set_bus_param(icl, 1 << (bps - 1)); | ||
| 610 | |||
| 611 | /* | ||
| 612 | * Without board specific bus width settings we only support the | ||
| 613 | * sensors native bus width | ||
| 614 | */ | ||
| 615 | return bps == 10 ? 0 : -EINVAL; | ||
| 616 | } | ||
| 617 | |||
| 713 | static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = { | 618 | static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = { |
| 714 | .s_stream = mt9m001_s_stream, | 619 | .s_stream = mt9m001_s_stream, |
| 715 | .s_mbus_fmt = mt9m001_s_fmt, | 620 | .s_mbus_fmt = mt9m001_s_fmt, |
| @@ -719,6 +624,8 @@ static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = { | |||
| 719 | .g_crop = mt9m001_g_crop, | 624 | .g_crop = mt9m001_g_crop, |
| 720 | .cropcap = mt9m001_cropcap, | 625 | .cropcap = mt9m001_cropcap, |
| 721 | .enum_mbus_fmt = mt9m001_enum_fmt, | 626 | .enum_mbus_fmt = mt9m001_enum_fmt, |
| 627 | .g_mbus_config = mt9m001_g_mbus_config, | ||
| 628 | .s_mbus_config = mt9m001_s_mbus_config, | ||
| 722 | }; | 629 | }; |
| 723 | 630 | ||
| 724 | static struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = { | 631 | static struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = { |
| @@ -735,17 +642,10 @@ static int mt9m001_probe(struct i2c_client *client, | |||
| 735 | const struct i2c_device_id *did) | 642 | const struct i2c_device_id *did) |
| 736 | { | 643 | { |
| 737 | struct mt9m001 *mt9m001; | 644 | struct mt9m001 *mt9m001; |
| 738 | struct soc_camera_device *icd = client->dev.platform_data; | ||
| 739 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 645 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
| 740 | struct soc_camera_link *icl; | 646 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
| 741 | int ret; | 647 | int ret; |
| 742 | 648 | ||
| 743 | if (!icd) { | ||
| 744 | dev_err(&client->dev, "MT9M001: missing soc-camera data!\n"); | ||
| 745 | return -EINVAL; | ||
| 746 | } | ||
| 747 | |||
| 748 | icl = to_soc_camera_link(icd); | ||
| 749 | if (!icl) { | 649 | if (!icl) { |
| 750 | dev_err(&client->dev, "MT9M001 driver needs platform data\n"); | 650 | dev_err(&client->dev, "MT9M001 driver needs platform data\n"); |
| 751 | return -EINVAL; | 651 | return -EINVAL; |
| @@ -762,25 +662,40 @@ static int mt9m001_probe(struct i2c_client *client, | |||
| 762 | return -ENOMEM; | 662 | return -ENOMEM; |
| 763 | 663 | ||
| 764 | v4l2_i2c_subdev_init(&mt9m001->subdev, client, &mt9m001_subdev_ops); | 664 | v4l2_i2c_subdev_init(&mt9m001->subdev, client, &mt9m001_subdev_ops); |
| 665 | v4l2_ctrl_handler_init(&mt9m001->hdl, 4); | ||
| 666 | v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops, | ||
| 667 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
| 668 | v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops, | ||
| 669 | V4L2_CID_GAIN, 0, 127, 1, 64); | ||
| 670 | mt9m001->exposure = v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops, | ||
| 671 | V4L2_CID_EXPOSURE, 1, 255, 1, 255); | ||
| 672 | /* | ||
| 673 | * Simulated autoexposure. If enabled, we calculate shutter width | ||
| 674 | * ourselves in the driver based on vertical blanking and frame width | ||
| 675 | */ | ||
| 676 | mt9m001->autoexposure = v4l2_ctrl_new_std_menu(&mt9m001->hdl, | ||
| 677 | &mt9m001_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, | ||
| 678 | V4L2_EXPOSURE_AUTO); | ||
| 679 | mt9m001->subdev.ctrl_handler = &mt9m001->hdl; | ||
| 680 | if (mt9m001->hdl.error) { | ||
| 681 | int err = mt9m001->hdl.error; | ||
| 765 | 682 | ||
| 766 | /* Second stage probe - when a capture adapter is there */ | 683 | kfree(mt9m001); |
| 767 | icd->ops = &mt9m001_ops; | 684 | return err; |
| 685 | } | ||
| 686 | v4l2_ctrl_auto_cluster(2, &mt9m001->autoexposure, | ||
| 687 | V4L2_EXPOSURE_MANUAL, true); | ||
| 768 | 688 | ||
| 689 | /* Second stage probe - when a capture adapter is there */ | ||
| 769 | mt9m001->y_skip_top = 0; | 690 | mt9m001->y_skip_top = 0; |
| 770 | mt9m001->rect.left = MT9M001_COLUMN_SKIP; | 691 | mt9m001->rect.left = MT9M001_COLUMN_SKIP; |
| 771 | mt9m001->rect.top = MT9M001_ROW_SKIP; | 692 | mt9m001->rect.top = MT9M001_ROW_SKIP; |
| 772 | mt9m001->rect.width = MT9M001_MAX_WIDTH; | 693 | mt9m001->rect.width = MT9M001_MAX_WIDTH; |
| 773 | mt9m001->rect.height = MT9M001_MAX_HEIGHT; | 694 | mt9m001->rect.height = MT9M001_MAX_HEIGHT; |
| 774 | 695 | ||
| 775 | /* | 696 | ret = mt9m001_video_probe(icl, client); |
| 776 | * Simulated autoexposure. If enabled, we calculate shutter width | ||
| 777 | * ourselves in the driver based on vertical blanking and frame width | ||
| 778 | */ | ||
| 779 | mt9m001->autoexposure = 1; | ||
| 780 | |||
| 781 | ret = mt9m001_video_probe(icd, client); | ||
| 782 | if (ret) { | 697 | if (ret) { |
| 783 | icd->ops = NULL; | 698 | v4l2_ctrl_handler_free(&mt9m001->hdl); |
| 784 | kfree(mt9m001); | 699 | kfree(mt9m001); |
| 785 | } | 700 | } |
| 786 | 701 | ||
| @@ -790,10 +705,11 @@ static int mt9m001_probe(struct i2c_client *client, | |||
| 790 | static int mt9m001_remove(struct i2c_client *client) | 705 | static int mt9m001_remove(struct i2c_client *client) |
| 791 | { | 706 | { |
| 792 | struct mt9m001 *mt9m001 = to_mt9m001(client); | 707 | struct mt9m001 *mt9m001 = to_mt9m001(client); |
| 793 | struct soc_camera_device *icd = client->dev.platform_data; | 708 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
| 794 | 709 | ||
| 795 | icd->ops = NULL; | 710 | v4l2_device_unregister_subdev(&mt9m001->subdev); |
| 796 | mt9m001_video_remove(icd); | 711 | v4l2_ctrl_handler_free(&mt9m001->hdl); |
| 712 | mt9m001_video_remove(icl); | ||
| 797 | kfree(mt9m001); | 713 | kfree(mt9m001); |
| 798 | 714 | ||
| 799 | return 0; | 715 | return 0; |
diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index 07af26e6bebd..f023cc092c2b 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c | |||
| @@ -13,10 +13,12 @@ | |||
| 13 | #include <linux/log2.h> | 13 | #include <linux/log2.h> |
| 14 | #include <linux/gpio.h> | 14 | #include <linux/gpio.h> |
| 15 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
| 16 | #include <linux/v4l2-mediabus.h> | ||
| 16 | 17 | ||
| 18 | #include <media/soc_camera.h> | ||
| 17 | #include <media/v4l2-common.h> | 19 | #include <media/v4l2-common.h> |
| 20 | #include <media/v4l2-ctrls.h> | ||
| 18 | #include <media/v4l2-chip-ident.h> | 21 | #include <media/v4l2-chip-ident.h> |
| 19 | #include <media/soc_camera.h> | ||
| 20 | 22 | ||
| 21 | /* | 23 | /* |
| 22 | * MT9M111, MT9M112 and MT9M131: | 24 | * MT9M111, MT9M112 and MT9M131: |
| @@ -177,6 +179,8 @@ enum mt9m111_context { | |||
| 177 | 179 | ||
| 178 | struct mt9m111 { | 180 | struct mt9m111 { |
| 179 | struct v4l2_subdev subdev; | 181 | struct v4l2_subdev subdev; |
| 182 | struct v4l2_ctrl_handler hdl; | ||
| 183 | struct v4l2_ctrl *gain; | ||
| 180 | int model; /* V4L2_IDENT_MT9M111 or V4L2_IDENT_MT9M112 code | 184 | int model; /* V4L2_IDENT_MT9M111 or V4L2_IDENT_MT9M112 code |
| 181 | * from v4l2-chip-ident.h */ | 185 | * from v4l2-chip-ident.h */ |
| 182 | enum mt9m111_context context; | 186 | enum mt9m111_context context; |
| @@ -185,13 +189,8 @@ struct mt9m111 { | |||
| 185 | int power_count; | 189 | int power_count; |
| 186 | const struct mt9m111_datafmt *fmt; | 190 | const struct mt9m111_datafmt *fmt; |
| 187 | int lastpage; /* PageMap cache value */ | 191 | int lastpage; /* PageMap cache value */ |
| 188 | unsigned int gain; | ||
| 189 | unsigned char autoexposure; | ||
| 190 | unsigned char datawidth; | 192 | unsigned char datawidth; |
| 191 | unsigned int powered:1; | 193 | unsigned int powered:1; |
| 192 | unsigned int hflip:1; | ||
| 193 | unsigned int vflip:1; | ||
| 194 | unsigned int autowhitebalance:1; | ||
| 195 | }; | 194 | }; |
| 196 | 195 | ||
| 197 | static struct mt9m111 *to_mt9m111(const struct i2c_client *client) | 196 | static struct mt9m111 *to_mt9m111(const struct i2c_client *client) |
| @@ -363,21 +362,6 @@ static int mt9m111_reset(struct mt9m111 *mt9m111) | |||
| 363 | return ret; | 362 | return ret; |
| 364 | } | 363 | } |
| 365 | 364 | ||
| 366 | static unsigned long mt9m111_query_bus_param(struct soc_camera_device *icd) | ||
| 367 | { | ||
| 368 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
| 369 | unsigned long flags = SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING | | ||
| 370 | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | | ||
| 371 | SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8; | ||
| 372 | |||
| 373 | return soc_camera_apply_sensor_flags(icl, flags); | ||
| 374 | } | ||
| 375 | |||
| 376 | static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f) | ||
| 377 | { | ||
| 378 | return 0; | ||
| 379 | } | ||
| 380 | |||
| 381 | static int mt9m111_make_rect(struct mt9m111 *mt9m111, | 365 | static int mt9m111_make_rect(struct mt9m111 *mt9m111, |
| 382 | struct v4l2_rect *rect) | 366 | struct v4l2_rect *rect) |
| 383 | { | 367 | { |
| @@ -660,50 +644,6 @@ static int mt9m111_s_register(struct v4l2_subdev *sd, | |||
| 660 | } | 644 | } |
| 661 | #endif | 645 | #endif |
| 662 | 646 | ||
| 663 | static const struct v4l2_queryctrl mt9m111_controls[] = { | ||
| 664 | { | ||
| 665 | .id = V4L2_CID_VFLIP, | ||
| 666 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 667 | .name = "Flip Verticaly", | ||
| 668 | .minimum = 0, | ||
| 669 | .maximum = 1, | ||
| 670 | .step = 1, | ||
| 671 | .default_value = 0, | ||
| 672 | }, { | ||
| 673 | .id = V4L2_CID_HFLIP, | ||
| 674 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 675 | .name = "Flip Horizontaly", | ||
| 676 | .minimum = 0, | ||
| 677 | .maximum = 1, | ||
| 678 | .step = 1, | ||
| 679 | .default_value = 0, | ||
| 680 | }, { /* gain = 1/32*val (=>gain=1 if val==32) */ | ||
| 681 | .id = V4L2_CID_GAIN, | ||
| 682 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 683 | .name = "Gain", | ||
| 684 | .minimum = 0, | ||
| 685 | .maximum = 63 * 2 * 2, | ||
| 686 | .step = 1, | ||
| 687 | .default_value = 32, | ||
| 688 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
| 689 | }, { | ||
| 690 | .id = V4L2_CID_EXPOSURE_AUTO, | ||
| 691 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 692 | .name = "Auto Exposure", | ||
| 693 | .minimum = 0, | ||
| 694 | .maximum = 1, | ||
| 695 | .step = 1, | ||
| 696 | .default_value = 1, | ||
| 697 | } | ||
| 698 | }; | ||
| 699 | |||
| 700 | static struct soc_camera_ops mt9m111_ops = { | ||
| 701 | .query_bus_param = mt9m111_query_bus_param, | ||
| 702 | .set_bus_param = mt9m111_set_bus_param, | ||
| 703 | .controls = mt9m111_controls, | ||
| 704 | .num_controls = ARRAY_SIZE(mt9m111_controls), | ||
| 705 | }; | ||
| 706 | |||
| 707 | static int mt9m111_set_flip(struct mt9m111 *mt9m111, int flip, int mask) | 647 | static int mt9m111_set_flip(struct mt9m111 *mt9m111, int flip, int mask) |
| 708 | { | 648 | { |
| 709 | struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); | 649 | struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); |
| @@ -744,7 +684,6 @@ static int mt9m111_set_global_gain(struct mt9m111 *mt9m111, int gain) | |||
| 744 | if (gain > 63 * 2 * 2) | 684 | if (gain > 63 * 2 * 2) |
| 745 | return -EINVAL; | 685 | return -EINVAL; |
| 746 | 686 | ||
| 747 | mt9m111->gain = gain; | ||
| 748 | if ((gain >= 64 * 2) && (gain < 63 * 2 * 2)) | 687 | if ((gain >= 64 * 2) && (gain < 63 * 2 * 2)) |
| 749 | val = (1 << 10) | (1 << 9) | (gain / 4); | 688 | val = (1 << 10) | (1 << 9) | (gain / 4); |
| 750 | else if ((gain >= 64) && (gain < 64 * 2)) | 689 | else if ((gain >= 64) && (gain < 64 * 2)) |
| @@ -758,118 +697,47 @@ static int mt9m111_set_global_gain(struct mt9m111 *mt9m111, int gain) | |||
| 758 | static int mt9m111_set_autoexposure(struct mt9m111 *mt9m111, int on) | 697 | static int mt9m111_set_autoexposure(struct mt9m111 *mt9m111, int on) |
| 759 | { | 698 | { |
| 760 | struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); | 699 | struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); |
| 761 | int ret; | ||
| 762 | 700 | ||
| 763 | if (on) | 701 | if (on) |
| 764 | ret = reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN); | 702 | return reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN); |
| 765 | else | 703 | return reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN); |
| 766 | ret = reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN); | ||
| 767 | |||
| 768 | if (!ret) | ||
| 769 | mt9m111->autoexposure = on; | ||
| 770 | |||
| 771 | return ret; | ||
| 772 | } | 704 | } |
| 773 | 705 | ||
| 774 | static int mt9m111_set_autowhitebalance(struct mt9m111 *mt9m111, int on) | 706 | static int mt9m111_set_autowhitebalance(struct mt9m111 *mt9m111, int on) |
| 775 | { | 707 | { |
| 776 | struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); | 708 | struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); |
| 777 | int ret; | ||
| 778 | 709 | ||
| 779 | if (on) | 710 | if (on) |
| 780 | ret = reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN); | 711 | return reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN); |
| 781 | else | 712 | return reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN); |
| 782 | ret = reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN); | ||
| 783 | |||
| 784 | if (!ret) | ||
| 785 | mt9m111->autowhitebalance = on; | ||
| 786 | |||
| 787 | return ret; | ||
| 788 | } | ||
| 789 | |||
| 790 | static int mt9m111_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
| 791 | { | ||
| 792 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 793 | struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); | ||
| 794 | int data; | ||
| 795 | |||
| 796 | switch (ctrl->id) { | ||
| 797 | case V4L2_CID_VFLIP: | ||
| 798 | if (mt9m111->context == HIGHPOWER) | ||
| 799 | data = reg_read(READ_MODE_B); | ||
| 800 | else | ||
| 801 | data = reg_read(READ_MODE_A); | ||
| 802 | |||
| 803 | if (data < 0) | ||
| 804 | return -EIO; | ||
| 805 | ctrl->value = !!(data & MT9M111_RMB_MIRROR_ROWS); | ||
| 806 | break; | ||
| 807 | case V4L2_CID_HFLIP: | ||
| 808 | if (mt9m111->context == HIGHPOWER) | ||
| 809 | data = reg_read(READ_MODE_B); | ||
| 810 | else | ||
| 811 | data = reg_read(READ_MODE_A); | ||
| 812 | |||
| 813 | if (data < 0) | ||
| 814 | return -EIO; | ||
| 815 | ctrl->value = !!(data & MT9M111_RMB_MIRROR_COLS); | ||
| 816 | break; | ||
| 817 | case V4L2_CID_GAIN: | ||
| 818 | data = mt9m111_get_global_gain(mt9m111); | ||
| 819 | if (data < 0) | ||
| 820 | return data; | ||
| 821 | ctrl->value = data; | ||
| 822 | break; | ||
| 823 | case V4L2_CID_EXPOSURE_AUTO: | ||
| 824 | ctrl->value = mt9m111->autoexposure; | ||
| 825 | break; | ||
| 826 | case V4L2_CID_AUTO_WHITE_BALANCE: | ||
| 827 | ctrl->value = mt9m111->autowhitebalance; | ||
| 828 | break; | ||
| 829 | } | ||
| 830 | return 0; | ||
| 831 | } | 713 | } |
| 832 | 714 | ||
| 833 | static int mt9m111_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 715 | static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl) |
| 834 | { | 716 | { |
| 835 | struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); | 717 | struct mt9m111 *mt9m111 = container_of(ctrl->handler, |
| 836 | const struct v4l2_queryctrl *qctrl; | 718 | struct mt9m111, hdl); |
| 837 | int ret; | ||
| 838 | |||
| 839 | qctrl = soc_camera_find_qctrl(&mt9m111_ops, ctrl->id); | ||
| 840 | if (!qctrl) | ||
| 841 | return -EINVAL; | ||
| 842 | 719 | ||
| 843 | switch (ctrl->id) { | 720 | switch (ctrl->id) { |
| 844 | case V4L2_CID_VFLIP: | 721 | case V4L2_CID_VFLIP: |
| 845 | mt9m111->vflip = ctrl->value; | 722 | return mt9m111_set_flip(mt9m111, ctrl->val, |
| 846 | ret = mt9m111_set_flip(mt9m111, ctrl->value, | ||
| 847 | MT9M111_RMB_MIRROR_ROWS); | 723 | MT9M111_RMB_MIRROR_ROWS); |
| 848 | break; | ||
| 849 | case V4L2_CID_HFLIP: | 724 | case V4L2_CID_HFLIP: |
| 850 | mt9m111->hflip = ctrl->value; | 725 | return mt9m111_set_flip(mt9m111, ctrl->val, |
| 851 | ret = mt9m111_set_flip(mt9m111, ctrl->value, | ||
| 852 | MT9M111_RMB_MIRROR_COLS); | 726 | MT9M111_RMB_MIRROR_COLS); |
| 853 | break; | ||
| 854 | case V4L2_CID_GAIN: | 727 | case V4L2_CID_GAIN: |
| 855 | ret = mt9m111_set_global_gain(mt9m111, ctrl->value); | 728 | return mt9m111_set_global_gain(mt9m111, ctrl->val); |
| 856 | break; | ||
| 857 | case V4L2_CID_EXPOSURE_AUTO: | 729 | case V4L2_CID_EXPOSURE_AUTO: |
| 858 | ret = mt9m111_set_autoexposure(mt9m111, ctrl->value); | 730 | return mt9m111_set_autoexposure(mt9m111, ctrl->val); |
| 859 | break; | ||
| 860 | case V4L2_CID_AUTO_WHITE_BALANCE: | 731 | case V4L2_CID_AUTO_WHITE_BALANCE: |
| 861 | ret = mt9m111_set_autowhitebalance(mt9m111, ctrl->value); | 732 | return mt9m111_set_autowhitebalance(mt9m111, ctrl->val); |
| 862 | break; | ||
| 863 | default: | ||
| 864 | ret = -EINVAL; | ||
| 865 | } | 733 | } |
| 866 | 734 | ||
| 867 | return ret; | 735 | return -EINVAL; |
| 868 | } | 736 | } |
| 869 | 737 | ||
| 870 | static int mt9m111_suspend(struct mt9m111 *mt9m111) | 738 | static int mt9m111_suspend(struct mt9m111 *mt9m111) |
| 871 | { | 739 | { |
| 872 | mt9m111->gain = mt9m111_get_global_gain(mt9m111); | 740 | v4l2_ctrl_s_ctrl(mt9m111->gain, mt9m111_get_global_gain(mt9m111)); |
| 873 | 741 | ||
| 874 | return 0; | 742 | return 0; |
| 875 | } | 743 | } |
| @@ -879,11 +747,7 @@ static void mt9m111_restore_state(struct mt9m111 *mt9m111) | |||
| 879 | mt9m111_set_context(mt9m111, mt9m111->context); | 747 | mt9m111_set_context(mt9m111, mt9m111->context); |
| 880 | mt9m111_set_pixfmt(mt9m111, mt9m111->fmt->code); | 748 | mt9m111_set_pixfmt(mt9m111, mt9m111->fmt->code); |
| 881 | mt9m111_setup_rect(mt9m111, &mt9m111->rect); | 749 | mt9m111_setup_rect(mt9m111, &mt9m111->rect); |
| 882 | mt9m111_set_flip(mt9m111, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS); | 750 | v4l2_ctrl_handler_setup(&mt9m111->hdl); |
| 883 | mt9m111_set_flip(mt9m111, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS); | ||
| 884 | mt9m111_set_global_gain(mt9m111, mt9m111->gain); | ||
| 885 | mt9m111_set_autoexposure(mt9m111, mt9m111->autoexposure); | ||
| 886 | mt9m111_set_autowhitebalance(mt9m111, mt9m111->autowhitebalance); | ||
| 887 | } | 751 | } |
| 888 | 752 | ||
| 889 | static int mt9m111_resume(struct mt9m111 *mt9m111) | 753 | static int mt9m111_resume(struct mt9m111 *mt9m111) |
| @@ -911,8 +775,6 @@ static int mt9m111_init(struct mt9m111 *mt9m111) | |||
| 911 | ret = mt9m111_reset(mt9m111); | 775 | ret = mt9m111_reset(mt9m111); |
| 912 | if (!ret) | 776 | if (!ret) |
| 913 | ret = mt9m111_set_context(mt9m111, mt9m111->context); | 777 | ret = mt9m111_set_context(mt9m111, mt9m111->context); |
| 914 | if (!ret) | ||
| 915 | ret = mt9m111_set_autoexposure(mt9m111, mt9m111->autoexposure); | ||
| 916 | if (ret) | 778 | if (ret) |
| 917 | dev_err(&client->dev, "mt9m111 init failed: %d\n", ret); | 779 | dev_err(&client->dev, "mt9m111 init failed: %d\n", ret); |
| 918 | return ret; | 780 | return ret; |
| @@ -922,22 +784,12 @@ static int mt9m111_init(struct mt9m111 *mt9m111) | |||
| 922 | * Interface active, can use i2c. If it fails, it can indeed mean, that | 784 | * Interface active, can use i2c. If it fails, it can indeed mean, that |
| 923 | * this wasn't our capture interface, so, we wait for the right one | 785 | * this wasn't our capture interface, so, we wait for the right one |
| 924 | */ | 786 | */ |
| 925 | static int mt9m111_video_probe(struct soc_camera_device *icd, | 787 | static int mt9m111_video_probe(struct i2c_client *client) |
| 926 | struct i2c_client *client) | ||
| 927 | { | 788 | { |
| 928 | struct mt9m111 *mt9m111 = to_mt9m111(client); | 789 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
| 929 | s32 data; | 790 | s32 data; |
| 930 | int ret; | 791 | int ret; |
| 931 | 792 | ||
| 932 | /* We must have a parent by now. And it cannot be a wrong one. */ | ||
| 933 | BUG_ON(!icd->parent || | ||
| 934 | to_soc_camera_host(icd->parent)->nr != icd->iface); | ||
| 935 | |||
| 936 | mt9m111->lastpage = -1; | ||
| 937 | |||
| 938 | mt9m111->autoexposure = 1; | ||
| 939 | mt9m111->autowhitebalance = 1; | ||
| 940 | |||
| 941 | data = reg_read(CHIP_VERSION); | 793 | data = reg_read(CHIP_VERSION); |
| 942 | 794 | ||
| 943 | switch (data) { | 795 | switch (data) { |
| @@ -951,17 +803,16 @@ static int mt9m111_video_probe(struct soc_camera_device *icd, | |||
| 951 | dev_info(&client->dev, "Detected a MT9M112 chip ID %x\n", data); | 803 | dev_info(&client->dev, "Detected a MT9M112 chip ID %x\n", data); |
| 952 | break; | 804 | break; |
| 953 | default: | 805 | default: |
| 954 | ret = -ENODEV; | ||
| 955 | dev_err(&client->dev, | 806 | dev_err(&client->dev, |
| 956 | "No MT9M111/MT9M112/MT9M131 chip detected register read %x\n", | 807 | "No MT9M111/MT9M112/MT9M131 chip detected register read %x\n", |
| 957 | data); | 808 | data); |
| 958 | goto ei2c; | 809 | return -ENODEV; |
| 959 | } | 810 | } |
| 960 | 811 | ||
| 961 | ret = mt9m111_init(mt9m111); | 812 | ret = mt9m111_init(mt9m111); |
| 962 | 813 | if (ret) | |
| 963 | ei2c: | 814 | return ret; |
| 964 | return ret; | 815 | return v4l2_ctrl_handler_setup(&mt9m111->hdl); |
| 965 | } | 816 | } |
| 966 | 817 | ||
| 967 | static int mt9m111_s_power(struct v4l2_subdev *sd, int on) | 818 | static int mt9m111_s_power(struct v4l2_subdev *sd, int on) |
| @@ -998,9 +849,11 @@ out: | |||
| 998 | return ret; | 849 | return ret; |
| 999 | } | 850 | } |
| 1000 | 851 | ||
| 852 | static const struct v4l2_ctrl_ops mt9m111_ctrl_ops = { | ||
| 853 | .s_ctrl = mt9m111_s_ctrl, | ||
| 854 | }; | ||
| 855 | |||
| 1001 | static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = { | 856 | static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = { |
| 1002 | .g_ctrl = mt9m111_g_ctrl, | ||
| 1003 | .s_ctrl = mt9m111_s_ctrl, | ||
| 1004 | .g_chip_ident = mt9m111_g_chip_ident, | 857 | .g_chip_ident = mt9m111_g_chip_ident, |
| 1005 | .s_power = mt9m111_s_power, | 858 | .s_power = mt9m111_s_power, |
| 1006 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 859 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
| @@ -1019,6 +872,21 @@ static int mt9m111_enum_fmt(struct v4l2_subdev *sd, unsigned int index, | |||
| 1019 | return 0; | 872 | return 0; |
| 1020 | } | 873 | } |
| 1021 | 874 | ||
| 875 | static int mt9m111_g_mbus_config(struct v4l2_subdev *sd, | ||
| 876 | struct v4l2_mbus_config *cfg) | ||
| 877 | { | ||
| 878 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 879 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
| 880 | |||
| 881 | cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | | ||
| 882 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | | ||
| 883 | V4L2_MBUS_DATA_ACTIVE_HIGH; | ||
| 884 | cfg->type = V4L2_MBUS_PARALLEL; | ||
| 885 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | ||
| 886 | |||
| 887 | return 0; | ||
| 888 | } | ||
| 889 | |||
| 1022 | static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { | 890 | static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { |
| 1023 | .s_mbus_fmt = mt9m111_s_fmt, | 891 | .s_mbus_fmt = mt9m111_s_fmt, |
| 1024 | .g_mbus_fmt = mt9m111_g_fmt, | 892 | .g_mbus_fmt = mt9m111_g_fmt, |
| @@ -1027,6 +895,7 @@ static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { | |||
| 1027 | .g_crop = mt9m111_g_crop, | 895 | .g_crop = mt9m111_g_crop, |
| 1028 | .cropcap = mt9m111_cropcap, | 896 | .cropcap = mt9m111_cropcap, |
| 1029 | .enum_mbus_fmt = mt9m111_enum_fmt, | 897 | .enum_mbus_fmt = mt9m111_enum_fmt, |
| 898 | .g_mbus_config = mt9m111_g_mbus_config, | ||
| 1030 | }; | 899 | }; |
| 1031 | 900 | ||
| 1032 | static struct v4l2_subdev_ops mt9m111_subdev_ops = { | 901 | static struct v4l2_subdev_ops mt9m111_subdev_ops = { |
| @@ -1038,17 +907,10 @@ static int mt9m111_probe(struct i2c_client *client, | |||
| 1038 | const struct i2c_device_id *did) | 907 | const struct i2c_device_id *did) |
| 1039 | { | 908 | { |
| 1040 | struct mt9m111 *mt9m111; | 909 | struct mt9m111 *mt9m111; |
| 1041 | struct soc_camera_device *icd = client->dev.platform_data; | ||
| 1042 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 910 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
| 1043 | struct soc_camera_link *icl; | 911 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
| 1044 | int ret; | 912 | int ret; |
| 1045 | 913 | ||
| 1046 | if (!icd) { | ||
| 1047 | dev_err(&client->dev, "mt9m111: soc-camera data missing!\n"); | ||
| 1048 | return -EINVAL; | ||
| 1049 | } | ||
| 1050 | |||
| 1051 | icl = to_soc_camera_link(icd); | ||
| 1052 | if (!icl) { | 914 | if (!icl) { |
| 1053 | dev_err(&client->dev, "mt9m111: driver needs platform data\n"); | 915 | dev_err(&client->dev, "mt9m111: driver needs platform data\n"); |
| 1054 | return -EINVAL; | 916 | return -EINVAL; |
| @@ -1065,19 +927,37 @@ static int mt9m111_probe(struct i2c_client *client, | |||
| 1065 | return -ENOMEM; | 927 | return -ENOMEM; |
| 1066 | 928 | ||
| 1067 | v4l2_i2c_subdev_init(&mt9m111->subdev, client, &mt9m111_subdev_ops); | 929 | v4l2_i2c_subdev_init(&mt9m111->subdev, client, &mt9m111_subdev_ops); |
| 930 | v4l2_ctrl_handler_init(&mt9m111->hdl, 5); | ||
| 931 | v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops, | ||
| 932 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
| 933 | v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops, | ||
| 934 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
| 935 | v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops, | ||
| 936 | V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); | ||
| 937 | mt9m111->gain = v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops, | ||
| 938 | V4L2_CID_GAIN, 0, 63 * 2 * 2, 1, 32); | ||
| 939 | v4l2_ctrl_new_std_menu(&mt9m111->hdl, | ||
| 940 | &mt9m111_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, | ||
| 941 | V4L2_EXPOSURE_AUTO); | ||
| 942 | mt9m111->subdev.ctrl_handler = &mt9m111->hdl; | ||
| 943 | if (mt9m111->hdl.error) { | ||
| 944 | int err = mt9m111->hdl.error; | ||
| 1068 | 945 | ||
| 1069 | /* Second stage probe - when a capture adapter is there */ | 946 | kfree(mt9m111); |
| 1070 | icd->ops = &mt9m111_ops; | 947 | return err; |
| 948 | } | ||
| 1071 | 949 | ||
| 950 | /* Second stage probe - when a capture adapter is there */ | ||
| 1072 | mt9m111->rect.left = MT9M111_MIN_DARK_COLS; | 951 | mt9m111->rect.left = MT9M111_MIN_DARK_COLS; |
| 1073 | mt9m111->rect.top = MT9M111_MIN_DARK_ROWS; | 952 | mt9m111->rect.top = MT9M111_MIN_DARK_ROWS; |
| 1074 | mt9m111->rect.width = MT9M111_MAX_WIDTH; | 953 | mt9m111->rect.width = MT9M111_MAX_WIDTH; |
| 1075 | mt9m111->rect.height = MT9M111_MAX_HEIGHT; | 954 | mt9m111->rect.height = MT9M111_MAX_HEIGHT; |
| 1076 | mt9m111->fmt = &mt9m111_colour_fmts[0]; | 955 | mt9m111->fmt = &mt9m111_colour_fmts[0]; |
| 956 | mt9m111->lastpage = -1; | ||
| 1077 | 957 | ||
| 1078 | ret = mt9m111_video_probe(icd, client); | 958 | ret = mt9m111_video_probe(client); |
| 1079 | if (ret) { | 959 | if (ret) { |
| 1080 | icd->ops = NULL; | 960 | v4l2_ctrl_handler_free(&mt9m111->hdl); |
| 1081 | kfree(mt9m111); | 961 | kfree(mt9m111); |
| 1082 | } | 962 | } |
| 1083 | 963 | ||
| @@ -1087,9 +967,9 @@ static int mt9m111_probe(struct i2c_client *client, | |||
| 1087 | static int mt9m111_remove(struct i2c_client *client) | 967 | static int mt9m111_remove(struct i2c_client *client) |
| 1088 | { | 968 | { |
| 1089 | struct mt9m111 *mt9m111 = to_mt9m111(client); | 969 | struct mt9m111 *mt9m111 = to_mt9m111(client); |
| 1090 | struct soc_camera_device *icd = client->dev.platform_data; | ||
| 1091 | 970 | ||
| 1092 | icd->ops = NULL; | 971 | v4l2_device_unregister_subdev(&mt9m111->subdev); |
| 972 | v4l2_ctrl_handler_free(&mt9m111->hdl); | ||
| 1093 | kfree(mt9m111); | 973 | kfree(mt9m111); |
| 1094 | 974 | ||
| 1095 | return 0; | 975 | return 0; |
diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c index 30547cc3f89b..7ee84cc578b9 100644 --- a/drivers/media/video/mt9t031.c +++ b/drivers/media/video/mt9t031.c | |||
| @@ -13,11 +13,20 @@ | |||
| 13 | #include <linux/log2.h> | 13 | #include <linux/log2.h> |
| 14 | #include <linux/pm.h> | 14 | #include <linux/pm.h> |
| 15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
| 16 | #include <linux/v4l2-mediabus.h> | ||
| 16 | #include <linux/videodev2.h> | 17 | #include <linux/videodev2.h> |
| 17 | 18 | ||
| 18 | #include <media/soc_camera.h> | 19 | #include <media/soc_camera.h> |
| 19 | #include <media/v4l2-chip-ident.h> | 20 | #include <media/v4l2-chip-ident.h> |
| 20 | #include <media/v4l2-subdev.h> | 21 | #include <media/v4l2-subdev.h> |
| 22 | #include <media/v4l2-ctrls.h> | ||
| 23 | |||
| 24 | /* | ||
| 25 | * ATTENTION: this driver still cannot be used outside of the soc-camera | ||
| 26 | * framework because of its PM implementation, using the video_device node. | ||
| 27 | * If hardware becomes available for testing, alternative PM approaches shall | ||
| 28 | * be considered and tested. | ||
| 29 | */ | ||
| 21 | 30 | ||
| 22 | /* | 31 | /* |
| 23 | * mt9t031 i2c address 0x5d | 32 | * mt9t031 i2c address 0x5d |
| @@ -57,21 +66,20 @@ | |||
| 57 | #define MT9T031_COLUMN_SKIP 32 | 66 | #define MT9T031_COLUMN_SKIP 32 |
| 58 | #define MT9T031_ROW_SKIP 20 | 67 | #define MT9T031_ROW_SKIP 20 |
| 59 | 68 | ||
| 60 | #define MT9T031_BUS_PARAM (SOCAM_PCLK_SAMPLE_RISING | \ | ||
| 61 | SOCAM_PCLK_SAMPLE_FALLING | SOCAM_HSYNC_ACTIVE_HIGH | \ | ||
| 62 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH | \ | ||
| 63 | SOCAM_MASTER | SOCAM_DATAWIDTH_10) | ||
| 64 | |||
| 65 | struct mt9t031 { | 69 | struct mt9t031 { |
| 66 | struct v4l2_subdev subdev; | 70 | struct v4l2_subdev subdev; |
| 71 | struct v4l2_ctrl_handler hdl; | ||
| 72 | struct { | ||
| 73 | /* exposure/auto-exposure cluster */ | ||
| 74 | struct v4l2_ctrl *autoexposure; | ||
| 75 | struct v4l2_ctrl *exposure; | ||
| 76 | }; | ||
| 67 | struct v4l2_rect rect; /* Sensor window */ | 77 | struct v4l2_rect rect; /* Sensor window */ |
| 68 | int model; /* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */ | 78 | int model; /* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */ |
| 69 | u16 xskip; | 79 | u16 xskip; |
| 70 | u16 yskip; | 80 | u16 yskip; |
| 71 | unsigned int gain; | 81 | unsigned int total_h; |
| 72 | unsigned short y_skip_top; /* Lines to skip at the top */ | 82 | unsigned short y_skip_top; /* Lines to skip at the top */ |
| 73 | unsigned int exposure; | ||
| 74 | unsigned char autoexposure; | ||
| 75 | }; | 83 | }; |
| 76 | 84 | ||
| 77 | static struct mt9t031 *to_mt9t031(const struct i2c_client *client) | 85 | static struct mt9t031 *to_mt9t031(const struct i2c_client *client) |
| @@ -179,95 +187,6 @@ static int mt9t031_s_stream(struct v4l2_subdev *sd, int enable) | |||
| 179 | return 0; | 187 | return 0; |
| 180 | } | 188 | } |
| 181 | 189 | ||
| 182 | static int mt9t031_set_bus_param(struct soc_camera_device *icd, | ||
| 183 | unsigned long flags) | ||
| 184 | { | ||
| 185 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); | ||
| 186 | |||
| 187 | /* The caller should have queried our parameters, check anyway */ | ||
| 188 | if (flags & ~MT9T031_BUS_PARAM) | ||
| 189 | return -EINVAL; | ||
| 190 | |||
| 191 | if (flags & SOCAM_PCLK_SAMPLE_FALLING) | ||
| 192 | reg_clear(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); | ||
| 193 | else | ||
| 194 | reg_set(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); | ||
| 195 | |||
| 196 | return 0; | ||
| 197 | } | ||
| 198 | |||
| 199 | static unsigned long mt9t031_query_bus_param(struct soc_camera_device *icd) | ||
| 200 | { | ||
| 201 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
| 202 | |||
| 203 | return soc_camera_apply_sensor_flags(icl, MT9T031_BUS_PARAM); | ||
| 204 | } | ||
| 205 | |||
| 206 | enum { | ||
| 207 | MT9T031_CTRL_VFLIP, | ||
| 208 | MT9T031_CTRL_HFLIP, | ||
| 209 | MT9T031_CTRL_GAIN, | ||
| 210 | MT9T031_CTRL_EXPOSURE, | ||
| 211 | MT9T031_CTRL_EXPOSURE_AUTO, | ||
| 212 | }; | ||
| 213 | |||
| 214 | static const struct v4l2_queryctrl mt9t031_controls[] = { | ||
| 215 | [MT9T031_CTRL_VFLIP] = { | ||
| 216 | .id = V4L2_CID_VFLIP, | ||
| 217 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 218 | .name = "Flip Vertically", | ||
| 219 | .minimum = 0, | ||
| 220 | .maximum = 1, | ||
| 221 | .step = 1, | ||
| 222 | .default_value = 0, | ||
| 223 | }, | ||
| 224 | [MT9T031_CTRL_HFLIP] = { | ||
| 225 | .id = V4L2_CID_HFLIP, | ||
| 226 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 227 | .name = "Flip Horizontally", | ||
| 228 | .minimum = 0, | ||
| 229 | .maximum = 1, | ||
| 230 | .step = 1, | ||
| 231 | .default_value = 0, | ||
| 232 | }, | ||
| 233 | [MT9T031_CTRL_GAIN] = { | ||
| 234 | .id = V4L2_CID_GAIN, | ||
| 235 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 236 | .name = "Gain", | ||
| 237 | .minimum = 0, | ||
| 238 | .maximum = 127, | ||
| 239 | .step = 1, | ||
| 240 | .default_value = 64, | ||
| 241 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
| 242 | }, | ||
| 243 | [MT9T031_CTRL_EXPOSURE] = { | ||
| 244 | .id = V4L2_CID_EXPOSURE, | ||
| 245 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 246 | .name = "Exposure", | ||
| 247 | .minimum = 1, | ||
| 248 | .maximum = 255, | ||
| 249 | .step = 1, | ||
| 250 | .default_value = 255, | ||
| 251 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
| 252 | }, | ||
| 253 | [MT9T031_CTRL_EXPOSURE_AUTO] = { | ||
| 254 | .id = V4L2_CID_EXPOSURE_AUTO, | ||
| 255 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 256 | .name = "Automatic Exposure", | ||
| 257 | .minimum = 0, | ||
| 258 | .maximum = 1, | ||
| 259 | .step = 1, | ||
| 260 | .default_value = 1, | ||
| 261 | } | ||
| 262 | }; | ||
| 263 | |||
| 264 | static struct soc_camera_ops mt9t031_ops = { | ||
| 265 | .set_bus_param = mt9t031_set_bus_param, | ||
| 266 | .query_bus_param = mt9t031_query_bus_param, | ||
| 267 | .controls = mt9t031_controls, | ||
| 268 | .num_controls = ARRAY_SIZE(mt9t031_controls), | ||
| 269 | }; | ||
| 270 | |||
| 271 | /* target must be _even_ */ | 190 | /* target must be _even_ */ |
| 272 | static u16 mt9t031_skip(s32 *source, s32 target, s32 max) | 191 | static u16 mt9t031_skip(s32 *source, s32 target, s32 max) |
| 273 | { | 192 | { |
| @@ -353,7 +272,7 @@ static int mt9t031_set_params(struct i2c_client *client, | |||
| 353 | 272 | ||
| 354 | /* | 273 | /* |
| 355 | * The caller provides a supported format, as guaranteed by | 274 | * The caller provides a supported format, as guaranteed by |
| 356 | * icd->try_fmt_cap(), soc_camera_s_crop() and soc_camera_cropcap() | 275 | * .try_mbus_fmt(), soc_camera_s_crop() and soc_camera_cropcap() |
| 357 | */ | 276 | */ |
| 358 | if (ret >= 0) | 277 | if (ret >= 0) |
| 359 | ret = reg_write(client, MT9T031_COLUMN_START, rect->left); | 278 | ret = reg_write(client, MT9T031_COLUMN_START, rect->left); |
| @@ -364,17 +283,10 @@ static int mt9t031_set_params(struct i2c_client *client, | |||
| 364 | if (ret >= 0) | 283 | if (ret >= 0) |
| 365 | ret = reg_write(client, MT9T031_WINDOW_HEIGHT, | 284 | ret = reg_write(client, MT9T031_WINDOW_HEIGHT, |
| 366 | rect->height + mt9t031->y_skip_top - 1); | 285 | rect->height + mt9t031->y_skip_top - 1); |
| 367 | if (ret >= 0 && mt9t031->autoexposure) { | 286 | if (ret >= 0 && v4l2_ctrl_g_ctrl(mt9t031->autoexposure) == V4L2_EXPOSURE_AUTO) { |
| 368 | unsigned int total_h = rect->height + mt9t031->y_skip_top + vblank; | 287 | mt9t031->total_h = rect->height + mt9t031->y_skip_top + vblank; |
| 369 | ret = set_shutter(client, total_h); | 288 | |
| 370 | if (ret >= 0) { | 289 | ret = set_shutter(client, mt9t031->total_h); |
| 371 | const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; | ||
| 372 | const struct v4l2_queryctrl *qctrl = | ||
| 373 | &mt9t031_controls[MT9T031_CTRL_EXPOSURE]; | ||
| 374 | mt9t031->exposure = (shutter_max / 2 + (total_h - 1) * | ||
| 375 | (qctrl->maximum - qctrl->minimum)) / | ||
| 376 | shutter_max + qctrl->minimum; | ||
| 377 | } | ||
| 378 | } | 290 | } |
| 379 | 291 | ||
| 380 | /* Re-enable register update, commit all changes */ | 292 | /* Re-enable register update, commit all changes */ |
| @@ -543,71 +455,57 @@ static int mt9t031_s_register(struct v4l2_subdev *sd, | |||
| 543 | } | 455 | } |
| 544 | #endif | 456 | #endif |
| 545 | 457 | ||
| 546 | static int mt9t031_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 458 | static int mt9t031_g_volatile_ctrl(struct v4l2_ctrl *ctrl) |
| 547 | { | 459 | { |
| 548 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 460 | struct mt9t031 *mt9t031 = container_of(ctrl->handler, |
| 549 | struct mt9t031 *mt9t031 = to_mt9t031(client); | 461 | struct mt9t031, hdl); |
| 550 | int data; | 462 | const u32 shutter_max = MT9T031_MAX_HEIGHT + MT9T031_VERTICAL_BLANK; |
| 463 | s32 min, max; | ||
| 551 | 464 | ||
| 552 | switch (ctrl->id) { | 465 | switch (ctrl->id) { |
| 553 | case V4L2_CID_VFLIP: | ||
| 554 | data = reg_read(client, MT9T031_READ_MODE_2); | ||
| 555 | if (data < 0) | ||
| 556 | return -EIO; | ||
| 557 | ctrl->value = !!(data & 0x8000); | ||
| 558 | break; | ||
| 559 | case V4L2_CID_HFLIP: | ||
| 560 | data = reg_read(client, MT9T031_READ_MODE_2); | ||
| 561 | if (data < 0) | ||
| 562 | return -EIO; | ||
| 563 | ctrl->value = !!(data & 0x4000); | ||
| 564 | break; | ||
| 565 | case V4L2_CID_EXPOSURE_AUTO: | 466 | case V4L2_CID_EXPOSURE_AUTO: |
| 566 | ctrl->value = mt9t031->autoexposure; | 467 | min = mt9t031->exposure->minimum; |
| 567 | break; | 468 | max = mt9t031->exposure->maximum; |
| 568 | case V4L2_CID_GAIN: | 469 | mt9t031->exposure->val = |
| 569 | ctrl->value = mt9t031->gain; | 470 | (shutter_max / 2 + (mt9t031->total_h - 1) * (max - min)) |
| 570 | break; | 471 | / shutter_max + min; |
| 571 | case V4L2_CID_EXPOSURE: | ||
| 572 | ctrl->value = mt9t031->exposure; | ||
| 573 | break; | 472 | break; |
| 574 | } | 473 | } |
| 575 | return 0; | 474 | return 0; |
| 576 | } | 475 | } |
| 577 | 476 | ||
| 578 | static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 477 | static int mt9t031_s_ctrl(struct v4l2_ctrl *ctrl) |
| 579 | { | 478 | { |
| 479 | struct mt9t031 *mt9t031 = container_of(ctrl->handler, | ||
| 480 | struct mt9t031, hdl); | ||
| 481 | struct v4l2_subdev *sd = &mt9t031->subdev; | ||
| 580 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 482 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 581 | struct mt9t031 *mt9t031 = to_mt9t031(client); | 483 | struct v4l2_ctrl *exp = mt9t031->exposure; |
| 582 | const struct v4l2_queryctrl *qctrl; | ||
| 583 | int data; | 484 | int data; |
| 584 | 485 | ||
| 585 | switch (ctrl->id) { | 486 | switch (ctrl->id) { |
| 586 | case V4L2_CID_VFLIP: | 487 | case V4L2_CID_VFLIP: |
| 587 | if (ctrl->value) | 488 | if (ctrl->val) |
| 588 | data = reg_set(client, MT9T031_READ_MODE_2, 0x8000); | 489 | data = reg_set(client, MT9T031_READ_MODE_2, 0x8000); |
| 589 | else | 490 | else |
| 590 | data = reg_clear(client, MT9T031_READ_MODE_2, 0x8000); | 491 | data = reg_clear(client, MT9T031_READ_MODE_2, 0x8000); |
| 591 | if (data < 0) | 492 | if (data < 0) |
| 592 | return -EIO; | 493 | return -EIO; |
| 593 | break; | 494 | return 0; |
| 594 | case V4L2_CID_HFLIP: | 495 | case V4L2_CID_HFLIP: |
| 595 | if (ctrl->value) | 496 | if (ctrl->val) |
| 596 | data = reg_set(client, MT9T031_READ_MODE_2, 0x4000); | 497 | data = reg_set(client, MT9T031_READ_MODE_2, 0x4000); |
| 597 | else | 498 | else |
| 598 | data = reg_clear(client, MT9T031_READ_MODE_2, 0x4000); | 499 | data = reg_clear(client, MT9T031_READ_MODE_2, 0x4000); |
| 599 | if (data < 0) | 500 | if (data < 0) |
| 600 | return -EIO; | 501 | return -EIO; |
| 601 | break; | 502 | return 0; |
| 602 | case V4L2_CID_GAIN: | 503 | case V4L2_CID_GAIN: |
| 603 | qctrl = &mt9t031_controls[MT9T031_CTRL_GAIN]; | ||
| 604 | if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) | ||
| 605 | return -EINVAL; | ||
| 606 | /* See Datasheet Table 7, Gain settings. */ | 504 | /* See Datasheet Table 7, Gain settings. */ |
| 607 | if (ctrl->value <= qctrl->default_value) { | 505 | if (ctrl->val <= ctrl->default_value) { |
| 608 | /* Pack it into 0..1 step 0.125, register values 0..8 */ | 506 | /* Pack it into 0..1 step 0.125, register values 0..8 */ |
| 609 | unsigned long range = qctrl->default_value - qctrl->minimum; | 507 | unsigned long range = ctrl->default_value - ctrl->minimum; |
| 610 | data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range; | 508 | data = ((ctrl->val - ctrl->minimum) * 8 + range / 2) / range; |
| 611 | 509 | ||
| 612 | dev_dbg(&client->dev, "Setting gain %d\n", data); | 510 | dev_dbg(&client->dev, "Setting gain %d\n", data); |
| 613 | data = reg_write(client, MT9T031_GLOBAL_GAIN, data); | 511 | data = reg_write(client, MT9T031_GLOBAL_GAIN, data); |
| @@ -616,9 +514,9 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
| 616 | } else { | 514 | } else { |
| 617 | /* Pack it into 1.125..128 variable step, register values 9..0x7860 */ | 515 | /* Pack it into 1.125..128 variable step, register values 9..0x7860 */ |
| 618 | /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */ | 516 | /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */ |
| 619 | unsigned long range = qctrl->maximum - qctrl->default_value - 1; | 517 | unsigned long range = ctrl->maximum - ctrl->default_value - 1; |
| 620 | /* calculated gain: map 65..127 to 9..1024 step 0.125 */ | 518 | /* calculated gain: map 65..127 to 9..1024 step 0.125 */ |
| 621 | unsigned long gain = ((ctrl->value - qctrl->default_value - 1) * | 519 | unsigned long gain = ((ctrl->val - ctrl->default_value - 1) * |
| 622 | 1015 + range / 2) / range + 9; | 520 | 1015 + range / 2) / range + 9; |
| 623 | 521 | ||
| 624 | if (gain <= 32) /* calculated gain 9..32 -> 9..32 */ | 522 | if (gain <= 32) /* calculated gain 9..32 -> 9..32 */ |
| @@ -635,19 +533,13 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
| 635 | if (data < 0) | 533 | if (data < 0) |
| 636 | return -EIO; | 534 | return -EIO; |
| 637 | } | 535 | } |
| 536 | return 0; | ||
| 638 | 537 | ||
| 639 | /* Success */ | 538 | case V4L2_CID_EXPOSURE_AUTO: |
| 640 | mt9t031->gain = ctrl->value; | 539 | if (ctrl->val == V4L2_EXPOSURE_MANUAL) { |
| 641 | break; | 540 | unsigned int range = exp->maximum - exp->minimum; |
| 642 | case V4L2_CID_EXPOSURE: | 541 | unsigned int shutter = ((exp->val - exp->minimum) * 1048 + |
| 643 | qctrl = &mt9t031_controls[MT9T031_CTRL_EXPOSURE]; | 542 | range / 2) / range + 1; |
| 644 | /* mt9t031 has maximum == default */ | ||
| 645 | if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) | ||
| 646 | return -EINVAL; | ||
| 647 | else { | ||
| 648 | const unsigned long range = qctrl->maximum - qctrl->minimum; | ||
| 649 | const u32 shutter = ((ctrl->value - qctrl->minimum) * 1048 + | ||
| 650 | range / 2) / range + 1; | ||
| 651 | u32 old; | 543 | u32 old; |
| 652 | 544 | ||
| 653 | get_shutter(client, &old); | 545 | get_shutter(client, &old); |
| @@ -655,27 +547,15 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
| 655 | old, shutter); | 547 | old, shutter); |
| 656 | if (set_shutter(client, shutter) < 0) | 548 | if (set_shutter(client, shutter) < 0) |
| 657 | return -EIO; | 549 | return -EIO; |
| 658 | mt9t031->exposure = ctrl->value; | 550 | } else { |
| 659 | mt9t031->autoexposure = 0; | ||
| 660 | } | ||
| 661 | break; | ||
| 662 | case V4L2_CID_EXPOSURE_AUTO: | ||
| 663 | if (ctrl->value) { | ||
| 664 | const u16 vblank = MT9T031_VERTICAL_BLANK; | 551 | const u16 vblank = MT9T031_VERTICAL_BLANK; |
| 665 | const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; | 552 | mt9t031->total_h = mt9t031->rect.height + |
| 666 | unsigned int total_h = mt9t031->rect.height + | ||
| 667 | mt9t031->y_skip_top + vblank; | 553 | mt9t031->y_skip_top + vblank; |
| 668 | 554 | ||
| 669 | if (set_shutter(client, total_h) < 0) | 555 | if (set_shutter(client, mt9t031->total_h) < 0) |
| 670 | return -EIO; | 556 | return -EIO; |
| 671 | qctrl = &mt9t031_controls[MT9T031_CTRL_EXPOSURE]; | 557 | } |
| 672 | mt9t031->exposure = (shutter_max / 2 + (total_h - 1) * | 558 | return 0; |
| 673 | (qctrl->maximum - qctrl->minimum)) / | ||
| 674 | shutter_max + qctrl->minimum; | ||
| 675 | mt9t031->autoexposure = 1; | ||
| 676 | } else | ||
| 677 | mt9t031->autoexposure = 0; | ||
| 678 | break; | ||
| 679 | default: | 559 | default: |
| 680 | return -EINVAL; | 560 | return -EINVAL; |
| 681 | } | 561 | } |
| @@ -700,8 +580,7 @@ static int mt9t031_runtime_suspend(struct device *dev) | |||
| 700 | static int mt9t031_runtime_resume(struct device *dev) | 580 | static int mt9t031_runtime_resume(struct device *dev) |
| 701 | { | 581 | { |
| 702 | struct video_device *vdev = to_video_device(dev); | 582 | struct video_device *vdev = to_video_device(dev); |
| 703 | struct soc_camera_device *icd = dev_get_drvdata(vdev->parent); | 583 | struct v4l2_subdev *sd = soc_camera_vdev_to_subdev(vdev); |
| 704 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
| 705 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 584 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 706 | struct mt9t031 *mt9t031 = to_mt9t031(client); | 585 | struct mt9t031 *mt9t031 = to_mt9t031(client); |
| 707 | 586 | ||
| @@ -734,6 +613,19 @@ static struct device_type mt9t031_dev_type = { | |||
| 734 | .pm = &mt9t031_dev_pm_ops, | 613 | .pm = &mt9t031_dev_pm_ops, |
| 735 | }; | 614 | }; |
| 736 | 615 | ||
| 616 | static int mt9t031_s_power(struct v4l2_subdev *sd, int on) | ||
| 617 | { | ||
| 618 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 619 | struct video_device *vdev = soc_camera_i2c_to_vdev(client); | ||
| 620 | |||
| 621 | if (on) | ||
| 622 | vdev->dev.type = &mt9t031_dev_type; | ||
| 623 | else | ||
| 624 | vdev->dev.type = NULL; | ||
| 625 | |||
| 626 | return 0; | ||
| 627 | } | ||
| 628 | |||
| 737 | /* | 629 | /* |
| 738 | * Interface active, can use i2c. If it fails, it can indeed mean, that | 630 | * Interface active, can use i2c. If it fails, it can indeed mean, that |
| 739 | * this wasn't our capture interface, so, we wait for the right one | 631 | * this wasn't our capture interface, so, we wait for the right one |
| @@ -741,7 +633,6 @@ static struct device_type mt9t031_dev_type = { | |||
| 741 | static int mt9t031_video_probe(struct i2c_client *client) | 633 | static int mt9t031_video_probe(struct i2c_client *client) |
| 742 | { | 634 | { |
| 743 | struct mt9t031 *mt9t031 = to_mt9t031(client); | 635 | struct mt9t031 *mt9t031 = to_mt9t031(client); |
| 744 | struct video_device *vdev = soc_camera_i2c_to_vdev(client); | ||
| 745 | s32 data; | 636 | s32 data; |
| 746 | int ret; | 637 | int ret; |
| 747 | 638 | ||
| @@ -768,11 +659,7 @@ static int mt9t031_video_probe(struct i2c_client *client) | |||
| 768 | if (ret < 0) | 659 | if (ret < 0) |
| 769 | dev_err(&client->dev, "Failed to initialise the camera\n"); | 660 | dev_err(&client->dev, "Failed to initialise the camera\n"); |
| 770 | else | 661 | else |
| 771 | vdev->dev.type = &mt9t031_dev_type; | 662 | v4l2_ctrl_handler_setup(&mt9t031->hdl); |
| 772 | |||
| 773 | /* mt9t031_idle() has reset the chip to default. */ | ||
| 774 | mt9t031->exposure = 255; | ||
| 775 | mt9t031->gain = 64; | ||
| 776 | 663 | ||
| 777 | return ret; | 664 | return ret; |
| 778 | } | 665 | } |
| @@ -787,10 +674,14 @@ static int mt9t031_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) | |||
| 787 | return 0; | 674 | return 0; |
| 788 | } | 675 | } |
| 789 | 676 | ||
| 677 | static const struct v4l2_ctrl_ops mt9t031_ctrl_ops = { | ||
| 678 | .g_volatile_ctrl = mt9t031_g_volatile_ctrl, | ||
| 679 | .s_ctrl = mt9t031_s_ctrl, | ||
| 680 | }; | ||
| 681 | |||
| 790 | static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = { | 682 | static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = { |
| 791 | .g_ctrl = mt9t031_g_ctrl, | ||
| 792 | .s_ctrl = mt9t031_s_ctrl, | ||
| 793 | .g_chip_ident = mt9t031_g_chip_ident, | 683 | .g_chip_ident = mt9t031_g_chip_ident, |
| 684 | .s_power = mt9t031_s_power, | ||
| 794 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 685 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
| 795 | .g_register = mt9t031_g_register, | 686 | .g_register = mt9t031_g_register, |
| 796 | .s_register = mt9t031_s_register, | 687 | .s_register = mt9t031_s_register, |
| @@ -807,6 +698,34 @@ static int mt9t031_enum_fmt(struct v4l2_subdev *sd, unsigned int index, | |||
| 807 | return 0; | 698 | return 0; |
| 808 | } | 699 | } |
| 809 | 700 | ||
| 701 | static int mt9t031_g_mbus_config(struct v4l2_subdev *sd, | ||
| 702 | struct v4l2_mbus_config *cfg) | ||
| 703 | { | ||
| 704 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 705 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
| 706 | |||
| 707 | cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | | ||
| 708 | V4L2_MBUS_PCLK_SAMPLE_FALLING | V4L2_MBUS_HSYNC_ACTIVE_HIGH | | ||
| 709 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH; | ||
| 710 | cfg->type = V4L2_MBUS_PARALLEL; | ||
| 711 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | ||
| 712 | |||
| 713 | return 0; | ||
| 714 | } | ||
| 715 | |||
| 716 | static int mt9t031_s_mbus_config(struct v4l2_subdev *sd, | ||
| 717 | const struct v4l2_mbus_config *cfg) | ||
| 718 | { | ||
| 719 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 720 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
| 721 | |||
| 722 | if (soc_camera_apply_board_flags(icl, cfg) & | ||
| 723 | V4L2_MBUS_PCLK_SAMPLE_FALLING) | ||
| 724 | return reg_clear(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); | ||
| 725 | else | ||
| 726 | return reg_set(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); | ||
| 727 | } | ||
| 728 | |||
| 810 | static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = { | 729 | static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = { |
| 811 | .s_stream = mt9t031_s_stream, | 730 | .s_stream = mt9t031_s_stream, |
| 812 | .s_mbus_fmt = mt9t031_s_fmt, | 731 | .s_mbus_fmt = mt9t031_s_fmt, |
| @@ -816,6 +735,8 @@ static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = { | |||
| 816 | .g_crop = mt9t031_g_crop, | 735 | .g_crop = mt9t031_g_crop, |
| 817 | .cropcap = mt9t031_cropcap, | 736 | .cropcap = mt9t031_cropcap, |
| 818 | .enum_mbus_fmt = mt9t031_enum_fmt, | 737 | .enum_mbus_fmt = mt9t031_enum_fmt, |
| 738 | .g_mbus_config = mt9t031_g_mbus_config, | ||
| 739 | .s_mbus_config = mt9t031_s_mbus_config, | ||
| 819 | }; | 740 | }; |
| 820 | 741 | ||
| 821 | static struct v4l2_subdev_sensor_ops mt9t031_subdev_sensor_ops = { | 742 | static struct v4l2_subdev_sensor_ops mt9t031_subdev_sensor_ops = { |
| @@ -832,18 +753,13 @@ static int mt9t031_probe(struct i2c_client *client, | |||
| 832 | const struct i2c_device_id *did) | 753 | const struct i2c_device_id *did) |
| 833 | { | 754 | { |
| 834 | struct mt9t031 *mt9t031; | 755 | struct mt9t031 *mt9t031; |
| 835 | struct soc_camera_device *icd = client->dev.platform_data; | 756 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
| 836 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 757 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
| 837 | int ret; | 758 | int ret; |
| 838 | 759 | ||
| 839 | if (icd) { | 760 | if (!icl) { |
| 840 | struct soc_camera_link *icl = to_soc_camera_link(icd); | 761 | dev_err(&client->dev, "MT9T031 driver needs platform data\n"); |
| 841 | if (!icl) { | 762 | return -EINVAL; |
| 842 | dev_err(&client->dev, "MT9T031 driver needs platform data\n"); | ||
| 843 | return -EINVAL; | ||
| 844 | } | ||
| 845 | |||
| 846 | icd->ops = &mt9t031_ops; | ||
| 847 | } | 763 | } |
| 848 | 764 | ||
| 849 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { | 765 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { |
| @@ -857,6 +773,33 @@ static int mt9t031_probe(struct i2c_client *client, | |||
| 857 | return -ENOMEM; | 773 | return -ENOMEM; |
| 858 | 774 | ||
| 859 | v4l2_i2c_subdev_init(&mt9t031->subdev, client, &mt9t031_subdev_ops); | 775 | v4l2_i2c_subdev_init(&mt9t031->subdev, client, &mt9t031_subdev_ops); |
| 776 | v4l2_ctrl_handler_init(&mt9t031->hdl, 5); | ||
| 777 | v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops, | ||
| 778 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
| 779 | v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops, | ||
| 780 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
| 781 | v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops, | ||
| 782 | V4L2_CID_GAIN, 0, 127, 1, 64); | ||
| 783 | |||
| 784 | /* | ||
| 785 | * Simulated autoexposure. If enabled, we calculate shutter width | ||
| 786 | * ourselves in the driver based on vertical blanking and frame width | ||
| 787 | */ | ||
| 788 | mt9t031->autoexposure = v4l2_ctrl_new_std_menu(&mt9t031->hdl, | ||
| 789 | &mt9t031_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, | ||
| 790 | V4L2_EXPOSURE_AUTO); | ||
| 791 | mt9t031->exposure = v4l2_ctrl_new_std(&mt9t031->hdl, &mt9t031_ctrl_ops, | ||
| 792 | V4L2_CID_EXPOSURE, 1, 255, 1, 255); | ||
| 793 | |||
| 794 | mt9t031->subdev.ctrl_handler = &mt9t031->hdl; | ||
| 795 | if (mt9t031->hdl.error) { | ||
| 796 | int err = mt9t031->hdl.error; | ||
| 797 | |||
| 798 | kfree(mt9t031); | ||
| 799 | return err; | ||
| 800 | } | ||
| 801 | v4l2_ctrl_auto_cluster(2, &mt9t031->autoexposure, | ||
| 802 | V4L2_EXPOSURE_MANUAL, true); | ||
| 860 | 803 | ||
| 861 | mt9t031->y_skip_top = 0; | 804 | mt9t031->y_skip_top = 0; |
| 862 | mt9t031->rect.left = MT9T031_COLUMN_SKIP; | 805 | mt9t031->rect.left = MT9T031_COLUMN_SKIP; |
| @@ -864,12 +807,6 @@ static int mt9t031_probe(struct i2c_client *client, | |||
| 864 | mt9t031->rect.width = MT9T031_MAX_WIDTH; | 807 | mt9t031->rect.width = MT9T031_MAX_WIDTH; |
| 865 | mt9t031->rect.height = MT9T031_MAX_HEIGHT; | 808 | mt9t031->rect.height = MT9T031_MAX_HEIGHT; |
| 866 | 809 | ||
| 867 | /* | ||
| 868 | * Simulated autoexposure. If enabled, we calculate shutter width | ||
| 869 | * ourselves in the driver based on vertical blanking and frame width | ||
| 870 | */ | ||
| 871 | mt9t031->autoexposure = 1; | ||
| 872 | |||
| 873 | mt9t031->xskip = 1; | 810 | mt9t031->xskip = 1; |
| 874 | mt9t031->yskip = 1; | 811 | mt9t031->yskip = 1; |
| 875 | 812 | ||
| @@ -880,8 +817,7 @@ static int mt9t031_probe(struct i2c_client *client, | |||
| 880 | mt9t031_disable(client); | 817 | mt9t031_disable(client); |
| 881 | 818 | ||
| 882 | if (ret) { | 819 | if (ret) { |
| 883 | if (icd) | 820 | v4l2_ctrl_handler_free(&mt9t031->hdl); |
| 884 | icd->ops = NULL; | ||
| 885 | kfree(mt9t031); | 821 | kfree(mt9t031); |
| 886 | } | 822 | } |
| 887 | 823 | ||
| @@ -891,10 +827,9 @@ static int mt9t031_probe(struct i2c_client *client, | |||
| 891 | static int mt9t031_remove(struct i2c_client *client) | 827 | static int mt9t031_remove(struct i2c_client *client) |
| 892 | { | 828 | { |
| 893 | struct mt9t031 *mt9t031 = to_mt9t031(client); | 829 | struct mt9t031 *mt9t031 = to_mt9t031(client); |
| 894 | struct soc_camera_device *icd = client->dev.platform_data; | ||
| 895 | 830 | ||
| 896 | if (icd) | 831 | v4l2_device_unregister_subdev(&mt9t031->subdev); |
| 897 | icd->ops = NULL; | 832 | v4l2_ctrl_handler_free(&mt9t031->hdl); |
| 898 | kfree(mt9t031); | 833 | kfree(mt9t031); |
| 899 | 834 | ||
| 900 | return 0; | 835 | return 0; |
diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c index d2e0a50063a2..32114a3c0ca7 100644 --- a/drivers/media/video/mt9t112.c +++ b/drivers/media/video/mt9t112.c | |||
| @@ -22,11 +22,11 @@ | |||
| 22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
| 23 | #include <linux/module.h> | 23 | #include <linux/module.h> |
| 24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
| 25 | #include <linux/v4l2-mediabus.h> | ||
| 25 | #include <linux/videodev2.h> | 26 | #include <linux/videodev2.h> |
| 26 | 27 | ||
| 27 | #include <media/mt9t112.h> | 28 | #include <media/mt9t112.h> |
| 28 | #include <media/soc_camera.h> | 29 | #include <media/soc_camera.h> |
| 29 | #include <media/soc_mediabus.h> | ||
| 30 | #include <media/v4l2-chip-ident.h> | 30 | #include <media/v4l2-chip-ident.h> |
| 31 | #include <media/v4l2-common.h> | 31 | #include <media/v4l2-common.h> |
| 32 | 32 | ||
| @@ -34,11 +34,7 @@ | |||
| 34 | /* #define EXT_CLOCK 24000000 */ | 34 | /* #define EXT_CLOCK 24000000 */ |
| 35 | 35 | ||
| 36 | /************************************************************************ | 36 | /************************************************************************ |
| 37 | |||
| 38 | |||
| 39 | macro | 37 | macro |
| 40 | |||
| 41 | |||
| 42 | ************************************************************************/ | 38 | ************************************************************************/ |
| 43 | /* | 39 | /* |
| 44 | * frame size | 40 | * frame size |
| @@ -80,17 +76,8 @@ | |||
| 80 | #define VAR8(id, offset) _VAR(id, offset, 0x8000) | 76 | #define VAR8(id, offset) _VAR(id, offset, 0x8000) |
| 81 | 77 | ||
| 82 | /************************************************************************ | 78 | /************************************************************************ |
| 83 | |||
| 84 | |||
| 85 | struct | 79 | struct |
| 86 | |||
| 87 | |||
| 88 | ************************************************************************/ | 80 | ************************************************************************/ |
| 89 | struct mt9t112_frame_size { | ||
| 90 | u16 width; | ||
| 91 | u16 height; | ||
| 92 | }; | ||
| 93 | |||
| 94 | struct mt9t112_format { | 81 | struct mt9t112_format { |
| 95 | enum v4l2_mbus_pixelcode code; | 82 | enum v4l2_mbus_pixelcode code; |
| 96 | enum v4l2_colorspace colorspace; | 83 | enum v4l2_colorspace colorspace; |
| @@ -102,21 +89,17 @@ struct mt9t112_priv { | |||
| 102 | struct v4l2_subdev subdev; | 89 | struct v4l2_subdev subdev; |
| 103 | struct mt9t112_camera_info *info; | 90 | struct mt9t112_camera_info *info; |
| 104 | struct i2c_client *client; | 91 | struct i2c_client *client; |
| 105 | struct soc_camera_device icd; | 92 | struct v4l2_rect frame; |
| 106 | struct mt9t112_frame_size frame; | ||
| 107 | const struct mt9t112_format *format; | 93 | const struct mt9t112_format *format; |
| 108 | int model; | 94 | int model; |
| 109 | u32 flags; | 95 | u32 flags; |
| 110 | /* for flags */ | 96 | /* for flags */ |
| 111 | #define INIT_DONE (1<<0) | 97 | #define INIT_DONE (1 << 0) |
| 98 | #define PCLK_RISING (1 << 1) | ||
| 112 | }; | 99 | }; |
| 113 | 100 | ||
| 114 | /************************************************************************ | 101 | /************************************************************************ |
| 115 | |||
| 116 | |||
| 117 | supported format | 102 | supported format |
| 118 | |||
| 119 | |||
| 120 | ************************************************************************/ | 103 | ************************************************************************/ |
| 121 | 104 | ||
| 122 | static const struct mt9t112_format mt9t112_cfmts[] = { | 105 | static const struct mt9t112_format mt9t112_cfmts[] = { |
| @@ -154,11 +137,7 @@ static const struct mt9t112_format mt9t112_cfmts[] = { | |||
| 154 | }; | 137 | }; |
| 155 | 138 | ||
| 156 | /************************************************************************ | 139 | /************************************************************************ |
| 157 | |||
| 158 | |||
| 159 | general function | 140 | general function |
| 160 | |||
| 161 | |||
| 162 | ************************************************************************/ | 141 | ************************************************************************/ |
| 163 | static struct mt9t112_priv *to_mt9t112(const struct i2c_client *client) | 142 | static struct mt9t112_priv *to_mt9t112(const struct i2c_client *client) |
| 164 | { | 143 | { |
| @@ -326,50 +305,47 @@ static int mt9t112_clock_info(const struct i2c_client *client, u32 ext) | |||
| 326 | n = (n >> 8) & 0x003f; | 305 | n = (n >> 8) & 0x003f; |
| 327 | 306 | ||
| 328 | enable = ((6000 > ext) || (54000 < ext)) ? "X" : ""; | 307 | enable = ((6000 > ext) || (54000 < ext)) ? "X" : ""; |
| 329 | dev_info(&client->dev, "EXTCLK : %10u K %s\n", ext, enable); | 308 | dev_dbg(&client->dev, "EXTCLK : %10u K %s\n", ext, enable); |
| 330 | 309 | ||
| 331 | vco = 2 * m * ext / (n+1); | 310 | vco = 2 * m * ext / (n+1); |
| 332 | enable = ((384000 > vco) || (768000 < vco)) ? "X" : ""; | 311 | enable = ((384000 > vco) || (768000 < vco)) ? "X" : ""; |
| 333 | dev_info(&client->dev, "VCO : %10u K %s\n", vco, enable); | 312 | dev_dbg(&client->dev, "VCO : %10u K %s\n", vco, enable); |
| 334 | 313 | ||
| 335 | clk = vco / (p1+1) / (p2+1); | 314 | clk = vco / (p1+1) / (p2+1); |
| 336 | enable = (96000 < clk) ? "X" : ""; | 315 | enable = (96000 < clk) ? "X" : ""; |
| 337 | dev_info(&client->dev, "PIXCLK : %10u K %s\n", clk, enable); | 316 | dev_dbg(&client->dev, "PIXCLK : %10u K %s\n", clk, enable); |
| 338 | 317 | ||
| 339 | clk = vco / (p3+1); | 318 | clk = vco / (p3+1); |
| 340 | enable = (768000 < clk) ? "X" : ""; | 319 | enable = (768000 < clk) ? "X" : ""; |
| 341 | dev_info(&client->dev, "MIPICLK : %10u K %s\n", clk, enable); | 320 | dev_dbg(&client->dev, "MIPICLK : %10u K %s\n", clk, enable); |
| 342 | 321 | ||
| 343 | clk = vco / (p6+1); | 322 | clk = vco / (p6+1); |
| 344 | enable = (96000 < clk) ? "X" : ""; | 323 | enable = (96000 < clk) ? "X" : ""; |
| 345 | dev_info(&client->dev, "MCU CLK : %10u K %s\n", clk, enable); | 324 | dev_dbg(&client->dev, "MCU CLK : %10u K %s\n", clk, enable); |
| 346 | 325 | ||
| 347 | clk = vco / (p5+1); | 326 | clk = vco / (p5+1); |
| 348 | enable = (54000 < clk) ? "X" : ""; | 327 | enable = (54000 < clk) ? "X" : ""; |
| 349 | dev_info(&client->dev, "SOC CLK : %10u K %s\n", clk, enable); | 328 | dev_dbg(&client->dev, "SOC CLK : %10u K %s\n", clk, enable); |
| 350 | 329 | ||
| 351 | clk = vco / (p4+1); | 330 | clk = vco / (p4+1); |
| 352 | enable = (70000 < clk) ? "X" : ""; | 331 | enable = (70000 < clk) ? "X" : ""; |
| 353 | dev_info(&client->dev, "Sensor CLK : %10u K %s\n", clk, enable); | 332 | dev_dbg(&client->dev, "Sensor CLK : %10u K %s\n", clk, enable); |
| 354 | 333 | ||
| 355 | clk = vco / (p7+1); | 334 | clk = vco / (p7+1); |
| 356 | dev_info(&client->dev, "External sensor : %10u K\n", clk); | 335 | dev_dbg(&client->dev, "External sensor : %10u K\n", clk); |
| 357 | 336 | ||
| 358 | clk = ext / (n+1); | 337 | clk = ext / (n+1); |
| 359 | enable = ((2000 > clk) || (24000 < clk)) ? "X" : ""; | 338 | enable = ((2000 > clk) || (24000 < clk)) ? "X" : ""; |
| 360 | dev_info(&client->dev, "PFD : %10u K %s\n", clk, enable); | 339 | dev_dbg(&client->dev, "PFD : %10u K %s\n", clk, enable); |
| 361 | 340 | ||
| 362 | return 0; | 341 | return 0; |
| 363 | } | 342 | } |
| 364 | #endif | 343 | #endif |
| 365 | 344 | ||
| 366 | static void mt9t112_frame_check(u32 *width, u32 *height) | 345 | static void mt9t112_frame_check(u32 *width, u32 *height, u32 *left, u32 *top) |
| 367 | { | 346 | { |
| 368 | if (*width > MAX_WIDTH) | 347 | soc_camera_limit_side(left, width, 0, 0, MAX_WIDTH); |
| 369 | *width = MAX_WIDTH; | 348 | soc_camera_limit_side(top, height, 0, 0, MAX_HEIGHT); |
| 370 | |||
| 371 | if (*height > MAX_HEIGHT) | ||
| 372 | *height = MAX_HEIGHT; | ||
| 373 | } | 349 | } |
| 374 | 350 | ||
| 375 | static int mt9t112_set_a_frame_size(const struct i2c_client *client, | 351 | static int mt9t112_set_a_frame_size(const struct i2c_client *client, |
| @@ -758,48 +734,7 @@ static int mt9t112_init_camera(const struct i2c_client *client) | |||
| 758 | } | 734 | } |
| 759 | 735 | ||
| 760 | /************************************************************************ | 736 | /************************************************************************ |
| 761 | |||
| 762 | |||
| 763 | soc_camera_ops | ||
| 764 | |||
| 765 | |||
| 766 | ************************************************************************/ | ||
| 767 | static int mt9t112_set_bus_param(struct soc_camera_device *icd, | ||
| 768 | unsigned long flags) | ||
| 769 | { | ||
| 770 | return 0; | ||
| 771 | } | ||
| 772 | |||
| 773 | static unsigned long mt9t112_query_bus_param(struct soc_camera_device *icd) | ||
| 774 | { | ||
| 775 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); | ||
| 776 | struct mt9t112_priv *priv = to_mt9t112(client); | ||
| 777 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
| 778 | unsigned long flags = SOCAM_MASTER | SOCAM_VSYNC_ACTIVE_HIGH | | ||
| 779 | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH; | ||
| 780 | |||
| 781 | flags |= (priv->info->flags & MT9T112_FLAG_PCLK_RISING_EDGE) ? | ||
| 782 | SOCAM_PCLK_SAMPLE_RISING : SOCAM_PCLK_SAMPLE_FALLING; | ||
| 783 | |||
| 784 | if (priv->info->flags & MT9T112_FLAG_DATAWIDTH_8) | ||
| 785 | flags |= SOCAM_DATAWIDTH_8; | ||
| 786 | else | ||
| 787 | flags |= SOCAM_DATAWIDTH_10; | ||
| 788 | |||
| 789 | return soc_camera_apply_sensor_flags(icl, flags); | ||
| 790 | } | ||
| 791 | |||
| 792 | static struct soc_camera_ops mt9t112_ops = { | ||
| 793 | .set_bus_param = mt9t112_set_bus_param, | ||
| 794 | .query_bus_param = mt9t112_query_bus_param, | ||
| 795 | }; | ||
| 796 | |||
| 797 | /************************************************************************ | ||
| 798 | |||
| 799 | |||
| 800 | v4l2_subdev_core_ops | 737 | v4l2_subdev_core_ops |
| 801 | |||
| 802 | |||
| 803 | ************************************************************************/ | 738 | ************************************************************************/ |
| 804 | static int mt9t112_g_chip_ident(struct v4l2_subdev *sd, | 739 | static int mt9t112_g_chip_ident(struct v4l2_subdev *sd, |
| 805 | struct v4l2_dbg_chip_ident *id) | 740 | struct v4l2_dbg_chip_ident *id) |
| @@ -850,11 +785,7 @@ static struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = { | |||
| 850 | 785 | ||
| 851 | 786 | ||
| 852 | /************************************************************************ | 787 | /************************************************************************ |
| 853 | |||
| 854 | |||
| 855 | v4l2_subdev_video_ops | 788 | v4l2_subdev_video_ops |
| 856 | |||
| 857 | |||
| 858 | ************************************************************************/ | 789 | ************************************************************************/ |
| 859 | static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable) | 790 | static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable) |
| 860 | { | 791 | { |
| @@ -877,8 +808,7 @@ static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable) | |||
| 877 | } | 808 | } |
| 878 | 809 | ||
| 879 | if (!(priv->flags & INIT_DONE)) { | 810 | if (!(priv->flags & INIT_DONE)) { |
| 880 | u16 param = (MT9T112_FLAG_PCLK_RISING_EDGE & | 811 | u16 param = PCLK_RISING & priv->flags ? 0x0001 : 0x0000; |
| 881 | priv->info->flags) ? 0x0001 : 0x0000; | ||
| 882 | 812 | ||
| 883 | ECHECKER(ret, mt9t112_init_camera(client)); | 813 | ECHECKER(ret, mt9t112_init_camera(client)); |
| 884 | 814 | ||
| @@ -910,19 +840,12 @@ static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable) | |||
| 910 | return ret; | 840 | return ret; |
| 911 | } | 841 | } |
| 912 | 842 | ||
| 913 | static int mt9t112_set_params(struct i2c_client *client, u32 width, u32 height, | 843 | static int mt9t112_set_params(struct mt9t112_priv *priv, |
| 844 | const struct v4l2_rect *rect, | ||
| 914 | enum v4l2_mbus_pixelcode code) | 845 | enum v4l2_mbus_pixelcode code) |
| 915 | { | 846 | { |
| 916 | struct mt9t112_priv *priv = to_mt9t112(client); | ||
| 917 | int i; | 847 | int i; |
| 918 | 848 | ||
| 919 | priv->format = NULL; | ||
| 920 | |||
| 921 | /* | ||
| 922 | * frame size check | ||
| 923 | */ | ||
| 924 | mt9t112_frame_check(&width, &height); | ||
| 925 | |||
| 926 | /* | 849 | /* |
| 927 | * get color format | 850 | * get color format |
| 928 | */ | 851 | */ |
| @@ -933,8 +856,13 @@ static int mt9t112_set_params(struct i2c_client *client, u32 width, u32 height, | |||
| 933 | if (i == ARRAY_SIZE(mt9t112_cfmts)) | 856 | if (i == ARRAY_SIZE(mt9t112_cfmts)) |
| 934 | return -EINVAL; | 857 | return -EINVAL; |
| 935 | 858 | ||
| 936 | priv->frame.width = (u16)width; | 859 | priv->frame = *rect; |
| 937 | priv->frame.height = (u16)height; | 860 | |
| 861 | /* | ||
| 862 | * frame size check | ||
| 863 | */ | ||
| 864 | mt9t112_frame_check(&priv->frame.width, &priv->frame.height, | ||
| 865 | &priv->frame.left, &priv->frame.top); | ||
| 938 | 866 | ||
| 939 | priv->format = mt9t112_cfmts + i; | 867 | priv->format = mt9t112_cfmts + i; |
| 940 | 868 | ||
| @@ -945,9 +873,12 @@ static int mt9t112_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | |||
| 945 | { | 873 | { |
| 946 | a->bounds.left = 0; | 874 | a->bounds.left = 0; |
| 947 | a->bounds.top = 0; | 875 | a->bounds.top = 0; |
| 948 | a->bounds.width = VGA_WIDTH; | 876 | a->bounds.width = MAX_WIDTH; |
| 949 | a->bounds.height = VGA_HEIGHT; | 877 | a->bounds.height = MAX_HEIGHT; |
| 950 | a->defrect = a->bounds; | 878 | a->defrect.left = 0; |
| 879 | a->defrect.top = 0; | ||
| 880 | a->defrect.width = VGA_WIDTH; | ||
| 881 | a->defrect.height = VGA_HEIGHT; | ||
| 951 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 882 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 952 | a->pixelaspect.numerator = 1; | 883 | a->pixelaspect.numerator = 1; |
| 953 | a->pixelaspect.denominator = 1; | 884 | a->pixelaspect.denominator = 1; |
| @@ -957,11 +888,11 @@ static int mt9t112_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | |||
| 957 | 888 | ||
| 958 | static int mt9t112_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 889 | static int mt9t112_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) |
| 959 | { | 890 | { |
| 960 | a->c.left = 0; | 891 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 961 | a->c.top = 0; | 892 | struct mt9t112_priv *priv = to_mt9t112(client); |
| 962 | a->c.width = VGA_WIDTH; | 893 | |
| 963 | a->c.height = VGA_HEIGHT; | 894 | a->c = priv->frame; |
| 964 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 895 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 965 | 896 | ||
| 966 | return 0; | 897 | return 0; |
| 967 | } | 898 | } |
| @@ -969,10 +900,10 @@ static int mt9t112_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
| 969 | static int mt9t112_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 900 | static int mt9t112_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) |
| 970 | { | 901 | { |
| 971 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 902 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 903 | struct mt9t112_priv *priv = to_mt9t112(client); | ||
| 972 | struct v4l2_rect *rect = &a->c; | 904 | struct v4l2_rect *rect = &a->c; |
| 973 | 905 | ||
| 974 | return mt9t112_set_params(client, rect->width, rect->height, | 906 | return mt9t112_set_params(priv, rect, priv->format->code); |
| 975 | V4L2_MBUS_FMT_UYVY8_2X8); | ||
| 976 | } | 907 | } |
| 977 | 908 | ||
| 978 | static int mt9t112_g_fmt(struct v4l2_subdev *sd, | 909 | static int mt9t112_g_fmt(struct v4l2_subdev *sd, |
| @@ -981,16 +912,9 @@ static int mt9t112_g_fmt(struct v4l2_subdev *sd, | |||
| 981 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 912 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 982 | struct mt9t112_priv *priv = to_mt9t112(client); | 913 | struct mt9t112_priv *priv = to_mt9t112(client); |
| 983 | 914 | ||
| 984 | if (!priv->format) { | ||
| 985 | int ret = mt9t112_set_params(client, VGA_WIDTH, VGA_HEIGHT, | ||
| 986 | V4L2_MBUS_FMT_UYVY8_2X8); | ||
| 987 | if (ret < 0) | ||
| 988 | return ret; | ||
| 989 | } | ||
| 990 | |||
| 991 | mf->width = priv->frame.width; | 915 | mf->width = priv->frame.width; |
| 992 | mf->height = priv->frame.height; | 916 | mf->height = priv->frame.height; |
| 993 | /* TODO: set colorspace */ | 917 | mf->colorspace = priv->format->colorspace; |
| 994 | mf->code = priv->format->code; | 918 | mf->code = priv->format->code; |
| 995 | mf->field = V4L2_FIELD_NONE; | 919 | mf->field = V4L2_FIELD_NONE; |
| 996 | 920 | ||
| @@ -1001,17 +925,42 @@ static int mt9t112_s_fmt(struct v4l2_subdev *sd, | |||
| 1001 | struct v4l2_mbus_framefmt *mf) | 925 | struct v4l2_mbus_framefmt *mf) |
| 1002 | { | 926 | { |
| 1003 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 927 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 928 | struct mt9t112_priv *priv = to_mt9t112(client); | ||
| 929 | struct v4l2_rect rect = { | ||
| 930 | .width = mf->width, | ||
| 931 | .height = mf->height, | ||
| 932 | .left = priv->frame.left, | ||
| 933 | .top = priv->frame.top, | ||
| 934 | }; | ||
| 935 | int ret; | ||
| 936 | |||
| 937 | ret = mt9t112_set_params(priv, &rect, mf->code); | ||
| 938 | |||
| 939 | if (!ret) | ||
| 940 | mf->colorspace = priv->format->colorspace; | ||
| 1004 | 941 | ||
| 1005 | /* TODO: set colorspace */ | 942 | return ret; |
| 1006 | return mt9t112_set_params(client, mf->width, mf->height, mf->code); | ||
| 1007 | } | 943 | } |
| 1008 | 944 | ||
| 1009 | static int mt9t112_try_fmt(struct v4l2_subdev *sd, | 945 | static int mt9t112_try_fmt(struct v4l2_subdev *sd, |
| 1010 | struct v4l2_mbus_framefmt *mf) | 946 | struct v4l2_mbus_framefmt *mf) |
| 1011 | { | 947 | { |
| 1012 | mt9t112_frame_check(&mf->width, &mf->height); | 948 | unsigned int top, left; |
| 949 | int i; | ||
| 950 | |||
| 951 | for (i = 0; i < ARRAY_SIZE(mt9t112_cfmts); i++) | ||
| 952 | if (mt9t112_cfmts[i].code == mf->code) | ||
| 953 | break; | ||
| 954 | |||
| 955 | if (i == ARRAY_SIZE(mt9t112_cfmts)) { | ||
| 956 | mf->code = V4L2_MBUS_FMT_UYVY8_2X8; | ||
| 957 | mf->colorspace = V4L2_COLORSPACE_JPEG; | ||
| 958 | } else { | ||
| 959 | mf->colorspace = mt9t112_cfmts[i].colorspace; | ||
| 960 | } | ||
| 961 | |||
| 962 | mt9t112_frame_check(&mf->width, &mf->height, &left, &top); | ||
| 1013 | 963 | ||
| 1014 | /* TODO: set colorspace */ | ||
| 1015 | mf->field = V4L2_FIELD_NONE; | 964 | mf->field = V4L2_FIELD_NONE; |
| 1016 | 965 | ||
| 1017 | return 0; | 966 | return 0; |
| @@ -1024,6 +973,35 @@ static int mt9t112_enum_fmt(struct v4l2_subdev *sd, unsigned int index, | |||
| 1024 | return -EINVAL; | 973 | return -EINVAL; |
| 1025 | 974 | ||
| 1026 | *code = mt9t112_cfmts[index].code; | 975 | *code = mt9t112_cfmts[index].code; |
| 976 | |||
| 977 | return 0; | ||
| 978 | } | ||
| 979 | |||
| 980 | static int mt9t112_g_mbus_config(struct v4l2_subdev *sd, | ||
| 981 | struct v4l2_mbus_config *cfg) | ||
| 982 | { | ||
| 983 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 984 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
| 985 | |||
| 986 | cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH | | ||
| 987 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH | | ||
| 988 | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING; | ||
| 989 | cfg->type = V4L2_MBUS_PARALLEL; | ||
| 990 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | ||
| 991 | |||
| 992 | return 0; | ||
| 993 | } | ||
| 994 | |||
| 995 | static int mt9t112_s_mbus_config(struct v4l2_subdev *sd, | ||
| 996 | const struct v4l2_mbus_config *cfg) | ||
| 997 | { | ||
| 998 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 999 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
| 1000 | struct mt9t112_priv *priv = to_mt9t112(client); | ||
| 1001 | |||
| 1002 | if (soc_camera_apply_board_flags(icl, cfg) & V4L2_MBUS_PCLK_SAMPLE_RISING) | ||
| 1003 | priv->flags |= PCLK_RISING; | ||
| 1004 | |||
| 1027 | return 0; | 1005 | return 0; |
| 1028 | } | 1006 | } |
| 1029 | 1007 | ||
| @@ -1036,31 +1014,24 @@ static struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = { | |||
| 1036 | .g_crop = mt9t112_g_crop, | 1014 | .g_crop = mt9t112_g_crop, |
| 1037 | .s_crop = mt9t112_s_crop, | 1015 | .s_crop = mt9t112_s_crop, |
| 1038 | .enum_mbus_fmt = mt9t112_enum_fmt, | 1016 | .enum_mbus_fmt = mt9t112_enum_fmt, |
| 1017 | .g_mbus_config = mt9t112_g_mbus_config, | ||
| 1018 | .s_mbus_config = mt9t112_s_mbus_config, | ||
| 1039 | }; | 1019 | }; |
| 1040 | 1020 | ||
| 1041 | /************************************************************************ | 1021 | /************************************************************************ |
| 1042 | |||
| 1043 | |||
| 1044 | i2c driver | 1022 | i2c driver |
| 1045 | |||
| 1046 | |||
| 1047 | ************************************************************************/ | 1023 | ************************************************************************/ |
| 1048 | static struct v4l2_subdev_ops mt9t112_subdev_ops = { | 1024 | static struct v4l2_subdev_ops mt9t112_subdev_ops = { |
| 1049 | .core = &mt9t112_subdev_core_ops, | 1025 | .core = &mt9t112_subdev_core_ops, |
| 1050 | .video = &mt9t112_subdev_video_ops, | 1026 | .video = &mt9t112_subdev_video_ops, |
| 1051 | }; | 1027 | }; |
| 1052 | 1028 | ||
| 1053 | static int mt9t112_camera_probe(struct soc_camera_device *icd, | 1029 | static int mt9t112_camera_probe(struct i2c_client *client) |
| 1054 | struct i2c_client *client) | ||
| 1055 | { | 1030 | { |
| 1056 | struct mt9t112_priv *priv = to_mt9t112(client); | 1031 | struct mt9t112_priv *priv = to_mt9t112(client); |
| 1057 | const char *devname; | 1032 | const char *devname; |
| 1058 | int chipid; | 1033 | int chipid; |
| 1059 | 1034 | ||
| 1060 | /* We must have a parent by now. And it cannot be a wrong one. */ | ||
| 1061 | BUG_ON(!icd->parent || | ||
| 1062 | to_soc_camera_host(icd->parent)->nr != icd->iface); | ||
| 1063 | |||
| 1064 | /* | 1035 | /* |
| 1065 | * check and show chip ID | 1036 | * check and show chip ID |
| 1066 | */ | 1037 | */ |
| @@ -1088,20 +1059,21 @@ static int mt9t112_camera_probe(struct soc_camera_device *icd, | |||
| 1088 | static int mt9t112_probe(struct i2c_client *client, | 1059 | static int mt9t112_probe(struct i2c_client *client, |
| 1089 | const struct i2c_device_id *did) | 1060 | const struct i2c_device_id *did) |
| 1090 | { | 1061 | { |
| 1091 | struct mt9t112_priv *priv; | 1062 | struct mt9t112_priv *priv; |
| 1092 | struct soc_camera_device *icd = client->dev.platform_data; | 1063 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
| 1093 | struct soc_camera_link *icl; | 1064 | struct v4l2_rect rect = { |
| 1094 | int ret; | 1065 | .width = VGA_WIDTH, |
| 1066 | .height = VGA_HEIGHT, | ||
| 1067 | .left = (MAX_WIDTH - VGA_WIDTH) / 2, | ||
| 1068 | .top = (MAX_HEIGHT - VGA_HEIGHT) / 2, | ||
| 1069 | }; | ||
| 1070 | int ret; | ||
| 1095 | 1071 | ||
| 1096 | if (!icd) { | 1072 | if (!icl || !icl->priv) { |
| 1097 | dev_err(&client->dev, "mt9t112: missing soc-camera data!\n"); | 1073 | dev_err(&client->dev, "mt9t112: missing platform data!\n"); |
| 1098 | return -EINVAL; | 1074 | return -EINVAL; |
| 1099 | } | 1075 | } |
| 1100 | 1076 | ||
| 1101 | icl = to_soc_camera_link(icd); | ||
| 1102 | if (!icl || !icl->priv) | ||
| 1103 | return -EINVAL; | ||
| 1104 | |||
| 1105 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | 1077 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); |
| 1106 | if (!priv) | 1078 | if (!priv) |
| 1107 | return -ENOMEM; | 1079 | return -ENOMEM; |
| @@ -1110,13 +1082,12 @@ static int mt9t112_probe(struct i2c_client *client, | |||
| 1110 | 1082 | ||
| 1111 | v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops); | 1083 | v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops); |
| 1112 | 1084 | ||
| 1113 | icd->ops = &mt9t112_ops; | 1085 | ret = mt9t112_camera_probe(client); |
| 1114 | 1086 | if (ret) | |
| 1115 | ret = mt9t112_camera_probe(icd, client); | ||
| 1116 | if (ret) { | ||
| 1117 | icd->ops = NULL; | ||
| 1118 | kfree(priv); | 1087 | kfree(priv); |
| 1119 | } | 1088 | |
| 1089 | /* Cannot fail: using the default supported pixel code */ | ||
| 1090 | mt9t112_set_params(priv, &rect, V4L2_MBUS_FMT_UYVY8_2X8); | ||
| 1120 | 1091 | ||
| 1121 | return ret; | 1092 | return ret; |
| 1122 | } | 1093 | } |
| @@ -1124,9 +1095,7 @@ static int mt9t112_probe(struct i2c_client *client, | |||
| 1124 | static int mt9t112_remove(struct i2c_client *client) | 1095 | static int mt9t112_remove(struct i2c_client *client) |
| 1125 | { | 1096 | { |
| 1126 | struct mt9t112_priv *priv = to_mt9t112(client); | 1097 | struct mt9t112_priv *priv = to_mt9t112(client); |
| 1127 | struct soc_camera_device *icd = client->dev.platform_data; | ||
| 1128 | 1098 | ||
| 1129 | icd->ops = NULL; | ||
| 1130 | kfree(priv); | 1099 | kfree(priv); |
| 1131 | return 0; | 1100 | return 0; |
| 1132 | } | 1101 | } |
| @@ -1147,11 +1116,7 @@ static struct i2c_driver mt9t112_i2c_driver = { | |||
| 1147 | }; | 1116 | }; |
| 1148 | 1117 | ||
| 1149 | /************************************************************************ | 1118 | /************************************************************************ |
| 1150 | |||
| 1151 | |||
| 1152 | module function | 1119 | module function |
| 1153 | |||
| 1154 | |||
| 1155 | ************************************************************************/ | 1120 | ************************************************************************/ |
| 1156 | static int __init mt9t112_module_init(void) | 1121 | static int __init mt9t112_module_init(void) |
| 1157 | { | 1122 | { |
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index 51b0fccbfe70..b6a29f7de82c 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c | |||
| @@ -14,9 +14,11 @@ | |||
| 14 | #include <linux/delay.h> | 14 | #include <linux/delay.h> |
| 15 | #include <linux/log2.h> | 15 | #include <linux/log2.h> |
| 16 | 16 | ||
| 17 | #include <media/soc_camera.h> | ||
| 18 | #include <media/soc_mediabus.h> | ||
| 17 | #include <media/v4l2-subdev.h> | 19 | #include <media/v4l2-subdev.h> |
| 18 | #include <media/v4l2-chip-ident.h> | 20 | #include <media/v4l2-chip-ident.h> |
| 19 | #include <media/soc_camera.h> | 21 | #include <media/v4l2-ctrls.h> |
| 20 | 22 | ||
| 21 | /* | 23 | /* |
| 22 | * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c | 24 | * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c |
| @@ -100,6 +102,17 @@ static const struct mt9v022_datafmt mt9v022_monochrome_fmts[] = { | |||
| 100 | 102 | ||
| 101 | struct mt9v022 { | 103 | struct mt9v022 { |
| 102 | struct v4l2_subdev subdev; | 104 | struct v4l2_subdev subdev; |
| 105 | struct v4l2_ctrl_handler hdl; | ||
| 106 | struct { | ||
| 107 | /* exposure/auto-exposure cluster */ | ||
| 108 | struct v4l2_ctrl *autoexposure; | ||
| 109 | struct v4l2_ctrl *exposure; | ||
| 110 | }; | ||
| 111 | struct { | ||
| 112 | /* gain/auto-gain cluster */ | ||
| 113 | struct v4l2_ctrl *autogain; | ||
| 114 | struct v4l2_ctrl *gain; | ||
| 115 | }; | ||
| 103 | struct v4l2_rect rect; /* Sensor window */ | 116 | struct v4l2_rect rect; /* Sensor window */ |
| 104 | const struct mt9v022_datafmt *fmt; | 117 | const struct mt9v022_datafmt *fmt; |
| 105 | const struct mt9v022_datafmt *fmts; | 118 | const struct mt9v022_datafmt *fmts; |
| @@ -178,6 +191,8 @@ static int mt9v022_init(struct i2c_client *client) | |||
| 178 | ret = reg_clear(client, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1); | 191 | ret = reg_clear(client, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1); |
| 179 | if (!ret) | 192 | if (!ret) |
| 180 | ret = reg_write(client, MT9V022_DIGITAL_TEST_PATTERN, 0); | 193 | ret = reg_write(client, MT9V022_DIGITAL_TEST_PATTERN, 0); |
| 194 | if (!ret) | ||
| 195 | return v4l2_ctrl_handler_setup(&mt9v022->hdl); | ||
| 181 | 196 | ||
| 182 | return ret; | 197 | return ret; |
| 183 | } | 198 | } |
| @@ -199,78 +214,6 @@ static int mt9v022_s_stream(struct v4l2_subdev *sd, int enable) | |||
| 199 | return 0; | 214 | return 0; |
| 200 | } | 215 | } |
| 201 | 216 | ||
| 202 | static int mt9v022_set_bus_param(struct soc_camera_device *icd, | ||
| 203 | unsigned long flags) | ||
| 204 | { | ||
| 205 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); | ||
| 206 | struct mt9v022 *mt9v022 = to_mt9v022(client); | ||
| 207 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
| 208 | unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK; | ||
| 209 | int ret; | ||
| 210 | u16 pixclk = 0; | ||
| 211 | |||
| 212 | /* Only one width bit may be set */ | ||
| 213 | if (!is_power_of_2(width_flag)) | ||
| 214 | return -EINVAL; | ||
| 215 | |||
| 216 | if (icl->set_bus_param) { | ||
| 217 | ret = icl->set_bus_param(icl, width_flag); | ||
| 218 | if (ret) | ||
| 219 | return ret; | ||
| 220 | } else { | ||
| 221 | /* | ||
| 222 | * Without board specific bus width settings we only support the | ||
| 223 | * sensors native bus width | ||
| 224 | */ | ||
| 225 | if (width_flag != SOCAM_DATAWIDTH_10) | ||
| 226 | return -EINVAL; | ||
| 227 | } | ||
| 228 | |||
| 229 | flags = soc_camera_apply_sensor_flags(icl, flags); | ||
| 230 | |||
| 231 | if (flags & SOCAM_PCLK_SAMPLE_FALLING) | ||
| 232 | pixclk |= 0x10; | ||
| 233 | |||
| 234 | if (!(flags & SOCAM_HSYNC_ACTIVE_HIGH)) | ||
| 235 | pixclk |= 0x1; | ||
| 236 | |||
| 237 | if (!(flags & SOCAM_VSYNC_ACTIVE_HIGH)) | ||
| 238 | pixclk |= 0x2; | ||
| 239 | |||
| 240 | ret = reg_write(client, MT9V022_PIXCLK_FV_LV, pixclk); | ||
| 241 | if (ret < 0) | ||
| 242 | return ret; | ||
| 243 | |||
| 244 | if (!(flags & SOCAM_MASTER)) | ||
| 245 | mt9v022->chip_control &= ~0x8; | ||
| 246 | |||
| 247 | ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control); | ||
| 248 | if (ret < 0) | ||
| 249 | return ret; | ||
| 250 | |||
| 251 | dev_dbg(&client->dev, "Calculated pixclk 0x%x, chip control 0x%x\n", | ||
| 252 | pixclk, mt9v022->chip_control); | ||
| 253 | |||
| 254 | return 0; | ||
| 255 | } | ||
| 256 | |||
| 257 | static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd) | ||
| 258 | { | ||
| 259 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
| 260 | unsigned int flags = SOCAM_MASTER | SOCAM_SLAVE | | ||
| 261 | SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING | | ||
| 262 | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW | | ||
| 263 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW | | ||
| 264 | SOCAM_DATA_ACTIVE_HIGH; | ||
| 265 | |||
| 266 | if (icl->query_bus_param) | ||
| 267 | flags |= icl->query_bus_param(icl) & SOCAM_DATAWIDTH_MASK; | ||
| 268 | else | ||
| 269 | flags |= SOCAM_DATAWIDTH_10; | ||
| 270 | |||
| 271 | return soc_camera_apply_sensor_flags(icl, flags); | ||
| 272 | } | ||
| 273 | |||
| 274 | static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 217 | static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) |
| 275 | { | 218 | { |
| 276 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 219 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| @@ -389,7 +332,7 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd, | |||
| 389 | 332 | ||
| 390 | /* | 333 | /* |
| 391 | * The caller provides a supported format, as verified per call to | 334 | * The caller provides a supported format, as verified per call to |
| 392 | * icd->try_fmt(), datawidth is from our supported format list | 335 | * .try_mbus_fmt(), datawidth is from our supported format list |
| 393 | */ | 336 | */ |
| 394 | switch (mf->code) { | 337 | switch (mf->code) { |
| 395 | case V4L2_MBUS_FMT_Y8_1X8: | 338 | case V4L2_MBUS_FMT_Y8_1X8: |
| @@ -502,236 +445,131 @@ static int mt9v022_s_register(struct v4l2_subdev *sd, | |||
| 502 | } | 445 | } |
| 503 | #endif | 446 | #endif |
| 504 | 447 | ||
| 505 | static const struct v4l2_queryctrl mt9v022_controls[] = { | 448 | static int mt9v022_g_volatile_ctrl(struct v4l2_ctrl *ctrl) |
| 506 | { | ||
| 507 | .id = V4L2_CID_VFLIP, | ||
| 508 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 509 | .name = "Flip Vertically", | ||
| 510 | .minimum = 0, | ||
| 511 | .maximum = 1, | ||
| 512 | .step = 1, | ||
| 513 | .default_value = 0, | ||
| 514 | }, { | ||
| 515 | .id = V4L2_CID_HFLIP, | ||
| 516 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 517 | .name = "Flip Horizontally", | ||
| 518 | .minimum = 0, | ||
| 519 | .maximum = 1, | ||
| 520 | .step = 1, | ||
| 521 | .default_value = 0, | ||
| 522 | }, { | ||
| 523 | .id = V4L2_CID_GAIN, | ||
| 524 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 525 | .name = "Analog Gain", | ||
| 526 | .minimum = 64, | ||
| 527 | .maximum = 127, | ||
| 528 | .step = 1, | ||
| 529 | .default_value = 64, | ||
| 530 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
| 531 | }, { | ||
| 532 | .id = V4L2_CID_EXPOSURE, | ||
| 533 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 534 | .name = "Exposure", | ||
| 535 | .minimum = 1, | ||
| 536 | .maximum = 255, | ||
| 537 | .step = 1, | ||
| 538 | .default_value = 255, | ||
| 539 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
| 540 | }, { | ||
| 541 | .id = V4L2_CID_AUTOGAIN, | ||
| 542 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 543 | .name = "Automatic Gain", | ||
| 544 | .minimum = 0, | ||
| 545 | .maximum = 1, | ||
| 546 | .step = 1, | ||
| 547 | .default_value = 1, | ||
| 548 | }, { | ||
| 549 | .id = V4L2_CID_EXPOSURE_AUTO, | ||
| 550 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 551 | .name = "Automatic Exposure", | ||
| 552 | .minimum = 0, | ||
| 553 | .maximum = 1, | ||
| 554 | .step = 1, | ||
| 555 | .default_value = 1, | ||
| 556 | } | ||
| 557 | }; | ||
| 558 | |||
| 559 | static struct soc_camera_ops mt9v022_ops = { | ||
| 560 | .set_bus_param = mt9v022_set_bus_param, | ||
| 561 | .query_bus_param = mt9v022_query_bus_param, | ||
| 562 | .controls = mt9v022_controls, | ||
| 563 | .num_controls = ARRAY_SIZE(mt9v022_controls), | ||
| 564 | }; | ||
| 565 | |||
| 566 | static int mt9v022_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
| 567 | { | 449 | { |
| 450 | struct mt9v022 *mt9v022 = container_of(ctrl->handler, | ||
| 451 | struct mt9v022, hdl); | ||
| 452 | struct v4l2_subdev *sd = &mt9v022->subdev; | ||
| 568 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 453 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 569 | const struct v4l2_queryctrl *qctrl; | 454 | struct v4l2_ctrl *gain = mt9v022->gain; |
| 455 | struct v4l2_ctrl *exp = mt9v022->exposure; | ||
| 570 | unsigned long range; | 456 | unsigned long range; |
| 571 | int data; | 457 | int data; |
| 572 | 458 | ||
| 573 | qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id); | ||
| 574 | |||
| 575 | switch (ctrl->id) { | 459 | switch (ctrl->id) { |
| 576 | case V4L2_CID_VFLIP: | ||
| 577 | data = reg_read(client, MT9V022_READ_MODE); | ||
| 578 | if (data < 0) | ||
| 579 | return -EIO; | ||
| 580 | ctrl->value = !!(data & 0x10); | ||
| 581 | break; | ||
| 582 | case V4L2_CID_HFLIP: | ||
| 583 | data = reg_read(client, MT9V022_READ_MODE); | ||
| 584 | if (data < 0) | ||
| 585 | return -EIO; | ||
| 586 | ctrl->value = !!(data & 0x20); | ||
| 587 | break; | ||
| 588 | case V4L2_CID_EXPOSURE_AUTO: | ||
| 589 | data = reg_read(client, MT9V022_AEC_AGC_ENABLE); | ||
| 590 | if (data < 0) | ||
| 591 | return -EIO; | ||
| 592 | ctrl->value = !!(data & 0x1); | ||
| 593 | break; | ||
| 594 | case V4L2_CID_AUTOGAIN: | 460 | case V4L2_CID_AUTOGAIN: |
| 595 | data = reg_read(client, MT9V022_AEC_AGC_ENABLE); | ||
| 596 | if (data < 0) | ||
| 597 | return -EIO; | ||
| 598 | ctrl->value = !!(data & 0x2); | ||
| 599 | break; | ||
| 600 | case V4L2_CID_GAIN: | ||
| 601 | data = reg_read(client, MT9V022_ANALOG_GAIN); | 461 | data = reg_read(client, MT9V022_ANALOG_GAIN); |
| 602 | if (data < 0) | 462 | if (data < 0) |
| 603 | return -EIO; | 463 | return -EIO; |
| 604 | 464 | ||
| 605 | range = qctrl->maximum - qctrl->minimum; | 465 | range = gain->maximum - gain->minimum; |
| 606 | ctrl->value = ((data - 16) * range + 24) / 48 + qctrl->minimum; | 466 | gain->val = ((data - 16) * range + 24) / 48 + gain->minimum; |
| 607 | 467 | return 0; | |
| 608 | break; | 468 | case V4L2_CID_EXPOSURE_AUTO: |
| 609 | case V4L2_CID_EXPOSURE: | ||
| 610 | data = reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH); | 469 | data = reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH); |
| 611 | if (data < 0) | 470 | if (data < 0) |
| 612 | return -EIO; | 471 | return -EIO; |
| 613 | 472 | ||
| 614 | range = qctrl->maximum - qctrl->minimum; | 473 | range = exp->maximum - exp->minimum; |
| 615 | ctrl->value = ((data - 1) * range + 239) / 479 + qctrl->minimum; | 474 | exp->val = ((data - 1) * range + 239) / 479 + exp->minimum; |
| 616 | 475 | return 0; | |
| 617 | break; | ||
| 618 | } | 476 | } |
| 619 | return 0; | 477 | return -EINVAL; |
| 620 | } | 478 | } |
| 621 | 479 | ||
| 622 | static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 480 | static int mt9v022_s_ctrl(struct v4l2_ctrl *ctrl) |
| 623 | { | 481 | { |
| 624 | int data; | 482 | struct mt9v022 *mt9v022 = container_of(ctrl->handler, |
| 483 | struct mt9v022, hdl); | ||
| 484 | struct v4l2_subdev *sd = &mt9v022->subdev; | ||
| 625 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 485 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 626 | const struct v4l2_queryctrl *qctrl; | 486 | int data; |
| 627 | |||
| 628 | qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id); | ||
| 629 | if (!qctrl) | ||
| 630 | return -EINVAL; | ||
| 631 | 487 | ||
| 632 | switch (ctrl->id) { | 488 | switch (ctrl->id) { |
| 633 | case V4L2_CID_VFLIP: | 489 | case V4L2_CID_VFLIP: |
| 634 | if (ctrl->value) | 490 | if (ctrl->val) |
| 635 | data = reg_set(client, MT9V022_READ_MODE, 0x10); | 491 | data = reg_set(client, MT9V022_READ_MODE, 0x10); |
| 636 | else | 492 | else |
| 637 | data = reg_clear(client, MT9V022_READ_MODE, 0x10); | 493 | data = reg_clear(client, MT9V022_READ_MODE, 0x10); |
| 638 | if (data < 0) | 494 | if (data < 0) |
| 639 | return -EIO; | 495 | return -EIO; |
| 640 | break; | 496 | return 0; |
| 641 | case V4L2_CID_HFLIP: | 497 | case V4L2_CID_HFLIP: |
| 642 | if (ctrl->value) | 498 | if (ctrl->val) |
| 643 | data = reg_set(client, MT9V022_READ_MODE, 0x20); | 499 | data = reg_set(client, MT9V022_READ_MODE, 0x20); |
| 644 | else | 500 | else |
| 645 | data = reg_clear(client, MT9V022_READ_MODE, 0x20); | 501 | data = reg_clear(client, MT9V022_READ_MODE, 0x20); |
| 646 | if (data < 0) | 502 | if (data < 0) |
| 647 | return -EIO; | 503 | return -EIO; |
| 648 | break; | 504 | return 0; |
| 649 | case V4L2_CID_GAIN: | 505 | case V4L2_CID_AUTOGAIN: |
| 650 | /* mt9v022 has minimum == default */ | 506 | if (ctrl->val) { |
| 651 | if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) | 507 | if (reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) |
| 652 | return -EINVAL; | 508 | return -EIO; |
| 653 | else { | 509 | } else { |
| 654 | unsigned long range = qctrl->maximum - qctrl->minimum; | 510 | struct v4l2_ctrl *gain = mt9v022->gain; |
| 511 | /* mt9v022 has minimum == default */ | ||
| 512 | unsigned long range = gain->maximum - gain->minimum; | ||
| 655 | /* Valid values 16 to 64, 32 to 64 must be even. */ | 513 | /* Valid values 16 to 64, 32 to 64 must be even. */ |
| 656 | unsigned long gain = ((ctrl->value - qctrl->minimum) * | 514 | unsigned long gain_val = ((gain->val - gain->minimum) * |
| 657 | 48 + range / 2) / range + 16; | 515 | 48 + range / 2) / range + 16; |
| 658 | if (gain >= 32) | 516 | |
| 659 | gain &= ~1; | 517 | if (gain_val >= 32) |
| 518 | gain_val &= ~1; | ||
| 519 | |||
| 660 | /* | 520 | /* |
| 661 | * The user wants to set gain manually, hope, she | 521 | * The user wants to set gain manually, hope, she |
| 662 | * knows, what she's doing... Switch AGC off. | 522 | * knows, what she's doing... Switch AGC off. |
| 663 | */ | 523 | */ |
| 664 | |||
| 665 | if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) | 524 | if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) |
| 666 | return -EIO; | 525 | return -EIO; |
| 667 | 526 | ||
| 668 | dev_dbg(&client->dev, "Setting gain from %d to %lu\n", | 527 | dev_dbg(&client->dev, "Setting gain from %d to %lu\n", |
| 669 | reg_read(client, MT9V022_ANALOG_GAIN), gain); | 528 | reg_read(client, MT9V022_ANALOG_GAIN), gain_val); |
| 670 | if (reg_write(client, MT9V022_ANALOG_GAIN, gain) < 0) | 529 | if (reg_write(client, MT9V022_ANALOG_GAIN, gain_val) < 0) |
| 671 | return -EIO; | 530 | return -EIO; |
| 672 | } | 531 | } |
| 673 | break; | 532 | return 0; |
| 674 | case V4L2_CID_EXPOSURE: | 533 | case V4L2_CID_EXPOSURE_AUTO: |
| 675 | /* mt9v022 has maximum == default */ | 534 | if (ctrl->val == V4L2_EXPOSURE_AUTO) { |
| 676 | if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) | 535 | data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x1); |
| 677 | return -EINVAL; | 536 | } else { |
| 678 | else { | 537 | struct v4l2_ctrl *exp = mt9v022->exposure; |
| 679 | unsigned long range = qctrl->maximum - qctrl->minimum; | 538 | unsigned long range = exp->maximum - exp->minimum; |
| 680 | unsigned long shutter = ((ctrl->value - qctrl->minimum) * | 539 | unsigned long shutter = ((exp->val - exp->minimum) * |
| 681 | 479 + range / 2) / range + 1; | 540 | 479 + range / 2) / range + 1; |
| 541 | |||
| 682 | /* | 542 | /* |
| 683 | * The user wants to set shutter width manually, hope, | 543 | * The user wants to set shutter width manually, hope, |
| 684 | * she knows, what she's doing... Switch AEC off. | 544 | * she knows, what she's doing... Switch AEC off. |
| 685 | */ | 545 | */ |
| 686 | 546 | data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1); | |
| 687 | if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1) < 0) | 547 | if (data < 0) |
| 688 | return -EIO; | 548 | return -EIO; |
| 689 | |||
| 690 | dev_dbg(&client->dev, "Shutter width from %d to %lu\n", | 549 | dev_dbg(&client->dev, "Shutter width from %d to %lu\n", |
| 691 | reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH), | 550 | reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH), |
| 692 | shutter); | 551 | shutter); |
| 693 | if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, | 552 | if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, |
| 694 | shutter) < 0) | 553 | shutter) < 0) |
| 695 | return -EIO; | 554 | return -EIO; |
| 696 | } | 555 | } |
| 697 | break; | 556 | return 0; |
| 698 | case V4L2_CID_AUTOGAIN: | ||
| 699 | if (ctrl->value) | ||
| 700 | data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x2); | ||
| 701 | else | ||
| 702 | data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2); | ||
| 703 | if (data < 0) | ||
| 704 | return -EIO; | ||
| 705 | break; | ||
| 706 | case V4L2_CID_EXPOSURE_AUTO: | ||
| 707 | if (ctrl->value) | ||
| 708 | data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x1); | ||
| 709 | else | ||
| 710 | data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1); | ||
| 711 | if (data < 0) | ||
| 712 | return -EIO; | ||
| 713 | break; | ||
| 714 | } | 557 | } |
| 715 | return 0; | 558 | return -EINVAL; |
| 716 | } | 559 | } |
| 717 | 560 | ||
| 718 | /* | 561 | /* |
| 719 | * Interface active, can use i2c. If it fails, it can indeed mean, that | 562 | * Interface active, can use i2c. If it fails, it can indeed mean, that |
| 720 | * this wasn't our capture interface, so, we wait for the right one | 563 | * this wasn't our capture interface, so, we wait for the right one |
| 721 | */ | 564 | */ |
| 722 | static int mt9v022_video_probe(struct soc_camera_device *icd, | 565 | static int mt9v022_video_probe(struct i2c_client *client) |
| 723 | struct i2c_client *client) | ||
| 724 | { | 566 | { |
| 725 | struct mt9v022 *mt9v022 = to_mt9v022(client); | 567 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
| 726 | struct soc_camera_link *icl = to_soc_camera_link(icd); | 568 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
| 727 | s32 data; | 569 | s32 data; |
| 728 | int ret; | 570 | int ret; |
| 729 | unsigned long flags; | 571 | unsigned long flags; |
| 730 | 572 | ||
| 731 | /* We must have a parent by now. And it cannot be a wrong one. */ | ||
| 732 | BUG_ON(!icd->parent || | ||
| 733 | to_soc_camera_host(icd->parent)->nr != icd->iface); | ||
| 734 | |||
| 735 | /* Read out the chip version register */ | 573 | /* Read out the chip version register */ |
| 736 | data = reg_read(client, MT9V022_CHIP_VERSION); | 574 | data = reg_read(client, MT9V022_CHIP_VERSION); |
| 737 | 575 | ||
| @@ -805,16 +643,6 @@ ei2c: | |||
| 805 | return ret; | 643 | return ret; |
| 806 | } | 644 | } |
| 807 | 645 | ||
| 808 | static void mt9v022_video_remove(struct soc_camera_device *icd) | ||
| 809 | { | ||
| 810 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
| 811 | |||
| 812 | dev_dbg(icd->pdev, "Video removed: %p, %p\n", | ||
| 813 | icd->parent, icd->vdev); | ||
| 814 | if (icl->free_bus) | ||
| 815 | icl->free_bus(icl); | ||
| 816 | } | ||
| 817 | |||
| 818 | static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) | 646 | static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) |
| 819 | { | 647 | { |
| 820 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 648 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| @@ -825,9 +653,12 @@ static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) | |||
| 825 | return 0; | 653 | return 0; |
| 826 | } | 654 | } |
| 827 | 655 | ||
| 656 | static const struct v4l2_ctrl_ops mt9v022_ctrl_ops = { | ||
| 657 | .g_volatile_ctrl = mt9v022_g_volatile_ctrl, | ||
| 658 | .s_ctrl = mt9v022_s_ctrl, | ||
| 659 | }; | ||
| 660 | |||
| 828 | static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = { | 661 | static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = { |
| 829 | .g_ctrl = mt9v022_g_ctrl, | ||
| 830 | .s_ctrl = mt9v022_s_ctrl, | ||
| 831 | .g_chip_ident = mt9v022_g_chip_ident, | 662 | .g_chip_ident = mt9v022_g_chip_ident, |
| 832 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 663 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
| 833 | .g_register = mt9v022_g_register, | 664 | .g_register = mt9v022_g_register, |
| @@ -848,6 +679,72 @@ static int mt9v022_enum_fmt(struct v4l2_subdev *sd, unsigned int index, | |||
| 848 | return 0; | 679 | return 0; |
| 849 | } | 680 | } |
| 850 | 681 | ||
| 682 | static int mt9v022_g_mbus_config(struct v4l2_subdev *sd, | ||
| 683 | struct v4l2_mbus_config *cfg) | ||
| 684 | { | ||
| 685 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 686 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
| 687 | |||
| 688 | cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE | | ||
| 689 | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | | ||
| 690 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW | | ||
| 691 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | | ||
| 692 | V4L2_MBUS_DATA_ACTIVE_HIGH; | ||
| 693 | cfg->type = V4L2_MBUS_PARALLEL; | ||
| 694 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | ||
| 695 | |||
| 696 | return 0; | ||
| 697 | } | ||
| 698 | |||
| 699 | static int mt9v022_s_mbus_config(struct v4l2_subdev *sd, | ||
| 700 | const struct v4l2_mbus_config *cfg) | ||
| 701 | { | ||
| 702 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 703 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
| 704 | struct mt9v022 *mt9v022 = to_mt9v022(client); | ||
| 705 | unsigned long flags = soc_camera_apply_board_flags(icl, cfg); | ||
| 706 | unsigned int bps = soc_mbus_get_fmtdesc(mt9v022->fmt->code)->bits_per_sample; | ||
| 707 | int ret; | ||
| 708 | u16 pixclk = 0; | ||
| 709 | |||
| 710 | if (icl->set_bus_param) { | ||
| 711 | ret = icl->set_bus_param(icl, 1 << (bps - 1)); | ||
| 712 | if (ret) | ||
| 713 | return ret; | ||
| 714 | } else if (bps != 10) { | ||
| 715 | /* | ||
| 716 | * Without board specific bus width settings we only support the | ||
| 717 | * sensors native bus width | ||
| 718 | */ | ||
| 719 | return -EINVAL; | ||
| 720 | } | ||
| 721 | |||
| 722 | if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) | ||
| 723 | pixclk |= 0x10; | ||
| 724 | |||
| 725 | if (!(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)) | ||
| 726 | pixclk |= 0x1; | ||
| 727 | |||
| 728 | if (!(flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)) | ||
| 729 | pixclk |= 0x2; | ||
| 730 | |||
| 731 | ret = reg_write(client, MT9V022_PIXCLK_FV_LV, pixclk); | ||
| 732 | if (ret < 0) | ||
| 733 | return ret; | ||
| 734 | |||
| 735 | if (!(flags & V4L2_MBUS_MASTER)) | ||
| 736 | mt9v022->chip_control &= ~0x8; | ||
| 737 | |||
| 738 | ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control); | ||
| 739 | if (ret < 0) | ||
| 740 | return ret; | ||
| 741 | |||
| 742 | dev_dbg(&client->dev, "Calculated pixclk 0x%x, chip control 0x%x\n", | ||
| 743 | pixclk, mt9v022->chip_control); | ||
| 744 | |||
| 745 | return 0; | ||
| 746 | } | ||
| 747 | |||
| 851 | static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { | 748 | static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { |
| 852 | .s_stream = mt9v022_s_stream, | 749 | .s_stream = mt9v022_s_stream, |
| 853 | .s_mbus_fmt = mt9v022_s_fmt, | 750 | .s_mbus_fmt = mt9v022_s_fmt, |
| @@ -857,6 +754,8 @@ static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { | |||
| 857 | .g_crop = mt9v022_g_crop, | 754 | .g_crop = mt9v022_g_crop, |
| 858 | .cropcap = mt9v022_cropcap, | 755 | .cropcap = mt9v022_cropcap, |
| 859 | .enum_mbus_fmt = mt9v022_enum_fmt, | 756 | .enum_mbus_fmt = mt9v022_enum_fmt, |
| 757 | .g_mbus_config = mt9v022_g_mbus_config, | ||
| 758 | .s_mbus_config = mt9v022_s_mbus_config, | ||
| 860 | }; | 759 | }; |
| 861 | 760 | ||
| 862 | static struct v4l2_subdev_sensor_ops mt9v022_subdev_sensor_ops = { | 761 | static struct v4l2_subdev_sensor_ops mt9v022_subdev_sensor_ops = { |
| @@ -873,17 +772,10 @@ static int mt9v022_probe(struct i2c_client *client, | |||
| 873 | const struct i2c_device_id *did) | 772 | const struct i2c_device_id *did) |
| 874 | { | 773 | { |
| 875 | struct mt9v022 *mt9v022; | 774 | struct mt9v022 *mt9v022; |
| 876 | struct soc_camera_device *icd = client->dev.platform_data; | 775 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
| 877 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 776 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
| 878 | struct soc_camera_link *icl; | ||
| 879 | int ret; | 777 | int ret; |
| 880 | 778 | ||
| 881 | if (!icd) { | ||
| 882 | dev_err(&client->dev, "MT9V022: missing soc-camera data!\n"); | ||
| 883 | return -EINVAL; | ||
| 884 | } | ||
| 885 | |||
| 886 | icl = to_soc_camera_link(icd); | ||
| 887 | if (!icl) { | 779 | if (!icl) { |
| 888 | dev_err(&client->dev, "MT9V022 driver needs platform data\n"); | 780 | dev_err(&client->dev, "MT9V022 driver needs platform data\n"); |
| 889 | return -EINVAL; | 781 | return -EINVAL; |
| @@ -900,10 +792,39 @@ static int mt9v022_probe(struct i2c_client *client, | |||
| 900 | return -ENOMEM; | 792 | return -ENOMEM; |
| 901 | 793 | ||
| 902 | v4l2_i2c_subdev_init(&mt9v022->subdev, client, &mt9v022_subdev_ops); | 794 | v4l2_i2c_subdev_init(&mt9v022->subdev, client, &mt9v022_subdev_ops); |
| 795 | v4l2_ctrl_handler_init(&mt9v022->hdl, 6); | ||
| 796 | v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, | ||
| 797 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
| 798 | v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, | ||
| 799 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
| 800 | mt9v022->autogain = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, | ||
| 801 | V4L2_CID_AUTOGAIN, 0, 1, 1, 1); | ||
| 802 | mt9v022->gain = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, | ||
| 803 | V4L2_CID_GAIN, 0, 127, 1, 64); | ||
| 804 | |||
| 805 | /* | ||
| 806 | * Simulated autoexposure. If enabled, we calculate shutter width | ||
| 807 | * ourselves in the driver based on vertical blanking and frame width | ||
| 808 | */ | ||
| 809 | mt9v022->autoexposure = v4l2_ctrl_new_std_menu(&mt9v022->hdl, | ||
| 810 | &mt9v022_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, | ||
| 811 | V4L2_EXPOSURE_AUTO); | ||
| 812 | mt9v022->exposure = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, | ||
| 813 | V4L2_CID_EXPOSURE, 1, 255, 1, 255); | ||
| 814 | |||
| 815 | mt9v022->subdev.ctrl_handler = &mt9v022->hdl; | ||
| 816 | if (mt9v022->hdl.error) { | ||
| 817 | int err = mt9v022->hdl.error; | ||
| 818 | |||
| 819 | kfree(mt9v022); | ||
| 820 | return err; | ||
| 821 | } | ||
| 822 | v4l2_ctrl_auto_cluster(2, &mt9v022->autoexposure, | ||
| 823 | V4L2_EXPOSURE_MANUAL, true); | ||
| 824 | v4l2_ctrl_auto_cluster(2, &mt9v022->autogain, 0, true); | ||
| 903 | 825 | ||
| 904 | mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT; | 826 | mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT; |
| 905 | 827 | ||
| 906 | icd->ops = &mt9v022_ops; | ||
| 907 | /* | 828 | /* |
| 908 | * MT9V022 _really_ corrupts the first read out line. | 829 | * MT9V022 _really_ corrupts the first read out line. |
| 909 | * TODO: verify on i.MX31 | 830 | * TODO: verify on i.MX31 |
| @@ -914,9 +835,9 @@ static int mt9v022_probe(struct i2c_client *client, | |||
| 914 | mt9v022->rect.width = MT9V022_MAX_WIDTH; | 835 | mt9v022->rect.width = MT9V022_MAX_WIDTH; |
| 915 | mt9v022->rect.height = MT9V022_MAX_HEIGHT; | 836 | mt9v022->rect.height = MT9V022_MAX_HEIGHT; |
| 916 | 837 | ||
| 917 | ret = mt9v022_video_probe(icd, client); | 838 | ret = mt9v022_video_probe(client); |
| 918 | if (ret) { | 839 | if (ret) { |
| 919 | icd->ops = NULL; | 840 | v4l2_ctrl_handler_free(&mt9v022->hdl); |
| 920 | kfree(mt9v022); | 841 | kfree(mt9v022); |
| 921 | } | 842 | } |
| 922 | 843 | ||
| @@ -926,10 +847,12 @@ static int mt9v022_probe(struct i2c_client *client, | |||
| 926 | static int mt9v022_remove(struct i2c_client *client) | 847 | static int mt9v022_remove(struct i2c_client *client) |
| 927 | { | 848 | { |
| 928 | struct mt9v022 *mt9v022 = to_mt9v022(client); | 849 | struct mt9v022 *mt9v022 = to_mt9v022(client); |
| 929 | struct soc_camera_device *icd = client->dev.platform_data; | 850 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
| 930 | 851 | ||
| 931 | icd->ops = NULL; | 852 | v4l2_device_unregister_subdev(&mt9v022->subdev); |
| 932 | mt9v022_video_remove(icd); | 853 | if (icl->free_bus) |
| 854 | icl->free_bus(icl); | ||
| 855 | v4l2_ctrl_handler_free(&mt9v022->hdl); | ||
| 933 | kfree(mt9v022); | 856 | kfree(mt9v022); |
| 934 | 857 | ||
| 935 | return 0; | 858 | return 0; |
diff --git a/drivers/media/video/mx1_camera.c b/drivers/media/video/mx1_camera.c index 087db12a3a67..18e94c7d2be8 100644 --- a/drivers/media/video/mx1_camera.c +++ b/drivers/media/video/mx1_camera.c | |||
| @@ -78,11 +78,10 @@ | |||
| 78 | #define CSI_IRQ_MASK (CSISR_SFF_OR_INT | CSISR_RFF_OR_INT | \ | 78 | #define CSI_IRQ_MASK (CSISR_SFF_OR_INT | CSISR_RFF_OR_INT | \ |
| 79 | CSISR_STATFF_INT | CSISR_RXFF_INT | CSISR_SOF_INT) | 79 | CSISR_STATFF_INT | CSISR_RXFF_INT | CSISR_SOF_INT) |
| 80 | 80 | ||
| 81 | #define CSI_BUS_FLAGS (SOCAM_MASTER | SOCAM_HSYNC_ACTIVE_HIGH | \ | 81 | #define CSI_BUS_FLAGS (V4L2_MBUS_MASTER | V4L2_MBUS_HSYNC_ACTIVE_HIGH | \ |
| 82 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW | \ | 82 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | \ |
| 83 | SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING | \ | 83 | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | \ |
| 84 | SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_LOW | \ | 84 | V4L2_MBUS_DATA_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_LOW) |
| 85 | SOCAM_DATAWIDTH_8) | ||
| 86 | 85 | ||
| 87 | #define MAX_VIDEO_MEM 16 /* Video memory limit in megabytes */ | 86 | #define MAX_VIDEO_MEM 16 /* Video memory limit in megabytes */ |
| 88 | 87 | ||
| @@ -490,59 +489,73 @@ static int mx1_camera_set_crop(struct soc_camera_device *icd, | |||
| 490 | 489 | ||
| 491 | static int mx1_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | 490 | static int mx1_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) |
| 492 | { | 491 | { |
| 492 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
| 493 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 493 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
| 494 | struct mx1_camera_dev *pcdev = ici->priv; | 494 | struct mx1_camera_dev *pcdev = ici->priv; |
| 495 | unsigned long camera_flags, common_flags; | 495 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; |
| 496 | unsigned long common_flags; | ||
| 496 | unsigned int csicr1; | 497 | unsigned int csicr1; |
| 497 | int ret; | 498 | int ret; |
| 498 | 499 | ||
| 499 | camera_flags = icd->ops->query_bus_param(icd); | ||
| 500 | |||
| 501 | /* MX1 supports only 8bit buswidth */ | 500 | /* MX1 supports only 8bit buswidth */ |
| 502 | common_flags = soc_camera_bus_param_compatible(camera_flags, | 501 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); |
| 503 | CSI_BUS_FLAGS); | 502 | if (!ret) { |
| 504 | if (!common_flags) | 503 | common_flags = soc_mbus_config_compatible(&cfg, CSI_BUS_FLAGS); |
| 505 | return -EINVAL; | 504 | if (!common_flags) { |
| 505 | dev_warn(icd->parent, | ||
| 506 | "Flags incompatible: camera 0x%x, host 0x%x\n", | ||
| 507 | cfg.flags, CSI_BUS_FLAGS); | ||
| 508 | return -EINVAL; | ||
| 509 | } | ||
| 510 | } else if (ret != -ENOIOCTLCMD) { | ||
| 511 | return ret; | ||
| 512 | } else { | ||
| 513 | common_flags = CSI_BUS_FLAGS; | ||
| 514 | } | ||
| 506 | 515 | ||
| 507 | /* Make choises, based on platform choice */ | 516 | /* Make choises, based on platform choice */ |
| 508 | if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && | 517 | if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && |
| 509 | (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { | 518 | (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { |
| 510 | if (!pcdev->pdata || | 519 | if (!pcdev->pdata || |
| 511 | pcdev->pdata->flags & MX1_CAMERA_VSYNC_HIGH) | 520 | pcdev->pdata->flags & MX1_CAMERA_VSYNC_HIGH) |
| 512 | common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; | 521 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; |
| 513 | else | 522 | else |
| 514 | common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; | 523 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; |
| 515 | } | 524 | } |
| 516 | 525 | ||
| 517 | if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && | 526 | if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && |
| 518 | (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { | 527 | (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { |
| 519 | if (!pcdev->pdata || | 528 | if (!pcdev->pdata || |
| 520 | pcdev->pdata->flags & MX1_CAMERA_PCLK_RISING) | 529 | pcdev->pdata->flags & MX1_CAMERA_PCLK_RISING) |
| 521 | common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; | 530 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; |
| 522 | else | 531 | else |
| 523 | common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; | 532 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; |
| 524 | } | 533 | } |
| 525 | 534 | ||
| 526 | if ((common_flags & SOCAM_DATA_ACTIVE_HIGH) && | 535 | if ((common_flags & V4L2_MBUS_DATA_ACTIVE_HIGH) && |
| 527 | (common_flags & SOCAM_DATA_ACTIVE_LOW)) { | 536 | (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW)) { |
| 528 | if (!pcdev->pdata || | 537 | if (!pcdev->pdata || |
| 529 | pcdev->pdata->flags & MX1_CAMERA_DATA_HIGH) | 538 | pcdev->pdata->flags & MX1_CAMERA_DATA_HIGH) |
| 530 | common_flags &= ~SOCAM_DATA_ACTIVE_LOW; | 539 | common_flags &= ~V4L2_MBUS_DATA_ACTIVE_LOW; |
| 531 | else | 540 | else |
| 532 | common_flags &= ~SOCAM_DATA_ACTIVE_HIGH; | 541 | common_flags &= ~V4L2_MBUS_DATA_ACTIVE_HIGH; |
| 533 | } | 542 | } |
| 534 | 543 | ||
| 535 | ret = icd->ops->set_bus_param(icd, common_flags); | 544 | cfg.flags = common_flags; |
| 536 | if (ret < 0) | 545 | ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); |
| 546 | if (ret < 0 && ret != -ENOIOCTLCMD) { | ||
| 547 | dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n", | ||
| 548 | common_flags, ret); | ||
| 537 | return ret; | 549 | return ret; |
| 550 | } | ||
| 538 | 551 | ||
| 539 | csicr1 = __raw_readl(pcdev->base + CSICR1); | 552 | csicr1 = __raw_readl(pcdev->base + CSICR1); |
| 540 | 553 | ||
| 541 | if (common_flags & SOCAM_PCLK_SAMPLE_RISING) | 554 | if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) |
| 542 | csicr1 |= CSICR1_REDGE; | 555 | csicr1 |= CSICR1_REDGE; |
| 543 | if (common_flags & SOCAM_VSYNC_ACTIVE_HIGH) | 556 | if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) |
| 544 | csicr1 |= CSICR1_SOF_POL; | 557 | csicr1 |= CSICR1_SOF_POL; |
| 545 | if (common_flags & SOCAM_DATA_ACTIVE_LOW) | 558 | if (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW) |
| 546 | csicr1 |= CSICR1_DATA_POL; | 559 | csicr1 |= CSICR1_DATA_POL; |
| 547 | 560 | ||
| 548 | __raw_writel(csicr1, pcdev->base + CSICR1); | 561 | __raw_writel(csicr1, pcdev->base + CSICR1); |
diff --git a/drivers/media/video/mx2_camera.c b/drivers/media/video/mx2_camera.c index ec2410c0c806..a803d9ea8fd6 100644 --- a/drivers/media/video/mx2_camera.c +++ b/drivers/media/video/mx2_camera.c | |||
| @@ -686,16 +686,15 @@ static void mx2_camera_init_videobuf(struct videobuf_queue *q, | |||
| 686 | icd, &icd->video_lock); | 686 | icd, &icd->video_lock); |
| 687 | } | 687 | } |
| 688 | 688 | ||
| 689 | #define MX2_BUS_FLAGS (SOCAM_DATAWIDTH_8 | \ | 689 | #define MX2_BUS_FLAGS (V4L2_MBUS_MASTER | \ |
| 690 | SOCAM_MASTER | \ | 690 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | \ |
| 691 | SOCAM_VSYNC_ACTIVE_HIGH | \ | 691 | V4L2_MBUS_VSYNC_ACTIVE_LOW | \ |
| 692 | SOCAM_VSYNC_ACTIVE_LOW | \ | 692 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | \ |
| 693 | SOCAM_HSYNC_ACTIVE_HIGH | \ | 693 | V4L2_MBUS_HSYNC_ACTIVE_LOW | \ |
| 694 | SOCAM_HSYNC_ACTIVE_LOW | \ | 694 | V4L2_MBUS_PCLK_SAMPLE_RISING | \ |
| 695 | SOCAM_PCLK_SAMPLE_RISING | \ | 695 | V4L2_MBUS_PCLK_SAMPLE_FALLING | \ |
| 696 | SOCAM_PCLK_SAMPLE_FALLING | \ | 696 | V4L2_MBUS_DATA_ACTIVE_HIGH | \ |
| 697 | SOCAM_DATA_ACTIVE_HIGH | \ | 697 | V4L2_MBUS_DATA_ACTIVE_LOW) |
| 698 | SOCAM_DATA_ACTIVE_LOW) | ||
| 699 | 698 | ||
| 700 | static int mx27_camera_emma_prp_reset(struct mx2_camera_dev *pcdev) | 699 | static int mx27_camera_emma_prp_reset(struct mx2_camera_dev *pcdev) |
| 701 | { | 700 | { |
| @@ -770,46 +769,59 @@ static void mx27_camera_emma_buf_init(struct soc_camera_device *icd, | |||
| 770 | static int mx2_camera_set_bus_param(struct soc_camera_device *icd, | 769 | static int mx2_camera_set_bus_param(struct soc_camera_device *icd, |
| 771 | __u32 pixfmt) | 770 | __u32 pixfmt) |
| 772 | { | 771 | { |
| 773 | struct soc_camera_host *ici = | 772 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
| 774 | to_soc_camera_host(icd->parent); | 773 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
| 775 | struct mx2_camera_dev *pcdev = ici->priv; | 774 | struct mx2_camera_dev *pcdev = ici->priv; |
| 776 | unsigned long camera_flags, common_flags; | 775 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; |
| 777 | int ret = 0; | 776 | unsigned long common_flags; |
| 777 | int ret; | ||
| 778 | int bytesperline; | 778 | int bytesperline; |
| 779 | u32 csicr1 = pcdev->csicr1; | 779 | u32 csicr1 = pcdev->csicr1; |
| 780 | 780 | ||
| 781 | camera_flags = icd->ops->query_bus_param(icd); | 781 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); |
| 782 | 782 | if (!ret) { | |
| 783 | common_flags = soc_camera_bus_param_compatible(camera_flags, | 783 | common_flags = soc_mbus_config_compatible(&cfg, MX2_BUS_FLAGS); |
| 784 | MX2_BUS_FLAGS); | 784 | if (!common_flags) { |
| 785 | if (!common_flags) | 785 | dev_warn(icd->parent, |
| 786 | return -EINVAL; | 786 | "Flags incompatible: camera 0x%x, host 0x%x\n", |
| 787 | cfg.flags, MX2_BUS_FLAGS); | ||
| 788 | return -EINVAL; | ||
| 789 | } | ||
| 790 | } else if (ret != -ENOIOCTLCMD) { | ||
| 791 | return ret; | ||
| 792 | } else { | ||
| 793 | common_flags = MX2_BUS_FLAGS; | ||
| 794 | } | ||
| 787 | 795 | ||
| 788 | if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && | 796 | if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && |
| 789 | (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { | 797 | (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { |
| 790 | if (pcdev->platform_flags & MX2_CAMERA_HSYNC_HIGH) | 798 | if (pcdev->platform_flags & MX2_CAMERA_HSYNC_HIGH) |
| 791 | common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; | 799 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; |
| 792 | else | 800 | else |
| 793 | common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; | 801 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; |
| 794 | } | 802 | } |
| 795 | 803 | ||
| 796 | if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && | 804 | if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && |
| 797 | (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { | 805 | (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { |
| 798 | if (pcdev->platform_flags & MX2_CAMERA_PCLK_SAMPLE_RISING) | 806 | if (pcdev->platform_flags & MX2_CAMERA_PCLK_SAMPLE_RISING) |
| 799 | common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; | 807 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; |
| 800 | else | 808 | else |
| 801 | common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; | 809 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; |
| 802 | } | 810 | } |
| 803 | 811 | ||
| 804 | ret = icd->ops->set_bus_param(icd, common_flags); | 812 | cfg.flags = common_flags; |
| 805 | if (ret < 0) | 813 | ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); |
| 814 | if (ret < 0 && ret != -ENOIOCTLCMD) { | ||
| 815 | dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n", | ||
| 816 | common_flags, ret); | ||
| 806 | return ret; | 817 | return ret; |
| 818 | } | ||
| 807 | 819 | ||
| 808 | if (common_flags & SOCAM_PCLK_SAMPLE_RISING) | 820 | if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) |
| 809 | csicr1 |= CSICR1_REDGE; | 821 | csicr1 |= CSICR1_REDGE; |
| 810 | if (common_flags & SOCAM_VSYNC_ACTIVE_HIGH) | 822 | if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) |
| 811 | csicr1 |= CSICR1_SOF_POL; | 823 | csicr1 |= CSICR1_SOF_POL; |
| 812 | if (common_flags & SOCAM_HSYNC_ACTIVE_HIGH) | 824 | if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) |
| 813 | csicr1 |= CSICR1_HSYNC_POL; | 825 | csicr1 |= CSICR1_HSYNC_POL; |
| 814 | if (pcdev->platform_flags & MX2_CAMERA_SWAP16) | 826 | if (pcdev->platform_flags & MX2_CAMERA_SWAP16) |
| 815 | csicr1 |= CSICR1_SWAP16_EN; | 827 | csicr1 |= CSICR1_SWAP16_EN; |
diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c index c8e958a07e91..f96f92f00f92 100644 --- a/drivers/media/video/mx3_camera.c +++ b/drivers/media/video/mx3_camera.c | |||
| @@ -109,10 +109,12 @@ struct mx3_camera_dev { | |||
| 109 | 109 | ||
| 110 | unsigned long platform_flags; | 110 | unsigned long platform_flags; |
| 111 | unsigned long mclk; | 111 | unsigned long mclk; |
| 112 | u16 width_flags; /* max 15 bits */ | ||
| 112 | 113 | ||
| 113 | struct list_head capture; | 114 | struct list_head capture; |
| 114 | spinlock_t lock; /* Protects video buffer lists */ | 115 | spinlock_t lock; /* Protects video buffer lists */ |
| 115 | struct mx3_camera_buffer *active; | 116 | struct mx3_camera_buffer *active; |
| 117 | size_t buf_total; | ||
| 116 | struct vb2_alloc_ctx *alloc_ctx; | 118 | struct vb2_alloc_ctx *alloc_ctx; |
| 117 | enum v4l2_field field; | 119 | enum v4l2_field field; |
| 118 | int sequence; | 120 | int sequence; |
| @@ -190,79 +192,53 @@ static void mx3_cam_dma_done(void *arg) | |||
| 190 | * Calculate the __buffer__ (not data) size and number of buffers. | 192 | * Calculate the __buffer__ (not data) size and number of buffers. |
| 191 | */ | 193 | */ |
| 192 | static int mx3_videobuf_setup(struct vb2_queue *vq, | 194 | static int mx3_videobuf_setup(struct vb2_queue *vq, |
| 195 | const struct v4l2_format *fmt, | ||
| 193 | unsigned int *count, unsigned int *num_planes, | 196 | unsigned int *count, unsigned int *num_planes, |
| 194 | unsigned int sizes[], void *alloc_ctxs[]) | 197 | unsigned int sizes[], void *alloc_ctxs[]) |
| 195 | { | 198 | { |
| 196 | struct soc_camera_device *icd = soc_camera_from_vb2q(vq); | 199 | struct soc_camera_device *icd = soc_camera_from_vb2q(vq); |
| 197 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 200 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
| 198 | struct mx3_camera_dev *mx3_cam = ici->priv; | 201 | struct mx3_camera_dev *mx3_cam = ici->priv; |
| 199 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, | 202 | int bytes_per_line; |
| 200 | icd->current_fmt->host_fmt); | 203 | unsigned int height; |
| 201 | |||
| 202 | if (bytes_per_line < 0) | ||
| 203 | return bytes_per_line; | ||
| 204 | 204 | ||
| 205 | if (!mx3_cam->idmac_channel[0]) | 205 | if (!mx3_cam->idmac_channel[0]) |
| 206 | return -EINVAL; | 206 | return -EINVAL; |
| 207 | 207 | ||
| 208 | *num_planes = 1; | 208 | if (fmt) { |
| 209 | 209 | const struct soc_camera_format_xlate *xlate = soc_camera_xlate_by_fourcc(icd, | |
| 210 | mx3_cam->sequence = 0; | 210 | fmt->fmt.pix.pixelformat); |
| 211 | sizes[0] = bytes_per_line * icd->user_height; | 211 | if (!xlate) |
| 212 | alloc_ctxs[0] = mx3_cam->alloc_ctx; | 212 | return -EINVAL; |
| 213 | 213 | bytes_per_line = soc_mbus_bytes_per_line(fmt->fmt.pix.width, | |
| 214 | if (!*count) | 214 | xlate->host_fmt); |
| 215 | *count = 32; | 215 | height = fmt->fmt.pix.height; |
| 216 | 216 | } else { | |
| 217 | if (sizes[0] * *count > MAX_VIDEO_MEM * 1024 * 1024) | 217 | /* Called from VIDIOC_REQBUFS or in compatibility mode */ |
| 218 | *count = MAX_VIDEO_MEM * 1024 * 1024 / sizes[0]; | 218 | bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, |
| 219 | |||
| 220 | return 0; | ||
| 221 | } | ||
| 222 | |||
| 223 | static int mx3_videobuf_prepare(struct vb2_buffer *vb) | ||
| 224 | { | ||
| 225 | struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); | ||
| 226 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
| 227 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
| 228 | struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; | ||
| 229 | struct scatterlist *sg; | ||
| 230 | struct mx3_camera_buffer *buf; | ||
| 231 | size_t new_size; | ||
| 232 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, | ||
| 233 | icd->current_fmt->host_fmt); | 219 | icd->current_fmt->host_fmt); |
| 234 | 220 | height = icd->user_height; | |
| 221 | } | ||
| 235 | if (bytes_per_line < 0) | 222 | if (bytes_per_line < 0) |
| 236 | return bytes_per_line; | 223 | return bytes_per_line; |
| 237 | 224 | ||
| 238 | buf = to_mx3_vb(vb); | 225 | sizes[0] = bytes_per_line * height; |
| 239 | sg = &buf->sg; | ||
| 240 | |||
| 241 | new_size = bytes_per_line * icd->user_height; | ||
| 242 | 226 | ||
| 243 | if (vb2_plane_size(vb, 0) < new_size) { | 227 | alloc_ctxs[0] = mx3_cam->alloc_ctx; |
| 244 | dev_err(icd->parent, "Buffer too small (%lu < %zu)\n", | ||
| 245 | vb2_plane_size(vb, 0), new_size); | ||
| 246 | return -ENOBUFS; | ||
| 247 | } | ||
| 248 | 228 | ||
| 249 | if (buf->state == CSI_BUF_NEEDS_INIT) { | 229 | if (!vq->num_buffers) |
| 250 | sg_dma_address(sg) = vb2_dma_contig_plane_dma_addr(vb, 0); | 230 | mx3_cam->sequence = 0; |
| 251 | sg_dma_len(sg) = new_size; | ||
| 252 | 231 | ||
| 253 | buf->txd = ichan->dma_chan.device->device_prep_slave_sg( | 232 | if (!*count) |
| 254 | &ichan->dma_chan, sg, 1, DMA_FROM_DEVICE, | 233 | *count = 2; |
| 255 | DMA_PREP_INTERRUPT); | ||
| 256 | if (!buf->txd) | ||
| 257 | return -EIO; | ||
| 258 | |||
| 259 | buf->txd->callback_param = buf->txd; | ||
| 260 | buf->txd->callback = mx3_cam_dma_done; | ||
| 261 | 234 | ||
| 262 | buf->state = CSI_BUF_PREPARED; | 235 | /* If *num_planes != 0, we have already verified *count. */ |
| 263 | } | 236 | if (!*num_planes && |
| 237 | sizes[0] * *count + mx3_cam->buf_total > MAX_VIDEO_MEM * 1024 * 1024) | ||
| 238 | *count = (MAX_VIDEO_MEM * 1024 * 1024 - mx3_cam->buf_total) / | ||
| 239 | sizes[0]; | ||
| 264 | 240 | ||
| 265 | vb2_set_plane_payload(vb, 0, new_size); | 241 | *num_planes = 1; |
| 266 | 242 | ||
| 267 | return 0; | 243 | return 0; |
| 268 | } | 244 | } |
| @@ -286,28 +262,58 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb) | |||
| 286 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 262 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
| 287 | struct mx3_camera_dev *mx3_cam = ici->priv; | 263 | struct mx3_camera_dev *mx3_cam = ici->priv; |
| 288 | struct mx3_camera_buffer *buf = to_mx3_vb(vb); | 264 | struct mx3_camera_buffer *buf = to_mx3_vb(vb); |
| 289 | struct dma_async_tx_descriptor *txd = buf->txd; | 265 | struct scatterlist *sg = &buf->sg; |
| 290 | struct idmac_channel *ichan = to_idmac_chan(txd->chan); | 266 | struct dma_async_tx_descriptor *txd; |
| 267 | struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; | ||
| 291 | struct idmac_video_param *video = &ichan->params.video; | 268 | struct idmac_video_param *video = &ichan->params.video; |
| 292 | dma_cookie_t cookie; | 269 | const struct soc_mbus_pixelfmt *host_fmt = icd->current_fmt->host_fmt; |
| 293 | u32 fourcc = icd->current_fmt->host_fmt->fourcc; | 270 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, host_fmt); |
| 294 | unsigned long flags; | 271 | unsigned long flags; |
| 272 | dma_cookie_t cookie; | ||
| 273 | size_t new_size; | ||
| 274 | |||
| 275 | BUG_ON(bytes_per_line <= 0); | ||
| 276 | |||
| 277 | new_size = bytes_per_line * icd->user_height; | ||
| 278 | |||
| 279 | if (vb2_plane_size(vb, 0) < new_size) { | ||
| 280 | dev_err(icd->parent, "Buffer #%d too small (%lu < %zu)\n", | ||
| 281 | vb->v4l2_buf.index, vb2_plane_size(vb, 0), new_size); | ||
| 282 | goto error; | ||
| 283 | } | ||
| 284 | |||
| 285 | if (buf->state == CSI_BUF_NEEDS_INIT) { | ||
| 286 | sg_dma_address(sg) = vb2_dma_contig_plane_dma_addr(vb, 0); | ||
| 287 | sg_dma_len(sg) = new_size; | ||
| 288 | |||
| 289 | txd = ichan->dma_chan.device->device_prep_slave_sg( | ||
| 290 | &ichan->dma_chan, sg, 1, DMA_FROM_DEVICE, | ||
| 291 | DMA_PREP_INTERRUPT); | ||
| 292 | if (!txd) | ||
| 293 | goto error; | ||
| 294 | |||
| 295 | txd->callback_param = txd; | ||
| 296 | txd->callback = mx3_cam_dma_done; | ||
| 297 | |||
| 298 | buf->state = CSI_BUF_PREPARED; | ||
| 299 | buf->txd = txd; | ||
| 300 | } else { | ||
| 301 | txd = buf->txd; | ||
| 302 | } | ||
| 303 | |||
| 304 | vb2_set_plane_payload(vb, 0, new_size); | ||
| 295 | 305 | ||
| 296 | /* This is the configuration of one sg-element */ | 306 | /* This is the configuration of one sg-element */ |
| 297 | video->out_pixel_fmt = fourcc_to_ipu_pix(fourcc); | 307 | video->out_pixel_fmt = fourcc_to_ipu_pix(host_fmt->fourcc); |
| 298 | 308 | ||
| 299 | if (video->out_pixel_fmt == IPU_PIX_FMT_GENERIC) { | 309 | if (video->out_pixel_fmt == IPU_PIX_FMT_GENERIC) { |
| 300 | /* | 310 | /* |
| 301 | * If the IPU DMA channel is configured to transport | 311 | * If the IPU DMA channel is configured to transfer generic |
| 302 | * generic 8-bit data, we have to set up correctly the | 312 | * 8-bit data, we have to set up the geometry parameters |
| 303 | * geometry parameters upon the current pixel format. | 313 | * correctly, according to the current pixel format. The DMA |
| 304 | * So, since the DMA horizontal parameters are expressed | 314 | * horizontal parameters in this case are expressed in bytes, |
| 305 | * in bytes not pixels, convert these in the right unit. | 315 | * not in pixels. |
| 306 | */ | 316 | */ |
| 307 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, | ||
| 308 | icd->current_fmt->host_fmt); | ||
| 309 | BUG_ON(bytes_per_line <= 0); | ||
| 310 | |||
| 311 | video->out_width = bytes_per_line; | 317 | video->out_width = bytes_per_line; |
| 312 | video->out_height = icd->user_height; | 318 | video->out_height = icd->user_height; |
| 313 | video->out_stride = bytes_per_line; | 319 | video->out_stride = bytes_per_line; |
| @@ -351,6 +357,7 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb) | |||
| 351 | mx3_cam->active = NULL; | 357 | mx3_cam->active = NULL; |
| 352 | 358 | ||
| 353 | spin_unlock_irqrestore(&mx3_cam->lock, flags); | 359 | spin_unlock_irqrestore(&mx3_cam->lock, flags); |
| 360 | error: | ||
| 354 | vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); | 361 | vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); |
| 355 | } | 362 | } |
| 356 | 363 | ||
| @@ -384,17 +391,24 @@ static void mx3_videobuf_release(struct vb2_buffer *vb) | |||
| 384 | } | 391 | } |
| 385 | 392 | ||
| 386 | spin_unlock_irqrestore(&mx3_cam->lock, flags); | 393 | spin_unlock_irqrestore(&mx3_cam->lock, flags); |
| 394 | |||
| 395 | mx3_cam->buf_total -= vb2_plane_size(vb, 0); | ||
| 387 | } | 396 | } |
| 388 | 397 | ||
| 389 | static int mx3_videobuf_init(struct vb2_buffer *vb) | 398 | static int mx3_videobuf_init(struct vb2_buffer *vb) |
| 390 | { | 399 | { |
| 400 | struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); | ||
| 401 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
| 402 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
| 391 | struct mx3_camera_buffer *buf = to_mx3_vb(vb); | 403 | struct mx3_camera_buffer *buf = to_mx3_vb(vb); |
| 404 | |||
| 392 | /* This is for locking debugging only */ | 405 | /* This is for locking debugging only */ |
| 393 | INIT_LIST_HEAD(&buf->queue); | 406 | INIT_LIST_HEAD(&buf->queue); |
| 394 | sg_init_table(&buf->sg, 1); | 407 | sg_init_table(&buf->sg, 1); |
| 395 | 408 | ||
| 396 | buf->state = CSI_BUF_NEEDS_INIT; | 409 | buf->state = CSI_BUF_NEEDS_INIT; |
| 397 | buf->txd = NULL; | 410 | |
| 411 | mx3_cam->buf_total += vb2_plane_size(vb, 0); | ||
| 398 | 412 | ||
| 399 | return 0; | 413 | return 0; |
| 400 | } | 414 | } |
| @@ -405,13 +419,12 @@ static int mx3_stop_streaming(struct vb2_queue *q) | |||
| 405 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 419 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
| 406 | struct mx3_camera_dev *mx3_cam = ici->priv; | 420 | struct mx3_camera_dev *mx3_cam = ici->priv; |
| 407 | struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; | 421 | struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; |
| 408 | struct dma_chan *chan; | ||
| 409 | struct mx3_camera_buffer *buf, *tmp; | 422 | struct mx3_camera_buffer *buf, *tmp; |
| 410 | unsigned long flags; | 423 | unsigned long flags; |
| 411 | 424 | ||
| 412 | if (ichan) { | 425 | if (ichan) { |
| 413 | chan = &ichan->dma_chan; | 426 | struct dma_chan *chan = &ichan->dma_chan; |
| 414 | chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); | 427 | chan->device->device_control(chan, DMA_PAUSE, 0); |
| 415 | } | 428 | } |
| 416 | 429 | ||
| 417 | spin_lock_irqsave(&mx3_cam->lock, flags); | 430 | spin_lock_irqsave(&mx3_cam->lock, flags); |
| @@ -419,8 +432,8 @@ static int mx3_stop_streaming(struct vb2_queue *q) | |||
| 419 | mx3_cam->active = NULL; | 432 | mx3_cam->active = NULL; |
| 420 | 433 | ||
| 421 | list_for_each_entry_safe(buf, tmp, &mx3_cam->capture, queue) { | 434 | list_for_each_entry_safe(buf, tmp, &mx3_cam->capture, queue) { |
| 422 | buf->state = CSI_BUF_NEEDS_INIT; | ||
| 423 | list_del_init(&buf->queue); | 435 | list_del_init(&buf->queue); |
| 436 | vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); | ||
| 424 | } | 437 | } |
| 425 | 438 | ||
| 426 | spin_unlock_irqrestore(&mx3_cam->lock, flags); | 439 | spin_unlock_irqrestore(&mx3_cam->lock, flags); |
| @@ -430,7 +443,6 @@ static int mx3_stop_streaming(struct vb2_queue *q) | |||
| 430 | 443 | ||
| 431 | static struct vb2_ops mx3_videobuf_ops = { | 444 | static struct vb2_ops mx3_videobuf_ops = { |
| 432 | .queue_setup = mx3_videobuf_setup, | 445 | .queue_setup = mx3_videobuf_setup, |
| 433 | .buf_prepare = mx3_videobuf_prepare, | ||
| 434 | .buf_queue = mx3_videobuf_queue, | 446 | .buf_queue = mx3_videobuf_queue, |
| 435 | .buf_cleanup = mx3_videobuf_release, | 447 | .buf_cleanup = mx3_videobuf_release, |
| 436 | .buf_init = mx3_videobuf_init, | 448 | .buf_init = mx3_videobuf_init, |
| @@ -514,6 +526,7 @@ static int mx3_camera_add_device(struct soc_camera_device *icd) | |||
| 514 | 526 | ||
| 515 | mx3_camera_activate(mx3_cam, icd); | 527 | mx3_camera_activate(mx3_cam, icd); |
| 516 | 528 | ||
| 529 | mx3_cam->buf_total = 0; | ||
| 517 | mx3_cam->icd = icd; | 530 | mx3_cam->icd = icd; |
| 518 | 531 | ||
| 519 | dev_info(icd->parent, "MX3 Camera driver attached to camera %d\n", | 532 | dev_info(icd->parent, "MX3 Camera driver attached to camera %d\n", |
| @@ -548,58 +561,27 @@ static int test_platform_param(struct mx3_camera_dev *mx3_cam, | |||
| 548 | unsigned char buswidth, unsigned long *flags) | 561 | unsigned char buswidth, unsigned long *flags) |
| 549 | { | 562 | { |
| 550 | /* | 563 | /* |
| 564 | * If requested data width is supported by the platform, use it or any | ||
| 565 | * possible lower value - i.MX31 is smart enough to shift bits | ||
| 566 | */ | ||
| 567 | if (buswidth > fls(mx3_cam->width_flags)) | ||
| 568 | return -EINVAL; | ||
| 569 | |||
| 570 | /* | ||
| 551 | * Platform specified synchronization and pixel clock polarities are | 571 | * Platform specified synchronization and pixel clock polarities are |
| 552 | * only a recommendation and are only used during probing. MX3x | 572 | * only a recommendation and are only used during probing. MX3x |
| 553 | * camera interface only works in master mode, i.e., uses HSYNC and | 573 | * camera interface only works in master mode, i.e., uses HSYNC and |
| 554 | * VSYNC signals from the sensor | 574 | * VSYNC signals from the sensor |
| 555 | */ | 575 | */ |
| 556 | *flags = SOCAM_MASTER | | 576 | *flags = V4L2_MBUS_MASTER | |
| 557 | SOCAM_HSYNC_ACTIVE_HIGH | | 577 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | |
| 558 | SOCAM_HSYNC_ACTIVE_LOW | | 578 | V4L2_MBUS_HSYNC_ACTIVE_LOW | |
| 559 | SOCAM_VSYNC_ACTIVE_HIGH | | 579 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | |
| 560 | SOCAM_VSYNC_ACTIVE_LOW | | 580 | V4L2_MBUS_VSYNC_ACTIVE_LOW | |
| 561 | SOCAM_PCLK_SAMPLE_RISING | | 581 | V4L2_MBUS_PCLK_SAMPLE_RISING | |
| 562 | SOCAM_PCLK_SAMPLE_FALLING | | 582 | V4L2_MBUS_PCLK_SAMPLE_FALLING | |
| 563 | SOCAM_DATA_ACTIVE_HIGH | | 583 | V4L2_MBUS_DATA_ACTIVE_HIGH | |
| 564 | SOCAM_DATA_ACTIVE_LOW; | 584 | V4L2_MBUS_DATA_ACTIVE_LOW; |
| 565 | |||
| 566 | /* | ||
| 567 | * If requested data width is supported by the platform, use it or any | ||
| 568 | * possible lower value - i.MX31 is smart enough to schift bits | ||
| 569 | */ | ||
| 570 | if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15) | ||
| 571 | *flags |= SOCAM_DATAWIDTH_15 | SOCAM_DATAWIDTH_10 | | ||
| 572 | SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_4; | ||
| 573 | else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10) | ||
| 574 | *flags |= SOCAM_DATAWIDTH_10 | SOCAM_DATAWIDTH_8 | | ||
| 575 | SOCAM_DATAWIDTH_4; | ||
| 576 | else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8) | ||
| 577 | *flags |= SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_4; | ||
| 578 | else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4) | ||
| 579 | *flags |= SOCAM_DATAWIDTH_4; | ||
| 580 | |||
| 581 | switch (buswidth) { | ||
| 582 | case 15: | ||
| 583 | if (!(*flags & SOCAM_DATAWIDTH_15)) | ||
| 584 | return -EINVAL; | ||
| 585 | break; | ||
| 586 | case 10: | ||
| 587 | if (!(*flags & SOCAM_DATAWIDTH_10)) | ||
| 588 | return -EINVAL; | ||
| 589 | break; | ||
| 590 | case 8: | ||
| 591 | if (!(*flags & SOCAM_DATAWIDTH_8)) | ||
| 592 | return -EINVAL; | ||
| 593 | break; | ||
| 594 | case 4: | ||
| 595 | if (!(*flags & SOCAM_DATAWIDTH_4)) | ||
| 596 | return -EINVAL; | ||
| 597 | break; | ||
| 598 | default: | ||
| 599 | dev_warn(mx3_cam->soc_host.v4l2_dev.dev, | ||
| 600 | "Unsupported bus width %d\n", buswidth); | ||
| 601 | return -EINVAL; | ||
| 602 | } | ||
| 603 | 585 | ||
| 604 | return 0; | 586 | return 0; |
| 605 | } | 587 | } |
| @@ -607,9 +589,11 @@ static int test_platform_param(struct mx3_camera_dev *mx3_cam, | |||
| 607 | static int mx3_camera_try_bus_param(struct soc_camera_device *icd, | 589 | static int mx3_camera_try_bus_param(struct soc_camera_device *icd, |
| 608 | const unsigned int depth) | 590 | const unsigned int depth) |
| 609 | { | 591 | { |
| 592 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
| 610 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 593 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
| 611 | struct mx3_camera_dev *mx3_cam = ici->priv; | 594 | struct mx3_camera_dev *mx3_cam = ici->priv; |
| 612 | unsigned long bus_flags, camera_flags; | 595 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; |
| 596 | unsigned long bus_flags, common_flags; | ||
| 613 | int ret = test_platform_param(mx3_cam, depth, &bus_flags); | 597 | int ret = test_platform_param(mx3_cam, depth, &bus_flags); |
| 614 | 598 | ||
| 615 | dev_dbg(icd->parent, "request bus width %d bit: %d\n", depth, ret); | 599 | dev_dbg(icd->parent, "request bus width %d bit: %d\n", depth, ret); |
| @@ -617,15 +601,21 @@ static int mx3_camera_try_bus_param(struct soc_camera_device *icd, | |||
| 617 | if (ret < 0) | 601 | if (ret < 0) |
| 618 | return ret; | 602 | return ret; |
| 619 | 603 | ||
| 620 | camera_flags = icd->ops->query_bus_param(icd); | 604 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); |
| 621 | 605 | if (!ret) { | |
| 622 | ret = soc_camera_bus_param_compatible(camera_flags, bus_flags); | 606 | common_flags = soc_mbus_config_compatible(&cfg, |
| 623 | if (ret < 0) | 607 | bus_flags); |
| 624 | dev_warn(icd->parent, | 608 | if (!common_flags) { |
| 625 | "Flags incompatible: camera %lx, host %lx\n", | 609 | dev_warn(icd->parent, |
| 626 | camera_flags, bus_flags); | 610 | "Flags incompatible: camera 0x%x, host 0x%lx\n", |
| 611 | cfg.flags, bus_flags); | ||
| 612 | return -EINVAL; | ||
| 613 | } | ||
| 614 | } else if (ret != -ENOIOCTLCMD) { | ||
| 615 | return ret; | ||
| 616 | } | ||
| 627 | 617 | ||
| 628 | return ret; | 618 | return 0; |
| 629 | } | 619 | } |
| 630 | 620 | ||
| 631 | static bool chan_filter(struct dma_chan *chan, void *arg) | 621 | static bool chan_filter(struct dma_chan *chan, void *arg) |
| @@ -994,9 +984,11 @@ static int mx3_camera_querycap(struct soc_camera_host *ici, | |||
| 994 | 984 | ||
| 995 | static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | 985 | static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) |
| 996 | { | 986 | { |
| 987 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
| 997 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 988 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
| 998 | struct mx3_camera_dev *mx3_cam = ici->priv; | 989 | struct mx3_camera_dev *mx3_cam = ici->priv; |
| 999 | unsigned long bus_flags, camera_flags, common_flags; | 990 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; |
| 991 | unsigned long bus_flags, common_flags; | ||
| 1000 | u32 dw, sens_conf; | 992 | u32 dw, sens_conf; |
| 1001 | const struct soc_mbus_pixelfmt *fmt; | 993 | const struct soc_mbus_pixelfmt *fmt; |
| 1002 | int buswidth; | 994 | int buswidth; |
| @@ -1008,83 +1000,76 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
| 1008 | if (!fmt) | 1000 | if (!fmt) |
| 1009 | return -EINVAL; | 1001 | return -EINVAL; |
| 1010 | 1002 | ||
| 1011 | buswidth = fmt->bits_per_sample; | ||
| 1012 | ret = test_platform_param(mx3_cam, buswidth, &bus_flags); | ||
| 1013 | |||
| 1014 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | 1003 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); |
| 1015 | if (!xlate) { | 1004 | if (!xlate) { |
| 1016 | dev_warn(dev, "Format %x not found\n", pixfmt); | 1005 | dev_warn(dev, "Format %x not found\n", pixfmt); |
| 1017 | return -EINVAL; | 1006 | return -EINVAL; |
| 1018 | } | 1007 | } |
| 1019 | 1008 | ||
| 1009 | buswidth = fmt->bits_per_sample; | ||
| 1010 | ret = test_platform_param(mx3_cam, buswidth, &bus_flags); | ||
| 1011 | |||
| 1020 | dev_dbg(dev, "requested bus width %d bit: %d\n", buswidth, ret); | 1012 | dev_dbg(dev, "requested bus width %d bit: %d\n", buswidth, ret); |
| 1021 | 1013 | ||
| 1022 | if (ret < 0) | 1014 | if (ret < 0) |
| 1023 | return ret; | 1015 | return ret; |
| 1024 | 1016 | ||
| 1025 | camera_flags = icd->ops->query_bus_param(icd); | 1017 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); |
| 1026 | 1018 | if (!ret) { | |
| 1027 | common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags); | 1019 | common_flags = soc_mbus_config_compatible(&cfg, |
| 1028 | dev_dbg(dev, "Flags cam: 0x%lx host: 0x%lx common: 0x%lx\n", | 1020 | bus_flags); |
| 1029 | camera_flags, bus_flags, common_flags); | 1021 | if (!common_flags) { |
| 1030 | if (!common_flags) { | 1022 | dev_warn(icd->parent, |
| 1031 | dev_dbg(dev, "no common flags"); | 1023 | "Flags incompatible: camera 0x%x, host 0x%lx\n", |
| 1032 | return -EINVAL; | 1024 | cfg.flags, bus_flags); |
| 1025 | return -EINVAL; | ||
| 1026 | } | ||
| 1027 | } else if (ret != -ENOIOCTLCMD) { | ||
| 1028 | return ret; | ||
| 1029 | } else { | ||
| 1030 | common_flags = bus_flags; | ||
| 1033 | } | 1031 | } |
| 1034 | 1032 | ||
| 1033 | dev_dbg(dev, "Flags cam: 0x%x host: 0x%lx common: 0x%lx\n", | ||
| 1034 | cfg.flags, bus_flags, common_flags); | ||
| 1035 | |||
| 1035 | /* Make choices, based on platform preferences */ | 1036 | /* Make choices, based on platform preferences */ |
| 1036 | if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && | 1037 | if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && |
| 1037 | (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { | 1038 | (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { |
| 1038 | if (mx3_cam->platform_flags & MX3_CAMERA_HSP) | 1039 | if (mx3_cam->platform_flags & MX3_CAMERA_HSP) |
| 1039 | common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; | 1040 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; |
| 1040 | else | 1041 | else |
| 1041 | common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; | 1042 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; |
| 1042 | } | 1043 | } |
| 1043 | 1044 | ||
| 1044 | if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && | 1045 | if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && |
| 1045 | (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { | 1046 | (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { |
| 1046 | if (mx3_cam->platform_flags & MX3_CAMERA_VSP) | 1047 | if (mx3_cam->platform_flags & MX3_CAMERA_VSP) |
| 1047 | common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; | 1048 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; |
| 1048 | else | 1049 | else |
| 1049 | common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; | 1050 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; |
| 1050 | } | 1051 | } |
| 1051 | 1052 | ||
| 1052 | if ((common_flags & SOCAM_DATA_ACTIVE_HIGH) && | 1053 | if ((common_flags & V4L2_MBUS_DATA_ACTIVE_HIGH) && |
| 1053 | (common_flags & SOCAM_DATA_ACTIVE_LOW)) { | 1054 | (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW)) { |
| 1054 | if (mx3_cam->platform_flags & MX3_CAMERA_DP) | 1055 | if (mx3_cam->platform_flags & MX3_CAMERA_DP) |
| 1055 | common_flags &= ~SOCAM_DATA_ACTIVE_HIGH; | 1056 | common_flags &= ~V4L2_MBUS_DATA_ACTIVE_HIGH; |
| 1056 | else | 1057 | else |
| 1057 | common_flags &= ~SOCAM_DATA_ACTIVE_LOW; | 1058 | common_flags &= ~V4L2_MBUS_DATA_ACTIVE_LOW; |
| 1058 | } | 1059 | } |
| 1059 | 1060 | ||
| 1060 | if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && | 1061 | if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && |
| 1061 | (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { | 1062 | (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { |
| 1062 | if (mx3_cam->platform_flags & MX3_CAMERA_PCP) | 1063 | if (mx3_cam->platform_flags & MX3_CAMERA_PCP) |
| 1063 | common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; | 1064 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; |
| 1064 | else | 1065 | else |
| 1065 | common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; | 1066 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; |
| 1066 | } | 1067 | } |
| 1067 | 1068 | ||
| 1068 | /* | 1069 | cfg.flags = common_flags; |
| 1069 | * Make the camera work in widest common mode, we'll take care of | 1070 | ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); |
| 1070 | * the rest | 1071 | if (ret < 0 && ret != -ENOIOCTLCMD) { |
| 1071 | */ | 1072 | dev_dbg(dev, "camera s_mbus_config(0x%lx) returned %d\n", |
| 1072 | if (common_flags & SOCAM_DATAWIDTH_15) | ||
| 1073 | common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | | ||
| 1074 | SOCAM_DATAWIDTH_15; | ||
| 1075 | else if (common_flags & SOCAM_DATAWIDTH_10) | ||
| 1076 | common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | | ||
| 1077 | SOCAM_DATAWIDTH_10; | ||
| 1078 | else if (common_flags & SOCAM_DATAWIDTH_8) | ||
| 1079 | common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | | ||
| 1080 | SOCAM_DATAWIDTH_8; | ||
| 1081 | else | ||
| 1082 | common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | | ||
| 1083 | SOCAM_DATAWIDTH_4; | ||
| 1084 | |||
| 1085 | ret = icd->ops->set_bus_param(icd, common_flags); | ||
| 1086 | if (ret < 0) { | ||
| 1087 | dev_dbg(dev, "camera set_bus_param(%lx) returned %d\n", | ||
| 1088 | common_flags, ret); | 1073 | common_flags, ret); |
| 1089 | return ret; | 1074 | return ret; |
| 1090 | } | 1075 | } |
| @@ -1108,13 +1093,13 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
| 1108 | /* This has been set in mx3_camera_activate(), but we clear it above */ | 1093 | /* This has been set in mx3_camera_activate(), but we clear it above */ |
| 1109 | sens_conf |= CSI_SENS_CONF_DATA_FMT_BAYER; | 1094 | sens_conf |= CSI_SENS_CONF_DATA_FMT_BAYER; |
| 1110 | 1095 | ||
| 1111 | if (common_flags & SOCAM_PCLK_SAMPLE_FALLING) | 1096 | if (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) |
| 1112 | sens_conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT; | 1097 | sens_conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT; |
| 1113 | if (common_flags & SOCAM_HSYNC_ACTIVE_LOW) | 1098 | if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) |
| 1114 | sens_conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT; | 1099 | sens_conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT; |
| 1115 | if (common_flags & SOCAM_VSYNC_ACTIVE_LOW) | 1100 | if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) |
| 1116 | sens_conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT; | 1101 | sens_conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT; |
| 1117 | if (common_flags & SOCAM_DATA_ACTIVE_LOW) | 1102 | if (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW) |
| 1118 | sens_conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT; | 1103 | sens_conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT; |
| 1119 | 1104 | ||
| 1120 | /* Just do what we're asked to do */ | 1105 | /* Just do what we're asked to do */ |
| @@ -1199,6 +1184,14 @@ static int __devinit mx3_camera_probe(struct platform_device *pdev) | |||
| 1199 | "data widths, using default 8 bit\n"); | 1184 | "data widths, using default 8 bit\n"); |
| 1200 | mx3_cam->platform_flags |= MX3_CAMERA_DATAWIDTH_8; | 1185 | mx3_cam->platform_flags |= MX3_CAMERA_DATAWIDTH_8; |
| 1201 | } | 1186 | } |
| 1187 | if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4) | ||
| 1188 | mx3_cam->width_flags = 1 << 3; | ||
| 1189 | if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8) | ||
| 1190 | mx3_cam->width_flags |= 1 << 7; | ||
| 1191 | if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10) | ||
| 1192 | mx3_cam->width_flags |= 1 << 9; | ||
| 1193 | if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15) | ||
| 1194 | mx3_cam->width_flags |= 1 << 14; | ||
| 1202 | 1195 | ||
| 1203 | mx3_cam->mclk = mx3_cam->pdata->mclk_10khz * 10000; | 1196 | mx3_cam->mclk = mx3_cam->pdata->mclk_10khz * 10000; |
| 1204 | if (!mx3_cam->mclk) { | 1197 | if (!mx3_cam->mclk) { |
| @@ -1281,8 +1274,6 @@ static int __devexit mx3_camera_remove(struct platform_device *pdev) | |||
| 1281 | 1274 | ||
| 1282 | dmaengine_put(); | 1275 | dmaengine_put(); |
| 1283 | 1276 | ||
| 1284 | dev_info(&pdev->dev, "i.MX3x Camera driver unloaded\n"); | ||
| 1285 | |||
| 1286 | return 0; | 1277 | return 0; |
| 1287 | } | 1278 | } |
| 1288 | 1279 | ||
diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c index 30d8896bb710..9c5c19f142de 100644 --- a/drivers/media/video/omap/omap_vout.c +++ b/drivers/media/video/omap/omap_vout.c | |||
| @@ -833,6 +833,15 @@ static void omap_vout_buffer_release(struct videobuf_queue *q, | |||
| 833 | /* | 833 | /* |
| 834 | * File operations | 834 | * File operations |
| 835 | */ | 835 | */ |
| 836 | static unsigned int omap_vout_poll(struct file *file, | ||
| 837 | struct poll_table_struct *wait) | ||
| 838 | { | ||
| 839 | struct omap_vout_device *vout = file->private_data; | ||
| 840 | struct videobuf_queue *q = &vout->vbq; | ||
| 841 | |||
| 842 | return videobuf_poll_stream(file, q, wait); | ||
| 843 | } | ||
| 844 | |||
| 836 | static void omap_vout_vm_open(struct vm_area_struct *vma) | 845 | static void omap_vout_vm_open(struct vm_area_struct *vma) |
| 837 | { | 846 | { |
| 838 | struct omap_vout_device *vout = vma->vm_private_data; | 847 | struct omap_vout_device *vout = vma->vm_private_data; |
| @@ -1861,6 +1870,7 @@ static const struct v4l2_ioctl_ops vout_ioctl_ops = { | |||
| 1861 | 1870 | ||
| 1862 | static const struct v4l2_file_operations omap_vout_fops = { | 1871 | static const struct v4l2_file_operations omap_vout_fops = { |
| 1863 | .owner = THIS_MODULE, | 1872 | .owner = THIS_MODULE, |
| 1873 | .poll = omap_vout_poll, | ||
| 1864 | .unlocked_ioctl = video_ioctl2, | 1874 | .unlocked_ioctl = video_ioctl2, |
| 1865 | .mmap = omap_vout_mmap, | 1875 | .mmap = omap_vout_mmap, |
| 1866 | .open = omap_vout_open, | 1876 | .open = omap_vout_open, |
diff --git a/drivers/media/video/omap1_camera.c b/drivers/media/video/omap1_camera.c index 8a947e603aca..e87ae2f634b2 100644 --- a/drivers/media/video/omap1_camera.c +++ b/drivers/media/video/omap1_camera.c | |||
| @@ -102,10 +102,10 @@ | |||
| 102 | /* end of OMAP1 Camera Interface registers */ | 102 | /* end of OMAP1 Camera Interface registers */ |
| 103 | 103 | ||
| 104 | 104 | ||
| 105 | #define SOCAM_BUS_FLAGS (SOCAM_MASTER | \ | 105 | #define SOCAM_BUS_FLAGS (V4L2_MBUS_MASTER | \ |
| 106 | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | \ | 106 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | \ |
| 107 | SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING | \ | 107 | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | \ |
| 108 | SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8) | 108 | V4L2_MBUS_DATA_ACTIVE_HIGH) |
| 109 | 109 | ||
| 110 | 110 | ||
| 111 | #define FIFO_SIZE ((THRESHOLD_MASK >> THRESHOLD_SHIFT) + 1) | 111 | #define FIFO_SIZE ((THRESHOLD_MASK >> THRESHOLD_SHIFT) + 1) |
| @@ -1438,41 +1438,55 @@ static int omap1_cam_querycap(struct soc_camera_host *ici, | |||
| 1438 | static int omap1_cam_set_bus_param(struct soc_camera_device *icd, | 1438 | static int omap1_cam_set_bus_param(struct soc_camera_device *icd, |
| 1439 | __u32 pixfmt) | 1439 | __u32 pixfmt) |
| 1440 | { | 1440 | { |
| 1441 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
| 1441 | struct device *dev = icd->parent; | 1442 | struct device *dev = icd->parent; |
| 1442 | struct soc_camera_host *ici = to_soc_camera_host(dev); | 1443 | struct soc_camera_host *ici = to_soc_camera_host(dev); |
| 1443 | struct omap1_cam_dev *pcdev = ici->priv; | 1444 | struct omap1_cam_dev *pcdev = ici->priv; |
| 1444 | const struct soc_camera_format_xlate *xlate; | 1445 | const struct soc_camera_format_xlate *xlate; |
| 1445 | const struct soc_mbus_pixelfmt *fmt; | 1446 | const struct soc_mbus_pixelfmt *fmt; |
| 1446 | unsigned long camera_flags, common_flags; | 1447 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; |
| 1448 | unsigned long common_flags; | ||
| 1447 | u32 ctrlclock, mode; | 1449 | u32 ctrlclock, mode; |
| 1448 | int ret; | 1450 | int ret; |
| 1449 | 1451 | ||
| 1450 | camera_flags = icd->ops->query_bus_param(icd); | 1452 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); |
| 1451 | 1453 | if (!ret) { | |
| 1452 | common_flags = soc_camera_bus_param_compatible(camera_flags, | 1454 | common_flags = soc_mbus_config_compatible(&cfg, SOCAM_BUS_FLAGS); |
| 1453 | SOCAM_BUS_FLAGS); | 1455 | if (!common_flags) { |
| 1454 | if (!common_flags) | 1456 | dev_warn(dev, |
| 1455 | return -EINVAL; | 1457 | "Flags incompatible: camera 0x%x, host 0x%x\n", |
| 1458 | cfg.flags, SOCAM_BUS_FLAGS); | ||
| 1459 | return -EINVAL; | ||
| 1460 | } | ||
| 1461 | } else if (ret != -ENOIOCTLCMD) { | ||
| 1462 | return ret; | ||
| 1463 | } else { | ||
| 1464 | common_flags = SOCAM_BUS_FLAGS; | ||
| 1465 | } | ||
| 1456 | 1466 | ||
| 1457 | /* Make choices, possibly based on platform configuration */ | 1467 | /* Make choices, possibly based on platform configuration */ |
| 1458 | if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && | 1468 | if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && |
| 1459 | (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { | 1469 | (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { |
| 1460 | if (!pcdev->pdata || | 1470 | if (!pcdev->pdata || |
| 1461 | pcdev->pdata->flags & OMAP1_CAMERA_LCLK_RISING) | 1471 | pcdev->pdata->flags & OMAP1_CAMERA_LCLK_RISING) |
| 1462 | common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; | 1472 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; |
| 1463 | else | 1473 | else |
| 1464 | common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; | 1474 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; |
| 1465 | } | 1475 | } |
| 1466 | 1476 | ||
| 1467 | ret = icd->ops->set_bus_param(icd, common_flags); | 1477 | cfg.flags = common_flags; |
| 1468 | if (ret < 0) | 1478 | ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); |
| 1479 | if (ret < 0 && ret != -ENOIOCTLCMD) { | ||
| 1480 | dev_dbg(dev, "camera s_mbus_config(0x%lx) returned %d\n", | ||
| 1481 | common_flags, ret); | ||
| 1469 | return ret; | 1482 | return ret; |
| 1483 | } | ||
| 1470 | 1484 | ||
| 1471 | ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK); | 1485 | ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK); |
| 1472 | if (ctrlclock & LCLK_EN) | 1486 | if (ctrlclock & LCLK_EN) |
| 1473 | CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN); | 1487 | CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN); |
| 1474 | 1488 | ||
| 1475 | if (common_flags & SOCAM_PCLK_SAMPLE_RISING) { | 1489 | if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) { |
| 1476 | dev_dbg(dev, "CTRLCLOCK_REG |= POLCLK\n"); | 1490 | dev_dbg(dev, "CTRLCLOCK_REG |= POLCLK\n"); |
| 1477 | ctrlclock |= POLCLK; | 1491 | ctrlclock |= POLCLK; |
| 1478 | } else { | 1492 | } else { |
| @@ -1565,10 +1579,10 @@ static int __init omap1_cam_probe(struct platform_device *pdev) | |||
| 1565 | pcdev->clk = clk; | 1579 | pcdev->clk = clk; |
| 1566 | 1580 | ||
| 1567 | pcdev->pdata = pdev->dev.platform_data; | 1581 | pcdev->pdata = pdev->dev.platform_data; |
| 1568 | pcdev->pflags = pcdev->pdata->flags; | 1582 | if (pcdev->pdata) { |
| 1569 | 1583 | pcdev->pflags = pcdev->pdata->flags; | |
| 1570 | if (pcdev->pdata) | ||
| 1571 | pcdev->camexclk = pcdev->pdata->camexclk_khz * 1000; | 1584 | pcdev->camexclk = pcdev->pdata->camexclk_khz * 1000; |
| 1585 | } | ||
| 1572 | 1586 | ||
| 1573 | switch (pcdev->camexclk) { | 1587 | switch (pcdev->camexclk) { |
| 1574 | case 6000000: | 1588 | case 6000000: |
| @@ -1578,6 +1592,7 @@ static int __init omap1_cam_probe(struct platform_device *pdev) | |||
| 1578 | case 24000000: | 1592 | case 24000000: |
| 1579 | break; | 1593 | break; |
| 1580 | default: | 1594 | default: |
| 1595 | /* pcdev->camexclk != 0 => pcdev->pdata != NULL */ | ||
| 1581 | dev_warn(&pdev->dev, | 1596 | dev_warn(&pdev->dev, |
| 1582 | "Incorrect sensor clock frequency %ld kHz, " | 1597 | "Incorrect sensor clock frequency %ld kHz, " |
| 1583 | "should be one of 0, 6, 8, 9.6, 12 or 24 MHz, " | 1598 | "should be one of 0, 6, 8, 9.6, 12 or 24 MHz, " |
| @@ -1585,8 +1600,7 @@ static int __init omap1_cam_probe(struct platform_device *pdev) | |||
| 1585 | pcdev->pdata->camexclk_khz); | 1600 | pcdev->pdata->camexclk_khz); |
| 1586 | pcdev->camexclk = 0; | 1601 | pcdev->camexclk = 0; |
| 1587 | case 0: | 1602 | case 0: |
| 1588 | dev_info(&pdev->dev, | 1603 | dev_info(&pdev->dev, "Not providing sensor clock\n"); |
| 1589 | "Not providing sensor clock\n"); | ||
| 1590 | } | 1604 | } |
| 1591 | 1605 | ||
| 1592 | INIT_LIST_HEAD(&pcdev->capture); | 1606 | INIT_LIST_HEAD(&pcdev->capture); |
| @@ -1716,5 +1730,5 @@ MODULE_PARM_DESC(sg_mode, "videobuf mode, 0: dma-contig (default), 1: dma-sg"); | |||
| 1716 | MODULE_DESCRIPTION("OMAP1 Camera Interface driver"); | 1730 | MODULE_DESCRIPTION("OMAP1 Camera Interface driver"); |
| 1717 | MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>"); | 1731 | MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>"); |
| 1718 | MODULE_LICENSE("GPL v2"); | 1732 | MODULE_LICENSE("GPL v2"); |
| 1719 | MODULE_LICENSE(DRIVER_VERSION); | 1733 | MODULE_VERSION(DRIVER_VERSION); |
| 1720 | MODULE_ALIAS("platform:" DRIVER_NAME); | 1734 | MODULE_ALIAS("platform:" DRIVER_NAME); |
diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c index 678e1252047a..b818cacf420f 100644 --- a/drivers/media/video/omap3isp/isp.c +++ b/drivers/media/video/omap3isp/isp.c | |||
| @@ -1704,6 +1704,7 @@ static int isp_register_entities(struct isp_device *isp) | |||
| 1704 | isp->media_dev.dev = isp->dev; | 1704 | isp->media_dev.dev = isp->dev; |
| 1705 | strlcpy(isp->media_dev.model, "TI OMAP3 ISP", | 1705 | strlcpy(isp->media_dev.model, "TI OMAP3 ISP", |
| 1706 | sizeof(isp->media_dev.model)); | 1706 | sizeof(isp->media_dev.model)); |
| 1707 | isp->media_dev.hw_revision = isp->revision; | ||
| 1707 | isp->media_dev.link_notify = isp_pipeline_link_notify; | 1708 | isp->media_dev.link_notify = isp_pipeline_link_notify; |
| 1708 | ret = media_device_register(&isp->media_dev); | 1709 | ret = media_device_register(&isp->media_dev); |
| 1709 | if (ret < 0) { | 1710 | if (ret < 0) { |
| @@ -2210,6 +2211,8 @@ error: | |||
| 2210 | regulator_put(isp->isp_csiphy2.vdd); | 2211 | regulator_put(isp->isp_csiphy2.vdd); |
| 2211 | regulator_put(isp->isp_csiphy1.vdd); | 2212 | regulator_put(isp->isp_csiphy1.vdd); |
| 2212 | platform_set_drvdata(pdev, NULL); | 2213 | platform_set_drvdata(pdev, NULL); |
| 2214 | |||
| 2215 | mutex_destroy(&isp->isp_mutex); | ||
| 2213 | kfree(isp); | 2216 | kfree(isp); |
| 2214 | 2217 | ||
| 2215 | return ret; | 2218 | return ret; |
diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c index 253fdcce2df2..b0b0fa5a3572 100644 --- a/drivers/media/video/omap3isp/ispccdc.c +++ b/drivers/media/video/omap3isp/ispccdc.c | |||
| @@ -1836,7 +1836,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, | |||
| 1836 | * callers to request an output size bigger than the input size | 1836 | * callers to request an output size bigger than the input size |
| 1837 | * up to the nearest multiple of 16. | 1837 | * up to the nearest multiple of 16. |
| 1838 | */ | 1838 | */ |
| 1839 | fmt->width = clamp_t(u32, width, 32, (fmt->width + 15) & ~15); | 1839 | fmt->width = clamp_t(u32, width, 32, fmt->width + 15); |
| 1840 | fmt->width &= ~15; | 1840 | fmt->width &= ~15; |
| 1841 | fmt->height = clamp_t(u32, height, 32, fmt->height); | 1841 | fmt->height = clamp_t(u32, height, 32, fmt->height); |
| 1842 | break; | 1842 | break; |
| @@ -2152,6 +2152,37 @@ static const struct media_entity_operations ccdc_media_ops = { | |||
| 2152 | .link_setup = ccdc_link_setup, | 2152 | .link_setup = ccdc_link_setup, |
| 2153 | }; | 2153 | }; |
| 2154 | 2154 | ||
| 2155 | void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc) | ||
| 2156 | { | ||
| 2157 | v4l2_device_unregister_subdev(&ccdc->subdev); | ||
| 2158 | omap3isp_video_unregister(&ccdc->video_out); | ||
| 2159 | } | ||
| 2160 | |||
| 2161 | int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc, | ||
| 2162 | struct v4l2_device *vdev) | ||
| 2163 | { | ||
| 2164 | int ret; | ||
| 2165 | |||
| 2166 | /* Register the subdev and video node. */ | ||
| 2167 | ret = v4l2_device_register_subdev(vdev, &ccdc->subdev); | ||
| 2168 | if (ret < 0) | ||
| 2169 | goto error; | ||
| 2170 | |||
| 2171 | ret = omap3isp_video_register(&ccdc->video_out, vdev); | ||
| 2172 | if (ret < 0) | ||
| 2173 | goto error; | ||
| 2174 | |||
| 2175 | return 0; | ||
| 2176 | |||
| 2177 | error: | ||
| 2178 | omap3isp_ccdc_unregister_entities(ccdc); | ||
| 2179 | return ret; | ||
| 2180 | } | ||
| 2181 | |||
| 2182 | /* ----------------------------------------------------------------------------- | ||
| 2183 | * ISP CCDC initialisation and cleanup | ||
| 2184 | */ | ||
| 2185 | |||
| 2155 | /* | 2186 | /* |
| 2156 | * ccdc_init_entities - Initialize V4L2 subdev and media entity | 2187 | * ccdc_init_entities - Initialize V4L2 subdev and media entity |
| 2157 | * @ccdc: ISP CCDC module | 2188 | * @ccdc: ISP CCDC module |
| @@ -2193,50 +2224,23 @@ static int ccdc_init_entities(struct isp_ccdc_device *ccdc) | |||
| 2193 | 2224 | ||
| 2194 | ret = omap3isp_video_init(&ccdc->video_out, "CCDC"); | 2225 | ret = omap3isp_video_init(&ccdc->video_out, "CCDC"); |
| 2195 | if (ret < 0) | 2226 | if (ret < 0) |
| 2196 | return ret; | 2227 | goto error_video; |
| 2197 | 2228 | ||
| 2198 | /* Connect the CCDC subdev to the video node. */ | 2229 | /* Connect the CCDC subdev to the video node. */ |
| 2199 | ret = media_entity_create_link(&ccdc->subdev.entity, CCDC_PAD_SOURCE_OF, | 2230 | ret = media_entity_create_link(&ccdc->subdev.entity, CCDC_PAD_SOURCE_OF, |
| 2200 | &ccdc->video_out.video.entity, 0, 0); | 2231 | &ccdc->video_out.video.entity, 0, 0); |
| 2201 | if (ret < 0) | 2232 | if (ret < 0) |
| 2202 | return ret; | 2233 | goto error_link; |
| 2203 | |||
| 2204 | return 0; | ||
| 2205 | } | ||
| 2206 | |||
| 2207 | void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc) | ||
| 2208 | { | ||
| 2209 | media_entity_cleanup(&ccdc->subdev.entity); | ||
| 2210 | |||
| 2211 | v4l2_device_unregister_subdev(&ccdc->subdev); | ||
| 2212 | omap3isp_video_unregister(&ccdc->video_out); | ||
| 2213 | } | ||
| 2214 | |||
| 2215 | int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc, | ||
| 2216 | struct v4l2_device *vdev) | ||
| 2217 | { | ||
| 2218 | int ret; | ||
| 2219 | |||
| 2220 | /* Register the subdev and video node. */ | ||
| 2221 | ret = v4l2_device_register_subdev(vdev, &ccdc->subdev); | ||
| 2222 | if (ret < 0) | ||
| 2223 | goto error; | ||
| 2224 | |||
| 2225 | ret = omap3isp_video_register(&ccdc->video_out, vdev); | ||
| 2226 | if (ret < 0) | ||
| 2227 | goto error; | ||
| 2228 | 2234 | ||
| 2229 | return 0; | 2235 | return 0; |
| 2230 | 2236 | ||
| 2231 | error: | 2237 | error_link: |
| 2232 | omap3isp_ccdc_unregister_entities(ccdc); | 2238 | omap3isp_video_cleanup(&ccdc->video_out); |
| 2239 | error_video: | ||
| 2240 | media_entity_cleanup(me); | ||
| 2233 | return ret; | 2241 | return ret; |
| 2234 | } | 2242 | } |
| 2235 | 2243 | ||
| 2236 | /* ----------------------------------------------------------------------------- | ||
| 2237 | * ISP CCDC initialisation and cleanup | ||
| 2238 | */ | ||
| 2239 | |||
| 2240 | /* | 2244 | /* |
| 2241 | * omap3isp_ccdc_init - CCDC module initialization. | 2245 | * omap3isp_ccdc_init - CCDC module initialization. |
| 2242 | * @dev: Device pointer specific to the OMAP3 ISP. | 2246 | * @dev: Device pointer specific to the OMAP3 ISP. |
| @@ -2248,6 +2252,7 @@ error: | |||
| 2248 | int omap3isp_ccdc_init(struct isp_device *isp) | 2252 | int omap3isp_ccdc_init(struct isp_device *isp) |
| 2249 | { | 2253 | { |
| 2250 | struct isp_ccdc_device *ccdc = &isp->isp_ccdc; | 2254 | struct isp_ccdc_device *ccdc = &isp->isp_ccdc; |
| 2255 | int ret; | ||
| 2251 | 2256 | ||
| 2252 | spin_lock_init(&ccdc->lock); | 2257 | spin_lock_init(&ccdc->lock); |
| 2253 | init_waitqueue_head(&ccdc->wait); | 2258 | init_waitqueue_head(&ccdc->wait); |
| @@ -2276,7 +2281,13 @@ int omap3isp_ccdc_init(struct isp_device *isp) | |||
| 2276 | ccdc->update = OMAP3ISP_CCDC_BLCLAMP; | 2281 | ccdc->update = OMAP3ISP_CCDC_BLCLAMP; |
| 2277 | ccdc_apply_controls(ccdc); | 2282 | ccdc_apply_controls(ccdc); |
| 2278 | 2283 | ||
| 2279 | return ccdc_init_entities(ccdc); | 2284 | ret = ccdc_init_entities(ccdc); |
| 2285 | if (ret < 0) { | ||
| 2286 | mutex_destroy(&ccdc->ioctl_lock); | ||
| 2287 | return ret; | ||
| 2288 | } | ||
| 2289 | |||
| 2290 | return 0; | ||
| 2280 | } | 2291 | } |
| 2281 | 2292 | ||
| 2282 | /* | 2293 | /* |
| @@ -2287,6 +2298,9 @@ void omap3isp_ccdc_cleanup(struct isp_device *isp) | |||
| 2287 | { | 2298 | { |
| 2288 | struct isp_ccdc_device *ccdc = &isp->isp_ccdc; | 2299 | struct isp_ccdc_device *ccdc = &isp->isp_ccdc; |
| 2289 | 2300 | ||
| 2301 | omap3isp_video_cleanup(&ccdc->video_out); | ||
| 2302 | media_entity_cleanup(&ccdc->subdev.entity); | ||
| 2303 | |||
| 2290 | /* Free LSC requests. As the CCDC is stopped there's no active request, | 2304 | /* Free LSC requests. As the CCDC is stopped there's no active request, |
| 2291 | * so only the pending request and the free queue need to be handled. | 2305 | * so only the pending request and the free queue need to be handled. |
| 2292 | */ | 2306 | */ |
| @@ -2296,4 +2310,6 @@ void omap3isp_ccdc_cleanup(struct isp_device *isp) | |||
| 2296 | 2310 | ||
| 2297 | if (ccdc->fpc.fpcaddr != 0) | 2311 | if (ccdc->fpc.fpcaddr != 0) |
| 2298 | omap_iommu_vfree(isp->domain, isp->iommu, ccdc->fpc.fpcaddr); | 2312 | omap_iommu_vfree(isp->domain, isp->iommu, ccdc->fpc.fpcaddr); |
| 2313 | |||
| 2314 | mutex_destroy(&ccdc->ioctl_lock); | ||
| 2299 | } | 2315 | } |
diff --git a/drivers/media/video/omap3isp/ispccp2.c b/drivers/media/video/omap3isp/ispccp2.c index fa1d09b0ad98..904ca8c8b17f 100644 --- a/drivers/media/video/omap3isp/ispccp2.c +++ b/drivers/media/video/omap3isp/ispccp2.c | |||
| @@ -1032,6 +1032,48 @@ static const struct media_entity_operations ccp2_media_ops = { | |||
| 1032 | }; | 1032 | }; |
| 1033 | 1033 | ||
| 1034 | /* | 1034 | /* |
| 1035 | * omap3isp_ccp2_unregister_entities - Unregister media entities: subdev | ||
| 1036 | * @ccp2: Pointer to ISP CCP2 device | ||
| 1037 | */ | ||
| 1038 | void omap3isp_ccp2_unregister_entities(struct isp_ccp2_device *ccp2) | ||
| 1039 | { | ||
| 1040 | v4l2_device_unregister_subdev(&ccp2->subdev); | ||
| 1041 | omap3isp_video_unregister(&ccp2->video_in); | ||
| 1042 | } | ||
| 1043 | |||
| 1044 | /* | ||
| 1045 | * omap3isp_ccp2_register_entities - Register the subdev media entity | ||
| 1046 | * @ccp2: Pointer to ISP CCP2 device | ||
| 1047 | * @vdev: Pointer to v4l device | ||
| 1048 | * return negative error code or zero on success | ||
| 1049 | */ | ||
| 1050 | |||
| 1051 | int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2, | ||
| 1052 | struct v4l2_device *vdev) | ||
| 1053 | { | ||
| 1054 | int ret; | ||
| 1055 | |||
| 1056 | /* Register the subdev and video nodes. */ | ||
| 1057 | ret = v4l2_device_register_subdev(vdev, &ccp2->subdev); | ||
| 1058 | if (ret < 0) | ||
| 1059 | goto error; | ||
| 1060 | |||
| 1061 | ret = omap3isp_video_register(&ccp2->video_in, vdev); | ||
| 1062 | if (ret < 0) | ||
| 1063 | goto error; | ||
| 1064 | |||
| 1065 | return 0; | ||
| 1066 | |||
| 1067 | error: | ||
| 1068 | omap3isp_ccp2_unregister_entities(ccp2); | ||
| 1069 | return ret; | ||
| 1070 | } | ||
| 1071 | |||
| 1072 | /* ----------------------------------------------------------------------------- | ||
| 1073 | * ISP ccp2 initialisation and cleanup | ||
| 1074 | */ | ||
| 1075 | |||
| 1076 | /* | ||
| 1035 | * ccp2_init_entities - Initialize ccp2 subdev and media entity. | 1077 | * ccp2_init_entities - Initialize ccp2 subdev and media entity. |
| 1036 | * @ccp2: Pointer to ISP CCP2 device | 1078 | * @ccp2: Pointer to ISP CCP2 device |
| 1037 | * return negative error code or zero on success | 1079 | * return negative error code or zero on success |
| @@ -1083,72 +1125,23 @@ static int ccp2_init_entities(struct isp_ccp2_device *ccp2) | |||
| 1083 | 1125 | ||
| 1084 | ret = omap3isp_video_init(&ccp2->video_in, "CCP2"); | 1126 | ret = omap3isp_video_init(&ccp2->video_in, "CCP2"); |
| 1085 | if (ret < 0) | 1127 | if (ret < 0) |
| 1086 | return ret; | 1128 | goto error_video; |
| 1087 | 1129 | ||
| 1088 | /* Connect the video node to the ccp2 subdev. */ | 1130 | /* Connect the video node to the ccp2 subdev. */ |
| 1089 | ret = media_entity_create_link(&ccp2->video_in.video.entity, 0, | 1131 | ret = media_entity_create_link(&ccp2->video_in.video.entity, 0, |
| 1090 | &ccp2->subdev.entity, CCP2_PAD_SINK, 0); | 1132 | &ccp2->subdev.entity, CCP2_PAD_SINK, 0); |
| 1091 | if (ret < 0) | 1133 | if (ret < 0) |
| 1092 | return ret; | 1134 | goto error_link; |
| 1093 | 1135 | ||
| 1094 | return 0; | 1136 | return 0; |
| 1095 | } | ||
| 1096 | 1137 | ||
| 1097 | /* | 1138 | error_link: |
| 1098 | * omap3isp_ccp2_unregister_entities - Unregister media entities: subdev | 1139 | omap3isp_video_cleanup(&ccp2->video_in); |
| 1099 | * @ccp2: Pointer to ISP CCP2 device | 1140 | error_video: |
| 1100 | */ | ||
| 1101 | void omap3isp_ccp2_unregister_entities(struct isp_ccp2_device *ccp2) | ||
| 1102 | { | ||
| 1103 | media_entity_cleanup(&ccp2->subdev.entity); | 1141 | media_entity_cleanup(&ccp2->subdev.entity); |
| 1104 | |||
| 1105 | v4l2_device_unregister_subdev(&ccp2->subdev); | ||
| 1106 | omap3isp_video_unregister(&ccp2->video_in); | ||
| 1107 | } | ||
| 1108 | |||
| 1109 | /* | ||
| 1110 | * omap3isp_ccp2_register_entities - Register the subdev media entity | ||
| 1111 | * @ccp2: Pointer to ISP CCP2 device | ||
| 1112 | * @vdev: Pointer to v4l device | ||
| 1113 | * return negative error code or zero on success | ||
| 1114 | */ | ||
| 1115 | |||
| 1116 | int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2, | ||
| 1117 | struct v4l2_device *vdev) | ||
| 1118 | { | ||
| 1119 | int ret; | ||
| 1120 | |||
| 1121 | /* Register the subdev and video nodes. */ | ||
| 1122 | ret = v4l2_device_register_subdev(vdev, &ccp2->subdev); | ||
| 1123 | if (ret < 0) | ||
| 1124 | goto error; | ||
| 1125 | |||
| 1126 | ret = omap3isp_video_register(&ccp2->video_in, vdev); | ||
| 1127 | if (ret < 0) | ||
| 1128 | goto error; | ||
| 1129 | |||
| 1130 | return 0; | ||
| 1131 | |||
| 1132 | error: | ||
| 1133 | omap3isp_ccp2_unregister_entities(ccp2); | ||
| 1134 | return ret; | 1142 | return ret; |
| 1135 | } | 1143 | } |
| 1136 | 1144 | ||
| 1137 | /* ----------------------------------------------------------------------------- | ||
| 1138 | * ISP ccp2 initialisation and cleanup | ||
| 1139 | */ | ||
| 1140 | |||
| 1141 | /* | ||
| 1142 | * omap3isp_ccp2_cleanup - CCP2 un-initialization | ||
| 1143 | * @isp : Pointer to ISP device | ||
| 1144 | */ | ||
| 1145 | void omap3isp_ccp2_cleanup(struct isp_device *isp) | ||
| 1146 | { | ||
| 1147 | struct isp_ccp2_device *ccp2 = &isp->isp_ccp2; | ||
| 1148 | |||
| 1149 | regulator_put(ccp2->vdds_csib); | ||
| 1150 | } | ||
| 1151 | |||
| 1152 | /* | 1145 | /* |
| 1153 | * omap3isp_ccp2_init - CCP2 initialization. | 1146 | * omap3isp_ccp2_init - CCP2 initialization. |
| 1154 | * @isp : Pointer to ISP device | 1147 | * @isp : Pointer to ISP device |
| @@ -1184,13 +1177,25 @@ int omap3isp_ccp2_init(struct isp_device *isp) | |||
| 1184 | } | 1177 | } |
| 1185 | 1178 | ||
| 1186 | ret = ccp2_init_entities(ccp2); | 1179 | ret = ccp2_init_entities(ccp2); |
| 1187 | if (ret < 0) | 1180 | if (ret < 0) { |
| 1188 | goto out; | 1181 | regulator_put(ccp2->vdds_csib); |
| 1182 | return ret; | ||
| 1183 | } | ||
| 1189 | 1184 | ||
| 1190 | ccp2_reset(ccp2); | 1185 | ccp2_reset(ccp2); |
| 1191 | out: | 1186 | return 0; |
| 1192 | if (ret) | 1187 | } |
| 1193 | omap3isp_ccp2_cleanup(isp); | ||
| 1194 | 1188 | ||
| 1195 | return ret; | 1189 | /* |
| 1190 | * omap3isp_ccp2_cleanup - CCP2 un-initialization | ||
| 1191 | * @isp : Pointer to ISP device | ||
| 1192 | */ | ||
| 1193 | void omap3isp_ccp2_cleanup(struct isp_device *isp) | ||
| 1194 | { | ||
| 1195 | struct isp_ccp2_device *ccp2 = &isp->isp_ccp2; | ||
| 1196 | |||
| 1197 | omap3isp_video_cleanup(&ccp2->video_in); | ||
| 1198 | media_entity_cleanup(&ccp2->subdev.entity); | ||
| 1199 | |||
| 1200 | regulator_put(ccp2->vdds_csib); | ||
| 1196 | } | 1201 | } |
diff --git a/drivers/media/video/omap3isp/ispcsi2.c b/drivers/media/video/omap3isp/ispcsi2.c index 69161a682b3d..0c5f1cb9d99d 100644 --- a/drivers/media/video/omap3isp/ispcsi2.c +++ b/drivers/media/video/omap3isp/ispcsi2.c | |||
| @@ -1187,6 +1187,37 @@ static const struct media_entity_operations csi2_media_ops = { | |||
| 1187 | .link_setup = csi2_link_setup, | 1187 | .link_setup = csi2_link_setup, |
| 1188 | }; | 1188 | }; |
| 1189 | 1189 | ||
| 1190 | void omap3isp_csi2_unregister_entities(struct isp_csi2_device *csi2) | ||
| 1191 | { | ||
| 1192 | v4l2_device_unregister_subdev(&csi2->subdev); | ||
| 1193 | omap3isp_video_unregister(&csi2->video_out); | ||
| 1194 | } | ||
| 1195 | |||
| 1196 | int omap3isp_csi2_register_entities(struct isp_csi2_device *csi2, | ||
| 1197 | struct v4l2_device *vdev) | ||
| 1198 | { | ||
| 1199 | int ret; | ||
| 1200 | |||
| 1201 | /* Register the subdev and video nodes. */ | ||
| 1202 | ret = v4l2_device_register_subdev(vdev, &csi2->subdev); | ||
| 1203 | if (ret < 0) | ||
| 1204 | goto error; | ||
| 1205 | |||
| 1206 | ret = omap3isp_video_register(&csi2->video_out, vdev); | ||
| 1207 | if (ret < 0) | ||
| 1208 | goto error; | ||
| 1209 | |||
| 1210 | return 0; | ||
| 1211 | |||
| 1212 | error: | ||
| 1213 | omap3isp_csi2_unregister_entities(csi2); | ||
| 1214 | return ret; | ||
| 1215 | } | ||
| 1216 | |||
| 1217 | /* ----------------------------------------------------------------------------- | ||
| 1218 | * ISP CSI2 initialisation and cleanup | ||
| 1219 | */ | ||
| 1220 | |||
| 1190 | /* | 1221 | /* |
| 1191 | * csi2_init_entities - Initialize subdev and media entity. | 1222 | * csi2_init_entities - Initialize subdev and media entity. |
| 1192 | * @csi2: Pointer to csi2 structure. | 1223 | * @csi2: Pointer to csi2 structure. |
| @@ -1228,57 +1259,23 @@ static int csi2_init_entities(struct isp_csi2_device *csi2) | |||
| 1228 | 1259 | ||
| 1229 | ret = omap3isp_video_init(&csi2->video_out, "CSI2a"); | 1260 | ret = omap3isp_video_init(&csi2->video_out, "CSI2a"); |
| 1230 | if (ret < 0) | 1261 | if (ret < 0) |
| 1231 | return ret; | 1262 | goto error_video; |
| 1232 | 1263 | ||
| 1233 | /* Connect the CSI2 subdev to the video node. */ | 1264 | /* Connect the CSI2 subdev to the video node. */ |
| 1234 | ret = media_entity_create_link(&csi2->subdev.entity, CSI2_PAD_SOURCE, | 1265 | ret = media_entity_create_link(&csi2->subdev.entity, CSI2_PAD_SOURCE, |
| 1235 | &csi2->video_out.video.entity, 0, 0); | 1266 | &csi2->video_out.video.entity, 0, 0); |
| 1236 | if (ret < 0) | 1267 | if (ret < 0) |
| 1237 | return ret; | 1268 | goto error_link; |
| 1238 | 1269 | ||
| 1239 | return 0; | 1270 | return 0; |
| 1240 | } | ||
| 1241 | 1271 | ||
| 1242 | void omap3isp_csi2_unregister_entities(struct isp_csi2_device *csi2) | 1272 | error_link: |
| 1243 | { | 1273 | omap3isp_video_cleanup(&csi2->video_out); |
| 1274 | error_video: | ||
| 1244 | media_entity_cleanup(&csi2->subdev.entity); | 1275 | media_entity_cleanup(&csi2->subdev.entity); |
| 1245 | |||
| 1246 | v4l2_device_unregister_subdev(&csi2->subdev); | ||
| 1247 | omap3isp_video_unregister(&csi2->video_out); | ||
| 1248 | } | ||
| 1249 | |||
| 1250 | int omap3isp_csi2_register_entities(struct isp_csi2_device *csi2, | ||
| 1251 | struct v4l2_device *vdev) | ||
| 1252 | { | ||
| 1253 | int ret; | ||
| 1254 | |||
| 1255 | /* Register the subdev and video nodes. */ | ||
| 1256 | ret = v4l2_device_register_subdev(vdev, &csi2->subdev); | ||
| 1257 | if (ret < 0) | ||
| 1258 | goto error; | ||
| 1259 | |||
| 1260 | ret = omap3isp_video_register(&csi2->video_out, vdev); | ||
| 1261 | if (ret < 0) | ||
| 1262 | goto error; | ||
| 1263 | |||
| 1264 | return 0; | ||
| 1265 | |||
| 1266 | error: | ||
| 1267 | omap3isp_csi2_unregister_entities(csi2); | ||
| 1268 | return ret; | 1276 | return ret; |
| 1269 | } | 1277 | } |
| 1270 | 1278 | ||
| 1271 | /* ----------------------------------------------------------------------------- | ||
| 1272 | * ISP CSI2 initialisation and cleanup | ||
| 1273 | */ | ||
| 1274 | |||
| 1275 | /* | ||
| 1276 | * omap3isp_csi2_cleanup - Routine for module driver cleanup | ||
| 1277 | */ | ||
| 1278 | void omap3isp_csi2_cleanup(struct isp_device *isp) | ||
| 1279 | { | ||
| 1280 | } | ||
| 1281 | |||
| 1282 | /* | 1279 | /* |
| 1283 | * omap3isp_csi2_init - Routine for module driver init | 1280 | * omap3isp_csi2_init - Routine for module driver init |
| 1284 | */ | 1281 | */ |
| @@ -1298,7 +1295,7 @@ int omap3isp_csi2_init(struct isp_device *isp) | |||
| 1298 | 1295 | ||
| 1299 | ret = csi2_init_entities(csi2a); | 1296 | ret = csi2_init_entities(csi2a); |
| 1300 | if (ret < 0) | 1297 | if (ret < 0) |
| 1301 | goto fail; | 1298 | return ret; |
| 1302 | 1299 | ||
| 1303 | if (isp->revision == ISP_REVISION_15_0) { | 1300 | if (isp->revision == ISP_REVISION_15_0) { |
| 1304 | csi2c->isp = isp; | 1301 | csi2c->isp = isp; |
| @@ -1311,7 +1308,15 @@ int omap3isp_csi2_init(struct isp_device *isp) | |||
| 1311 | } | 1308 | } |
| 1312 | 1309 | ||
| 1313 | return 0; | 1310 | return 0; |
| 1314 | fail: | 1311 | } |
| 1315 | omap3isp_csi2_cleanup(isp); | 1312 | |
| 1316 | return ret; | 1313 | /* |
| 1314 | * omap3isp_csi2_cleanup - Routine for module driver cleanup | ||
| 1315 | */ | ||
| 1316 | void omap3isp_csi2_cleanup(struct isp_device *isp) | ||
| 1317 | { | ||
| 1318 | struct isp_csi2_device *csi2a = &isp->isp_csi2a; | ||
| 1319 | |||
| 1320 | omap3isp_video_cleanup(&csi2a->video_out); | ||
| 1321 | media_entity_cleanup(&csi2a->subdev.entity); | ||
| 1317 | } | 1322 | } |
diff --git a/drivers/media/video/omap3isp/isph3a_aewb.c b/drivers/media/video/omap3isp/isph3a_aewb.c index 8068cefd8d89..a3c76bf18175 100644 --- a/drivers/media/video/omap3isp/isph3a_aewb.c +++ b/drivers/media/video/omap3isp/isph3a_aewb.c | |||
| @@ -370,5 +370,5 @@ void omap3isp_h3a_aewb_cleanup(struct isp_device *isp) | |||
| 370 | { | 370 | { |
| 371 | kfree(isp->isp_aewb.priv); | 371 | kfree(isp->isp_aewb.priv); |
| 372 | kfree(isp->isp_aewb.recover_priv); | 372 | kfree(isp->isp_aewb.recover_priv); |
| 373 | omap3isp_stat_free(&isp->isp_aewb); | 373 | omap3isp_stat_cleanup(&isp->isp_aewb); |
| 374 | } | 374 | } |
diff --git a/drivers/media/video/omap3isp/isph3a_af.c b/drivers/media/video/omap3isp/isph3a_af.c index ba54d0acdecf..58e0bc414899 100644 --- a/drivers/media/video/omap3isp/isph3a_af.c +++ b/drivers/media/video/omap3isp/isph3a_af.c | |||
| @@ -425,5 +425,5 @@ void omap3isp_h3a_af_cleanup(struct isp_device *isp) | |||
| 425 | { | 425 | { |
| 426 | kfree(isp->isp_af.priv); | 426 | kfree(isp->isp_af.priv); |
| 427 | kfree(isp->isp_af.recover_priv); | 427 | kfree(isp->isp_af.recover_priv); |
| 428 | omap3isp_stat_free(&isp->isp_af); | 428 | omap3isp_stat_cleanup(&isp->isp_af); |
| 429 | } | 429 | } |
diff --git a/drivers/media/video/omap3isp/isphist.c b/drivers/media/video/omap3isp/isphist.c index 1743856b30d1..1163907bcddc 100644 --- a/drivers/media/video/omap3isp/isphist.c +++ b/drivers/media/video/omap3isp/isphist.c | |||
| @@ -516,5 +516,5 @@ void omap3isp_hist_cleanup(struct isp_device *isp) | |||
| 516 | if (HIST_USING_DMA(&isp->isp_hist)) | 516 | if (HIST_USING_DMA(&isp->isp_hist)) |
| 517 | omap_free_dma(isp->isp_hist.dma_ch); | 517 | omap_free_dma(isp->isp_hist.dma_ch); |
| 518 | kfree(isp->isp_hist.priv); | 518 | kfree(isp->isp_hist.priv); |
| 519 | omap3isp_stat_free(&isp->isp_hist); | 519 | omap3isp_stat_cleanup(&isp->isp_hist); |
| 520 | } | 520 | } |
diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c index aba537af87e4..ccb876fe023f 100644 --- a/drivers/media/video/omap3isp/isppreview.c +++ b/drivers/media/video/omap3isp/isppreview.c | |||
| @@ -76,9 +76,51 @@ static struct omap3isp_prev_csc flr_prev_csc = { | |||
| 76 | 76 | ||
| 77 | #define DEF_DETECT_CORRECT_VAL 0xe | 77 | #define DEF_DETECT_CORRECT_VAL 0xe |
| 78 | 78 | ||
| 79 | #define PREV_MIN_WIDTH 64 | 79 | /* |
| 80 | #define PREV_MIN_HEIGHT 8 | 80 | * Margins and image size limits. |
| 81 | #define PREV_MAX_HEIGHT 16384 | 81 | * |
| 82 | * The preview engine crops several rows and columns internally depending on | ||
| 83 | * which filters are enabled. To avoid format changes when the filters are | ||
| 84 | * enabled or disabled (which would prevent them from being turned on or off | ||
| 85 | * during streaming), the driver assumes all the filters are enabled when | ||
| 86 | * computing sink crop and source format limits. | ||
| 87 | * | ||
| 88 | * If a filter is disabled, additional cropping is automatically added at the | ||
| 89 | * preview engine input by the driver to avoid overflow at line and frame end. | ||
| 90 | * This is completely transparent for applications. | ||
| 91 | * | ||
| 92 | * Median filter 4 pixels | ||
| 93 | * Noise filter, | ||
| 94 | * Faulty pixels correction 4 pixels, 4 lines | ||
| 95 | * CFA filter 4 pixels, 4 lines in Bayer mode | ||
| 96 | * 2 lines in other modes | ||
| 97 | * Color suppression 2 pixels | ||
| 98 | * or luma enhancement | ||
| 99 | * ------------------------------------------------------------- | ||
| 100 | * Maximum total 14 pixels, 8 lines | ||
| 101 | * | ||
| 102 | * The color suppression and luma enhancement filters are applied after bayer to | ||
| 103 | * YUV conversion. They thus can crop one pixel on the left and one pixel on the | ||
| 104 | * right side of the image without changing the color pattern. When both those | ||
| 105 | * filters are disabled, the driver must crop the two pixels on the same side of | ||
| 106 | * the image to avoid changing the bayer pattern. The left margin is thus set to | ||
| 107 | * 8 pixels and the right margin to 6 pixels. | ||
| 108 | */ | ||
| 109 | |||
| 110 | #define PREV_MARGIN_LEFT 8 | ||
| 111 | #define PREV_MARGIN_RIGHT 6 | ||
| 112 | #define PREV_MARGIN_TOP 4 | ||
| 113 | #define PREV_MARGIN_BOTTOM 4 | ||
| 114 | |||
| 115 | #define PREV_MIN_IN_WIDTH 64 | ||
| 116 | #define PREV_MIN_IN_HEIGHT 8 | ||
| 117 | #define PREV_MAX_IN_HEIGHT 16384 | ||
| 118 | |||
| 119 | #define PREV_MIN_OUT_WIDTH 0 | ||
| 120 | #define PREV_MIN_OUT_HEIGHT 0 | ||
| 121 | #define PREV_MAX_OUT_WIDTH 1280 | ||
| 122 | #define PREV_MAX_OUT_WIDTH_ES2 3300 | ||
| 123 | #define PREV_MAX_OUT_WIDTH_3630 4096 | ||
| 82 | 124 | ||
| 83 | /* | 125 | /* |
| 84 | * Coeficient Tables for the submodules in Preview. | 126 | * Coeficient Tables for the submodules in Preview. |
| @@ -979,52 +1021,36 @@ static void preview_config_averager(struct isp_prev_device *prev, u8 average) | |||
| 979 | * enabled when reporting source pad formats to userspace. If this assumption is | 1021 | * enabled when reporting source pad formats to userspace. If this assumption is |
| 980 | * not true, rows and columns must be manually cropped at the preview engine | 1022 | * not true, rows and columns must be manually cropped at the preview engine |
| 981 | * input to avoid overflows at the end of lines and frames. | 1023 | * input to avoid overflows at the end of lines and frames. |
| 1024 | * | ||
| 1025 | * See the explanation at the PREV_MARGIN_* definitions for more details. | ||
| 982 | */ | 1026 | */ |
| 983 | static void preview_config_input_size(struct isp_prev_device *prev) | 1027 | static void preview_config_input_size(struct isp_prev_device *prev) |
| 984 | { | 1028 | { |
| 985 | struct isp_device *isp = to_isp_device(prev); | 1029 | struct isp_device *isp = to_isp_device(prev); |
| 986 | struct prev_params *params = &prev->params; | 1030 | struct prev_params *params = &prev->params; |
| 987 | struct v4l2_mbus_framefmt *format = &prev->formats[PREV_PAD_SINK]; | 1031 | unsigned int sph = prev->crop.left; |
| 988 | unsigned int sph = 0; | 1032 | unsigned int eph = prev->crop.left + prev->crop.width - 1; |
| 989 | unsigned int eph = format->width - 1; | 1033 | unsigned int slv = prev->crop.top; |
| 990 | unsigned int slv = 0; | 1034 | unsigned int elv = prev->crop.top + prev->crop.height - 1; |
| 991 | unsigned int elv = format->height - 1; | 1035 | |
| 992 | 1036 | if (params->features & PREV_CFA) { | |
| 993 | if (prev->input == PREVIEW_INPUT_CCDC) { | 1037 | sph -= 2; |
| 994 | sph += 2; | 1038 | eph += 2; |
| 995 | eph -= 2; | 1039 | slv -= 2; |
| 1040 | elv += 2; | ||
| 996 | } | 1041 | } |
| 997 | 1042 | if (params->features & (PREV_DEFECT_COR | PREV_NOISE_FILTER)) { | |
| 998 | /* | 1043 | sph -= 2; |
| 999 | * Median filter 4 pixels | 1044 | eph += 2; |
| 1000 | * Noise filter 4 pixels, 4 lines | 1045 | slv -= 2; |
| 1001 | * or faulty pixels correction | 1046 | elv += 2; |
| 1002 | * CFA filter 4 pixels, 4 lines in Bayer mode | ||
| 1003 | * 2 lines in other modes | ||
| 1004 | * Color suppression 2 pixels | ||
| 1005 | * or luma enhancement | ||
| 1006 | * ------------------------------------------------------------- | ||
| 1007 | * Maximum total 14 pixels, 8 lines | ||
| 1008 | */ | ||
| 1009 | |||
| 1010 | if (!(params->features & PREV_CFA)) { | ||
| 1011 | sph += 2; | ||
| 1012 | eph -= 2; | ||
| 1013 | slv += 2; | ||
| 1014 | elv -= 2; | ||
| 1015 | } | 1047 | } |
| 1016 | if (!(params->features & (PREV_DEFECT_COR | PREV_NOISE_FILTER))) { | 1048 | if (params->features & PREV_HORZ_MEDIAN_FILTER) { |
| 1017 | sph += 2; | 1049 | sph -= 2; |
| 1018 | eph -= 2; | 1050 | eph += 2; |
| 1019 | slv += 2; | ||
| 1020 | elv -= 2; | ||
| 1021 | } | 1051 | } |
| 1022 | if (!(params->features & PREV_HORZ_MEDIAN_FILTER)) { | 1052 | if (params->features & (PREV_CHROMA_SUPPRESS | PREV_LUMA_ENHANCE)) |
| 1023 | sph += 2; | 1053 | sph -= 2; |
| 1024 | eph -= 2; | ||
| 1025 | } | ||
| 1026 | if (!(params->features & (PREV_CHROMA_SUPPRESS | PREV_LUMA_ENHANCE))) | ||
| 1027 | sph += 2; | ||
| 1028 | 1054 | ||
| 1029 | isp_reg_writel(isp, (sph << ISPPRV_HORZ_INFO_SPH_SHIFT) | eph, | 1055 | isp_reg_writel(isp, (sph << ISPPRV_HORZ_INFO_SPH_SHIFT) | eph, |
| 1030 | OMAP3_ISP_IOMEM_PREV, ISPPRV_HORZ_INFO); | 1056 | OMAP3_ISP_IOMEM_PREV, ISPPRV_HORZ_INFO); |
| @@ -1228,7 +1254,6 @@ static void preview_init_params(struct isp_prev_device *prev) | |||
| 1228 | /* Init values */ | 1254 | /* Init values */ |
| 1229 | params->contrast = ISPPRV_CONTRAST_DEF * ISPPRV_CONTRAST_UNITS; | 1255 | params->contrast = ISPPRV_CONTRAST_DEF * ISPPRV_CONTRAST_UNITS; |
| 1230 | params->brightness = ISPPRV_BRIGHT_DEF * ISPPRV_BRIGHT_UNITS; | 1256 | params->brightness = ISPPRV_BRIGHT_DEF * ISPPRV_BRIGHT_UNITS; |
| 1231 | params->average = NO_AVE; | ||
| 1232 | params->cfa.format = OMAP3ISP_CFAFMT_BAYER; | 1257 | params->cfa.format = OMAP3ISP_CFAFMT_BAYER; |
| 1233 | memcpy(params->cfa.table, cfa_coef_table, | 1258 | memcpy(params->cfa.table, cfa_coef_table, |
| 1234 | sizeof(params->cfa.table)); | 1259 | sizeof(params->cfa.table)); |
| @@ -1281,14 +1306,14 @@ static unsigned int preview_max_out_width(struct isp_prev_device *prev) | |||
| 1281 | 1306 | ||
| 1282 | switch (isp->revision) { | 1307 | switch (isp->revision) { |
| 1283 | case ISP_REVISION_1_0: | 1308 | case ISP_REVISION_1_0: |
| 1284 | return ISPPRV_MAXOUTPUT_WIDTH; | 1309 | return PREV_MAX_OUT_WIDTH; |
| 1285 | 1310 | ||
| 1286 | case ISP_REVISION_2_0: | 1311 | case ISP_REVISION_2_0: |
| 1287 | default: | 1312 | default: |
| 1288 | return ISPPRV_MAXOUTPUT_WIDTH_ES2; | 1313 | return PREV_MAX_OUT_WIDTH_ES2; |
| 1289 | 1314 | ||
| 1290 | case ISP_REVISION_15_0: | 1315 | case ISP_REVISION_15_0: |
| 1291 | return ISPPRV_MAXOUTPUT_WIDTH_3630; | 1316 | return PREV_MAX_OUT_WIDTH_3630; |
| 1292 | } | 1317 | } |
| 1293 | } | 1318 | } |
| 1294 | 1319 | ||
| @@ -1296,8 +1321,6 @@ static void preview_configure(struct isp_prev_device *prev) | |||
| 1296 | { | 1321 | { |
| 1297 | struct isp_device *isp = to_isp_device(prev); | 1322 | struct isp_device *isp = to_isp_device(prev); |
| 1298 | struct v4l2_mbus_framefmt *format; | 1323 | struct v4l2_mbus_framefmt *format; |
| 1299 | unsigned int max_out_width; | ||
| 1300 | unsigned int format_avg; | ||
| 1301 | 1324 | ||
| 1302 | preview_setup_hw(prev); | 1325 | preview_setup_hw(prev); |
| 1303 | 1326 | ||
| @@ -1335,10 +1358,7 @@ static void preview_configure(struct isp_prev_device *prev) | |||
| 1335 | preview_config_outlineoffset(prev, | 1358 | preview_config_outlineoffset(prev, |
| 1336 | ALIGN(format->width, 0x10) * 2); | 1359 | ALIGN(format->width, 0x10) * 2); |
| 1337 | 1360 | ||
| 1338 | max_out_width = preview_max_out_width(prev); | 1361 | preview_config_averager(prev, 0); |
| 1339 | |||
| 1340 | format_avg = fls(DIV_ROUND_UP(format->width, max_out_width) - 1); | ||
| 1341 | preview_config_averager(prev, format_avg); | ||
| 1342 | preview_config_ycpos(prev, format->code); | 1362 | preview_config_ycpos(prev, format->code); |
| 1343 | } | 1363 | } |
| 1344 | 1364 | ||
| @@ -1597,6 +1617,16 @@ __preview_get_format(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh, | |||
| 1597 | return &prev->formats[pad]; | 1617 | return &prev->formats[pad]; |
| 1598 | } | 1618 | } |
| 1599 | 1619 | ||
| 1620 | static struct v4l2_rect * | ||
| 1621 | __preview_get_crop(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh, | ||
| 1622 | enum v4l2_subdev_format_whence which) | ||
| 1623 | { | ||
| 1624 | if (which == V4L2_SUBDEV_FORMAT_TRY) | ||
| 1625 | return v4l2_subdev_get_try_crop(fh, PREV_PAD_SINK); | ||
| 1626 | else | ||
| 1627 | return &prev->crop; | ||
| 1628 | } | ||
| 1629 | |||
| 1600 | /* previewer format descriptions */ | 1630 | /* previewer format descriptions */ |
| 1601 | static const unsigned int preview_input_fmts[] = { | 1631 | static const unsigned int preview_input_fmts[] = { |
| 1602 | V4L2_MBUS_FMT_SGRBG10_1X10, | 1632 | V4L2_MBUS_FMT_SGRBG10_1X10, |
| @@ -1611,24 +1641,25 @@ static const unsigned int preview_output_fmts[] = { | |||
| 1611 | }; | 1641 | }; |
| 1612 | 1642 | ||
| 1613 | /* | 1643 | /* |
| 1614 | * preview_try_format - Handle try format by pad subdev method | 1644 | * preview_try_format - Validate a format |
| 1615 | * @prev: ISP preview device | 1645 | * @prev: ISP preview engine |
| 1616 | * @fh : V4L2 subdev file handle | 1646 | * @fh: V4L2 subdev file handle |
| 1617 | * @pad: pad num | 1647 | * @pad: pad number |
| 1618 | * @fmt: pointer to v4l2 format structure | 1648 | * @fmt: format to be validated |
| 1649 | * @which: try/active format selector | ||
| 1650 | * | ||
| 1651 | * Validate and adjust the given format for the given pad based on the preview | ||
| 1652 | * engine limits and the format and crop rectangles on other pads. | ||
| 1619 | */ | 1653 | */ |
| 1620 | static void preview_try_format(struct isp_prev_device *prev, | 1654 | static void preview_try_format(struct isp_prev_device *prev, |
| 1621 | struct v4l2_subdev_fh *fh, unsigned int pad, | 1655 | struct v4l2_subdev_fh *fh, unsigned int pad, |
| 1622 | struct v4l2_mbus_framefmt *fmt, | 1656 | struct v4l2_mbus_framefmt *fmt, |
| 1623 | enum v4l2_subdev_format_whence which) | 1657 | enum v4l2_subdev_format_whence which) |
| 1624 | { | 1658 | { |
| 1625 | struct v4l2_mbus_framefmt *format; | ||
| 1626 | unsigned int max_out_width; | ||
| 1627 | enum v4l2_mbus_pixelcode pixelcode; | 1659 | enum v4l2_mbus_pixelcode pixelcode; |
| 1660 | struct v4l2_rect *crop; | ||
| 1628 | unsigned int i; | 1661 | unsigned int i; |
| 1629 | 1662 | ||
| 1630 | max_out_width = preview_max_out_width(prev); | ||
| 1631 | |||
| 1632 | switch (pad) { | 1663 | switch (pad) { |
| 1633 | case PREV_PAD_SINK: | 1664 | case PREV_PAD_SINK: |
| 1634 | /* When reading data from the CCDC, the input size has already | 1665 | /* When reading data from the CCDC, the input size has already |
| @@ -1641,10 +1672,11 @@ static void preview_try_format(struct isp_prev_device *prev, | |||
| 1641 | * filter array interpolation. | 1672 | * filter array interpolation. |
| 1642 | */ | 1673 | */ |
| 1643 | if (prev->input == PREVIEW_INPUT_MEMORY) { | 1674 | if (prev->input == PREVIEW_INPUT_MEMORY) { |
| 1644 | fmt->width = clamp_t(u32, fmt->width, PREV_MIN_WIDTH, | 1675 | fmt->width = clamp_t(u32, fmt->width, PREV_MIN_IN_WIDTH, |
| 1645 | max_out_width * 8); | 1676 | preview_max_out_width(prev)); |
| 1646 | fmt->height = clamp_t(u32, fmt->height, PREV_MIN_HEIGHT, | 1677 | fmt->height = clamp_t(u32, fmt->height, |
| 1647 | PREV_MAX_HEIGHT); | 1678 | PREV_MIN_IN_HEIGHT, |
| 1679 | PREV_MAX_IN_HEIGHT); | ||
| 1648 | } | 1680 | } |
| 1649 | 1681 | ||
| 1650 | fmt->colorspace = V4L2_COLORSPACE_SRGB; | 1682 | fmt->colorspace = V4L2_COLORSPACE_SRGB; |
| @@ -1661,15 +1693,8 @@ static void preview_try_format(struct isp_prev_device *prev, | |||
| 1661 | 1693 | ||
| 1662 | case PREV_PAD_SOURCE: | 1694 | case PREV_PAD_SOURCE: |
| 1663 | pixelcode = fmt->code; | 1695 | pixelcode = fmt->code; |
| 1664 | format = __preview_get_format(prev, fh, PREV_PAD_SINK, which); | 1696 | *fmt = *__preview_get_format(prev, fh, PREV_PAD_SINK, which); |
| 1665 | memcpy(fmt, format, sizeof(*fmt)); | ||
| 1666 | 1697 | ||
| 1667 | /* The preview module output size is configurable through the | ||
| 1668 | * input interface (horizontal and vertical cropping) and the | ||
| 1669 | * averager (horizontal scaling by 1/1, 1/2, 1/4 or 1/8). In | ||
| 1670 | * spite of this, hardcode the output size to the biggest | ||
| 1671 | * possible value for simplicity reasons. | ||
| 1672 | */ | ||
| 1673 | switch (pixelcode) { | 1698 | switch (pixelcode) { |
| 1674 | case V4L2_MBUS_FMT_YUYV8_1X16: | 1699 | case V4L2_MBUS_FMT_YUYV8_1X16: |
| 1675 | case V4L2_MBUS_FMT_UYVY8_1X16: | 1700 | case V4L2_MBUS_FMT_UYVY8_1X16: |
| @@ -1681,31 +1706,14 @@ static void preview_try_format(struct isp_prev_device *prev, | |||
| 1681 | break; | 1706 | break; |
| 1682 | } | 1707 | } |
| 1683 | 1708 | ||
| 1684 | /* The TRM states (12.1.4.7.1.2) that 2 pixels must be cropped | 1709 | /* The preview module output size is configurable through the |
| 1685 | * from the left and right sides when the input source is the | 1710 | * averager (horizontal scaling by 1/1, 1/2, 1/4 or 1/8). This |
| 1686 | * CCDC. This seems not to be needed in practice, investigation | 1711 | * is not supported yet, hardcode the output size to the crop |
| 1687 | * is required. | 1712 | * rectangle size. |
| 1688 | */ | ||
| 1689 | if (prev->input == PREVIEW_INPUT_CCDC) | ||
| 1690 | fmt->width -= 4; | ||
| 1691 | |||
| 1692 | /* The preview module can output a maximum of 3312 pixels | ||
| 1693 | * horizontally due to fixed memory-line sizes. Compute the | ||
| 1694 | * horizontal averaging factor accordingly. Note that the limit | ||
| 1695 | * applies to the noise filter and CFA interpolation blocks, so | ||
| 1696 | * it doesn't take cropping by further blocks into account. | ||
| 1697 | * | ||
| 1698 | * ES 1.0 hardware revision is limited to 1280 pixels | ||
| 1699 | * horizontally. | ||
| 1700 | */ | ||
| 1701 | fmt->width >>= fls(DIV_ROUND_UP(fmt->width, max_out_width) - 1); | ||
| 1702 | |||
| 1703 | /* Assume that all blocks are enabled and crop pixels and lines | ||
| 1704 | * accordingly. See preview_config_input_size() for more | ||
| 1705 | * information. | ||
| 1706 | */ | 1713 | */ |
| 1707 | fmt->width -= 14; | 1714 | crop = __preview_get_crop(prev, fh, which); |
| 1708 | fmt->height -= 8; | 1715 | fmt->width = crop->width; |
| 1716 | fmt->height = crop->height; | ||
| 1709 | 1717 | ||
| 1710 | fmt->colorspace = V4L2_COLORSPACE_JPEG; | 1718 | fmt->colorspace = V4L2_COLORSPACE_JPEG; |
| 1711 | break; | 1719 | break; |
| @@ -1715,6 +1723,49 @@ static void preview_try_format(struct isp_prev_device *prev, | |||
| 1715 | } | 1723 | } |
| 1716 | 1724 | ||
| 1717 | /* | 1725 | /* |
| 1726 | * preview_try_crop - Validate a crop rectangle | ||
| 1727 | * @prev: ISP preview engine | ||
| 1728 | * @sink: format on the sink pad | ||
| 1729 | * @crop: crop rectangle to be validated | ||
| 1730 | * | ||
| 1731 | * The preview engine crops lines and columns for its internal operation, | ||
| 1732 | * depending on which filters are enabled. Enforce minimum crop margins to | ||
| 1733 | * handle that transparently for userspace. | ||
| 1734 | * | ||
| 1735 | * See the explanation at the PREV_MARGIN_* definitions for more details. | ||
| 1736 | */ | ||
| 1737 | static void preview_try_crop(struct isp_prev_device *prev, | ||
| 1738 | const struct v4l2_mbus_framefmt *sink, | ||
| 1739 | struct v4l2_rect *crop) | ||
| 1740 | { | ||
| 1741 | unsigned int left = PREV_MARGIN_LEFT; | ||
| 1742 | unsigned int right = sink->width - PREV_MARGIN_RIGHT; | ||
| 1743 | unsigned int top = PREV_MARGIN_TOP; | ||
| 1744 | unsigned int bottom = sink->height - PREV_MARGIN_BOTTOM; | ||
| 1745 | |||
| 1746 | /* When processing data on-the-fly from the CCDC, at least 2 pixels must | ||
| 1747 | * be cropped from the left and right sides of the image. As we don't | ||
| 1748 | * know which filters will be enabled, increase the left and right | ||
| 1749 | * margins by two. | ||
| 1750 | */ | ||
| 1751 | if (prev->input == PREVIEW_INPUT_CCDC) { | ||
| 1752 | left += 2; | ||
| 1753 | right -= 2; | ||
| 1754 | } | ||
| 1755 | |||
| 1756 | /* Restrict left/top to even values to keep the Bayer pattern. */ | ||
| 1757 | crop->left &= ~1; | ||
| 1758 | crop->top &= ~1; | ||
| 1759 | |||
| 1760 | crop->left = clamp_t(u32, crop->left, left, right - PREV_MIN_OUT_WIDTH); | ||
| 1761 | crop->top = clamp_t(u32, crop->top, top, bottom - PREV_MIN_OUT_HEIGHT); | ||
| 1762 | crop->width = clamp_t(u32, crop->width, PREV_MIN_OUT_WIDTH, | ||
| 1763 | right - crop->left); | ||
| 1764 | crop->height = clamp_t(u32, crop->height, PREV_MIN_OUT_HEIGHT, | ||
| 1765 | bottom - crop->top); | ||
| 1766 | } | ||
| 1767 | |||
| 1768 | /* | ||
| 1718 | * preview_enum_mbus_code - Handle pixel format enumeration | 1769 | * preview_enum_mbus_code - Handle pixel format enumeration |
| 1719 | * @sd : pointer to v4l2 subdev structure | 1770 | * @sd : pointer to v4l2 subdev structure |
| 1720 | * @fh : V4L2 subdev file handle | 1771 | * @fh : V4L2 subdev file handle |
| @@ -1776,6 +1827,60 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd, | |||
| 1776 | } | 1827 | } |
| 1777 | 1828 | ||
| 1778 | /* | 1829 | /* |
| 1830 | * preview_get_crop - Retrieve the crop rectangle on a pad | ||
| 1831 | * @sd: ISP preview V4L2 subdevice | ||
| 1832 | * @fh: V4L2 subdev file handle | ||
| 1833 | * @crop: crop rectangle | ||
| 1834 | * | ||
| 1835 | * Return 0 on success or a negative error code otherwise. | ||
| 1836 | */ | ||
| 1837 | static int preview_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
| 1838 | struct v4l2_subdev_crop *crop) | ||
| 1839 | { | ||
| 1840 | struct isp_prev_device *prev = v4l2_get_subdevdata(sd); | ||
| 1841 | |||
| 1842 | /* Cropping is only supported on the sink pad. */ | ||
| 1843 | if (crop->pad != PREV_PAD_SINK) | ||
| 1844 | return -EINVAL; | ||
| 1845 | |||
| 1846 | crop->rect = *__preview_get_crop(prev, fh, crop->which); | ||
| 1847 | return 0; | ||
| 1848 | } | ||
| 1849 | |||
| 1850 | /* | ||
| 1851 | * preview_set_crop - Retrieve the crop rectangle on a pad | ||
| 1852 | * @sd: ISP preview V4L2 subdevice | ||
| 1853 | * @fh: V4L2 subdev file handle | ||
| 1854 | * @crop: crop rectangle | ||
| 1855 | * | ||
| 1856 | * Return 0 on success or a negative error code otherwise. | ||
| 1857 | */ | ||
| 1858 | static int preview_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
| 1859 | struct v4l2_subdev_crop *crop) | ||
| 1860 | { | ||
| 1861 | struct isp_prev_device *prev = v4l2_get_subdevdata(sd); | ||
| 1862 | struct v4l2_mbus_framefmt *format; | ||
| 1863 | |||
| 1864 | /* Cropping is only supported on the sink pad. */ | ||
| 1865 | if (crop->pad != PREV_PAD_SINK) | ||
| 1866 | return -EINVAL; | ||
| 1867 | |||
| 1868 | /* The crop rectangle can't be changed while streaming. */ | ||
| 1869 | if (prev->state != ISP_PIPELINE_STREAM_STOPPED) | ||
| 1870 | return -EBUSY; | ||
| 1871 | |||
| 1872 | format = __preview_get_format(prev, fh, PREV_PAD_SINK, crop->which); | ||
| 1873 | preview_try_crop(prev, format, &crop->rect); | ||
| 1874 | *__preview_get_crop(prev, fh, crop->which) = crop->rect; | ||
| 1875 | |||
| 1876 | /* Update the source format. */ | ||
| 1877 | format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, crop->which); | ||
| 1878 | preview_try_format(prev, fh, PREV_PAD_SOURCE, format, crop->which); | ||
| 1879 | |||
| 1880 | return 0; | ||
| 1881 | } | ||
| 1882 | |||
| 1883 | /* | ||
| 1779 | * preview_get_format - Handle get format by pads subdev method | 1884 | * preview_get_format - Handle get format by pads subdev method |
| 1780 | * @sd : pointer to v4l2 subdev structure | 1885 | * @sd : pointer to v4l2 subdev structure |
| 1781 | * @fh : V4L2 subdev file handle | 1886 | * @fh : V4L2 subdev file handle |
| @@ -1808,6 +1913,7 @@ static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | |||
| 1808 | { | 1913 | { |
| 1809 | struct isp_prev_device *prev = v4l2_get_subdevdata(sd); | 1914 | struct isp_prev_device *prev = v4l2_get_subdevdata(sd); |
| 1810 | struct v4l2_mbus_framefmt *format; | 1915 | struct v4l2_mbus_framefmt *format; |
| 1916 | struct v4l2_rect *crop; | ||
| 1811 | 1917 | ||
| 1812 | format = __preview_get_format(prev, fh, fmt->pad, fmt->which); | 1918 | format = __preview_get_format(prev, fh, fmt->pad, fmt->which); |
| 1813 | if (format == NULL) | 1919 | if (format == NULL) |
| @@ -1818,9 +1924,18 @@ static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | |||
| 1818 | 1924 | ||
| 1819 | /* Propagate the format from sink to source */ | 1925 | /* Propagate the format from sink to source */ |
| 1820 | if (fmt->pad == PREV_PAD_SINK) { | 1926 | if (fmt->pad == PREV_PAD_SINK) { |
| 1927 | /* Reset the crop rectangle. */ | ||
| 1928 | crop = __preview_get_crop(prev, fh, fmt->which); | ||
| 1929 | crop->left = 0; | ||
| 1930 | crop->top = 0; | ||
| 1931 | crop->width = fmt->format.width; | ||
| 1932 | crop->height = fmt->format.height; | ||
| 1933 | |||
| 1934 | preview_try_crop(prev, &fmt->format, crop); | ||
| 1935 | |||
| 1936 | /* Update the source format. */ | ||
| 1821 | format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, | 1937 | format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, |
| 1822 | fmt->which); | 1938 | fmt->which); |
| 1823 | *format = fmt->format; | ||
| 1824 | preview_try_format(prev, fh, PREV_PAD_SOURCE, format, | 1939 | preview_try_format(prev, fh, PREV_PAD_SOURCE, format, |
| 1825 | fmt->which); | 1940 | fmt->which); |
| 1826 | } | 1941 | } |
| @@ -1869,6 +1984,8 @@ static const struct v4l2_subdev_pad_ops preview_v4l2_pad_ops = { | |||
| 1869 | .enum_frame_size = preview_enum_frame_size, | 1984 | .enum_frame_size = preview_enum_frame_size, |
| 1870 | .get_fmt = preview_get_format, | 1985 | .get_fmt = preview_get_format, |
| 1871 | .set_fmt = preview_set_format, | 1986 | .set_fmt = preview_set_format, |
| 1987 | .get_crop = preview_get_crop, | ||
| 1988 | .set_crop = preview_set_crop, | ||
| 1872 | }; | 1989 | }; |
| 1873 | 1990 | ||
| 1874 | /* subdev operations */ | 1991 | /* subdev operations */ |
| @@ -1966,8 +2083,44 @@ static const struct media_entity_operations preview_media_ops = { | |||
| 1966 | .link_setup = preview_link_setup, | 2083 | .link_setup = preview_link_setup, |
| 1967 | }; | 2084 | }; |
| 1968 | 2085 | ||
| 2086 | void omap3isp_preview_unregister_entities(struct isp_prev_device *prev) | ||
| 2087 | { | ||
| 2088 | v4l2_device_unregister_subdev(&prev->subdev); | ||
| 2089 | omap3isp_video_unregister(&prev->video_in); | ||
| 2090 | omap3isp_video_unregister(&prev->video_out); | ||
| 2091 | } | ||
| 2092 | |||
| 2093 | int omap3isp_preview_register_entities(struct isp_prev_device *prev, | ||
| 2094 | struct v4l2_device *vdev) | ||
| 2095 | { | ||
| 2096 | int ret; | ||
| 2097 | |||
| 2098 | /* Register the subdev and video nodes. */ | ||
| 2099 | ret = v4l2_device_register_subdev(vdev, &prev->subdev); | ||
| 2100 | if (ret < 0) | ||
| 2101 | goto error; | ||
| 2102 | |||
| 2103 | ret = omap3isp_video_register(&prev->video_in, vdev); | ||
| 2104 | if (ret < 0) | ||
| 2105 | goto error; | ||
| 2106 | |||
| 2107 | ret = omap3isp_video_register(&prev->video_out, vdev); | ||
| 2108 | if (ret < 0) | ||
| 2109 | goto error; | ||
| 2110 | |||
| 2111 | return 0; | ||
| 2112 | |||
| 2113 | error: | ||
| 2114 | omap3isp_preview_unregister_entities(prev); | ||
| 2115 | return ret; | ||
| 2116 | } | ||
| 2117 | |||
| 2118 | /* ----------------------------------------------------------------------------- | ||
| 2119 | * ISP previewer initialisation and cleanup | ||
| 2120 | */ | ||
| 2121 | |||
| 1969 | /* | 2122 | /* |
| 1970 | * review_init_entities - Initialize subdev and media entity. | 2123 | * preview_init_entities - Initialize subdev and media entity. |
| 1971 | * @prev : Pointer to preview structure | 2124 | * @prev : Pointer to preview structure |
| 1972 | * return -ENOMEM or zero on success | 2125 | * return -ENOMEM or zero on success |
| 1973 | */ | 2126 | */ |
| @@ -2024,69 +2177,34 @@ static int preview_init_entities(struct isp_prev_device *prev) | |||
| 2024 | 2177 | ||
| 2025 | ret = omap3isp_video_init(&prev->video_in, "preview"); | 2178 | ret = omap3isp_video_init(&prev->video_in, "preview"); |
| 2026 | if (ret < 0) | 2179 | if (ret < 0) |
| 2027 | return ret; | 2180 | goto error_video_in; |
| 2028 | 2181 | ||
| 2029 | ret = omap3isp_video_init(&prev->video_out, "preview"); | 2182 | ret = omap3isp_video_init(&prev->video_out, "preview"); |
| 2030 | if (ret < 0) | 2183 | if (ret < 0) |
| 2031 | return ret; | 2184 | goto error_video_out; |
| 2032 | 2185 | ||
| 2033 | /* Connect the video nodes to the previewer subdev. */ | 2186 | /* Connect the video nodes to the previewer subdev. */ |
| 2034 | ret = media_entity_create_link(&prev->video_in.video.entity, 0, | 2187 | ret = media_entity_create_link(&prev->video_in.video.entity, 0, |
| 2035 | &prev->subdev.entity, PREV_PAD_SINK, 0); | 2188 | &prev->subdev.entity, PREV_PAD_SINK, 0); |
| 2036 | if (ret < 0) | 2189 | if (ret < 0) |
| 2037 | return ret; | 2190 | goto error_link; |
| 2038 | 2191 | ||
| 2039 | ret = media_entity_create_link(&prev->subdev.entity, PREV_PAD_SOURCE, | 2192 | ret = media_entity_create_link(&prev->subdev.entity, PREV_PAD_SOURCE, |
| 2040 | &prev->video_out.video.entity, 0, 0); | 2193 | &prev->video_out.video.entity, 0, 0); |
| 2041 | if (ret < 0) | 2194 | if (ret < 0) |
| 2042 | return ret; | 2195 | goto error_link; |
| 2043 | 2196 | ||
| 2044 | return 0; | 2197 | return 0; |
| 2045 | } | ||
| 2046 | 2198 | ||
| 2047 | void omap3isp_preview_unregister_entities(struct isp_prev_device *prev) | 2199 | error_link: |
| 2048 | { | 2200 | omap3isp_video_cleanup(&prev->video_out); |
| 2201 | error_video_out: | ||
| 2202 | omap3isp_video_cleanup(&prev->video_in); | ||
| 2203 | error_video_in: | ||
| 2049 | media_entity_cleanup(&prev->subdev.entity); | 2204 | media_entity_cleanup(&prev->subdev.entity); |
| 2050 | |||
| 2051 | v4l2_device_unregister_subdev(&prev->subdev); | ||
| 2052 | v4l2_ctrl_handler_free(&prev->ctrls); | ||
| 2053 | omap3isp_video_unregister(&prev->video_in); | ||
| 2054 | omap3isp_video_unregister(&prev->video_out); | ||
| 2055 | } | ||
| 2056 | |||
| 2057 | int omap3isp_preview_register_entities(struct isp_prev_device *prev, | ||
| 2058 | struct v4l2_device *vdev) | ||
| 2059 | { | ||
| 2060 | int ret; | ||
| 2061 | |||
| 2062 | /* Register the subdev and video nodes. */ | ||
| 2063 | ret = v4l2_device_register_subdev(vdev, &prev->subdev); | ||
| 2064 | if (ret < 0) | ||
| 2065 | goto error; | ||
| 2066 | |||
| 2067 | ret = omap3isp_video_register(&prev->video_in, vdev); | ||
| 2068 | if (ret < 0) | ||
| 2069 | goto error; | ||
| 2070 | |||
| 2071 | ret = omap3isp_video_register(&prev->video_out, vdev); | ||
| 2072 | if (ret < 0) | ||
| 2073 | goto error; | ||
| 2074 | |||
| 2075 | return 0; | ||
| 2076 | |||
| 2077 | error: | ||
| 2078 | omap3isp_preview_unregister_entities(prev); | ||
| 2079 | return ret; | 2205 | return ret; |
| 2080 | } | 2206 | } |
| 2081 | 2207 | ||
| 2082 | /* ----------------------------------------------------------------------------- | ||
| 2083 | * ISP previewer initialisation and cleanup | ||
| 2084 | */ | ||
| 2085 | |||
| 2086 | void omap3isp_preview_cleanup(struct isp_device *isp) | ||
| 2087 | { | ||
| 2088 | } | ||
| 2089 | |||
| 2090 | /* | 2208 | /* |
| 2091 | * isp_preview_init - Previewer initialization. | 2209 | * isp_preview_init - Previewer initialization. |
| 2092 | * @dev : Pointer to ISP device | 2210 | * @dev : Pointer to ISP device |
| @@ -2095,19 +2213,20 @@ void omap3isp_preview_cleanup(struct isp_device *isp) | |||
| 2095 | int omap3isp_preview_init(struct isp_device *isp) | 2213 | int omap3isp_preview_init(struct isp_device *isp) |
| 2096 | { | 2214 | { |
| 2097 | struct isp_prev_device *prev = &isp->isp_prev; | 2215 | struct isp_prev_device *prev = &isp->isp_prev; |
| 2098 | int ret; | ||
| 2099 | 2216 | ||
| 2100 | spin_lock_init(&prev->lock); | 2217 | spin_lock_init(&prev->lock); |
| 2101 | init_waitqueue_head(&prev->wait); | 2218 | init_waitqueue_head(&prev->wait); |
| 2102 | preview_init_params(prev); | 2219 | preview_init_params(prev); |
| 2103 | 2220 | ||
| 2104 | ret = preview_init_entities(prev); | 2221 | return preview_init_entities(prev); |
| 2105 | if (ret < 0) | 2222 | } |
| 2106 | goto out; | ||
| 2107 | 2223 | ||
| 2108 | out: | 2224 | void omap3isp_preview_cleanup(struct isp_device *isp) |
| 2109 | if (ret) | 2225 | { |
| 2110 | omap3isp_preview_cleanup(isp); | 2226 | struct isp_prev_device *prev = &isp->isp_prev; |
| 2111 | 2227 | ||
| 2112 | return ret; | 2228 | v4l2_ctrl_handler_free(&prev->ctrls); |
| 2229 | omap3isp_video_cleanup(&prev->video_in); | ||
| 2230 | omap3isp_video_cleanup(&prev->video_out); | ||
| 2231 | media_entity_cleanup(&prev->subdev.entity); | ||
| 2113 | } | 2232 | } |
diff --git a/drivers/media/video/omap3isp/isppreview.h b/drivers/media/video/omap3isp/isppreview.h index fa943bd05c7f..f54e775c2df4 100644 --- a/drivers/media/video/omap3isp/isppreview.h +++ b/drivers/media/video/omap3isp/isppreview.h | |||
| @@ -45,11 +45,6 @@ | |||
| 45 | #define ISPPRV_CONTRAST_HIGH 0xFF | 45 | #define ISPPRV_CONTRAST_HIGH 0xFF |
| 46 | #define ISPPRV_CONTRAST_UNITS 0x1 | 46 | #define ISPPRV_CONTRAST_UNITS 0x1 |
| 47 | 47 | ||
| 48 | #define NO_AVE 0x0 | ||
| 49 | #define AVE_2_PIX 0x1 | ||
| 50 | #define AVE_4_PIX 0x2 | ||
| 51 | #define AVE_8_PIX 0x3 | ||
| 52 | |||
| 53 | /* Features list */ | 48 | /* Features list */ |
| 54 | #define PREV_LUMA_ENHANCE OMAP3ISP_PREV_LUMAENH | 49 | #define PREV_LUMA_ENHANCE OMAP3ISP_PREV_LUMAENH |
| 55 | #define PREV_INVERSE_ALAW OMAP3ISP_PREV_INVALAW | 50 | #define PREV_INVERSE_ALAW OMAP3ISP_PREV_INVALAW |
| @@ -106,7 +101,6 @@ enum preview_ycpos_mode { | |||
| 106 | * @rgb2ycbcr: RGB to ycbcr parameters. | 101 | * @rgb2ycbcr: RGB to ycbcr parameters. |
| 107 | * @hmed: Horizontal median filter. | 102 | * @hmed: Horizontal median filter. |
| 108 | * @yclimit: YC limits parameters. | 103 | * @yclimit: YC limits parameters. |
| 109 | * @average: Downsampling rate for averager. | ||
| 110 | * @contrast: Contrast. | 104 | * @contrast: Contrast. |
| 111 | * @brightness: Brightness. | 105 | * @brightness: Brightness. |
| 112 | */ | 106 | */ |
| @@ -124,7 +118,6 @@ struct prev_params { | |||
| 124 | struct omap3isp_prev_csc rgb2ycbcr; | 118 | struct omap3isp_prev_csc rgb2ycbcr; |
| 125 | struct omap3isp_prev_hmed hmed; | 119 | struct omap3isp_prev_hmed hmed; |
| 126 | struct omap3isp_prev_yclimit yclimit; | 120 | struct omap3isp_prev_yclimit yclimit; |
| 127 | u8 average; | ||
| 128 | u8 contrast; | 121 | u8 contrast; |
| 129 | u8 brightness; | 122 | u8 brightness; |
| 130 | }; | 123 | }; |
| @@ -159,6 +152,7 @@ struct isptables_update { | |||
| 159 | * @subdev: V4L2 subdevice | 152 | * @subdev: V4L2 subdevice |
| 160 | * @pads: Media entity pads | 153 | * @pads: Media entity pads |
| 161 | * @formats: Active formats at the subdev pad | 154 | * @formats: Active formats at the subdev pad |
| 155 | * @crop: Active crop rectangle | ||
| 162 | * @input: Module currently connected to the input pad | 156 | * @input: Module currently connected to the input pad |
| 163 | * @output: Bitmask of the active output | 157 | * @output: Bitmask of the active output |
| 164 | * @video_in: Input video entity | 158 | * @video_in: Input video entity |
| @@ -177,6 +171,7 @@ struct isp_prev_device { | |||
| 177 | struct v4l2_subdev subdev; | 171 | struct v4l2_subdev subdev; |
| 178 | struct media_pad pads[PREV_PADS_NUM]; | 172 | struct media_pad pads[PREV_PADS_NUM]; |
| 179 | struct v4l2_mbus_framefmt formats[PREV_PADS_NUM]; | 173 | struct v4l2_mbus_framefmt formats[PREV_PADS_NUM]; |
| 174 | struct v4l2_rect crop; | ||
| 180 | 175 | ||
| 181 | struct v4l2_ctrl_handler ctrls; | 176 | struct v4l2_ctrl_handler ctrls; |
| 182 | 177 | ||
diff --git a/drivers/media/video/omap3isp/ispreg.h b/drivers/media/video/omap3isp/ispreg.h index 69f6af6f6b9c..084ea77d65a7 100644 --- a/drivers/media/video/omap3isp/ispreg.h +++ b/drivers/media/video/omap3isp/ispreg.h | |||
| @@ -402,9 +402,6 @@ | |||
| 402 | #define ISPPRV_YENH_TABLE_ADDR 0x1000 | 402 | #define ISPPRV_YENH_TABLE_ADDR 0x1000 |
| 403 | #define ISPPRV_CFA_TABLE_ADDR 0x1400 | 403 | #define ISPPRV_CFA_TABLE_ADDR 0x1400 |
| 404 | 404 | ||
| 405 | #define ISPPRV_MAXOUTPUT_WIDTH 1280 | ||
| 406 | #define ISPPRV_MAXOUTPUT_WIDTH_ES2 3300 | ||
| 407 | #define ISPPRV_MAXOUTPUT_WIDTH_3630 4096 | ||
| 408 | #define ISPRSZ_MIN_OUTPUT 64 | 405 | #define ISPRSZ_MIN_OUTPUT 64 |
| 409 | #define ISPRSZ_MAX_OUTPUT 3312 | 406 | #define ISPRSZ_MAX_OUTPUT 3312 |
| 410 | 407 | ||
diff --git a/drivers/media/video/omap3isp/ispresizer.c b/drivers/media/video/omap3isp/ispresizer.c index 0bb0f8cd36f5..50e593bfcfaf 100644 --- a/drivers/media/video/omap3isp/ispresizer.c +++ b/drivers/media/video/omap3isp/ispresizer.c | |||
| @@ -1608,6 +1608,42 @@ static const struct media_entity_operations resizer_media_ops = { | |||
| 1608 | .link_setup = resizer_link_setup, | 1608 | .link_setup = resizer_link_setup, |
| 1609 | }; | 1609 | }; |
| 1610 | 1610 | ||
| 1611 | void omap3isp_resizer_unregister_entities(struct isp_res_device *res) | ||
| 1612 | { | ||
| 1613 | v4l2_device_unregister_subdev(&res->subdev); | ||
| 1614 | omap3isp_video_unregister(&res->video_in); | ||
| 1615 | omap3isp_video_unregister(&res->video_out); | ||
| 1616 | } | ||
| 1617 | |||
| 1618 | int omap3isp_resizer_register_entities(struct isp_res_device *res, | ||
| 1619 | struct v4l2_device *vdev) | ||
| 1620 | { | ||
| 1621 | int ret; | ||
| 1622 | |||
| 1623 | /* Register the subdev and video nodes. */ | ||
| 1624 | ret = v4l2_device_register_subdev(vdev, &res->subdev); | ||
| 1625 | if (ret < 0) | ||
| 1626 | goto error; | ||
| 1627 | |||
| 1628 | ret = omap3isp_video_register(&res->video_in, vdev); | ||
| 1629 | if (ret < 0) | ||
| 1630 | goto error; | ||
| 1631 | |||
| 1632 | ret = omap3isp_video_register(&res->video_out, vdev); | ||
| 1633 | if (ret < 0) | ||
| 1634 | goto error; | ||
| 1635 | |||
| 1636 | return 0; | ||
| 1637 | |||
| 1638 | error: | ||
| 1639 | omap3isp_resizer_unregister_entities(res); | ||
| 1640 | return ret; | ||
| 1641 | } | ||
| 1642 | |||
| 1643 | /* ----------------------------------------------------------------------------- | ||
| 1644 | * ISP resizer initialization and cleanup | ||
| 1645 | */ | ||
| 1646 | |||
| 1611 | /* | 1647 | /* |
| 1612 | * resizer_init_entities - Initialize resizer subdev and media entity. | 1648 | * resizer_init_entities - Initialize resizer subdev and media entity. |
| 1613 | * @res : Pointer to resizer device structure | 1649 | * @res : Pointer to resizer device structure |
| @@ -1652,68 +1688,34 @@ static int resizer_init_entities(struct isp_res_device *res) | |||
| 1652 | 1688 | ||
| 1653 | ret = omap3isp_video_init(&res->video_in, "resizer"); | 1689 | ret = omap3isp_video_init(&res->video_in, "resizer"); |
| 1654 | if (ret < 0) | 1690 | if (ret < 0) |
| 1655 | return ret; | 1691 | goto error_video_in; |
| 1656 | 1692 | ||
| 1657 | ret = omap3isp_video_init(&res->video_out, "resizer"); | 1693 | ret = omap3isp_video_init(&res->video_out, "resizer"); |
| 1658 | if (ret < 0) | 1694 | if (ret < 0) |
| 1659 | return ret; | 1695 | goto error_video_out; |
| 1660 | 1696 | ||
| 1661 | /* Connect the video nodes to the resizer subdev. */ | 1697 | /* Connect the video nodes to the resizer subdev. */ |
| 1662 | ret = media_entity_create_link(&res->video_in.video.entity, 0, | 1698 | ret = media_entity_create_link(&res->video_in.video.entity, 0, |
| 1663 | &res->subdev.entity, RESZ_PAD_SINK, 0); | 1699 | &res->subdev.entity, RESZ_PAD_SINK, 0); |
| 1664 | if (ret < 0) | 1700 | if (ret < 0) |
| 1665 | return ret; | 1701 | goto error_link; |
| 1666 | 1702 | ||
| 1667 | ret = media_entity_create_link(&res->subdev.entity, RESZ_PAD_SOURCE, | 1703 | ret = media_entity_create_link(&res->subdev.entity, RESZ_PAD_SOURCE, |
| 1668 | &res->video_out.video.entity, 0, 0); | 1704 | &res->video_out.video.entity, 0, 0); |
| 1669 | if (ret < 0) | 1705 | if (ret < 0) |
| 1670 | return ret; | 1706 | goto error_link; |
| 1671 | 1707 | ||
| 1672 | return 0; | 1708 | return 0; |
| 1673 | } | ||
| 1674 | 1709 | ||
| 1675 | void omap3isp_resizer_unregister_entities(struct isp_res_device *res) | 1710 | error_link: |
| 1676 | { | 1711 | omap3isp_video_cleanup(&res->video_out); |
| 1712 | error_video_out: | ||
| 1713 | omap3isp_video_cleanup(&res->video_in); | ||
| 1714 | error_video_in: | ||
| 1677 | media_entity_cleanup(&res->subdev.entity); | 1715 | media_entity_cleanup(&res->subdev.entity); |
| 1678 | |||
| 1679 | v4l2_device_unregister_subdev(&res->subdev); | ||
| 1680 | omap3isp_video_unregister(&res->video_in); | ||
| 1681 | omap3isp_video_unregister(&res->video_out); | ||
| 1682 | } | ||
| 1683 | |||
| 1684 | int omap3isp_resizer_register_entities(struct isp_res_device *res, | ||
| 1685 | struct v4l2_device *vdev) | ||
| 1686 | { | ||
| 1687 | int ret; | ||
| 1688 | |||
| 1689 | /* Register the subdev and video nodes. */ | ||
| 1690 | ret = v4l2_device_register_subdev(vdev, &res->subdev); | ||
| 1691 | if (ret < 0) | ||
| 1692 | goto error; | ||
| 1693 | |||
| 1694 | ret = omap3isp_video_register(&res->video_in, vdev); | ||
| 1695 | if (ret < 0) | ||
| 1696 | goto error; | ||
| 1697 | |||
| 1698 | ret = omap3isp_video_register(&res->video_out, vdev); | ||
| 1699 | if (ret < 0) | ||
| 1700 | goto error; | ||
| 1701 | |||
| 1702 | return 0; | ||
| 1703 | |||
| 1704 | error: | ||
| 1705 | omap3isp_resizer_unregister_entities(res); | ||
| 1706 | return ret; | 1716 | return ret; |
| 1707 | } | 1717 | } |
| 1708 | 1718 | ||
| 1709 | /* ----------------------------------------------------------------------------- | ||
| 1710 | * ISP resizer initialization and cleanup | ||
| 1711 | */ | ||
| 1712 | |||
| 1713 | void omap3isp_resizer_cleanup(struct isp_device *isp) | ||
| 1714 | { | ||
| 1715 | } | ||
| 1716 | |||
| 1717 | /* | 1719 | /* |
| 1718 | * isp_resizer_init - Resizer initialization. | 1720 | * isp_resizer_init - Resizer initialization. |
| 1719 | * @isp : Pointer to ISP device | 1721 | * @isp : Pointer to ISP device |
| @@ -1722,17 +1724,17 @@ void omap3isp_resizer_cleanup(struct isp_device *isp) | |||
| 1722 | int omap3isp_resizer_init(struct isp_device *isp) | 1724 | int omap3isp_resizer_init(struct isp_device *isp) |
| 1723 | { | 1725 | { |
| 1724 | struct isp_res_device *res = &isp->isp_res; | 1726 | struct isp_res_device *res = &isp->isp_res; |
| 1725 | int ret; | ||
| 1726 | 1727 | ||
| 1727 | init_waitqueue_head(&res->wait); | 1728 | init_waitqueue_head(&res->wait); |
| 1728 | atomic_set(&res->stopping, 0); | 1729 | atomic_set(&res->stopping, 0); |
| 1729 | ret = resizer_init_entities(res); | 1730 | return resizer_init_entities(res); |
| 1730 | if (ret < 0) | 1731 | } |
| 1731 | goto out; | ||
| 1732 | 1732 | ||
| 1733 | out: | 1733 | void omap3isp_resizer_cleanup(struct isp_device *isp) |
| 1734 | if (ret) | 1734 | { |
| 1735 | omap3isp_resizer_cleanup(isp); | 1735 | struct isp_res_device *res = &isp->isp_res; |
| 1736 | 1736 | ||
| 1737 | return ret; | 1737 | omap3isp_video_cleanup(&res->video_in); |
| 1738 | omap3isp_video_cleanup(&res->video_out); | ||
| 1739 | media_entity_cleanup(&res->subdev.entity); | ||
| 1738 | } | 1740 | } |
diff --git a/drivers/media/video/omap3isp/ispstat.c b/drivers/media/video/omap3isp/ispstat.c index 732905552261..68d539456c55 100644 --- a/drivers/media/video/omap3isp/ispstat.c +++ b/drivers/media/video/omap3isp/ispstat.c | |||
| @@ -1023,24 +1023,6 @@ void omap3isp_stat_dma_isr(struct ispstat *stat) | |||
| 1023 | __stat_isr(stat, 1); | 1023 | __stat_isr(stat, 1); |
| 1024 | } | 1024 | } |
| 1025 | 1025 | ||
| 1026 | static int isp_stat_init_entities(struct ispstat *stat, const char *name, | ||
| 1027 | const struct v4l2_subdev_ops *sd_ops) | ||
| 1028 | { | ||
| 1029 | struct v4l2_subdev *subdev = &stat->subdev; | ||
| 1030 | struct media_entity *me = &subdev->entity; | ||
| 1031 | |||
| 1032 | v4l2_subdev_init(subdev, sd_ops); | ||
| 1033 | snprintf(subdev->name, V4L2_SUBDEV_NAME_SIZE, "OMAP3 ISP %s", name); | ||
| 1034 | subdev->grp_id = 1 << 16; /* group ID for isp subdevs */ | ||
| 1035 | subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
| 1036 | v4l2_set_subdevdata(subdev, stat); | ||
| 1037 | |||
| 1038 | stat->pad.flags = MEDIA_PAD_FL_SINK; | ||
| 1039 | me->ops = NULL; | ||
| 1040 | |||
| 1041 | return media_entity_init(me, 1, &stat->pad, 0); | ||
| 1042 | } | ||
| 1043 | |||
| 1044 | int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev, | 1026 | int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev, |
| 1045 | struct v4l2_fh *fh, | 1027 | struct v4l2_fh *fh, |
| 1046 | struct v4l2_event_subscription *sub) | 1028 | struct v4l2_event_subscription *sub) |
| @@ -1062,7 +1044,6 @@ int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev, | |||
| 1062 | 1044 | ||
| 1063 | void omap3isp_stat_unregister_entities(struct ispstat *stat) | 1045 | void omap3isp_stat_unregister_entities(struct ispstat *stat) |
| 1064 | { | 1046 | { |
| 1065 | media_entity_cleanup(&stat->subdev.entity); | ||
| 1066 | v4l2_device_unregister_subdev(&stat->subdev); | 1047 | v4l2_device_unregister_subdev(&stat->subdev); |
| 1067 | } | 1048 | } |
| 1068 | 1049 | ||
| @@ -1072,21 +1053,50 @@ int omap3isp_stat_register_entities(struct ispstat *stat, | |||
| 1072 | return v4l2_device_register_subdev(vdev, &stat->subdev); | 1053 | return v4l2_device_register_subdev(vdev, &stat->subdev); |
| 1073 | } | 1054 | } |
| 1074 | 1055 | ||
| 1056 | static int isp_stat_init_entities(struct ispstat *stat, const char *name, | ||
| 1057 | const struct v4l2_subdev_ops *sd_ops) | ||
| 1058 | { | ||
| 1059 | struct v4l2_subdev *subdev = &stat->subdev; | ||
| 1060 | struct media_entity *me = &subdev->entity; | ||
| 1061 | |||
| 1062 | v4l2_subdev_init(subdev, sd_ops); | ||
| 1063 | snprintf(subdev->name, V4L2_SUBDEV_NAME_SIZE, "OMAP3 ISP %s", name); | ||
| 1064 | subdev->grp_id = 1 << 16; /* group ID for isp subdevs */ | ||
| 1065 | subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
| 1066 | v4l2_set_subdevdata(subdev, stat); | ||
| 1067 | |||
| 1068 | stat->pad.flags = MEDIA_PAD_FL_SINK; | ||
| 1069 | me->ops = NULL; | ||
| 1070 | |||
| 1071 | return media_entity_init(me, 1, &stat->pad, 0); | ||
| 1072 | } | ||
| 1073 | |||
| 1075 | int omap3isp_stat_init(struct ispstat *stat, const char *name, | 1074 | int omap3isp_stat_init(struct ispstat *stat, const char *name, |
| 1076 | const struct v4l2_subdev_ops *sd_ops) | 1075 | const struct v4l2_subdev_ops *sd_ops) |
| 1077 | { | 1076 | { |
| 1077 | int ret; | ||
| 1078 | |||
| 1078 | stat->buf = kcalloc(STAT_MAX_BUFS, sizeof(*stat->buf), GFP_KERNEL); | 1079 | stat->buf = kcalloc(STAT_MAX_BUFS, sizeof(*stat->buf), GFP_KERNEL); |
| 1079 | if (!stat->buf) | 1080 | if (!stat->buf) |
| 1080 | return -ENOMEM; | 1081 | return -ENOMEM; |
| 1082 | |||
| 1081 | isp_stat_buf_clear(stat); | 1083 | isp_stat_buf_clear(stat); |
| 1082 | mutex_init(&stat->ioctl_lock); | 1084 | mutex_init(&stat->ioctl_lock); |
| 1083 | atomic_set(&stat->buf_err, 0); | 1085 | atomic_set(&stat->buf_err, 0); |
| 1084 | 1086 | ||
| 1085 | return isp_stat_init_entities(stat, name, sd_ops); | 1087 | ret = isp_stat_init_entities(stat, name, sd_ops); |
| 1088 | if (ret < 0) { | ||
| 1089 | mutex_destroy(&stat->ioctl_lock); | ||
| 1090 | kfree(stat->buf); | ||
| 1091 | } | ||
| 1092 | |||
| 1093 | return ret; | ||
| 1086 | } | 1094 | } |
| 1087 | 1095 | ||
| 1088 | void omap3isp_stat_free(struct ispstat *stat) | 1096 | void omap3isp_stat_cleanup(struct ispstat *stat) |
| 1089 | { | 1097 | { |
| 1098 | media_entity_cleanup(&stat->subdev.entity); | ||
| 1099 | mutex_destroy(&stat->ioctl_lock); | ||
| 1090 | isp_stat_bufs_free(stat); | 1100 | isp_stat_bufs_free(stat); |
| 1091 | kfree(stat->buf); | 1101 | kfree(stat->buf); |
| 1092 | } | 1102 | } |
diff --git a/drivers/media/video/omap3isp/ispstat.h b/drivers/media/video/omap3isp/ispstat.h index d86da94fa50d..9b7c8654dc8a 100644 --- a/drivers/media/video/omap3isp/ispstat.h +++ b/drivers/media/video/omap3isp/ispstat.h | |||
| @@ -144,7 +144,7 @@ int omap3isp_stat_request_statistics(struct ispstat *stat, | |||
| 144 | struct omap3isp_stat_data *data); | 144 | struct omap3isp_stat_data *data); |
| 145 | int omap3isp_stat_init(struct ispstat *stat, const char *name, | 145 | int omap3isp_stat_init(struct ispstat *stat, const char *name, |
| 146 | const struct v4l2_subdev_ops *sd_ops); | 146 | const struct v4l2_subdev_ops *sd_ops); |
| 147 | void omap3isp_stat_free(struct ispstat *stat); | 147 | void omap3isp_stat_cleanup(struct ispstat *stat); |
| 148 | int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev, | 148 | int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev, |
| 149 | struct v4l2_fh *fh, | 149 | struct v4l2_fh *fh, |
| 150 | struct v4l2_event_subscription *sub); | 150 | struct v4l2_event_subscription *sub); |
diff --git a/drivers/media/video/omap3isp/ispvideo.c b/drivers/media/video/omap3isp/ispvideo.c index 0cb8a9f9d675..d1000723c5ae 100644 --- a/drivers/media/video/omap3isp/ispvideo.c +++ b/drivers/media/video/omap3isp/ispvideo.c | |||
| @@ -1325,6 +1325,13 @@ int omap3isp_video_init(struct isp_video *video, const char *name) | |||
| 1325 | return 0; | 1325 | return 0; |
| 1326 | } | 1326 | } |
| 1327 | 1327 | ||
| 1328 | void omap3isp_video_cleanup(struct isp_video *video) | ||
| 1329 | { | ||
| 1330 | media_entity_cleanup(&video->video.entity); | ||
| 1331 | mutex_destroy(&video->stream_lock); | ||
| 1332 | mutex_destroy(&video->mutex); | ||
| 1333 | } | ||
| 1334 | |||
| 1328 | int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev) | 1335 | int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev) |
| 1329 | { | 1336 | { |
| 1330 | int ret; | 1337 | int ret; |
| @@ -1341,8 +1348,6 @@ int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev) | |||
| 1341 | 1348 | ||
| 1342 | void omap3isp_video_unregister(struct isp_video *video) | 1349 | void omap3isp_video_unregister(struct isp_video *video) |
| 1343 | { | 1350 | { |
| 1344 | if (video_is_registered(&video->video)) { | 1351 | if (video_is_registered(&video->video)) |
| 1345 | media_entity_cleanup(&video->video.entity); | ||
| 1346 | video_unregister_device(&video->video); | 1352 | video_unregister_device(&video->video); |
| 1347 | } | ||
| 1348 | } | 1353 | } |
diff --git a/drivers/media/video/omap3isp/ispvideo.h b/drivers/media/video/omap3isp/ispvideo.h index 53160aa24e6e..08cbfa144e6e 100644 --- a/drivers/media/video/omap3isp/ispvideo.h +++ b/drivers/media/video/omap3isp/ispvideo.h | |||
| @@ -190,6 +190,7 @@ struct isp_video_fh { | |||
| 190 | container_of(q, struct isp_video_fh, queue) | 190 | container_of(q, struct isp_video_fh, queue) |
| 191 | 191 | ||
| 192 | int omap3isp_video_init(struct isp_video *video, const char *name); | 192 | int omap3isp_video_init(struct isp_video *video, const char *name); |
| 193 | void omap3isp_video_cleanup(struct isp_video *video); | ||
| 193 | int omap3isp_video_register(struct isp_video *video, | 194 | int omap3isp_video_register(struct isp_video *video, |
| 194 | struct v4l2_device *vdev); | 195 | struct v4l2_device *vdev); |
| 195 | void omap3isp_video_unregister(struct isp_video *video); | 196 | void omap3isp_video_unregister(struct isp_video *video); |
diff --git a/drivers/media/video/ov2640.c b/drivers/media/video/ov2640.c index 9ce2fa037b94..b5247cb64fde 100644 --- a/drivers/media/video/ov2640.c +++ b/drivers/media/video/ov2640.c | |||
| @@ -18,11 +18,13 @@ | |||
| 18 | #include <linux/i2c.h> | 18 | #include <linux/i2c.h> |
| 19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
| 20 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
| 21 | #include <linux/v4l2-mediabus.h> | ||
| 21 | #include <linux/videodev2.h> | 22 | #include <linux/videodev2.h> |
| 23 | |||
| 24 | #include <media/soc_camera.h> | ||
| 22 | #include <media/v4l2-chip-ident.h> | 25 | #include <media/v4l2-chip-ident.h> |
| 23 | #include <media/v4l2-subdev.h> | 26 | #include <media/v4l2-subdev.h> |
| 24 | #include <media/soc_camera.h> | 27 | #include <media/v4l2-ctrls.h> |
| 25 | #include <media/soc_mediabus.h> | ||
| 26 | 28 | ||
| 27 | #define VAL_SET(x, mask, rshift, lshift) \ | 29 | #define VAL_SET(x, mask, rshift, lshift) \ |
| 28 | ((((x) >> rshift) & mask) << lshift) | 30 | ((((x) >> rshift) & mask) << lshift) |
| @@ -299,12 +301,10 @@ struct ov2640_win_size { | |||
| 299 | 301 | ||
| 300 | struct ov2640_priv { | 302 | struct ov2640_priv { |
| 301 | struct v4l2_subdev subdev; | 303 | struct v4l2_subdev subdev; |
| 302 | struct ov2640_camera_info *info; | 304 | struct v4l2_ctrl_handler hdl; |
| 303 | enum v4l2_mbus_pixelcode cfmt_code; | 305 | enum v4l2_mbus_pixelcode cfmt_code; |
| 304 | const struct ov2640_win_size *win; | 306 | const struct ov2640_win_size *win; |
| 305 | int model; | 307 | int model; |
| 306 | u16 flag_vflip:1; | ||
| 307 | u16 flag_hflip:1; | ||
| 308 | }; | 308 | }; |
| 309 | 309 | ||
| 310 | /* | 310 | /* |
| @@ -610,29 +610,6 @@ static enum v4l2_mbus_pixelcode ov2640_codes[] = { | |||
| 610 | }; | 610 | }; |
| 611 | 611 | ||
| 612 | /* | 612 | /* |
| 613 | * Supported controls | ||
| 614 | */ | ||
| 615 | static const struct v4l2_queryctrl ov2640_controls[] = { | ||
| 616 | { | ||
| 617 | .id = V4L2_CID_VFLIP, | ||
| 618 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 619 | .name = "Flip Vertically", | ||
| 620 | .minimum = 0, | ||
| 621 | .maximum = 1, | ||
| 622 | .step = 1, | ||
| 623 | .default_value = 0, | ||
| 624 | }, { | ||
| 625 | .id = V4L2_CID_HFLIP, | ||
| 626 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 627 | .name = "Flip Horizontally", | ||
| 628 | .minimum = 0, | ||
| 629 | .maximum = 1, | ||
| 630 | .step = 1, | ||
| 631 | .default_value = 0, | ||
| 632 | }, | ||
| 633 | }; | ||
| 634 | |||
| 635 | /* | ||
| 636 | * General functions | 613 | * General functions |
| 637 | */ | 614 | */ |
| 638 | static struct ov2640_priv *to_ov2640(const struct i2c_client *client) | 615 | static struct ov2640_priv *to_ov2640(const struct i2c_client *client) |
| @@ -701,81 +678,23 @@ static int ov2640_s_stream(struct v4l2_subdev *sd, int enable) | |||
| 701 | return 0; | 678 | return 0; |
| 702 | } | 679 | } |
| 703 | 680 | ||
| 704 | static int ov2640_set_bus_param(struct soc_camera_device *icd, | 681 | static int ov2640_s_ctrl(struct v4l2_ctrl *ctrl) |
| 705 | unsigned long flags) | ||
| 706 | { | ||
| 707 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
| 708 | unsigned long width_flag = flags & SOCAM_DATAWIDTH_MASK; | ||
| 709 | |||
| 710 | /* Only one width bit may be set */ | ||
| 711 | if (!is_power_of_2(width_flag)) | ||
| 712 | return -EINVAL; | ||
| 713 | |||
| 714 | if (icl->set_bus_param) | ||
| 715 | return icl->set_bus_param(icl, width_flag); | ||
| 716 | |||
| 717 | /* | ||
| 718 | * Without board specific bus width settings we support only the | ||
| 719 | * sensors native bus width witch are tested working | ||
| 720 | */ | ||
| 721 | if (width_flag & (SOCAM_DATAWIDTH_10 | SOCAM_DATAWIDTH_8)) | ||
| 722 | return 0; | ||
| 723 | |||
| 724 | return 0; | ||
| 725 | } | ||
| 726 | |||
| 727 | static unsigned long ov2640_query_bus_param(struct soc_camera_device *icd) | ||
| 728 | { | ||
| 729 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
| 730 | unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | | ||
| 731 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | | ||
| 732 | SOCAM_DATA_ACTIVE_HIGH; | ||
| 733 | |||
| 734 | if (icl->query_bus_param) | ||
| 735 | flags |= icl->query_bus_param(icl) & SOCAM_DATAWIDTH_MASK; | ||
| 736 | else | ||
| 737 | flags |= SOCAM_DATAWIDTH_10; | ||
| 738 | |||
| 739 | return soc_camera_apply_sensor_flags(icl, flags); | ||
| 740 | } | ||
| 741 | |||
| 742 | static int ov2640_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
| 743 | { | 682 | { |
| 683 | struct v4l2_subdev *sd = | ||
| 684 | &container_of(ctrl->handler, struct ov2640_priv, hdl)->subdev; | ||
| 744 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 685 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 745 | struct ov2640_priv *priv = to_ov2640(client); | ||
| 746 | |||
| 747 | switch (ctrl->id) { | ||
| 748 | case V4L2_CID_VFLIP: | ||
| 749 | ctrl->value = priv->flag_vflip; | ||
| 750 | break; | ||
| 751 | case V4L2_CID_HFLIP: | ||
| 752 | ctrl->value = priv->flag_hflip; | ||
| 753 | break; | ||
| 754 | } | ||
| 755 | return 0; | ||
| 756 | } | ||
| 757 | |||
| 758 | static int ov2640_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
| 759 | { | ||
| 760 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 761 | struct ov2640_priv *priv = to_ov2640(client); | ||
| 762 | int ret = 0; | ||
| 763 | u8 val; | 686 | u8 val; |
| 764 | 687 | ||
| 765 | switch (ctrl->id) { | 688 | switch (ctrl->id) { |
| 766 | case V4L2_CID_VFLIP: | 689 | case V4L2_CID_VFLIP: |
| 767 | val = ctrl->value ? REG04_VFLIP_IMG : 0x00; | 690 | val = ctrl->val ? REG04_VFLIP_IMG : 0x00; |
| 768 | priv->flag_vflip = ctrl->value ? 1 : 0; | 691 | return ov2640_mask_set(client, REG04, REG04_VFLIP_IMG, val); |
| 769 | ret = ov2640_mask_set(client, REG04, REG04_VFLIP_IMG, val); | ||
| 770 | break; | ||
| 771 | case V4L2_CID_HFLIP: | 692 | case V4L2_CID_HFLIP: |
| 772 | val = ctrl->value ? REG04_HFLIP_IMG : 0x00; | 693 | val = ctrl->val ? REG04_HFLIP_IMG : 0x00; |
| 773 | priv->flag_hflip = ctrl->value ? 1 : 0; | 694 | return ov2640_mask_set(client, REG04, REG04_HFLIP_IMG, val); |
| 774 | ret = ov2640_mask_set(client, REG04, REG04_HFLIP_IMG, val); | ||
| 775 | break; | ||
| 776 | } | 695 | } |
| 777 | 696 | ||
| 778 | return ret; | 697 | return -EINVAL; |
| 779 | } | 698 | } |
| 780 | 699 | ||
| 781 | static int ov2640_g_chip_ident(struct v4l2_subdev *sd, | 700 | static int ov2640_g_chip_ident(struct v4l2_subdev *sd, |
| @@ -1023,18 +942,13 @@ static int ov2640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | |||
| 1023 | return 0; | 942 | return 0; |
| 1024 | } | 943 | } |
| 1025 | 944 | ||
| 1026 | static int ov2640_video_probe(struct soc_camera_device *icd, | 945 | static int ov2640_video_probe(struct i2c_client *client) |
| 1027 | struct i2c_client *client) | ||
| 1028 | { | 946 | { |
| 1029 | struct ov2640_priv *priv = to_ov2640(client); | 947 | struct ov2640_priv *priv = to_ov2640(client); |
| 1030 | u8 pid, ver, midh, midl; | 948 | u8 pid, ver, midh, midl; |
| 1031 | const char *devname; | 949 | const char *devname; |
| 1032 | int ret; | 950 | int ret; |
| 1033 | 951 | ||
| 1034 | /* We must have a parent by now. And it cannot be a wrong one. */ | ||
| 1035 | BUG_ON(!icd->parent || | ||
| 1036 | to_soc_camera_host(icd->parent)->nr != icd->iface); | ||
| 1037 | |||
| 1038 | /* | 952 | /* |
| 1039 | * check and show product ID and manufacturer ID | 953 | * check and show product ID and manufacturer ID |
| 1040 | */ | 954 | */ |
| @@ -1060,22 +974,17 @@ static int ov2640_video_probe(struct soc_camera_device *icd, | |||
| 1060 | "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", | 974 | "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", |
| 1061 | devname, pid, ver, midh, midl); | 975 | devname, pid, ver, midh, midl); |
| 1062 | 976 | ||
| 1063 | return 0; | 977 | return v4l2_ctrl_handler_setup(&priv->hdl); |
| 1064 | 978 | ||
| 1065 | err: | 979 | err: |
| 1066 | return ret; | 980 | return ret; |
| 1067 | } | 981 | } |
| 1068 | 982 | ||
| 1069 | static struct soc_camera_ops ov2640_ops = { | 983 | static const struct v4l2_ctrl_ops ov2640_ctrl_ops = { |
| 1070 | .set_bus_param = ov2640_set_bus_param, | 984 | .s_ctrl = ov2640_s_ctrl, |
| 1071 | .query_bus_param = ov2640_query_bus_param, | ||
| 1072 | .controls = ov2640_controls, | ||
| 1073 | .num_controls = ARRAY_SIZE(ov2640_controls), | ||
| 1074 | }; | 985 | }; |
| 1075 | 986 | ||
| 1076 | static struct v4l2_subdev_core_ops ov2640_subdev_core_ops = { | 987 | static struct v4l2_subdev_core_ops ov2640_subdev_core_ops = { |
| 1077 | .g_ctrl = ov2640_g_ctrl, | ||
| 1078 | .s_ctrl = ov2640_s_ctrl, | ||
| 1079 | .g_chip_ident = ov2640_g_chip_ident, | 988 | .g_chip_ident = ov2640_g_chip_ident, |
| 1080 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 989 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
| 1081 | .g_register = ov2640_g_register, | 990 | .g_register = ov2640_g_register, |
| @@ -1083,6 +992,21 @@ static struct v4l2_subdev_core_ops ov2640_subdev_core_ops = { | |||
| 1083 | #endif | 992 | #endif |
| 1084 | }; | 993 | }; |
| 1085 | 994 | ||
| 995 | static int ov2640_g_mbus_config(struct v4l2_subdev *sd, | ||
| 996 | struct v4l2_mbus_config *cfg) | ||
| 997 | { | ||
| 998 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 999 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
| 1000 | |||
| 1001 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | | ||
| 1002 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | | ||
| 1003 | V4L2_MBUS_DATA_ACTIVE_HIGH; | ||
| 1004 | cfg->type = V4L2_MBUS_PARALLEL; | ||
| 1005 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | ||
| 1006 | |||
| 1007 | return 0; | ||
| 1008 | } | ||
| 1009 | |||
| 1086 | static struct v4l2_subdev_video_ops ov2640_subdev_video_ops = { | 1010 | static struct v4l2_subdev_video_ops ov2640_subdev_video_ops = { |
| 1087 | .s_stream = ov2640_s_stream, | 1011 | .s_stream = ov2640_s_stream, |
| 1088 | .g_mbus_fmt = ov2640_g_fmt, | 1012 | .g_mbus_fmt = ov2640_g_fmt, |
| @@ -1091,6 +1015,7 @@ static struct v4l2_subdev_video_ops ov2640_subdev_video_ops = { | |||
| 1091 | .cropcap = ov2640_cropcap, | 1015 | .cropcap = ov2640_cropcap, |
| 1092 | .g_crop = ov2640_g_crop, | 1016 | .g_crop = ov2640_g_crop, |
| 1093 | .enum_mbus_fmt = ov2640_enum_fmt, | 1017 | .enum_mbus_fmt = ov2640_enum_fmt, |
| 1018 | .g_mbus_config = ov2640_g_mbus_config, | ||
| 1094 | }; | 1019 | }; |
| 1095 | 1020 | ||
| 1096 | static struct v4l2_subdev_ops ov2640_subdev_ops = { | 1021 | static struct v4l2_subdev_ops ov2640_subdev_ops = { |
| @@ -1104,18 +1029,11 @@ static struct v4l2_subdev_ops ov2640_subdev_ops = { | |||
| 1104 | static int ov2640_probe(struct i2c_client *client, | 1029 | static int ov2640_probe(struct i2c_client *client, |
| 1105 | const struct i2c_device_id *did) | 1030 | const struct i2c_device_id *did) |
| 1106 | { | 1031 | { |
| 1107 | struct ov2640_priv *priv; | 1032 | struct ov2640_priv *priv; |
| 1108 | struct soc_camera_device *icd = client->dev.platform_data; | 1033 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
| 1109 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 1034 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
| 1110 | struct soc_camera_link *icl; | 1035 | int ret; |
| 1111 | int ret; | ||
| 1112 | |||
| 1113 | if (!icd) { | ||
| 1114 | dev_err(&adapter->dev, "OV2640: missing soc-camera data!\n"); | ||
| 1115 | return -EINVAL; | ||
| 1116 | } | ||
| 1117 | 1036 | ||
| 1118 | icl = to_soc_camera_link(icd); | ||
| 1119 | if (!icl) { | 1037 | if (!icl) { |
| 1120 | dev_err(&adapter->dev, | 1038 | dev_err(&adapter->dev, |
| 1121 | "OV2640: Missing platform_data for driver\n"); | 1039 | "OV2640: Missing platform_data for driver\n"); |
| @@ -1135,15 +1053,23 @@ static int ov2640_probe(struct i2c_client *client, | |||
| 1135 | return -ENOMEM; | 1053 | return -ENOMEM; |
| 1136 | } | 1054 | } |
| 1137 | 1055 | ||
| 1138 | priv->info = icl->priv; | ||
| 1139 | |||
| 1140 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov2640_subdev_ops); | 1056 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov2640_subdev_ops); |
| 1057 | v4l2_ctrl_handler_init(&priv->hdl, 2); | ||
| 1058 | v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops, | ||
| 1059 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
| 1060 | v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops, | ||
| 1061 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
| 1062 | priv->subdev.ctrl_handler = &priv->hdl; | ||
| 1063 | if (priv->hdl.error) { | ||
| 1064 | int err = priv->hdl.error; | ||
| 1141 | 1065 | ||
| 1142 | icd->ops = &ov2640_ops; | 1066 | kfree(priv); |
| 1067 | return err; | ||
| 1068 | } | ||
| 1143 | 1069 | ||
| 1144 | ret = ov2640_video_probe(icd, client); | 1070 | ret = ov2640_video_probe(client); |
| 1145 | if (ret) { | 1071 | if (ret) { |
| 1146 | icd->ops = NULL; | 1072 | v4l2_ctrl_handler_free(&priv->hdl); |
| 1147 | kfree(priv); | 1073 | kfree(priv); |
| 1148 | } else { | 1074 | } else { |
| 1149 | dev_info(&adapter->dev, "OV2640 Probed\n"); | 1075 | dev_info(&adapter->dev, "OV2640 Probed\n"); |
| @@ -1155,9 +1081,9 @@ static int ov2640_probe(struct i2c_client *client, | |||
| 1155 | static int ov2640_remove(struct i2c_client *client) | 1081 | static int ov2640_remove(struct i2c_client *client) |
| 1156 | { | 1082 | { |
| 1157 | struct ov2640_priv *priv = to_ov2640(client); | 1083 | struct ov2640_priv *priv = to_ov2640(client); |
| 1158 | struct soc_camera_device *icd = client->dev.platform_data; | ||
| 1159 | 1084 | ||
| 1160 | icd->ops = NULL; | 1085 | v4l2_device_unregister_subdev(&priv->subdev); |
| 1086 | v4l2_ctrl_handler_free(&priv->hdl); | ||
| 1161 | kfree(priv); | 1087 | kfree(priv); |
| 1162 | return 0; | 1088 | return 0; |
| 1163 | } | 1089 | } |
diff --git a/drivers/media/video/ov5642.c b/drivers/media/video/ov5642.c index 349a4ad3ccc1..bb37ec80f274 100644 --- a/drivers/media/video/ov5642.c +++ b/drivers/media/video/ov5642.c | |||
| @@ -14,14 +14,16 @@ | |||
| 14 | * published by the Free Software Foundation. | 14 | * published by the Free Software Foundation. |
| 15 | */ | 15 | */ |
| 16 | 16 | ||
| 17 | #include <linux/bitops.h> | ||
| 17 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
| 18 | #include <linux/i2c.h> | 19 | #include <linux/i2c.h> |
| 20 | #include <linux/kernel.h> | ||
| 19 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
| 20 | #include <linux/videodev2.h> | 22 | #include <linux/videodev2.h> |
| 21 | #include <linux/module.h> | 23 | #include <linux/module.h> |
| 24 | #include <linux/v4l2-mediabus.h> | ||
| 22 | 25 | ||
| 23 | #include <media/soc_camera.h> | 26 | #include <media/soc_camera.h> |
| 24 | #include <media/soc_mediabus.h> | ||
| 25 | #include <media/v4l2-chip-ident.h> | 27 | #include <media/v4l2-chip-ident.h> |
| 26 | #include <media/v4l2-subdev.h> | 28 | #include <media/v4l2-subdev.h> |
| 27 | 29 | ||
| @@ -35,7 +37,7 @@ | |||
| 35 | #define REG_WINDOW_START_Y_LOW 0x3803 | 37 | #define REG_WINDOW_START_Y_LOW 0x3803 |
| 36 | #define REG_WINDOW_WIDTH_HIGH 0x3804 | 38 | #define REG_WINDOW_WIDTH_HIGH 0x3804 |
| 37 | #define REG_WINDOW_WIDTH_LOW 0x3805 | 39 | #define REG_WINDOW_WIDTH_LOW 0x3805 |
| 38 | #define REG_WINDOW_HEIGHT_HIGH 0x3806 | 40 | #define REG_WINDOW_HEIGHT_HIGH 0x3806 |
| 39 | #define REG_WINDOW_HEIGHT_LOW 0x3807 | 41 | #define REG_WINDOW_HEIGHT_LOW 0x3807 |
| 40 | #define REG_OUT_WIDTH_HIGH 0x3808 | 42 | #define REG_OUT_WIDTH_HIGH 0x3808 |
| 41 | #define REG_OUT_WIDTH_LOW 0x3809 | 43 | #define REG_OUT_WIDTH_LOW 0x3809 |
| @@ -45,19 +47,44 @@ | |||
| 45 | #define REG_OUT_TOTAL_WIDTH_LOW 0x380d | 47 | #define REG_OUT_TOTAL_WIDTH_LOW 0x380d |
| 46 | #define REG_OUT_TOTAL_HEIGHT_HIGH 0x380e | 48 | #define REG_OUT_TOTAL_HEIGHT_HIGH 0x380e |
| 47 | #define REG_OUT_TOTAL_HEIGHT_LOW 0x380f | 49 | #define REG_OUT_TOTAL_HEIGHT_LOW 0x380f |
| 50 | #define REG_OUTPUT_FORMAT 0x4300 | ||
| 51 | #define REG_ISP_CTRL_01 0x5001 | ||
| 52 | #define REG_AVG_WINDOW_END_X_HIGH 0x5682 | ||
| 53 | #define REG_AVG_WINDOW_END_X_LOW 0x5683 | ||
| 54 | #define REG_AVG_WINDOW_END_Y_HIGH 0x5686 | ||
| 55 | #define REG_AVG_WINDOW_END_Y_LOW 0x5687 | ||
| 56 | |||
| 57 | /* active pixel array size */ | ||
| 58 | #define OV5642_SENSOR_SIZE_X 2592 | ||
| 59 | #define OV5642_SENSOR_SIZE_Y 1944 | ||
| 48 | 60 | ||
| 49 | /* | 61 | /* |
| 50 | * define standard resolution. | 62 | * About OV5642 resolution, cropping and binning: |
| 51 | * Works currently only for up to 720 lines | 63 | * This sensor supports it all, at least in the feature description. |
| 52 | * eg. 320x240, 640x480, 800x600, 1280x720, 2048x720 | 64 | * Unfortunately, no combination of appropriate registers settings could make |
| 65 | * the chip work the intended way. As it works with predefined register lists, | ||
| 66 | * some undocumented registers are presumably changed there to achieve their | ||
| 67 | * goals. | ||
| 68 | * This driver currently only works for resolutions up to 720 lines with a | ||
| 69 | * 1:1 scale. Hopefully these restrictions will be removed in the future. | ||
| 53 | */ | 70 | */ |
| 71 | #define OV5642_MAX_WIDTH OV5642_SENSOR_SIZE_X | ||
| 72 | #define OV5642_MAX_HEIGHT 720 | ||
| 54 | 73 | ||
| 55 | #define OV5642_WIDTH 1280 | 74 | /* default sizes */ |
| 56 | #define OV5642_HEIGHT 720 | 75 | #define OV5642_DEFAULT_WIDTH 1280 |
| 57 | #define OV5642_TOTAL_WIDTH 3200 | 76 | #define OV5642_DEFAULT_HEIGHT OV5642_MAX_HEIGHT |
| 58 | #define OV5642_TOTAL_HEIGHT 2000 | 77 | |
| 59 | #define OV5642_SENSOR_SIZE_X 2592 | 78 | /* minimum extra blanking */ |
| 60 | #define OV5642_SENSOR_SIZE_Y 1944 | 79 | #define BLANKING_EXTRA_WIDTH 500 |
| 80 | #define BLANKING_EXTRA_HEIGHT 20 | ||
| 81 | |||
| 82 | /* | ||
| 83 | * the sensor's autoexposure is buggy when setting total_height low. | ||
| 84 | * It tries to expose longer than 1 frame period without taking care of it | ||
| 85 | * and this leads to weird output. So we set 1000 lines as minimum. | ||
| 86 | */ | ||
| 87 | #define BLANKING_MIN_HEIGHT 1000 | ||
| 61 | 88 | ||
| 62 | struct regval_list { | 89 | struct regval_list { |
| 63 | u16 reg_num; | 90 | u16 reg_num; |
| @@ -582,6 +609,11 @@ struct ov5642_datafmt { | |||
| 582 | struct ov5642 { | 609 | struct ov5642 { |
| 583 | struct v4l2_subdev subdev; | 610 | struct v4l2_subdev subdev; |
| 584 | const struct ov5642_datafmt *fmt; | 611 | const struct ov5642_datafmt *fmt; |
| 612 | struct v4l2_rect crop_rect; | ||
| 613 | |||
| 614 | /* blanking information */ | ||
| 615 | int total_width; | ||
| 616 | int total_height; | ||
| 585 | }; | 617 | }; |
| 586 | 618 | ||
| 587 | static const struct ov5642_datafmt ov5642_colour_fmts[] = { | 619 | static const struct ov5642_datafmt ov5642_colour_fmts[] = { |
| @@ -642,6 +674,21 @@ static int reg_write(struct i2c_client *client, u16 reg, u8 val) | |||
| 642 | 674 | ||
| 643 | return 0; | 675 | return 0; |
| 644 | } | 676 | } |
| 677 | |||
| 678 | /* | ||
| 679 | * convenience function to write 16 bit register values that are split up | ||
| 680 | * into two consecutive high and low parts | ||
| 681 | */ | ||
| 682 | static int reg_write16(struct i2c_client *client, u16 reg, u16 val16) | ||
| 683 | { | ||
| 684 | int ret; | ||
| 685 | |||
| 686 | ret = reg_write(client, reg, val16 >> 8); | ||
| 687 | if (ret) | ||
| 688 | return ret; | ||
| 689 | return reg_write(client, reg + 1, val16 & 0x00ff); | ||
| 690 | } | ||
| 691 | |||
| 645 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 692 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
| 646 | static int ov5642_get_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) | 693 | static int ov5642_get_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) |
| 647 | { | 694 | { |
| @@ -685,58 +732,55 @@ static int ov5642_write_array(struct i2c_client *client, | |||
| 685 | return 0; | 732 | return 0; |
| 686 | } | 733 | } |
| 687 | 734 | ||
| 688 | static int ov5642_set_resolution(struct i2c_client *client) | 735 | static int ov5642_set_resolution(struct v4l2_subdev *sd) |
| 689 | { | 736 | { |
| 737 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 738 | struct ov5642 *priv = to_ov5642(client); | ||
| 739 | int width = priv->crop_rect.width; | ||
| 740 | int height = priv->crop_rect.height; | ||
| 741 | int total_width = priv->total_width; | ||
| 742 | int total_height = priv->total_height; | ||
| 743 | int start_x = (OV5642_SENSOR_SIZE_X - width) / 2; | ||
| 744 | int start_y = (OV5642_SENSOR_SIZE_Y - height) / 2; | ||
| 690 | int ret; | 745 | int ret; |
| 691 | u8 start_x_high = ((OV5642_SENSOR_SIZE_X - OV5642_WIDTH) / 2) >> 8; | ||
| 692 | u8 start_x_low = ((OV5642_SENSOR_SIZE_X - OV5642_WIDTH) / 2) & 0xff; | ||
| 693 | u8 start_y_high = ((OV5642_SENSOR_SIZE_Y - OV5642_HEIGHT) / 2) >> 8; | ||
| 694 | u8 start_y_low = ((OV5642_SENSOR_SIZE_Y - OV5642_HEIGHT) / 2) & 0xff; | ||
| 695 | |||
| 696 | u8 width_high = OV5642_WIDTH >> 8; | ||
| 697 | u8 width_low = OV5642_WIDTH & 0xff; | ||
| 698 | u8 height_high = OV5642_HEIGHT >> 8; | ||
| 699 | u8 height_low = OV5642_HEIGHT & 0xff; | ||
| 700 | |||
| 701 | u8 total_width_high = OV5642_TOTAL_WIDTH >> 8; | ||
| 702 | u8 total_width_low = OV5642_TOTAL_WIDTH & 0xff; | ||
| 703 | u8 total_height_high = OV5642_TOTAL_HEIGHT >> 8; | ||
| 704 | u8 total_height_low = OV5642_TOTAL_HEIGHT & 0xff; | ||
| 705 | |||
| 706 | ret = reg_write(client, REG_WINDOW_START_X_HIGH, start_x_high); | ||
| 707 | if (!ret) | ||
| 708 | ret = reg_write(client, REG_WINDOW_START_X_LOW, start_x_low); | ||
| 709 | if (!ret) | ||
| 710 | ret = reg_write(client, REG_WINDOW_START_Y_HIGH, start_y_high); | ||
| 711 | if (!ret) | ||
| 712 | ret = reg_write(client, REG_WINDOW_START_Y_LOW, start_y_low); | ||
| 713 | 746 | ||
| 747 | /* | ||
| 748 | * This should set the starting point for cropping. | ||
| 749 | * Doesn't work so far. | ||
| 750 | */ | ||
| 751 | ret = reg_write16(client, REG_WINDOW_START_X_HIGH, start_x); | ||
| 714 | if (!ret) | 752 | if (!ret) |
| 715 | ret = reg_write(client, REG_WINDOW_WIDTH_HIGH, width_high); | 753 | ret = reg_write16(client, REG_WINDOW_START_Y_HIGH, start_y); |
| 716 | if (!ret) | 754 | if (!ret) { |
| 717 | ret = reg_write(client, REG_WINDOW_WIDTH_LOW , width_low); | 755 | priv->crop_rect.left = start_x; |
| 718 | if (!ret) | 756 | priv->crop_rect.top = start_y; |
| 719 | ret = reg_write(client, REG_WINDOW_HEIGHT_HIGH, height_high); | 757 | } |
| 720 | if (!ret) | ||
| 721 | ret = reg_write(client, REG_WINDOW_HEIGHT_LOW, height_low); | ||
| 722 | 758 | ||
| 723 | if (!ret) | 759 | if (!ret) |
| 724 | ret = reg_write(client, REG_OUT_WIDTH_HIGH, width_high); | 760 | ret = reg_write16(client, REG_WINDOW_WIDTH_HIGH, width); |
| 725 | if (!ret) | 761 | if (!ret) |
| 726 | ret = reg_write(client, REG_OUT_WIDTH_LOW , width_low); | 762 | ret = reg_write16(client, REG_WINDOW_HEIGHT_HIGH, height); |
| 727 | if (!ret) | 763 | if (ret) |
| 728 | ret = reg_write(client, REG_OUT_HEIGHT_HIGH, height_high); | 764 | return ret; |
| 765 | priv->crop_rect.width = width; | ||
| 766 | priv->crop_rect.height = height; | ||
| 767 | |||
| 768 | /* Set the output window size. Only 1:1 scale is supported so far. */ | ||
| 769 | ret = reg_write16(client, REG_OUT_WIDTH_HIGH, width); | ||
| 729 | if (!ret) | 770 | if (!ret) |
| 730 | ret = reg_write(client, REG_OUT_HEIGHT_LOW, height_low); | 771 | ret = reg_write16(client, REG_OUT_HEIGHT_HIGH, height); |
| 731 | 772 | ||
| 773 | /* Total width = output size + blanking */ | ||
| 732 | if (!ret) | 774 | if (!ret) |
| 733 | ret = reg_write(client, REG_OUT_TOTAL_WIDTH_HIGH, total_width_high); | 775 | ret = reg_write16(client, REG_OUT_TOTAL_WIDTH_HIGH, total_width); |
| 734 | if (!ret) | 776 | if (!ret) |
| 735 | ret = reg_write(client, REG_OUT_TOTAL_WIDTH_LOW, total_width_low); | 777 | ret = reg_write16(client, REG_OUT_TOTAL_HEIGHT_HIGH, total_height); |
| 778 | |||
| 779 | /* Sets the window for AWB calculations */ | ||
| 736 | if (!ret) | 780 | if (!ret) |
| 737 | ret = reg_write(client, REG_OUT_TOTAL_HEIGHT_HIGH, total_height_high); | 781 | ret = reg_write16(client, REG_AVG_WINDOW_END_X_HIGH, width); |
| 738 | if (!ret) | 782 | if (!ret) |
| 739 | ret = reg_write(client, REG_OUT_TOTAL_HEIGHT_LOW, total_height_low); | 783 | ret = reg_write16(client, REG_AVG_WINDOW_END_Y_HIGH, height); |
| 740 | 784 | ||
| 741 | return ret; | 785 | return ret; |
| 742 | } | 786 | } |
| @@ -744,18 +788,18 @@ static int ov5642_set_resolution(struct i2c_client *client) | |||
| 744 | static int ov5642_try_fmt(struct v4l2_subdev *sd, | 788 | static int ov5642_try_fmt(struct v4l2_subdev *sd, |
| 745 | struct v4l2_mbus_framefmt *mf) | 789 | struct v4l2_mbus_framefmt *mf) |
| 746 | { | 790 | { |
| 791 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 792 | struct ov5642 *priv = to_ov5642(client); | ||
| 747 | const struct ov5642_datafmt *fmt = ov5642_find_datafmt(mf->code); | 793 | const struct ov5642_datafmt *fmt = ov5642_find_datafmt(mf->code); |
| 748 | 794 | ||
| 749 | dev_dbg(sd->v4l2_dev->dev, "%s(%u) width: %u heigth: %u\n", | 795 | mf->width = priv->crop_rect.width; |
| 750 | __func__, mf->code, mf->width, mf->height); | 796 | mf->height = priv->crop_rect.height; |
| 751 | 797 | ||
| 752 | if (!fmt) { | 798 | if (!fmt) { |
| 753 | mf->code = ov5642_colour_fmts[0].code; | 799 | mf->code = ov5642_colour_fmts[0].code; |
| 754 | mf->colorspace = ov5642_colour_fmts[0].colorspace; | 800 | mf->colorspace = ov5642_colour_fmts[0].colorspace; |
| 755 | } | 801 | } |
| 756 | 802 | ||
| 757 | mf->width = OV5642_WIDTH; | ||
| 758 | mf->height = OV5642_HEIGHT; | ||
| 759 | mf->field = V4L2_FIELD_NONE; | 803 | mf->field = V4L2_FIELD_NONE; |
| 760 | 804 | ||
| 761 | return 0; | 805 | return 0; |
| @@ -767,20 +811,13 @@ static int ov5642_s_fmt(struct v4l2_subdev *sd, | |||
| 767 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 811 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 768 | struct ov5642 *priv = to_ov5642(client); | 812 | struct ov5642 *priv = to_ov5642(client); |
| 769 | 813 | ||
| 770 | dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code); | ||
| 771 | |||
| 772 | /* MIPI CSI could have changed the format, double-check */ | 814 | /* MIPI CSI could have changed the format, double-check */ |
| 773 | if (!ov5642_find_datafmt(mf->code)) | 815 | if (!ov5642_find_datafmt(mf->code)) |
| 774 | return -EINVAL; | 816 | return -EINVAL; |
| 775 | 817 | ||
| 776 | ov5642_try_fmt(sd, mf); | 818 | ov5642_try_fmt(sd, mf); |
| 777 | |||
| 778 | priv->fmt = ov5642_find_datafmt(mf->code); | 819 | priv->fmt = ov5642_find_datafmt(mf->code); |
| 779 | 820 | ||
| 780 | ov5642_write_array(client, ov5642_default_regs_init); | ||
| 781 | ov5642_set_resolution(client); | ||
| 782 | ov5642_write_array(client, ov5642_default_regs_finalise); | ||
| 783 | |||
| 784 | return 0; | 821 | return 0; |
| 785 | } | 822 | } |
| 786 | 823 | ||
| @@ -794,8 +831,8 @@ static int ov5642_g_fmt(struct v4l2_subdev *sd, | |||
| 794 | 831 | ||
| 795 | mf->code = fmt->code; | 832 | mf->code = fmt->code; |
| 796 | mf->colorspace = fmt->colorspace; | 833 | mf->colorspace = fmt->colorspace; |
| 797 | mf->width = OV5642_WIDTH; | 834 | mf->width = priv->crop_rect.width; |
| 798 | mf->height = OV5642_HEIGHT; | 835 | mf->height = priv->crop_rect.height; |
| 799 | mf->field = V4L2_FIELD_NONE; | 836 | mf->field = V4L2_FIELD_NONE; |
| 800 | 837 | ||
| 801 | return 0; | 838 | return 0; |
| @@ -828,15 +865,44 @@ static int ov5642_g_chip_ident(struct v4l2_subdev *sd, | |||
| 828 | return 0; | 865 | return 0; |
| 829 | } | 866 | } |
| 830 | 867 | ||
| 868 | static int ov5642_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | ||
| 869 | { | ||
| 870 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 871 | struct ov5642 *priv = to_ov5642(client); | ||
| 872 | struct v4l2_rect *rect = &a->c; | ||
| 873 | int ret; | ||
| 874 | |||
| 875 | v4l_bound_align_image(&rect->width, 48, OV5642_MAX_WIDTH, 1, | ||
| 876 | &rect->height, 32, OV5642_MAX_HEIGHT, 1, 0); | ||
| 877 | |||
| 878 | priv->crop_rect.width = rect->width; | ||
| 879 | priv->crop_rect.height = rect->height; | ||
| 880 | priv->total_width = rect->width + BLANKING_EXTRA_WIDTH; | ||
| 881 | priv->total_height = max_t(int, rect->height + | ||
| 882 | BLANKING_EXTRA_HEIGHT, | ||
| 883 | BLANKING_MIN_HEIGHT); | ||
| 884 | priv->crop_rect.width = rect->width; | ||
| 885 | priv->crop_rect.height = rect->height; | ||
| 886 | |||
| 887 | ret = ov5642_write_array(client, ov5642_default_regs_init); | ||
| 888 | if (!ret) | ||
| 889 | ret = ov5642_set_resolution(sd); | ||
| 890 | if (!ret) | ||
| 891 | ret = ov5642_write_array(client, ov5642_default_regs_finalise); | ||
| 892 | |||
| 893 | return ret; | ||
| 894 | } | ||
| 895 | |||
| 831 | static int ov5642_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 896 | static int ov5642_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) |
| 832 | { | 897 | { |
| 898 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 899 | struct ov5642 *priv = to_ov5642(client); | ||
| 833 | struct v4l2_rect *rect = &a->c; | 900 | struct v4l2_rect *rect = &a->c; |
| 834 | 901 | ||
| 835 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 902 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
| 836 | rect->top = 0; | 903 | return -EINVAL; |
| 837 | rect->left = 0; | 904 | |
| 838 | rect->width = OV5642_WIDTH; | 905 | *rect = priv->crop_rect; |
| 839 | rect->height = OV5642_HEIGHT; | ||
| 840 | 906 | ||
| 841 | return 0; | 907 | return 0; |
| 842 | } | 908 | } |
| @@ -845,8 +911,8 @@ static int ov5642_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | |||
| 845 | { | 911 | { |
| 846 | a->bounds.left = 0; | 912 | a->bounds.left = 0; |
| 847 | a->bounds.top = 0; | 913 | a->bounds.top = 0; |
| 848 | a->bounds.width = OV5642_WIDTH; | 914 | a->bounds.width = OV5642_MAX_WIDTH; |
| 849 | a->bounds.height = OV5642_HEIGHT; | 915 | a->bounds.height = OV5642_MAX_HEIGHT; |
| 850 | a->defrect = a->bounds; | 916 | a->defrect = a->bounds; |
| 851 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 917 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 852 | a->pixelaspect.numerator = 1; | 918 | a->pixelaspect.numerator = 1; |
| @@ -855,16 +921,47 @@ static int ov5642_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | |||
| 855 | return 0; | 921 | return 0; |
| 856 | } | 922 | } |
| 857 | 923 | ||
| 924 | static int ov5642_g_mbus_config(struct v4l2_subdev *sd, | ||
| 925 | struct v4l2_mbus_config *cfg) | ||
| 926 | { | ||
| 927 | cfg->type = V4L2_MBUS_CSI2; | ||
| 928 | cfg->flags = V4L2_MBUS_CSI2_2_LANE | V4L2_MBUS_CSI2_CHANNEL_0 | | ||
| 929 | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; | ||
| 930 | |||
| 931 | return 0; | ||
| 932 | } | ||
| 933 | |||
| 934 | static int ov5642_s_power(struct v4l2_subdev *sd, int on) | ||
| 935 | { | ||
| 936 | struct i2c_client *client; | ||
| 937 | int ret; | ||
| 938 | |||
| 939 | if (!on) | ||
| 940 | return 0; | ||
| 941 | |||
| 942 | client = v4l2_get_subdevdata(sd); | ||
| 943 | ret = ov5642_write_array(client, ov5642_default_regs_init); | ||
| 944 | if (!ret) | ||
| 945 | ret = ov5642_set_resolution(sd); | ||
| 946 | if (!ret) | ||
| 947 | ret = ov5642_write_array(client, ov5642_default_regs_finalise); | ||
| 948 | |||
| 949 | return ret; | ||
| 950 | } | ||
| 951 | |||
| 858 | static struct v4l2_subdev_video_ops ov5642_subdev_video_ops = { | 952 | static struct v4l2_subdev_video_ops ov5642_subdev_video_ops = { |
| 859 | .s_mbus_fmt = ov5642_s_fmt, | 953 | .s_mbus_fmt = ov5642_s_fmt, |
| 860 | .g_mbus_fmt = ov5642_g_fmt, | 954 | .g_mbus_fmt = ov5642_g_fmt, |
| 861 | .try_mbus_fmt = ov5642_try_fmt, | 955 | .try_mbus_fmt = ov5642_try_fmt, |
| 862 | .enum_mbus_fmt = ov5642_enum_fmt, | 956 | .enum_mbus_fmt = ov5642_enum_fmt, |
| 957 | .s_crop = ov5642_s_crop, | ||
| 863 | .g_crop = ov5642_g_crop, | 958 | .g_crop = ov5642_g_crop, |
| 864 | .cropcap = ov5642_cropcap, | 959 | .cropcap = ov5642_cropcap, |
| 960 | .g_mbus_config = ov5642_g_mbus_config, | ||
| 865 | }; | 961 | }; |
| 866 | 962 | ||
| 867 | static struct v4l2_subdev_core_ops ov5642_subdev_core_ops = { | 963 | static struct v4l2_subdev_core_ops ov5642_subdev_core_ops = { |
| 964 | .s_power = ov5642_s_power, | ||
| 868 | .g_chip_ident = ov5642_g_chip_ident, | 965 | .g_chip_ident = ov5642_g_chip_ident, |
| 869 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 966 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
| 870 | .g_register = ov5642_get_register, | 967 | .g_register = ov5642_get_register, |
| @@ -877,28 +974,7 @@ static struct v4l2_subdev_ops ov5642_subdev_ops = { | |||
| 877 | .video = &ov5642_subdev_video_ops, | 974 | .video = &ov5642_subdev_video_ops, |
| 878 | }; | 975 | }; |
| 879 | 976 | ||
| 880 | /* | 977 | static int ov5642_video_probe(struct i2c_client *client) |
| 881 | * We have to provide soc-camera operations, but we don't have anything to say | ||
| 882 | * there. The MIPI CSI2 driver will provide .query_bus_param and .set_bus_param | ||
| 883 | */ | ||
| 884 | static unsigned long soc_ov5642_query_bus_param(struct soc_camera_device *icd) | ||
| 885 | { | ||
| 886 | return 0; | ||
| 887 | } | ||
| 888 | |||
| 889 | static int soc_ov5642_set_bus_param(struct soc_camera_device *icd, | ||
| 890 | unsigned long flags) | ||
| 891 | { | ||
| 892 | return -EINVAL; | ||
| 893 | } | ||
| 894 | |||
| 895 | static struct soc_camera_ops soc_ov5642_ops = { | ||
| 896 | .query_bus_param = soc_ov5642_query_bus_param, | ||
| 897 | .set_bus_param = soc_ov5642_set_bus_param, | ||
| 898 | }; | ||
| 899 | |||
| 900 | static int ov5642_video_probe(struct soc_camera_device *icd, | ||
| 901 | struct i2c_client *client) | ||
| 902 | { | 978 | { |
| 903 | int ret; | 979 | int ret; |
| 904 | u8 id_high, id_low; | 980 | u8 id_high, id_low; |
| @@ -929,16 +1005,9 @@ static int ov5642_probe(struct i2c_client *client, | |||
| 929 | const struct i2c_device_id *did) | 1005 | const struct i2c_device_id *did) |
| 930 | { | 1006 | { |
| 931 | struct ov5642 *priv; | 1007 | struct ov5642 *priv; |
| 932 | struct soc_camera_device *icd = client->dev.platform_data; | 1008 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
| 933 | struct soc_camera_link *icl; | ||
| 934 | int ret; | 1009 | int ret; |
| 935 | 1010 | ||
| 936 | if (!icd) { | ||
| 937 | dev_err(&client->dev, "OV5642: missing soc-camera data!\n"); | ||
| 938 | return -EINVAL; | ||
| 939 | } | ||
| 940 | |||
| 941 | icl = to_soc_camera_link(icd); | ||
| 942 | if (!icl) { | 1011 | if (!icl) { |
| 943 | dev_err(&client->dev, "OV5642: missing platform data!\n"); | 1012 | dev_err(&client->dev, "OV5642: missing platform data!\n"); |
| 944 | return -EINVAL; | 1013 | return -EINVAL; |
| @@ -950,17 +1019,24 @@ static int ov5642_probe(struct i2c_client *client, | |||
| 950 | 1019 | ||
| 951 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov5642_subdev_ops); | 1020 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov5642_subdev_ops); |
| 952 | 1021 | ||
| 953 | icd->ops = &soc_ov5642_ops; | 1022 | priv->fmt = &ov5642_colour_fmts[0]; |
| 954 | priv->fmt = &ov5642_colour_fmts[0]; | 1023 | |
| 1024 | priv->crop_rect.width = OV5642_DEFAULT_WIDTH; | ||
| 1025 | priv->crop_rect.height = OV5642_DEFAULT_HEIGHT; | ||
| 1026 | priv->crop_rect.left = (OV5642_MAX_WIDTH - OV5642_DEFAULT_WIDTH) / 2; | ||
| 1027 | priv->crop_rect.top = (OV5642_MAX_HEIGHT - OV5642_DEFAULT_HEIGHT) / 2; | ||
| 1028 | priv->crop_rect.width = OV5642_DEFAULT_WIDTH; | ||
| 1029 | priv->crop_rect.height = OV5642_DEFAULT_HEIGHT; | ||
| 1030 | priv->total_width = OV5642_DEFAULT_WIDTH + BLANKING_EXTRA_WIDTH; | ||
| 1031 | priv->total_height = BLANKING_MIN_HEIGHT; | ||
| 955 | 1032 | ||
| 956 | ret = ov5642_video_probe(icd, client); | 1033 | ret = ov5642_video_probe(client); |
| 957 | if (ret < 0) | 1034 | if (ret < 0) |
| 958 | goto error; | 1035 | goto error; |
| 959 | 1036 | ||
| 960 | return 0; | 1037 | return 0; |
| 961 | 1038 | ||
| 962 | error: | 1039 | error: |
| 963 | icd->ops = NULL; | ||
| 964 | kfree(priv); | 1040 | kfree(priv); |
| 965 | return ret; | 1041 | return ret; |
| 966 | } | 1042 | } |
| @@ -968,10 +1044,8 @@ error: | |||
| 968 | static int ov5642_remove(struct i2c_client *client) | 1044 | static int ov5642_remove(struct i2c_client *client) |
| 969 | { | 1045 | { |
| 970 | struct ov5642 *priv = to_ov5642(client); | 1046 | struct ov5642 *priv = to_ov5642(client); |
| 971 | struct soc_camera_device *icd = client->dev.platform_data; | 1047 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
| 972 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
| 973 | 1048 | ||
| 974 | icd->ops = NULL; | ||
| 975 | if (icl->free_bus) | 1049 | if (icl->free_bus) |
| 976 | icl->free_bus(icl); | 1050 | icl->free_bus(icl); |
| 977 | kfree(priv); | 1051 | kfree(priv); |
diff --git a/drivers/media/video/ov6650.c b/drivers/media/video/ov6650.c index 456d9ad9ae5a..d5b057207a7b 100644 --- a/drivers/media/video/ov6650.c +++ b/drivers/media/video/ov6650.c | |||
| @@ -28,10 +28,11 @@ | |||
| 28 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
| 29 | #include <linux/i2c.h> | 29 | #include <linux/i2c.h> |
| 30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
| 31 | #include <linux/v4l2-mediabus.h> | ||
| 31 | 32 | ||
| 32 | #include <media/soc_camera.h> | 33 | #include <media/soc_camera.h> |
| 33 | #include <media/v4l2-chip-ident.h> | 34 | #include <media/v4l2-chip-ident.h> |
| 34 | 35 | #include <media/v4l2-ctrls.h> | |
| 35 | 36 | ||
| 36 | /* Register definitions */ | 37 | /* Register definitions */ |
| 37 | #define REG_GAIN 0x00 /* range 00 - 3F */ | 38 | #define REG_GAIN 0x00 /* range 00 - 3F */ |
| @@ -177,20 +178,23 @@ struct ov6650_reg { | |||
| 177 | 178 | ||
| 178 | struct ov6650 { | 179 | struct ov6650 { |
| 179 | struct v4l2_subdev subdev; | 180 | struct v4l2_subdev subdev; |
| 180 | 181 | struct v4l2_ctrl_handler hdl; | |
| 181 | int gain; | 182 | struct { |
| 182 | int blue; | 183 | /* exposure/autoexposure cluster */ |
| 183 | int red; | 184 | struct v4l2_ctrl *autoexposure; |
| 184 | int saturation; | 185 | struct v4l2_ctrl *exposure; |
| 185 | int hue; | 186 | }; |
| 186 | int brightness; | 187 | struct { |
| 187 | int exposure; | 188 | /* gain/autogain cluster */ |
| 188 | int gamma; | 189 | struct v4l2_ctrl *autogain; |
| 189 | int aec; | 190 | struct v4l2_ctrl *gain; |
| 190 | bool vflip; | 191 | }; |
| 191 | bool hflip; | 192 | struct { |
| 192 | bool awb; | 193 | /* blue/red/autowhitebalance cluster */ |
| 193 | bool agc; | 194 | struct v4l2_ctrl *autowb; |
| 195 | struct v4l2_ctrl *blue; | ||
| 196 | struct v4l2_ctrl *red; | ||
| 197 | }; | ||
| 194 | bool half_scale; /* scale down output by 2 */ | 198 | bool half_scale; /* scale down output by 2 */ |
| 195 | struct v4l2_rect rect; /* sensor cropping window */ | 199 | struct v4l2_rect rect; /* sensor cropping window */ |
| 196 | unsigned long pclk_limit; /* from host */ | 200 | unsigned long pclk_limit; /* from host */ |
| @@ -210,126 +214,6 @@ static enum v4l2_mbus_pixelcode ov6650_codes[] = { | |||
| 210 | V4L2_MBUS_FMT_Y8_1X8, | 214 | V4L2_MBUS_FMT_Y8_1X8, |
| 211 | }; | 215 | }; |
| 212 | 216 | ||
| 213 | static const struct v4l2_queryctrl ov6650_controls[] = { | ||
| 214 | { | ||
| 215 | .id = V4L2_CID_AUTOGAIN, | ||
| 216 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 217 | .name = "AGC", | ||
| 218 | .minimum = 0, | ||
| 219 | .maximum = 1, | ||
| 220 | .step = 1, | ||
| 221 | .default_value = 1, | ||
| 222 | }, | ||
| 223 | { | ||
| 224 | .id = V4L2_CID_GAIN, | ||
| 225 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 226 | .name = "Gain", | ||
| 227 | .minimum = 0, | ||
| 228 | .maximum = 0x3f, | ||
| 229 | .step = 1, | ||
| 230 | .default_value = DEF_GAIN, | ||
| 231 | }, | ||
| 232 | { | ||
| 233 | .id = V4L2_CID_AUTO_WHITE_BALANCE, | ||
| 234 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 235 | .name = "AWB", | ||
| 236 | .minimum = 0, | ||
| 237 | .maximum = 1, | ||
| 238 | .step = 1, | ||
| 239 | .default_value = 1, | ||
| 240 | }, | ||
| 241 | { | ||
| 242 | .id = V4L2_CID_BLUE_BALANCE, | ||
| 243 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 244 | .name = "Blue", | ||
| 245 | .minimum = 0, | ||
| 246 | .maximum = 0xff, | ||
| 247 | .step = 1, | ||
| 248 | .default_value = DEF_BLUE, | ||
| 249 | }, | ||
| 250 | { | ||
| 251 | .id = V4L2_CID_RED_BALANCE, | ||
| 252 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 253 | .name = "Red", | ||
| 254 | .minimum = 0, | ||
| 255 | .maximum = 0xff, | ||
| 256 | .step = 1, | ||
| 257 | .default_value = DEF_RED, | ||
| 258 | }, | ||
| 259 | { | ||
| 260 | .id = V4L2_CID_SATURATION, | ||
| 261 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 262 | .name = "Saturation", | ||
| 263 | .minimum = 0, | ||
| 264 | .maximum = 0xf, | ||
| 265 | .step = 1, | ||
| 266 | .default_value = 0x8, | ||
| 267 | }, | ||
| 268 | { | ||
| 269 | .id = V4L2_CID_HUE, | ||
| 270 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 271 | .name = "Hue", | ||
| 272 | .minimum = 0, | ||
| 273 | .maximum = HUE_MASK, | ||
| 274 | .step = 1, | ||
| 275 | .default_value = DEF_HUE, | ||
| 276 | }, | ||
| 277 | { | ||
| 278 | .id = V4L2_CID_BRIGHTNESS, | ||
| 279 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 280 | .name = "Brightness", | ||
| 281 | .minimum = 0, | ||
| 282 | .maximum = 0xff, | ||
| 283 | .step = 1, | ||
| 284 | .default_value = 0x80, | ||
| 285 | }, | ||
| 286 | { | ||
| 287 | .id = V4L2_CID_EXPOSURE_AUTO, | ||
| 288 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 289 | .name = "AEC", | ||
| 290 | .minimum = 0, | ||
| 291 | .maximum = 3, | ||
| 292 | .step = 1, | ||
| 293 | .default_value = 0, | ||
| 294 | }, | ||
| 295 | { | ||
| 296 | .id = V4L2_CID_EXPOSURE, | ||
| 297 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 298 | .name = "Exposure", | ||
| 299 | .minimum = 0, | ||
| 300 | .maximum = 0xff, | ||
| 301 | .step = 1, | ||
| 302 | .default_value = DEF_AECH, | ||
| 303 | }, | ||
| 304 | { | ||
| 305 | .id = V4L2_CID_GAMMA, | ||
| 306 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 307 | .name = "Gamma", | ||
| 308 | .minimum = 0, | ||
| 309 | .maximum = 0xff, | ||
| 310 | .step = 1, | ||
| 311 | .default_value = 0x12, | ||
| 312 | }, | ||
| 313 | { | ||
| 314 | .id = V4L2_CID_VFLIP, | ||
| 315 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 316 | .name = "Flip Vertically", | ||
| 317 | .minimum = 0, | ||
| 318 | .maximum = 1, | ||
| 319 | .step = 1, | ||
| 320 | .default_value = 0, | ||
| 321 | }, | ||
| 322 | { | ||
| 323 | .id = V4L2_CID_HFLIP, | ||
| 324 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 325 | .name = "Flip Horizontally", | ||
| 326 | .minimum = 0, | ||
| 327 | .maximum = 1, | ||
| 328 | .step = 1, | ||
| 329 | .default_value = 0, | ||
| 330 | }, | ||
| 331 | }; | ||
| 332 | |||
| 333 | /* read a register */ | 217 | /* read a register */ |
| 334 | static int ov6650_reg_read(struct i2c_client *client, u8 reg, u8 *val) | 218 | static int ov6650_reg_read(struct i2c_client *client, u8 reg, u8 *val) |
| 335 | { | 219 | { |
| @@ -419,213 +303,90 @@ static int ov6650_s_stream(struct v4l2_subdev *sd, int enable) | |||
| 419 | return 0; | 303 | return 0; |
| 420 | } | 304 | } |
| 421 | 305 | ||
| 422 | /* Alter bus settings on camera side */ | ||
| 423 | static int ov6650_set_bus_param(struct soc_camera_device *icd, | ||
| 424 | unsigned long flags) | ||
| 425 | { | ||
| 426 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
| 427 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); | ||
| 428 | int ret; | ||
| 429 | |||
| 430 | flags = soc_camera_apply_sensor_flags(icl, flags); | ||
| 431 | |||
| 432 | if (flags & SOCAM_PCLK_SAMPLE_RISING) | ||
| 433 | ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_PCLK_RISING, 0); | ||
| 434 | else | ||
| 435 | ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_PCLK_RISING); | ||
| 436 | if (ret) | ||
| 437 | return ret; | ||
| 438 | |||
| 439 | if (flags & SOCAM_HSYNC_ACTIVE_LOW) | ||
| 440 | ret = ov6650_reg_rmw(client, REG_COMF, COMF_HREF_LOW, 0); | ||
| 441 | else | ||
| 442 | ret = ov6650_reg_rmw(client, REG_COMF, 0, COMF_HREF_LOW); | ||
| 443 | if (ret) | ||
| 444 | return ret; | ||
| 445 | |||
| 446 | if (flags & SOCAM_VSYNC_ACTIVE_HIGH) | ||
| 447 | ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_VSYNC_HIGH, 0); | ||
| 448 | else | ||
| 449 | ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_VSYNC_HIGH); | ||
| 450 | |||
| 451 | return ret; | ||
| 452 | } | ||
| 453 | |||
| 454 | /* Request bus settings on camera side */ | ||
| 455 | static unsigned long ov6650_query_bus_param(struct soc_camera_device *icd) | ||
| 456 | { | ||
| 457 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
| 458 | |||
| 459 | unsigned long flags = SOCAM_MASTER | | ||
| 460 | SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING | | ||
| 461 | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW | | ||
| 462 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW | | ||
| 463 | SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8; | ||
| 464 | |||
| 465 | return soc_camera_apply_sensor_flags(icl, flags); | ||
| 466 | } | ||
| 467 | |||
| 468 | /* Get status of additional camera capabilities */ | 306 | /* Get status of additional camera capabilities */ |
| 469 | static int ov6650_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 307 | static int ov6550_g_volatile_ctrl(struct v4l2_ctrl *ctrl) |
| 470 | { | 308 | { |
| 309 | struct ov6650 *priv = container_of(ctrl->handler, struct ov6650, hdl); | ||
| 310 | struct v4l2_subdev *sd = &priv->subdev; | ||
| 471 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 311 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 472 | struct ov6650 *priv = to_ov6650(client); | 312 | uint8_t reg, reg2; |
| 473 | uint8_t reg; | 313 | int ret; |
| 474 | int ret = 0; | ||
| 475 | 314 | ||
| 476 | switch (ctrl->id) { | 315 | switch (ctrl->id) { |
| 477 | case V4L2_CID_AUTOGAIN: | 316 | case V4L2_CID_AUTOGAIN: |
| 478 | ctrl->value = priv->agc; | 317 | ret = ov6650_reg_read(client, REG_GAIN, ®); |
| 479 | break; | 318 | if (!ret) |
| 480 | case V4L2_CID_GAIN: | 319 | priv->gain->val = reg; |
| 481 | if (priv->agc) { | 320 | return ret; |
| 482 | ret = ov6650_reg_read(client, REG_GAIN, ®); | ||
| 483 | ctrl->value = reg; | ||
| 484 | } else { | ||
| 485 | ctrl->value = priv->gain; | ||
| 486 | } | ||
| 487 | break; | ||
| 488 | case V4L2_CID_AUTO_WHITE_BALANCE: | 321 | case V4L2_CID_AUTO_WHITE_BALANCE: |
| 489 | ctrl->value = priv->awb; | 322 | ret = ov6650_reg_read(client, REG_BLUE, ®); |
| 490 | break; | 323 | if (!ret) |
| 491 | case V4L2_CID_BLUE_BALANCE: | 324 | ret = ov6650_reg_read(client, REG_RED, ®2); |
| 492 | if (priv->awb) { | 325 | if (!ret) { |
| 493 | ret = ov6650_reg_read(client, REG_BLUE, ®); | 326 | priv->blue->val = reg; |
| 494 | ctrl->value = reg; | 327 | priv->red->val = reg2; |
| 495 | } else { | ||
| 496 | ctrl->value = priv->blue; | ||
| 497 | } | ||
| 498 | break; | ||
| 499 | case V4L2_CID_RED_BALANCE: | ||
| 500 | if (priv->awb) { | ||
| 501 | ret = ov6650_reg_read(client, REG_RED, ®); | ||
| 502 | ctrl->value = reg; | ||
| 503 | } else { | ||
| 504 | ctrl->value = priv->red; | ||
| 505 | } | 328 | } |
| 506 | break; | 329 | return ret; |
| 507 | case V4L2_CID_SATURATION: | ||
| 508 | ctrl->value = priv->saturation; | ||
| 509 | break; | ||
| 510 | case V4L2_CID_HUE: | ||
| 511 | ctrl->value = priv->hue; | ||
| 512 | break; | ||
| 513 | case V4L2_CID_BRIGHTNESS: | ||
| 514 | ctrl->value = priv->brightness; | ||
| 515 | break; | ||
| 516 | case V4L2_CID_EXPOSURE_AUTO: | 330 | case V4L2_CID_EXPOSURE_AUTO: |
| 517 | ctrl->value = priv->aec; | 331 | ret = ov6650_reg_read(client, REG_AECH, ®); |
| 518 | break; | 332 | if (!ret) |
| 519 | case V4L2_CID_EXPOSURE: | 333 | priv->exposure->val = reg; |
| 520 | if (priv->aec) { | 334 | return ret; |
| 521 | ret = ov6650_reg_read(client, REG_AECH, ®); | ||
| 522 | ctrl->value = reg; | ||
| 523 | } else { | ||
| 524 | ctrl->value = priv->exposure; | ||
| 525 | } | ||
| 526 | break; | ||
| 527 | case V4L2_CID_GAMMA: | ||
| 528 | ctrl->value = priv->gamma; | ||
| 529 | break; | ||
| 530 | case V4L2_CID_VFLIP: | ||
| 531 | ctrl->value = priv->vflip; | ||
| 532 | break; | ||
| 533 | case V4L2_CID_HFLIP: | ||
| 534 | ctrl->value = priv->hflip; | ||
| 535 | break; | ||
| 536 | } | 335 | } |
| 537 | return ret; | 336 | return -EINVAL; |
| 538 | } | 337 | } |
| 539 | 338 | ||
| 540 | /* Set status of additional camera capabilities */ | 339 | /* Set status of additional camera capabilities */ |
| 541 | static int ov6650_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 340 | static int ov6550_s_ctrl(struct v4l2_ctrl *ctrl) |
| 542 | { | 341 | { |
| 342 | struct ov6650 *priv = container_of(ctrl->handler, struct ov6650, hdl); | ||
| 343 | struct v4l2_subdev *sd = &priv->subdev; | ||
| 543 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 344 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 544 | struct ov6650 *priv = to_ov6650(client); | 345 | int ret; |
| 545 | int ret = 0; | ||
| 546 | 346 | ||
| 547 | switch (ctrl->id) { | 347 | switch (ctrl->id) { |
| 548 | case V4L2_CID_AUTOGAIN: | 348 | case V4L2_CID_AUTOGAIN: |
| 549 | ret = ov6650_reg_rmw(client, REG_COMB, | 349 | ret = ov6650_reg_rmw(client, REG_COMB, |
| 550 | ctrl->value ? COMB_AGC : 0, COMB_AGC); | 350 | ctrl->val ? COMB_AGC : 0, COMB_AGC); |
| 551 | if (!ret) | 351 | if (!ret && !ctrl->val) |
| 552 | priv->agc = ctrl->value; | 352 | ret = ov6650_reg_write(client, REG_GAIN, priv->gain->val); |
| 553 | break; | 353 | return ret; |
| 554 | case V4L2_CID_GAIN: | ||
| 555 | ret = ov6650_reg_write(client, REG_GAIN, ctrl->value); | ||
| 556 | if (!ret) | ||
| 557 | priv->gain = ctrl->value; | ||
| 558 | break; | ||
| 559 | case V4L2_CID_AUTO_WHITE_BALANCE: | 354 | case V4L2_CID_AUTO_WHITE_BALANCE: |
| 560 | ret = ov6650_reg_rmw(client, REG_COMB, | 355 | ret = ov6650_reg_rmw(client, REG_COMB, |
| 561 | ctrl->value ? COMB_AWB : 0, COMB_AWB); | 356 | ctrl->val ? COMB_AWB : 0, COMB_AWB); |
| 562 | if (!ret) | 357 | if (!ret && !ctrl->val) { |
| 563 | priv->awb = ctrl->value; | 358 | ret = ov6650_reg_write(client, REG_BLUE, priv->blue->val); |
| 564 | break; | 359 | if (!ret) |
| 565 | case V4L2_CID_BLUE_BALANCE: | 360 | ret = ov6650_reg_write(client, REG_RED, |
| 566 | ret = ov6650_reg_write(client, REG_BLUE, ctrl->value); | 361 | priv->red->val); |
| 567 | if (!ret) | 362 | } |
| 568 | priv->blue = ctrl->value; | 363 | return ret; |
| 569 | break; | ||
| 570 | case V4L2_CID_RED_BALANCE: | ||
| 571 | ret = ov6650_reg_write(client, REG_RED, ctrl->value); | ||
| 572 | if (!ret) | ||
| 573 | priv->red = ctrl->value; | ||
| 574 | break; | ||
| 575 | case V4L2_CID_SATURATION: | 364 | case V4L2_CID_SATURATION: |
| 576 | ret = ov6650_reg_rmw(client, REG_SAT, SET_SAT(ctrl->value), | 365 | return ov6650_reg_rmw(client, REG_SAT, SET_SAT(ctrl->val), |
| 577 | SAT_MASK); | 366 | SAT_MASK); |
| 578 | if (!ret) | ||
| 579 | priv->saturation = ctrl->value; | ||
| 580 | break; | ||
| 581 | case V4L2_CID_HUE: | 367 | case V4L2_CID_HUE: |
| 582 | ret = ov6650_reg_rmw(client, REG_HUE, SET_HUE(ctrl->value), | 368 | return ov6650_reg_rmw(client, REG_HUE, SET_HUE(ctrl->val), |
| 583 | HUE_MASK); | 369 | HUE_MASK); |
| 584 | if (!ret) | ||
| 585 | priv->hue = ctrl->value; | ||
| 586 | break; | ||
| 587 | case V4L2_CID_BRIGHTNESS: | 370 | case V4L2_CID_BRIGHTNESS: |
| 588 | ret = ov6650_reg_write(client, REG_BRT, ctrl->value); | 371 | return ov6650_reg_write(client, REG_BRT, ctrl->val); |
| 589 | if (!ret) | ||
| 590 | priv->brightness = ctrl->value; | ||
| 591 | break; | ||
| 592 | case V4L2_CID_EXPOSURE_AUTO: | 372 | case V4L2_CID_EXPOSURE_AUTO: |
| 593 | switch (ctrl->value) { | 373 | ret = ov6650_reg_rmw(client, REG_COMB, ctrl->val == |
| 594 | case V4L2_EXPOSURE_AUTO: | 374 | V4L2_EXPOSURE_AUTO ? COMB_AEC : 0, COMB_AEC); |
| 595 | ret = ov6650_reg_rmw(client, REG_COMB, COMB_AEC, 0); | 375 | if (!ret && ctrl->val == V4L2_EXPOSURE_MANUAL) |
| 596 | break; | 376 | ret = ov6650_reg_write(client, REG_AECH, |
| 597 | default: | 377 | priv->exposure->val); |
| 598 | ret = ov6650_reg_rmw(client, REG_COMB, 0, COMB_AEC); | 378 | return ret; |
| 599 | break; | ||
| 600 | } | ||
| 601 | if (!ret) | ||
| 602 | priv->aec = ctrl->value; | ||
| 603 | break; | ||
| 604 | case V4L2_CID_EXPOSURE: | ||
| 605 | ret = ov6650_reg_write(client, REG_AECH, ctrl->value); | ||
| 606 | if (!ret) | ||
| 607 | priv->exposure = ctrl->value; | ||
| 608 | break; | ||
| 609 | case V4L2_CID_GAMMA: | 379 | case V4L2_CID_GAMMA: |
| 610 | ret = ov6650_reg_write(client, REG_GAM1, ctrl->value); | 380 | return ov6650_reg_write(client, REG_GAM1, ctrl->val); |
| 611 | if (!ret) | ||
| 612 | priv->gamma = ctrl->value; | ||
| 613 | break; | ||
| 614 | case V4L2_CID_VFLIP: | 381 | case V4L2_CID_VFLIP: |
| 615 | ret = ov6650_reg_rmw(client, REG_COMB, | 382 | return ov6650_reg_rmw(client, REG_COMB, |
| 616 | ctrl->value ? COMB_FLIP_V : 0, COMB_FLIP_V); | 383 | ctrl->val ? COMB_FLIP_V : 0, COMB_FLIP_V); |
| 617 | if (!ret) | ||
| 618 | priv->vflip = ctrl->value; | ||
| 619 | break; | ||
| 620 | case V4L2_CID_HFLIP: | 384 | case V4L2_CID_HFLIP: |
| 621 | ret = ov6650_reg_rmw(client, REG_COMB, | 385 | return ov6650_reg_rmw(client, REG_COMB, |
| 622 | ctrl->value ? COMB_FLIP_H : 0, COMB_FLIP_H); | 386 | ctrl->val ? COMB_FLIP_H : 0, COMB_FLIP_H); |
| 623 | if (!ret) | ||
| 624 | priv->hflip = ctrl->value; | ||
| 625 | break; | ||
| 626 | } | 387 | } |
| 627 | 388 | ||
| 628 | return ret; | 389 | return -EINVAL; |
| 629 | } | 390 | } |
| 630 | 391 | ||
| 631 | /* Get chip identification */ | 392 | /* Get chip identification */ |
| @@ -778,7 +539,7 @@ static u8 to_clkrc(struct v4l2_fract *timeperframe, | |||
| 778 | static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) | 539 | static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) |
| 779 | { | 540 | { |
| 780 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 541 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 781 | struct soc_camera_device *icd = client->dev.platform_data; | 542 | struct soc_camera_device *icd = (struct soc_camera_device *)sd->grp_id; |
| 782 | struct soc_camera_sense *sense = icd->sense; | 543 | struct soc_camera_sense *sense = icd->sense; |
| 783 | struct ov6650 *priv = to_ov6650(client); | 544 | struct ov6650 *priv = to_ov6650(client); |
| 784 | bool half_scale = !is_unscaled_ok(mf->width, mf->height, &priv->rect); | 545 | bool half_scale = !is_unscaled_ok(mf->width, mf->height, &priv->rect); |
| @@ -1057,8 +818,7 @@ static int ov6650_prog_dflt(struct i2c_client *client) | |||
| 1057 | return ret; | 818 | return ret; |
| 1058 | } | 819 | } |
| 1059 | 820 | ||
| 1060 | static int ov6650_video_probe(struct soc_camera_device *icd, | 821 | static int ov6650_video_probe(struct i2c_client *client) |
| 1061 | struct i2c_client *client) | ||
| 1062 | { | 822 | { |
| 1063 | u8 pidh, pidl, midh, midl; | 823 | u8 pidh, pidl, midh, midl; |
| 1064 | int ret = 0; | 824 | int ret = 0; |
| @@ -1094,16 +854,12 @@ static int ov6650_video_probe(struct soc_camera_device *icd, | |||
| 1094 | return ret; | 854 | return ret; |
| 1095 | } | 855 | } |
| 1096 | 856 | ||
| 1097 | static struct soc_camera_ops ov6650_ops = { | 857 | static const struct v4l2_ctrl_ops ov6550_ctrl_ops = { |
| 1098 | .set_bus_param = ov6650_set_bus_param, | 858 | .g_volatile_ctrl = ov6550_g_volatile_ctrl, |
| 1099 | .query_bus_param = ov6650_query_bus_param, | 859 | .s_ctrl = ov6550_s_ctrl, |
| 1100 | .controls = ov6650_controls, | ||
| 1101 | .num_controls = ARRAY_SIZE(ov6650_controls), | ||
| 1102 | }; | 860 | }; |
| 1103 | 861 | ||
| 1104 | static struct v4l2_subdev_core_ops ov6650_core_ops = { | 862 | static struct v4l2_subdev_core_ops ov6650_core_ops = { |
| 1105 | .g_ctrl = ov6650_g_ctrl, | ||
| 1106 | .s_ctrl = ov6650_s_ctrl, | ||
| 1107 | .g_chip_ident = ov6650_g_chip_ident, | 863 | .g_chip_ident = ov6650_g_chip_ident, |
| 1108 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 864 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
| 1109 | .g_register = ov6650_get_register, | 865 | .g_register = ov6650_get_register, |
| @@ -1111,6 +867,55 @@ static struct v4l2_subdev_core_ops ov6650_core_ops = { | |||
| 1111 | #endif | 867 | #endif |
| 1112 | }; | 868 | }; |
| 1113 | 869 | ||
| 870 | /* Request bus settings on camera side */ | ||
| 871 | static int ov6650_g_mbus_config(struct v4l2_subdev *sd, | ||
| 872 | struct v4l2_mbus_config *cfg) | ||
| 873 | { | ||
| 874 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 875 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
| 876 | |||
| 877 | cfg->flags = V4L2_MBUS_MASTER | | ||
| 878 | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | | ||
| 879 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW | | ||
| 880 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | | ||
| 881 | V4L2_MBUS_DATA_ACTIVE_HIGH; | ||
| 882 | cfg->type = V4L2_MBUS_PARALLEL; | ||
| 883 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | ||
| 884 | |||
| 885 | return 0; | ||
| 886 | } | ||
| 887 | |||
| 888 | /* Alter bus settings on camera side */ | ||
| 889 | static int ov6650_s_mbus_config(struct v4l2_subdev *sd, | ||
| 890 | const struct v4l2_mbus_config *cfg) | ||
| 891 | { | ||
| 892 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 893 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
| 894 | unsigned long flags = soc_camera_apply_board_flags(icl, cfg); | ||
| 895 | int ret; | ||
| 896 | |||
| 897 | if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING) | ||
| 898 | ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_PCLK_RISING, 0); | ||
| 899 | else | ||
| 900 | ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_PCLK_RISING); | ||
| 901 | if (ret) | ||
| 902 | return ret; | ||
| 903 | |||
| 904 | if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) | ||
| 905 | ret = ov6650_reg_rmw(client, REG_COMF, COMF_HREF_LOW, 0); | ||
| 906 | else | ||
| 907 | ret = ov6650_reg_rmw(client, REG_COMF, 0, COMF_HREF_LOW); | ||
| 908 | if (ret) | ||
| 909 | return ret; | ||
| 910 | |||
| 911 | if (flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) | ||
| 912 | ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_VSYNC_HIGH, 0); | ||
| 913 | else | ||
| 914 | ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_VSYNC_HIGH); | ||
| 915 | |||
| 916 | return ret; | ||
| 917 | } | ||
| 918 | |||
| 1114 | static struct v4l2_subdev_video_ops ov6650_video_ops = { | 919 | static struct v4l2_subdev_video_ops ov6650_video_ops = { |
| 1115 | .s_stream = ov6650_s_stream, | 920 | .s_stream = ov6650_s_stream, |
| 1116 | .g_mbus_fmt = ov6650_g_fmt, | 921 | .g_mbus_fmt = ov6650_g_fmt, |
| @@ -1122,6 +927,8 @@ static struct v4l2_subdev_video_ops ov6650_video_ops = { | |||
| 1122 | .s_crop = ov6650_s_crop, | 927 | .s_crop = ov6650_s_crop, |
| 1123 | .g_parm = ov6650_g_parm, | 928 | .g_parm = ov6650_g_parm, |
| 1124 | .s_parm = ov6650_s_parm, | 929 | .s_parm = ov6650_s_parm, |
| 930 | .g_mbus_config = ov6650_g_mbus_config, | ||
| 931 | .s_mbus_config = ov6650_s_mbus_config, | ||
| 1125 | }; | 932 | }; |
| 1126 | 933 | ||
| 1127 | static struct v4l2_subdev_ops ov6650_subdev_ops = { | 934 | static struct v4l2_subdev_ops ov6650_subdev_ops = { |
| @@ -1136,16 +943,9 @@ static int ov6650_probe(struct i2c_client *client, | |||
| 1136 | const struct i2c_device_id *did) | 943 | const struct i2c_device_id *did) |
| 1137 | { | 944 | { |
| 1138 | struct ov6650 *priv; | 945 | struct ov6650 *priv; |
| 1139 | struct soc_camera_device *icd = client->dev.platform_data; | 946 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
| 1140 | struct soc_camera_link *icl; | ||
| 1141 | int ret; | 947 | int ret; |
| 1142 | 948 | ||
| 1143 | if (!icd) { | ||
| 1144 | dev_err(&client->dev, "Missing soc-camera data!\n"); | ||
| 1145 | return -EINVAL; | ||
| 1146 | } | ||
| 1147 | |||
| 1148 | icl = to_soc_camera_link(icd); | ||
| 1149 | if (!icl) { | 949 | if (!icl) { |
| 1150 | dev_err(&client->dev, "Missing platform_data for driver\n"); | 950 | dev_err(&client->dev, "Missing platform_data for driver\n"); |
| 1151 | return -EINVAL; | 951 | return -EINVAL; |
| @@ -1159,8 +959,46 @@ static int ov6650_probe(struct i2c_client *client, | |||
| 1159 | } | 959 | } |
| 1160 | 960 | ||
| 1161 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov6650_subdev_ops); | 961 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov6650_subdev_ops); |
| 962 | v4l2_ctrl_handler_init(&priv->hdl, 13); | ||
| 963 | v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
| 964 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
| 965 | v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
| 966 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
| 967 | priv->autogain = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
| 968 | V4L2_CID_AUTOGAIN, 0, 1, 1, 1); | ||
| 969 | priv->gain = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
| 970 | V4L2_CID_GAIN, 0, 0x3f, 1, DEF_GAIN); | ||
| 971 | priv->autowb = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
| 972 | V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); | ||
| 973 | priv->blue = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
| 974 | V4L2_CID_BLUE_BALANCE, 0, 0xff, 1, DEF_BLUE); | ||
| 975 | priv->red = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
| 976 | V4L2_CID_RED_BALANCE, 0, 0xff, 1, DEF_RED); | ||
| 977 | v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
| 978 | V4L2_CID_SATURATION, 0, 0xf, 1, 0x8); | ||
| 979 | v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
| 980 | V4L2_CID_HUE, 0, HUE_MASK, 1, DEF_HUE); | ||
| 981 | v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
| 982 | V4L2_CID_BRIGHTNESS, 0, 0xff, 1, 0x80); | ||
| 983 | priv->autoexposure = v4l2_ctrl_new_std_menu(&priv->hdl, | ||
| 984 | &ov6550_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, | ||
| 985 | V4L2_EXPOSURE_MANUAL, 0, V4L2_EXPOSURE_AUTO); | ||
| 986 | priv->exposure = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
| 987 | V4L2_CID_EXPOSURE, 0, 0xff, 1, DEF_AECH); | ||
| 988 | v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, | ||
| 989 | V4L2_CID_GAMMA, 0, 0xff, 1, 0x12); | ||
| 990 | |||
| 991 | priv->subdev.ctrl_handler = &priv->hdl; | ||
| 992 | if (priv->hdl.error) { | ||
| 993 | int err = priv->hdl.error; | ||
| 1162 | 994 | ||
| 1163 | icd->ops = &ov6650_ops; | 995 | kfree(priv); |
| 996 | return err; | ||
| 997 | } | ||
| 998 | v4l2_ctrl_auto_cluster(2, &priv->autogain, 0, true); | ||
| 999 | v4l2_ctrl_auto_cluster(3, &priv->autowb, 0, true); | ||
| 1000 | v4l2_ctrl_auto_cluster(2, &priv->autoexposure, | ||
| 1001 | V4L2_EXPOSURE_MANUAL, true); | ||
| 1164 | 1002 | ||
| 1165 | priv->rect.left = DEF_HSTRT << 1; | 1003 | priv->rect.left = DEF_HSTRT << 1; |
| 1166 | priv->rect.top = DEF_VSTRT << 1; | 1004 | priv->rect.top = DEF_VSTRT << 1; |
| @@ -1170,10 +1008,12 @@ static int ov6650_probe(struct i2c_client *client, | |||
| 1170 | priv->code = V4L2_MBUS_FMT_YUYV8_2X8; | 1008 | priv->code = V4L2_MBUS_FMT_YUYV8_2X8; |
| 1171 | priv->colorspace = V4L2_COLORSPACE_JPEG; | 1009 | priv->colorspace = V4L2_COLORSPACE_JPEG; |
| 1172 | 1010 | ||
| 1173 | ret = ov6650_video_probe(icd, client); | 1011 | ret = ov6650_video_probe(client); |
| 1012 | if (!ret) | ||
| 1013 | ret = v4l2_ctrl_handler_setup(&priv->hdl); | ||
| 1174 | 1014 | ||
| 1175 | if (ret) { | 1015 | if (ret) { |
| 1176 | icd->ops = NULL; | 1016 | v4l2_ctrl_handler_free(&priv->hdl); |
| 1177 | kfree(priv); | 1017 | kfree(priv); |
| 1178 | } | 1018 | } |
| 1179 | 1019 | ||
| @@ -1184,6 +1024,8 @@ static int ov6650_remove(struct i2c_client *client) | |||
| 1184 | { | 1024 | { |
| 1185 | struct ov6650 *priv = to_ov6650(client); | 1025 | struct ov6650 *priv = to_ov6650(client); |
| 1186 | 1026 | ||
| 1027 | v4l2_device_unregister_subdev(&priv->subdev); | ||
| 1028 | v4l2_ctrl_handler_free(&priv->hdl); | ||
| 1187 | kfree(priv); | 1029 | kfree(priv); |
| 1188 | return 0; | 1030 | return 0; |
| 1189 | } | 1031 | } |
diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c index 397870f076c1..9f6ce3d8a29e 100644 --- a/drivers/media/video/ov772x.c +++ b/drivers/media/video/ov772x.c | |||
| @@ -20,12 +20,14 @@ | |||
| 20 | #include <linux/i2c.h> | 20 | #include <linux/i2c.h> |
| 21 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
| 22 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
| 23 | #include <linux/v4l2-mediabus.h> | ||
| 23 | #include <linux/videodev2.h> | 24 | #include <linux/videodev2.h> |
| 25 | |||
| 26 | #include <media/ov772x.h> | ||
| 27 | #include <media/soc_camera.h> | ||
| 28 | #include <media/v4l2-ctrls.h> | ||
| 24 | #include <media/v4l2-chip-ident.h> | 29 | #include <media/v4l2-chip-ident.h> |
| 25 | #include <media/v4l2-subdev.h> | 30 | #include <media/v4l2-subdev.h> |
| 26 | #include <media/soc_camera.h> | ||
| 27 | #include <media/soc_mediabus.h> | ||
| 28 | #include <media/ov772x.h> | ||
| 29 | 31 | ||
| 30 | /* | 32 | /* |
| 31 | * register offset | 33 | * register offset |
| @@ -400,6 +402,7 @@ struct ov772x_win_size { | |||
| 400 | 402 | ||
| 401 | struct ov772x_priv { | 403 | struct ov772x_priv { |
| 402 | struct v4l2_subdev subdev; | 404 | struct v4l2_subdev subdev; |
| 405 | struct v4l2_ctrl_handler hdl; | ||
| 403 | struct ov772x_camera_info *info; | 406 | struct ov772x_camera_info *info; |
| 404 | const struct ov772x_color_format *cfmt; | 407 | const struct ov772x_color_format *cfmt; |
| 405 | const struct ov772x_win_size *win; | 408 | const struct ov772x_win_size *win; |
| @@ -517,36 +520,6 @@ static const struct ov772x_win_size ov772x_win_qvga = { | |||
| 517 | .regs = ov772x_qvga_regs, | 520 | .regs = ov772x_qvga_regs, |
| 518 | }; | 521 | }; |
| 519 | 522 | ||
| 520 | static const struct v4l2_queryctrl ov772x_controls[] = { | ||
| 521 | { | ||
| 522 | .id = V4L2_CID_VFLIP, | ||
| 523 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 524 | .name = "Flip Vertically", | ||
| 525 | .minimum = 0, | ||
| 526 | .maximum = 1, | ||
| 527 | .step = 1, | ||
| 528 | .default_value = 0, | ||
| 529 | }, | ||
| 530 | { | ||
| 531 | .id = V4L2_CID_HFLIP, | ||
| 532 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 533 | .name = "Flip Horizontally", | ||
| 534 | .minimum = 0, | ||
| 535 | .maximum = 1, | ||
| 536 | .step = 1, | ||
| 537 | .default_value = 0, | ||
| 538 | }, | ||
| 539 | { | ||
| 540 | .id = V4L2_CID_BAND_STOP_FILTER, | ||
| 541 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 542 | .name = "Band-stop filter", | ||
| 543 | .minimum = 0, | ||
| 544 | .maximum = 256, | ||
| 545 | .step = 1, | ||
| 546 | .default_value = 0, | ||
| 547 | }, | ||
| 548 | }; | ||
| 549 | |||
| 550 | /* | 523 | /* |
| 551 | * general function | 524 | * general function |
| 552 | */ | 525 | */ |
| @@ -620,75 +593,30 @@ static int ov772x_s_stream(struct v4l2_subdev *sd, int enable) | |||
| 620 | return 0; | 593 | return 0; |
| 621 | } | 594 | } |
| 622 | 595 | ||
| 623 | static int ov772x_set_bus_param(struct soc_camera_device *icd, | 596 | static int ov772x_s_ctrl(struct v4l2_ctrl *ctrl) |
| 624 | unsigned long flags) | ||
| 625 | { | ||
| 626 | return 0; | ||
| 627 | } | ||
| 628 | |||
| 629 | static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd) | ||
| 630 | { | ||
| 631 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); | ||
| 632 | struct ov772x_priv *priv = i2c_get_clientdata(client); | ||
| 633 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
| 634 | unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | | ||
| 635 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | | ||
| 636 | SOCAM_DATA_ACTIVE_HIGH; | ||
| 637 | |||
| 638 | if (priv->info->flags & OV772X_FLAG_8BIT) | ||
| 639 | flags |= SOCAM_DATAWIDTH_8; | ||
| 640 | else | ||
| 641 | flags |= SOCAM_DATAWIDTH_10; | ||
| 642 | |||
| 643 | return soc_camera_apply_sensor_flags(icl, flags); | ||
| 644 | } | ||
| 645 | |||
| 646 | static int ov772x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
| 647 | { | ||
| 648 | struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev); | ||
| 649 | |||
| 650 | switch (ctrl->id) { | ||
| 651 | case V4L2_CID_VFLIP: | ||
| 652 | ctrl->value = priv->flag_vflip; | ||
| 653 | break; | ||
| 654 | case V4L2_CID_HFLIP: | ||
| 655 | ctrl->value = priv->flag_hflip; | ||
| 656 | break; | ||
| 657 | case V4L2_CID_BAND_STOP_FILTER: | ||
| 658 | ctrl->value = priv->band_filter; | ||
| 659 | break; | ||
| 660 | } | ||
| 661 | return 0; | ||
| 662 | } | ||
| 663 | |||
| 664 | static int ov772x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
| 665 | { | 597 | { |
| 598 | struct ov772x_priv *priv = container_of(ctrl->handler, | ||
| 599 | struct ov772x_priv, hdl); | ||
| 600 | struct v4l2_subdev *sd = &priv->subdev; | ||
| 666 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 601 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 667 | struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev); | ||
| 668 | int ret = 0; | 602 | int ret = 0; |
| 669 | u8 val; | 603 | u8 val; |
| 670 | 604 | ||
| 671 | switch (ctrl->id) { | 605 | switch (ctrl->id) { |
| 672 | case V4L2_CID_VFLIP: | 606 | case V4L2_CID_VFLIP: |
| 673 | val = ctrl->value ? VFLIP_IMG : 0x00; | 607 | val = ctrl->val ? VFLIP_IMG : 0x00; |
| 674 | priv->flag_vflip = ctrl->value; | 608 | priv->flag_vflip = ctrl->val; |
| 675 | if (priv->info->flags & OV772X_FLAG_VFLIP) | 609 | if (priv->info->flags & OV772X_FLAG_VFLIP) |
| 676 | val ^= VFLIP_IMG; | 610 | val ^= VFLIP_IMG; |
| 677 | ret = ov772x_mask_set(client, COM3, VFLIP_IMG, val); | 611 | return ov772x_mask_set(client, COM3, VFLIP_IMG, val); |
| 678 | break; | ||
| 679 | case V4L2_CID_HFLIP: | 612 | case V4L2_CID_HFLIP: |
| 680 | val = ctrl->value ? HFLIP_IMG : 0x00; | 613 | val = ctrl->val ? HFLIP_IMG : 0x00; |
| 681 | priv->flag_hflip = ctrl->value; | 614 | priv->flag_hflip = ctrl->val; |
| 682 | if (priv->info->flags & OV772X_FLAG_HFLIP) | 615 | if (priv->info->flags & OV772X_FLAG_HFLIP) |
| 683 | val ^= HFLIP_IMG; | 616 | val ^= HFLIP_IMG; |
| 684 | ret = ov772x_mask_set(client, COM3, HFLIP_IMG, val); | 617 | return ov772x_mask_set(client, COM3, HFLIP_IMG, val); |
| 685 | break; | ||
| 686 | case V4L2_CID_BAND_STOP_FILTER: | 618 | case V4L2_CID_BAND_STOP_FILTER: |
| 687 | if ((unsigned)ctrl->value > 256) | 619 | if (!ctrl->val) { |
| 688 | ctrl->value = 256; | ||
| 689 | if (ctrl->value == priv->band_filter) | ||
| 690 | break; | ||
| 691 | if (!ctrl->value) { | ||
| 692 | /* Switch the filter off, it is on now */ | 620 | /* Switch the filter off, it is on now */ |
| 693 | ret = ov772x_mask_set(client, BDBASE, 0xff, 0xff); | 621 | ret = ov772x_mask_set(client, BDBASE, 0xff, 0xff); |
| 694 | if (!ret) | 622 | if (!ret) |
| @@ -696,7 +624,7 @@ static int ov772x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
| 696 | BNDF_ON_OFF, 0); | 624 | BNDF_ON_OFF, 0); |
| 697 | } else { | 625 | } else { |
| 698 | /* Switch the filter on, set AEC low limit */ | 626 | /* Switch the filter on, set AEC low limit */ |
| 699 | val = 256 - ctrl->value; | 627 | val = 256 - ctrl->val; |
| 700 | ret = ov772x_mask_set(client, COM8, | 628 | ret = ov772x_mask_set(client, COM8, |
| 701 | BNDF_ON_OFF, BNDF_ON_OFF); | 629 | BNDF_ON_OFF, BNDF_ON_OFF); |
| 702 | if (!ret) | 630 | if (!ret) |
| @@ -704,11 +632,11 @@ static int ov772x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
| 704 | 0xff, val); | 632 | 0xff, val); |
| 705 | } | 633 | } |
| 706 | if (!ret) | 634 | if (!ret) |
| 707 | priv->band_filter = ctrl->value; | 635 | priv->band_filter = ctrl->val; |
| 708 | break; | 636 | return ret; |
| 709 | } | 637 | } |
| 710 | 638 | ||
| 711 | return ret; | 639 | return -EINVAL; |
| 712 | } | 640 | } |
| 713 | 641 | ||
| 714 | static int ov772x_g_chip_ident(struct v4l2_subdev *sd, | 642 | static int ov772x_g_chip_ident(struct v4l2_subdev *sd, |
| @@ -822,13 +750,13 @@ static int ov772x_set_params(struct i2c_client *client, u32 *width, u32 *height, | |||
| 822 | goto ov772x_set_fmt_error; | 750 | goto ov772x_set_fmt_error; |
| 823 | 751 | ||
| 824 | ret = ov772x_mask_set(client, | 752 | ret = ov772x_mask_set(client, |
| 825 | EDGE_TRSHLD, EDGE_THRESHOLD_MASK, | 753 | EDGE_TRSHLD, OV772X_EDGE_THRESHOLD_MASK, |
| 826 | priv->info->edgectrl.threshold); | 754 | priv->info->edgectrl.threshold); |
| 827 | if (ret < 0) | 755 | if (ret < 0) |
| 828 | goto ov772x_set_fmt_error; | 756 | goto ov772x_set_fmt_error; |
| 829 | 757 | ||
| 830 | ret = ov772x_mask_set(client, | 758 | ret = ov772x_mask_set(client, |
| 831 | EDGE_STRNGT, EDGE_STRENGTH_MASK, | 759 | EDGE_STRNGT, OV772X_EDGE_STRENGTH_MASK, |
| 832 | priv->info->edgectrl.strength); | 760 | priv->info->edgectrl.strength); |
| 833 | if (ret < 0) | 761 | if (ret < 0) |
| 834 | goto ov772x_set_fmt_error; | 762 | goto ov772x_set_fmt_error; |
| @@ -840,13 +768,13 @@ static int ov772x_set_params(struct i2c_client *client, u32 *width, u32 *height, | |||
| 840 | * set upper and lower limit | 768 | * set upper and lower limit |
| 841 | */ | 769 | */ |
| 842 | ret = ov772x_mask_set(client, | 770 | ret = ov772x_mask_set(client, |
| 843 | EDGE_UPPER, EDGE_UPPER_MASK, | 771 | EDGE_UPPER, OV772X_EDGE_UPPER_MASK, |
| 844 | priv->info->edgectrl.upper); | 772 | priv->info->edgectrl.upper); |
| 845 | if (ret < 0) | 773 | if (ret < 0) |
| 846 | goto ov772x_set_fmt_error; | 774 | goto ov772x_set_fmt_error; |
| 847 | 775 | ||
| 848 | ret = ov772x_mask_set(client, | 776 | ret = ov772x_mask_set(client, |
| 849 | EDGE_LOWER, EDGE_LOWER_MASK, | 777 | EDGE_LOWER, OV772X_EDGE_LOWER_MASK, |
| 850 | priv->info->edgectrl.lower); | 778 | priv->info->edgectrl.lower); |
| 851 | if (ret < 0) | 779 | if (ret < 0) |
| 852 | goto ov772x_set_fmt_error; | 780 | goto ov772x_set_fmt_error; |
| @@ -1025,17 +953,12 @@ static int ov772x_try_fmt(struct v4l2_subdev *sd, | |||
| 1025 | return 0; | 953 | return 0; |
| 1026 | } | 954 | } |
| 1027 | 955 | ||
| 1028 | static int ov772x_video_probe(struct soc_camera_device *icd, | 956 | static int ov772x_video_probe(struct i2c_client *client) |
| 1029 | struct i2c_client *client) | ||
| 1030 | { | 957 | { |
| 1031 | struct ov772x_priv *priv = to_ov772x(client); | 958 | struct ov772x_priv *priv = to_ov772x(client); |
| 1032 | u8 pid, ver; | 959 | u8 pid, ver; |
| 1033 | const char *devname; | 960 | const char *devname; |
| 1034 | 961 | ||
| 1035 | /* We must have a parent by now. And it cannot be a wrong one. */ | ||
| 1036 | BUG_ON(!icd->parent || | ||
| 1037 | to_soc_camera_host(icd->parent)->nr != icd->iface); | ||
| 1038 | |||
| 1039 | /* | 962 | /* |
| 1040 | * check and show product ID and manufacturer ID | 963 | * check and show product ID and manufacturer ID |
| 1041 | */ | 964 | */ |
| @@ -1064,20 +987,14 @@ static int ov772x_video_probe(struct soc_camera_device *icd, | |||
| 1064 | ver, | 987 | ver, |
| 1065 | i2c_smbus_read_byte_data(client, MIDH), | 988 | i2c_smbus_read_byte_data(client, MIDH), |
| 1066 | i2c_smbus_read_byte_data(client, MIDL)); | 989 | i2c_smbus_read_byte_data(client, MIDL)); |
| 1067 | 990 | return v4l2_ctrl_handler_setup(&priv->hdl); | |
| 1068 | return 0; | ||
| 1069 | } | 991 | } |
| 1070 | 992 | ||
| 1071 | static struct soc_camera_ops ov772x_ops = { | 993 | static const struct v4l2_ctrl_ops ov772x_ctrl_ops = { |
| 1072 | .set_bus_param = ov772x_set_bus_param, | 994 | .s_ctrl = ov772x_s_ctrl, |
| 1073 | .query_bus_param = ov772x_query_bus_param, | ||
| 1074 | .controls = ov772x_controls, | ||
| 1075 | .num_controls = ARRAY_SIZE(ov772x_controls), | ||
| 1076 | }; | 995 | }; |
| 1077 | 996 | ||
| 1078 | static struct v4l2_subdev_core_ops ov772x_subdev_core_ops = { | 997 | static struct v4l2_subdev_core_ops ov772x_subdev_core_ops = { |
| 1079 | .g_ctrl = ov772x_g_ctrl, | ||
| 1080 | .s_ctrl = ov772x_s_ctrl, | ||
| 1081 | .g_chip_ident = ov772x_g_chip_ident, | 998 | .g_chip_ident = ov772x_g_chip_ident, |
| 1082 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 999 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
| 1083 | .g_register = ov772x_g_register, | 1000 | .g_register = ov772x_g_register, |
| @@ -1095,6 +1012,21 @@ static int ov772x_enum_fmt(struct v4l2_subdev *sd, unsigned int index, | |||
| 1095 | return 0; | 1012 | return 0; |
| 1096 | } | 1013 | } |
| 1097 | 1014 | ||
| 1015 | static int ov772x_g_mbus_config(struct v4l2_subdev *sd, | ||
| 1016 | struct v4l2_mbus_config *cfg) | ||
| 1017 | { | ||
| 1018 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 1019 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
| 1020 | |||
| 1021 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | | ||
| 1022 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | | ||
| 1023 | V4L2_MBUS_DATA_ACTIVE_HIGH; | ||
| 1024 | cfg->type = V4L2_MBUS_PARALLEL; | ||
| 1025 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | ||
| 1026 | |||
| 1027 | return 0; | ||
| 1028 | } | ||
| 1029 | |||
| 1098 | static struct v4l2_subdev_video_ops ov772x_subdev_video_ops = { | 1030 | static struct v4l2_subdev_video_ops ov772x_subdev_video_ops = { |
| 1099 | .s_stream = ov772x_s_stream, | 1031 | .s_stream = ov772x_s_stream, |
| 1100 | .g_mbus_fmt = ov772x_g_fmt, | 1032 | .g_mbus_fmt = ov772x_g_fmt, |
| @@ -1103,6 +1035,7 @@ static struct v4l2_subdev_video_ops ov772x_subdev_video_ops = { | |||
| 1103 | .cropcap = ov772x_cropcap, | 1035 | .cropcap = ov772x_cropcap, |
| 1104 | .g_crop = ov772x_g_crop, | 1036 | .g_crop = ov772x_g_crop, |
| 1105 | .enum_mbus_fmt = ov772x_enum_fmt, | 1037 | .enum_mbus_fmt = ov772x_enum_fmt, |
| 1038 | .g_mbus_config = ov772x_g_mbus_config, | ||
| 1106 | }; | 1039 | }; |
| 1107 | 1040 | ||
| 1108 | static struct v4l2_subdev_ops ov772x_subdev_ops = { | 1041 | static struct v4l2_subdev_ops ov772x_subdev_ops = { |
| @@ -1117,20 +1050,15 @@ static struct v4l2_subdev_ops ov772x_subdev_ops = { | |||
| 1117 | static int ov772x_probe(struct i2c_client *client, | 1050 | static int ov772x_probe(struct i2c_client *client, |
| 1118 | const struct i2c_device_id *did) | 1051 | const struct i2c_device_id *did) |
| 1119 | { | 1052 | { |
| 1120 | struct ov772x_priv *priv; | 1053 | struct ov772x_priv *priv; |
| 1121 | struct soc_camera_device *icd = client->dev.platform_data; | 1054 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
| 1122 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 1055 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
| 1123 | struct soc_camera_link *icl; | 1056 | int ret; |
| 1124 | int ret; | ||
| 1125 | |||
| 1126 | if (!icd) { | ||
| 1127 | dev_err(&client->dev, "OV772X: missing soc-camera data!\n"); | ||
| 1128 | return -EINVAL; | ||
| 1129 | } | ||
| 1130 | 1057 | ||
| 1131 | icl = to_soc_camera_link(icd); | 1058 | if (!icl || !icl->priv) { |
| 1132 | if (!icl || !icl->priv) | 1059 | dev_err(&client->dev, "OV772X: missing platform data!\n"); |
| 1133 | return -EINVAL; | 1060 | return -EINVAL; |
| 1061 | } | ||
| 1134 | 1062 | ||
| 1135 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { | 1063 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { |
| 1136 | dev_err(&adapter->dev, | 1064 | dev_err(&adapter->dev, |
| @@ -1146,12 +1074,24 @@ static int ov772x_probe(struct i2c_client *client, | |||
| 1146 | priv->info = icl->priv; | 1074 | priv->info = icl->priv; |
| 1147 | 1075 | ||
| 1148 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops); | 1076 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops); |
| 1077 | v4l2_ctrl_handler_init(&priv->hdl, 3); | ||
| 1078 | v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops, | ||
| 1079 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
| 1080 | v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops, | ||
| 1081 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
| 1082 | v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops, | ||
| 1083 | V4L2_CID_BAND_STOP_FILTER, 0, 256, 1, 0); | ||
| 1084 | priv->subdev.ctrl_handler = &priv->hdl; | ||
| 1085 | if (priv->hdl.error) { | ||
| 1086 | int err = priv->hdl.error; | ||
| 1149 | 1087 | ||
| 1150 | icd->ops = &ov772x_ops; | 1088 | kfree(priv); |
| 1089 | return err; | ||
| 1090 | } | ||
| 1151 | 1091 | ||
| 1152 | ret = ov772x_video_probe(icd, client); | 1092 | ret = ov772x_video_probe(client); |
| 1153 | if (ret) { | 1093 | if (ret) { |
| 1154 | icd->ops = NULL; | 1094 | v4l2_ctrl_handler_free(&priv->hdl); |
| 1155 | kfree(priv); | 1095 | kfree(priv); |
| 1156 | } | 1096 | } |
| 1157 | 1097 | ||
| @@ -1161,9 +1101,9 @@ static int ov772x_probe(struct i2c_client *client, | |||
| 1161 | static int ov772x_remove(struct i2c_client *client) | 1101 | static int ov772x_remove(struct i2c_client *client) |
| 1162 | { | 1102 | { |
| 1163 | struct ov772x_priv *priv = to_ov772x(client); | 1103 | struct ov772x_priv *priv = to_ov772x(client); |
| 1164 | struct soc_camera_device *icd = client->dev.platform_data; | ||
| 1165 | 1104 | ||
| 1166 | icd->ops = NULL; | 1105 | v4l2_device_unregister_subdev(&priv->subdev); |
| 1106 | v4l2_ctrl_handler_free(&priv->hdl); | ||
| 1167 | kfree(priv); | 1107 | kfree(priv); |
| 1168 | return 0; | 1108 | return 0; |
| 1169 | } | 1109 | } |
diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c index 3681a6ff0815..a4f99797eb56 100644 --- a/drivers/media/video/ov9640.c +++ b/drivers/media/video/ov9640.c | |||
| @@ -24,10 +24,13 @@ | |||
| 24 | #include <linux/i2c.h> | 24 | #include <linux/i2c.h> |
| 25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
| 26 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
| 27 | #include <linux/v4l2-mediabus.h> | ||
| 27 | #include <linux/videodev2.h> | 28 | #include <linux/videodev2.h> |
| 29 | |||
| 30 | #include <media/soc_camera.h> | ||
| 28 | #include <media/v4l2-chip-ident.h> | 31 | #include <media/v4l2-chip-ident.h> |
| 29 | #include <media/v4l2-common.h> | 32 | #include <media/v4l2-common.h> |
| 30 | #include <media/soc_camera.h> | 33 | #include <media/v4l2-ctrls.h> |
| 31 | 34 | ||
| 32 | #include "ov9640.h" | 35 | #include "ov9640.h" |
| 33 | 36 | ||
| @@ -162,27 +165,6 @@ static enum v4l2_mbus_pixelcode ov9640_codes[] = { | |||
| 162 | V4L2_MBUS_FMT_RGB565_2X8_LE, | 165 | V4L2_MBUS_FMT_RGB565_2X8_LE, |
| 163 | }; | 166 | }; |
| 164 | 167 | ||
| 165 | static const struct v4l2_queryctrl ov9640_controls[] = { | ||
| 166 | { | ||
| 167 | .id = V4L2_CID_VFLIP, | ||
| 168 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 169 | .name = "Flip Vertically", | ||
| 170 | .minimum = 0, | ||
| 171 | .maximum = 1, | ||
| 172 | .step = 1, | ||
| 173 | .default_value = 0, | ||
| 174 | }, | ||
| 175 | { | ||
| 176 | .id = V4L2_CID_HFLIP, | ||
| 177 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 178 | .name = "Flip Horizontally", | ||
| 179 | .minimum = 0, | ||
| 180 | .maximum = 1, | ||
| 181 | .step = 1, | ||
| 182 | .default_value = 0, | ||
| 183 | }, | ||
| 184 | }; | ||
| 185 | |||
| 186 | /* read a register */ | 168 | /* read a register */ |
| 187 | static int ov9640_reg_read(struct i2c_client *client, u8 reg, u8 *val) | 169 | static int ov9640_reg_read(struct i2c_client *client, u8 reg, u8 *val) |
| 188 | { | 170 | { |
| @@ -284,75 +266,25 @@ static int ov9640_s_stream(struct v4l2_subdev *sd, int enable) | |||
| 284 | return 0; | 266 | return 0; |
| 285 | } | 267 | } |
| 286 | 268 | ||
| 287 | /* Alter bus settings on camera side */ | ||
| 288 | static int ov9640_set_bus_param(struct soc_camera_device *icd, | ||
| 289 | unsigned long flags) | ||
| 290 | { | ||
| 291 | return 0; | ||
| 292 | } | ||
| 293 | |||
| 294 | /* Request bus settings on camera side */ | ||
| 295 | static unsigned long ov9640_query_bus_param(struct soc_camera_device *icd) | ||
| 296 | { | ||
| 297 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
| 298 | |||
| 299 | /* | ||
| 300 | * REVISIT: the camera probably can do 10 bit transfers, but I don't | ||
| 301 | * have those pins connected on my hardware. | ||
| 302 | */ | ||
| 303 | unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | | ||
| 304 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | | ||
| 305 | SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8; | ||
| 306 | |||
| 307 | return soc_camera_apply_sensor_flags(icl, flags); | ||
| 308 | } | ||
| 309 | |||
| 310 | /* Get status of additional camera capabilities */ | ||
| 311 | static int ov9640_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
| 312 | { | ||
| 313 | struct ov9640_priv *priv = to_ov9640_sensor(sd); | ||
| 314 | |||
| 315 | switch (ctrl->id) { | ||
| 316 | case V4L2_CID_VFLIP: | ||
| 317 | ctrl->value = priv->flag_vflip; | ||
| 318 | break; | ||
| 319 | case V4L2_CID_HFLIP: | ||
| 320 | ctrl->value = priv->flag_hflip; | ||
| 321 | break; | ||
| 322 | } | ||
| 323 | return 0; | ||
| 324 | } | ||
| 325 | |||
| 326 | /* Set status of additional camera capabilities */ | 269 | /* Set status of additional camera capabilities */ |
| 327 | static int ov9640_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 270 | static int ov9640_s_ctrl(struct v4l2_ctrl *ctrl) |
| 328 | { | 271 | { |
| 329 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 272 | struct ov9640_priv *priv = container_of(ctrl->handler, struct ov9640_priv, hdl); |
| 330 | struct ov9640_priv *priv = to_ov9640_sensor(sd); | 273 | struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev); |
| 331 | |||
| 332 | int ret = 0; | ||
| 333 | 274 | ||
| 334 | switch (ctrl->id) { | 275 | switch (ctrl->id) { |
| 335 | case V4L2_CID_VFLIP: | 276 | case V4L2_CID_VFLIP: |
| 336 | priv->flag_vflip = ctrl->value; | 277 | if (ctrl->val) |
| 337 | if (ctrl->value) | 278 | return ov9640_reg_rmw(client, OV9640_MVFP, |
| 338 | ret = ov9640_reg_rmw(client, OV9640_MVFP, | ||
| 339 | OV9640_MVFP_V, 0); | 279 | OV9640_MVFP_V, 0); |
| 340 | else | 280 | return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_V); |
| 341 | ret = ov9640_reg_rmw(client, OV9640_MVFP, | ||
| 342 | 0, OV9640_MVFP_V); | ||
| 343 | break; | ||
| 344 | case V4L2_CID_HFLIP: | 281 | case V4L2_CID_HFLIP: |
| 345 | priv->flag_hflip = ctrl->value; | 282 | if (ctrl->val) |
| 346 | if (ctrl->value) | 283 | return ov9640_reg_rmw(client, OV9640_MVFP, |
| 347 | ret = ov9640_reg_rmw(client, OV9640_MVFP, | ||
| 348 | OV9640_MVFP_H, 0); | 284 | OV9640_MVFP_H, 0); |
| 349 | else | 285 | return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_H); |
| 350 | ret = ov9640_reg_rmw(client, OV9640_MVFP, | ||
| 351 | 0, OV9640_MVFP_H); | ||
| 352 | break; | ||
| 353 | } | 286 | } |
| 354 | 287 | return -EINVAL; | |
| 355 | return ret; | ||
| 356 | } | 288 | } |
| 357 | 289 | ||
| 358 | /* Get chip identification */ | 290 | /* Get chip identification */ |
| @@ -646,10 +578,7 @@ static int ov9640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | |||
| 646 | return 0; | 578 | return 0; |
| 647 | } | 579 | } |
| 648 | 580 | ||
| 649 | 581 | static int ov9640_video_probe(struct i2c_client *client) | |
| 650 | |||
| 651 | static int ov9640_video_probe(struct soc_camera_device *icd, | ||
| 652 | struct i2c_client *client) | ||
| 653 | { | 582 | { |
| 654 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | 583 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
| 655 | struct ov9640_priv *priv = to_ov9640_sensor(sd); | 584 | struct ov9640_priv *priv = to_ov9640_sensor(sd); |
| @@ -657,29 +586,19 @@ static int ov9640_video_probe(struct soc_camera_device *icd, | |||
| 657 | const char *devname; | 586 | const char *devname; |
| 658 | int ret = 0; | 587 | int ret = 0; |
| 659 | 588 | ||
| 660 | /* We must have a parent by now. And it cannot be a wrong one. */ | ||
| 661 | BUG_ON(!icd->parent || | ||
| 662 | to_soc_camera_host(icd->parent)->nr != icd->iface); | ||
| 663 | |||
| 664 | /* | 589 | /* |
| 665 | * check and show product ID and manufacturer ID | 590 | * check and show product ID and manufacturer ID |
| 666 | */ | 591 | */ |
| 667 | 592 | ||
| 668 | ret = ov9640_reg_read(client, OV9640_PID, &pid); | 593 | ret = ov9640_reg_read(client, OV9640_PID, &pid); |
| 594 | if (!ret) | ||
| 595 | ret = ov9640_reg_read(client, OV9640_VER, &ver); | ||
| 596 | if (!ret) | ||
| 597 | ret = ov9640_reg_read(client, OV9640_MIDH, &midh); | ||
| 598 | if (!ret) | ||
| 599 | ret = ov9640_reg_read(client, OV9640_MIDL, &midl); | ||
| 669 | if (ret) | 600 | if (ret) |
| 670 | goto err; | 601 | return ret; |
| 671 | |||
| 672 | ret = ov9640_reg_read(client, OV9640_VER, &ver); | ||
| 673 | if (ret) | ||
| 674 | goto err; | ||
| 675 | |||
| 676 | ret = ov9640_reg_read(client, OV9640_MIDH, &midh); | ||
| 677 | if (ret) | ||
| 678 | goto err; | ||
| 679 | |||
| 680 | ret = ov9640_reg_read(client, OV9640_MIDL, &midl); | ||
| 681 | if (ret) | ||
| 682 | goto err; | ||
| 683 | 602 | ||
| 684 | switch (VERSION(pid, ver)) { | 603 | switch (VERSION(pid, ver)) { |
| 685 | case OV9640_V2: | 604 | case OV9640_V2: |
| @@ -693,27 +612,20 @@ static int ov9640_video_probe(struct soc_camera_device *icd, | |||
| 693 | break; | 612 | break; |
| 694 | default: | 613 | default: |
| 695 | dev_err(&client->dev, "Product ID error %x:%x\n", pid, ver); | 614 | dev_err(&client->dev, "Product ID error %x:%x\n", pid, ver); |
| 696 | ret = -ENODEV; | 615 | return -ENODEV; |
| 697 | goto err; | ||
| 698 | } | 616 | } |
| 699 | 617 | ||
| 700 | dev_info(&client->dev, "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", | 618 | dev_info(&client->dev, "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", |
| 701 | devname, pid, ver, midh, midl); | 619 | devname, pid, ver, midh, midl); |
| 702 | 620 | ||
| 703 | err: | 621 | return v4l2_ctrl_handler_setup(&priv->hdl); |
| 704 | return ret; | ||
| 705 | } | 622 | } |
| 706 | 623 | ||
| 707 | static struct soc_camera_ops ov9640_ops = { | 624 | static const struct v4l2_ctrl_ops ov9640_ctrl_ops = { |
| 708 | .set_bus_param = ov9640_set_bus_param, | 625 | .s_ctrl = ov9640_s_ctrl, |
| 709 | .query_bus_param = ov9640_query_bus_param, | ||
| 710 | .controls = ov9640_controls, | ||
| 711 | .num_controls = ARRAY_SIZE(ov9640_controls), | ||
| 712 | }; | 626 | }; |
| 713 | 627 | ||
| 714 | static struct v4l2_subdev_core_ops ov9640_core_ops = { | 628 | static struct v4l2_subdev_core_ops ov9640_core_ops = { |
| 715 | .g_ctrl = ov9640_g_ctrl, | ||
| 716 | .s_ctrl = ov9640_s_ctrl, | ||
| 717 | .g_chip_ident = ov9640_g_chip_ident, | 629 | .g_chip_ident = ov9640_g_chip_ident, |
| 718 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 630 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
| 719 | .g_register = ov9640_get_register, | 631 | .g_register = ov9640_get_register, |
| @@ -722,6 +634,22 @@ static struct v4l2_subdev_core_ops ov9640_core_ops = { | |||
| 722 | 634 | ||
| 723 | }; | 635 | }; |
| 724 | 636 | ||
| 637 | /* Request bus settings on camera side */ | ||
| 638 | static int ov9640_g_mbus_config(struct v4l2_subdev *sd, | ||
| 639 | struct v4l2_mbus_config *cfg) | ||
| 640 | { | ||
| 641 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 642 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
| 643 | |||
| 644 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | | ||
| 645 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | | ||
| 646 | V4L2_MBUS_DATA_ACTIVE_HIGH; | ||
| 647 | cfg->type = V4L2_MBUS_PARALLEL; | ||
| 648 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | ||
| 649 | |||
| 650 | return 0; | ||
| 651 | } | ||
| 652 | |||
| 725 | static struct v4l2_subdev_video_ops ov9640_video_ops = { | 653 | static struct v4l2_subdev_video_ops ov9640_video_ops = { |
| 726 | .s_stream = ov9640_s_stream, | 654 | .s_stream = ov9640_s_stream, |
| 727 | .s_mbus_fmt = ov9640_s_fmt, | 655 | .s_mbus_fmt = ov9640_s_fmt, |
| @@ -729,7 +657,7 @@ static struct v4l2_subdev_video_ops ov9640_video_ops = { | |||
| 729 | .enum_mbus_fmt = ov9640_enum_fmt, | 657 | .enum_mbus_fmt = ov9640_enum_fmt, |
| 730 | .cropcap = ov9640_cropcap, | 658 | .cropcap = ov9640_cropcap, |
| 731 | .g_crop = ov9640_g_crop, | 659 | .g_crop = ov9640_g_crop, |
| 732 | 660 | .g_mbus_config = ov9640_g_mbus_config, | |
| 733 | }; | 661 | }; |
| 734 | 662 | ||
| 735 | static struct v4l2_subdev_ops ov9640_subdev_ops = { | 663 | static struct v4l2_subdev_ops ov9640_subdev_ops = { |
| @@ -744,16 +672,9 @@ static int ov9640_probe(struct i2c_client *client, | |||
| 744 | const struct i2c_device_id *did) | 672 | const struct i2c_device_id *did) |
| 745 | { | 673 | { |
| 746 | struct ov9640_priv *priv; | 674 | struct ov9640_priv *priv; |
| 747 | struct soc_camera_device *icd = client->dev.platform_data; | 675 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
| 748 | struct soc_camera_link *icl; | ||
| 749 | int ret; | 676 | int ret; |
| 750 | 677 | ||
| 751 | if (!icd) { | ||
| 752 | dev_err(&client->dev, "Missing soc-camera data!\n"); | ||
| 753 | return -EINVAL; | ||
| 754 | } | ||
| 755 | |||
| 756 | icl = to_soc_camera_link(icd); | ||
| 757 | if (!icl) { | 678 | if (!icl) { |
| 758 | dev_err(&client->dev, "Missing platform_data for driver\n"); | 679 | dev_err(&client->dev, "Missing platform_data for driver\n"); |
| 759 | return -EINVAL; | 680 | return -EINVAL; |
| @@ -768,12 +689,23 @@ static int ov9640_probe(struct i2c_client *client, | |||
| 768 | 689 | ||
| 769 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov9640_subdev_ops); | 690 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov9640_subdev_ops); |
| 770 | 691 | ||
| 771 | icd->ops = &ov9640_ops; | 692 | v4l2_ctrl_handler_init(&priv->hdl, 2); |
| 693 | v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops, | ||
| 694 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
| 695 | v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops, | ||
| 696 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
| 697 | priv->subdev.ctrl_handler = &priv->hdl; | ||
| 698 | if (priv->hdl.error) { | ||
| 699 | int err = priv->hdl.error; | ||
| 700 | |||
| 701 | kfree(priv); | ||
| 702 | return err; | ||
| 703 | } | ||
| 772 | 704 | ||
| 773 | ret = ov9640_video_probe(icd, client); | 705 | ret = ov9640_video_probe(client); |
| 774 | 706 | ||
| 775 | if (ret) { | 707 | if (ret) { |
| 776 | icd->ops = NULL; | 708 | v4l2_ctrl_handler_free(&priv->hdl); |
| 777 | kfree(priv); | 709 | kfree(priv); |
| 778 | } | 710 | } |
| 779 | 711 | ||
| @@ -785,6 +717,8 @@ static int ov9640_remove(struct i2c_client *client) | |||
| 785 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | 717 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
| 786 | struct ov9640_priv *priv = to_ov9640_sensor(sd); | 718 | struct ov9640_priv *priv = to_ov9640_sensor(sd); |
| 787 | 719 | ||
| 720 | v4l2_device_unregister_subdev(&priv->subdev); | ||
| 721 | v4l2_ctrl_handler_free(&priv->hdl); | ||
| 788 | kfree(priv); | 722 | kfree(priv); |
| 789 | return 0; | 723 | return 0; |
| 790 | } | 724 | } |
diff --git a/drivers/media/video/ov9640.h b/drivers/media/video/ov9640.h index f8a51b70792e..6b33a972c83c 100644 --- a/drivers/media/video/ov9640.h +++ b/drivers/media/video/ov9640.h | |||
| @@ -198,12 +198,10 @@ struct ov9640_reg { | |||
| 198 | 198 | ||
| 199 | struct ov9640_priv { | 199 | struct ov9640_priv { |
| 200 | struct v4l2_subdev subdev; | 200 | struct v4l2_subdev subdev; |
| 201 | struct v4l2_ctrl_handler hdl; | ||
| 201 | 202 | ||
| 202 | int model; | 203 | int model; |
| 203 | int revision; | 204 | int revision; |
| 204 | |||
| 205 | bool flag_vflip; | ||
| 206 | bool flag_hflip; | ||
| 207 | }; | 205 | }; |
| 208 | 206 | ||
| 209 | #endif /* __DRIVERS_MEDIA_VIDEO_OV9640_H__ */ | 207 | #endif /* __DRIVERS_MEDIA_VIDEO_OV9640_H__ */ |
diff --git a/drivers/media/video/ov9740.c b/drivers/media/video/ov9740.c index edd1ffcca30b..d9a9f7174f7a 100644 --- a/drivers/media/video/ov9740.c +++ b/drivers/media/video/ov9740.c | |||
| @@ -14,8 +14,11 @@ | |||
| 14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
| 15 | #include <linux/i2c.h> | 15 | #include <linux/i2c.h> |
| 16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
| 17 | #include <media/v4l2-chip-ident.h> | 17 | #include <linux/v4l2-mediabus.h> |
| 18 | |||
| 18 | #include <media/soc_camera.h> | 19 | #include <media/soc_camera.h> |
| 20 | #include <media/v4l2-chip-ident.h> | ||
| 21 | #include <media/v4l2-ctrls.h> | ||
| 19 | 22 | ||
| 20 | #define to_ov9740(sd) container_of(sd, struct ov9740_priv, subdev) | 23 | #define to_ov9740(sd) container_of(sd, struct ov9740_priv, subdev) |
| 21 | 24 | ||
| @@ -192,6 +195,7 @@ struct ov9740_reg { | |||
| 192 | 195 | ||
| 193 | struct ov9740_priv { | 196 | struct ov9740_priv { |
| 194 | struct v4l2_subdev subdev; | 197 | struct v4l2_subdev subdev; |
| 198 | struct v4l2_ctrl_handler hdl; | ||
| 195 | 199 | ||
| 196 | int ident; | 200 | int ident; |
| 197 | u16 model; | 201 | u16 model; |
| @@ -392,27 +396,6 @@ static enum v4l2_mbus_pixelcode ov9740_codes[] = { | |||
| 392 | V4L2_MBUS_FMT_YUYV8_2X8, | 396 | V4L2_MBUS_FMT_YUYV8_2X8, |
| 393 | }; | 397 | }; |
| 394 | 398 | ||
| 395 | static const struct v4l2_queryctrl ov9740_controls[] = { | ||
| 396 | { | ||
| 397 | .id = V4L2_CID_VFLIP, | ||
| 398 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 399 | .name = "Flip Vertically", | ||
| 400 | .minimum = 0, | ||
| 401 | .maximum = 1, | ||
| 402 | .step = 1, | ||
| 403 | .default_value = 0, | ||
| 404 | }, | ||
| 405 | { | ||
| 406 | .id = V4L2_CID_HFLIP, | ||
| 407 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 408 | .name = "Flip Horizontally", | ||
| 409 | .minimum = 0, | ||
| 410 | .maximum = 1, | ||
| 411 | .step = 1, | ||
| 412 | .default_value = 0, | ||
| 413 | }, | ||
| 414 | }; | ||
| 415 | |||
| 416 | /* read a register */ | 399 | /* read a register */ |
| 417 | static int ov9740_reg_read(struct i2c_client *client, u16 reg, u8 *val) | 400 | static int ov9740_reg_read(struct i2c_client *client, u16 reg, u8 *val) |
| 418 | { | 401 | { |
| @@ -560,25 +543,6 @@ static int ov9740_s_stream(struct v4l2_subdev *sd, int enable) | |||
| 560 | return ret; | 543 | return ret; |
| 561 | } | 544 | } |
| 562 | 545 | ||
| 563 | /* Alter bus settings on camera side */ | ||
| 564 | static int ov9740_set_bus_param(struct soc_camera_device *icd, | ||
| 565 | unsigned long flags) | ||
| 566 | { | ||
| 567 | return 0; | ||
| 568 | } | ||
| 569 | |||
| 570 | /* Request bus settings on camera side */ | ||
| 571 | static unsigned long ov9740_query_bus_param(struct soc_camera_device *icd) | ||
| 572 | { | ||
| 573 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
| 574 | |||
| 575 | unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | | ||
| 576 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | | ||
| 577 | SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8; | ||
| 578 | |||
| 579 | return soc_camera_apply_sensor_flags(icl, flags); | ||
| 580 | } | ||
| 581 | |||
| 582 | /* select nearest higher resolution for capture */ | 546 | /* select nearest higher resolution for capture */ |
| 583 | static void ov9740_res_roundup(u32 *width, u32 *height) | 547 | static void ov9740_res_roundup(u32 *width, u32 *height) |
| 584 | { | 548 | { |
| @@ -788,36 +752,18 @@ static int ov9740_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
| 788 | return 0; | 752 | return 0; |
| 789 | } | 753 | } |
| 790 | 754 | ||
| 791 | /* Get status of additional camera capabilities */ | ||
| 792 | static int ov9740_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
| 793 | { | ||
| 794 | struct ov9740_priv *priv = to_ov9740(sd); | ||
| 795 | |||
| 796 | switch (ctrl->id) { | ||
| 797 | case V4L2_CID_VFLIP: | ||
| 798 | ctrl->value = priv->flag_vflip; | ||
| 799 | break; | ||
| 800 | case V4L2_CID_HFLIP: | ||
| 801 | ctrl->value = priv->flag_hflip; | ||
| 802 | break; | ||
| 803 | default: | ||
| 804 | return -EINVAL; | ||
| 805 | } | ||
| 806 | |||
| 807 | return 0; | ||
| 808 | } | ||
| 809 | |||
| 810 | /* Set status of additional camera capabilities */ | 755 | /* Set status of additional camera capabilities */ |
| 811 | static int ov9740_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 756 | static int ov9740_s_ctrl(struct v4l2_ctrl *ctrl) |
| 812 | { | 757 | { |
| 813 | struct ov9740_priv *priv = to_ov9740(sd); | 758 | struct ov9740_priv *priv = |
| 759 | container_of(ctrl->handler, struct ov9740_priv, hdl); | ||
| 814 | 760 | ||
| 815 | switch (ctrl->id) { | 761 | switch (ctrl->id) { |
| 816 | case V4L2_CID_VFLIP: | 762 | case V4L2_CID_VFLIP: |
| 817 | priv->flag_vflip = ctrl->value; | 763 | priv->flag_vflip = ctrl->val; |
| 818 | break; | 764 | break; |
| 819 | case V4L2_CID_HFLIP: | 765 | case V4L2_CID_HFLIP: |
| 820 | priv->flag_hflip = ctrl->value; | 766 | priv->flag_hflip = ctrl->val; |
| 821 | break; | 767 | break; |
| 822 | default: | 768 | default: |
| 823 | return -EINVAL; | 769 | return -EINVAL; |
| @@ -890,18 +836,13 @@ static int ov9740_set_register(struct v4l2_subdev *sd, | |||
| 890 | } | 836 | } |
| 891 | #endif | 837 | #endif |
| 892 | 838 | ||
| 893 | static int ov9740_video_probe(struct soc_camera_device *icd, | 839 | static int ov9740_video_probe(struct i2c_client *client) |
| 894 | struct i2c_client *client) | ||
| 895 | { | 840 | { |
| 896 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | 841 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
| 897 | struct ov9740_priv *priv = to_ov9740(sd); | 842 | struct ov9740_priv *priv = to_ov9740(sd); |
| 898 | u8 modelhi, modello; | 843 | u8 modelhi, modello; |
| 899 | int ret; | 844 | int ret; |
| 900 | 845 | ||
| 901 | /* We must have a parent by now. And it cannot be a wrong one. */ | ||
| 902 | BUG_ON(!icd->parent || | ||
| 903 | to_soc_camera_host(icd->parent)->nr != icd->iface); | ||
| 904 | |||
| 905 | /* | 846 | /* |
| 906 | * check and show product ID and manufacturer ID | 847 | * check and show product ID and manufacturer ID |
| 907 | */ | 848 | */ |
| @@ -942,25 +883,33 @@ err: | |||
| 942 | return ret; | 883 | return ret; |
| 943 | } | 884 | } |
| 944 | 885 | ||
| 945 | static struct soc_camera_ops ov9740_ops = { | 886 | /* Request bus settings on camera side */ |
| 946 | .set_bus_param = ov9740_set_bus_param, | 887 | static int ov9740_g_mbus_config(struct v4l2_subdev *sd, |
| 947 | .query_bus_param = ov9740_query_bus_param, | 888 | struct v4l2_mbus_config *cfg) |
| 948 | .controls = ov9740_controls, | 889 | { |
| 949 | .num_controls = ARRAY_SIZE(ov9740_controls), | 890 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 950 | }; | 891 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
| 892 | |||
| 893 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | | ||
| 894 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | | ||
| 895 | V4L2_MBUS_DATA_ACTIVE_HIGH; | ||
| 896 | cfg->type = V4L2_MBUS_PARALLEL; | ||
| 897 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | ||
| 898 | |||
| 899 | return 0; | ||
| 900 | } | ||
| 951 | 901 | ||
| 952 | static struct v4l2_subdev_video_ops ov9740_video_ops = { | 902 | static struct v4l2_subdev_video_ops ov9740_video_ops = { |
| 953 | .s_stream = ov9740_s_stream, | 903 | .s_stream = ov9740_s_stream, |
| 954 | .s_mbus_fmt = ov9740_s_fmt, | 904 | .s_mbus_fmt = ov9740_s_fmt, |
| 955 | .try_mbus_fmt = ov9740_try_fmt, | 905 | .try_mbus_fmt = ov9740_try_fmt, |
| 956 | .enum_mbus_fmt = ov9740_enum_fmt, | 906 | .enum_mbus_fmt = ov9740_enum_fmt, |
| 957 | .cropcap = ov9740_cropcap, | 907 | .cropcap = ov9740_cropcap, |
| 958 | .g_crop = ov9740_g_crop, | 908 | .g_crop = ov9740_g_crop, |
| 909 | .g_mbus_config = ov9740_g_mbus_config, | ||
| 959 | }; | 910 | }; |
| 960 | 911 | ||
| 961 | static struct v4l2_subdev_core_ops ov9740_core_ops = { | 912 | static struct v4l2_subdev_core_ops ov9740_core_ops = { |
| 962 | .g_ctrl = ov9740_g_ctrl, | ||
| 963 | .s_ctrl = ov9740_s_ctrl, | ||
| 964 | .g_chip_ident = ov9740_g_chip_ident, | 913 | .g_chip_ident = ov9740_g_chip_ident, |
| 965 | .s_power = ov9740_s_power, | 914 | .s_power = ov9740_s_power, |
| 966 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 915 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
| @@ -974,6 +923,10 @@ static struct v4l2_subdev_ops ov9740_subdev_ops = { | |||
| 974 | .video = &ov9740_video_ops, | 923 | .video = &ov9740_video_ops, |
| 975 | }; | 924 | }; |
| 976 | 925 | ||
| 926 | static const struct v4l2_ctrl_ops ov9740_ctrl_ops = { | ||
| 927 | .s_ctrl = ov9740_s_ctrl, | ||
| 928 | }; | ||
| 929 | |||
| 977 | /* | 930 | /* |
| 978 | * i2c_driver function | 931 | * i2c_driver function |
| 979 | */ | 932 | */ |
| @@ -981,16 +934,9 @@ static int ov9740_probe(struct i2c_client *client, | |||
| 981 | const struct i2c_device_id *did) | 934 | const struct i2c_device_id *did) |
| 982 | { | 935 | { |
| 983 | struct ov9740_priv *priv; | 936 | struct ov9740_priv *priv; |
| 984 | struct soc_camera_device *icd = client->dev.platform_data; | 937 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
| 985 | struct soc_camera_link *icl; | ||
| 986 | int ret; | 938 | int ret; |
| 987 | 939 | ||
| 988 | if (!icd) { | ||
| 989 | dev_err(&client->dev, "Missing soc-camera data!\n"); | ||
| 990 | return -EINVAL; | ||
| 991 | } | ||
| 992 | |||
| 993 | icl = to_soc_camera_link(icd); | ||
| 994 | if (!icl) { | 940 | if (!icl) { |
| 995 | dev_err(&client->dev, "Missing platform_data for driver\n"); | 941 | dev_err(&client->dev, "Missing platform_data for driver\n"); |
| 996 | return -EINVAL; | 942 | return -EINVAL; |
| @@ -1003,12 +949,24 @@ static int ov9740_probe(struct i2c_client *client, | |||
| 1003 | } | 949 | } |
| 1004 | 950 | ||
| 1005 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov9740_subdev_ops); | 951 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov9740_subdev_ops); |
| 952 | v4l2_ctrl_handler_init(&priv->hdl, 13); | ||
| 953 | v4l2_ctrl_new_std(&priv->hdl, &ov9740_ctrl_ops, | ||
| 954 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
| 955 | v4l2_ctrl_new_std(&priv->hdl, &ov9740_ctrl_ops, | ||
| 956 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
| 957 | priv->subdev.ctrl_handler = &priv->hdl; | ||
| 958 | if (priv->hdl.error) { | ||
| 959 | int err = priv->hdl.error; | ||
| 1006 | 960 | ||
| 1007 | icd->ops = &ov9740_ops; | 961 | kfree(priv); |
| 962 | return err; | ||
| 963 | } | ||
| 1008 | 964 | ||
| 1009 | ret = ov9740_video_probe(icd, client); | 965 | ret = ov9740_video_probe(client); |
| 966 | if (!ret) | ||
| 967 | ret = v4l2_ctrl_handler_setup(&priv->hdl); | ||
| 1010 | if (ret < 0) { | 968 | if (ret < 0) { |
| 1011 | icd->ops = NULL; | 969 | v4l2_ctrl_handler_free(&priv->hdl); |
| 1012 | kfree(priv); | 970 | kfree(priv); |
| 1013 | } | 971 | } |
| 1014 | 972 | ||
| @@ -1019,8 +977,9 @@ static int ov9740_remove(struct i2c_client *client) | |||
| 1019 | { | 977 | { |
| 1020 | struct ov9740_priv *priv = i2c_get_clientdata(client); | 978 | struct ov9740_priv *priv = i2c_get_clientdata(client); |
| 1021 | 979 | ||
| 980 | v4l2_device_unregister_subdev(&priv->subdev); | ||
| 981 | v4l2_ctrl_handler_free(&priv->hdl); | ||
| 1022 | kfree(priv); | 982 | kfree(priv); |
| 1023 | |||
| 1024 | return 0; | 983 | return 0; |
| 1025 | } | 984 | } |
| 1026 | 985 | ||
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 360be226718d..01ff643e682d 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c | |||
| @@ -744,9 +744,9 @@ static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma) | |||
| 744 | /***************************************************************************/ | 744 | /***************************************************************************/ |
| 745 | /* Videobuf2 operations */ | 745 | /* Videobuf2 operations */ |
| 746 | 746 | ||
| 747 | static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, | 747 | static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, |
| 748 | unsigned int *nplanes, unsigned int sizes[], | 748 | unsigned int *nbuffers, unsigned int *nplanes, |
| 749 | void *alloc_ctxs[]) | 749 | unsigned int sizes[], void *alloc_ctxs[]) |
| 750 | { | 750 | { |
| 751 | struct pwc_device *pdev = vb2_get_drv_priv(vq); | 751 | struct pwc_device *pdev = vb2_get_drv_priv(vq); |
| 752 | 752 | ||
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index d07df22a5ec6..79fb22c89ae9 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c | |||
| @@ -214,6 +214,7 @@ struct pxa_camera_dev { | |||
| 214 | unsigned long ciclk; | 214 | unsigned long ciclk; |
| 215 | unsigned long mclk; | 215 | unsigned long mclk; |
| 216 | u32 mclk_divisor; | 216 | u32 mclk_divisor; |
| 217 | u16 width_flags; /* max 10 bits */ | ||
| 217 | 218 | ||
| 218 | struct list_head capture; | 219 | struct list_head capture; |
| 219 | 220 | ||
| @@ -1020,37 +1021,20 @@ static int test_platform_param(struct pxa_camera_dev *pcdev, | |||
| 1020 | * quick capture interface supports both. | 1021 | * quick capture interface supports both. |
| 1021 | */ | 1022 | */ |
| 1022 | *flags = (pcdev->platform_flags & PXA_CAMERA_MASTER ? | 1023 | *flags = (pcdev->platform_flags & PXA_CAMERA_MASTER ? |
| 1023 | SOCAM_MASTER : SOCAM_SLAVE) | | 1024 | V4L2_MBUS_MASTER : V4L2_MBUS_SLAVE) | |
| 1024 | SOCAM_HSYNC_ACTIVE_HIGH | | 1025 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | |
| 1025 | SOCAM_HSYNC_ACTIVE_LOW | | 1026 | V4L2_MBUS_HSYNC_ACTIVE_LOW | |
| 1026 | SOCAM_VSYNC_ACTIVE_HIGH | | 1027 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | |
| 1027 | SOCAM_VSYNC_ACTIVE_LOW | | 1028 | V4L2_MBUS_VSYNC_ACTIVE_LOW | |
| 1028 | SOCAM_DATA_ACTIVE_HIGH | | 1029 | V4L2_MBUS_DATA_ACTIVE_HIGH | |
| 1029 | SOCAM_PCLK_SAMPLE_RISING | | 1030 | V4L2_MBUS_PCLK_SAMPLE_RISING | |
| 1030 | SOCAM_PCLK_SAMPLE_FALLING; | 1031 | V4L2_MBUS_PCLK_SAMPLE_FALLING; |
| 1031 | 1032 | ||
| 1032 | /* If requested data width is supported by the platform, use it */ | 1033 | /* If requested data width is supported by the platform, use it */ |
| 1033 | switch (buswidth) { | 1034 | if ((1 << (buswidth - 1)) & pcdev->width_flags) |
| 1034 | case 10: | 1035 | return 0; |
| 1035 | if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10)) | ||
| 1036 | return -EINVAL; | ||
| 1037 | *flags |= SOCAM_DATAWIDTH_10; | ||
| 1038 | break; | ||
| 1039 | case 9: | ||
| 1040 | if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9)) | ||
| 1041 | return -EINVAL; | ||
| 1042 | *flags |= SOCAM_DATAWIDTH_9; | ||
| 1043 | break; | ||
| 1044 | case 8: | ||
| 1045 | if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8)) | ||
| 1046 | return -EINVAL; | ||
| 1047 | *flags |= SOCAM_DATAWIDTH_8; | ||
| 1048 | break; | ||
| 1049 | default: | ||
| 1050 | return -EINVAL; | ||
| 1051 | } | ||
| 1052 | 1036 | ||
| 1053 | return 0; | 1037 | return -EINVAL; |
| 1054 | } | 1038 | } |
| 1055 | 1039 | ||
| 1056 | static void pxa_camera_setup_cicr(struct soc_camera_device *icd, | 1040 | static void pxa_camera_setup_cicr(struct soc_camera_device *icd, |
| @@ -1070,12 +1054,12 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd, | |||
| 1070 | * Datawidth is now guaranteed to be equal to one of the three values. | 1054 | * Datawidth is now guaranteed to be equal to one of the three values. |
| 1071 | * We fix bit-per-pixel equal to data-width... | 1055 | * We fix bit-per-pixel equal to data-width... |
| 1072 | */ | 1056 | */ |
| 1073 | switch (flags & SOCAM_DATAWIDTH_MASK) { | 1057 | switch (icd->current_fmt->host_fmt->bits_per_sample) { |
| 1074 | case SOCAM_DATAWIDTH_10: | 1058 | case 10: |
| 1075 | dw = 4; | 1059 | dw = 4; |
| 1076 | bpp = 0x40; | 1060 | bpp = 0x40; |
| 1077 | break; | 1061 | break; |
| 1078 | case SOCAM_DATAWIDTH_9: | 1062 | case 9: |
| 1079 | dw = 3; | 1063 | dw = 3; |
| 1080 | bpp = 0x20; | 1064 | bpp = 0x20; |
| 1081 | break; | 1065 | break; |
| @@ -1084,7 +1068,7 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd, | |||
| 1084 | * Actually it can only be 8 now, | 1068 | * Actually it can only be 8 now, |
| 1085 | * default is just to silence compiler warnings | 1069 | * default is just to silence compiler warnings |
| 1086 | */ | 1070 | */ |
| 1087 | case SOCAM_DATAWIDTH_8: | 1071 | case 8: |
| 1088 | dw = 2; | 1072 | dw = 2; |
| 1089 | bpp = 0; | 1073 | bpp = 0; |
| 1090 | } | 1074 | } |
| @@ -1093,11 +1077,11 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd, | |||
| 1093 | cicr4 |= CICR4_PCLK_EN; | 1077 | cicr4 |= CICR4_PCLK_EN; |
| 1094 | if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) | 1078 | if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) |
| 1095 | cicr4 |= CICR4_MCLK_EN; | 1079 | cicr4 |= CICR4_MCLK_EN; |
| 1096 | if (flags & SOCAM_PCLK_SAMPLE_FALLING) | 1080 | if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) |
| 1097 | cicr4 |= CICR4_PCP; | 1081 | cicr4 |= CICR4_PCP; |
| 1098 | if (flags & SOCAM_HSYNC_ACTIVE_LOW) | 1082 | if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) |
| 1099 | cicr4 |= CICR4_HSP; | 1083 | cicr4 |= CICR4_HSP; |
| 1100 | if (flags & SOCAM_VSYNC_ACTIVE_LOW) | 1084 | if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) |
| 1101 | cicr4 |= CICR4_VSP; | 1085 | cicr4 |= CICR4_VSP; |
| 1102 | 1086 | ||
| 1103 | cicr0 = __raw_readl(pcdev->base + CICR0); | 1087 | cicr0 = __raw_readl(pcdev->base + CICR0); |
| @@ -1151,9 +1135,11 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd, | |||
| 1151 | 1135 | ||
| 1152 | static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | 1136 | static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) |
| 1153 | { | 1137 | { |
| 1138 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
| 1154 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 1139 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
| 1155 | struct pxa_camera_dev *pcdev = ici->priv; | 1140 | struct pxa_camera_dev *pcdev = ici->priv; |
| 1156 | unsigned long bus_flags, camera_flags, common_flags; | 1141 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; |
| 1142 | unsigned long bus_flags, common_flags; | ||
| 1157 | int ret; | 1143 | int ret; |
| 1158 | struct pxa_cam *cam = icd->host_priv; | 1144 | struct pxa_cam *cam = icd->host_priv; |
| 1159 | 1145 | ||
| @@ -1162,44 +1148,58 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
| 1162 | if (ret < 0) | 1148 | if (ret < 0) |
| 1163 | return ret; | 1149 | return ret; |
| 1164 | 1150 | ||
| 1165 | camera_flags = icd->ops->query_bus_param(icd); | 1151 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); |
| 1166 | 1152 | if (!ret) { | |
| 1167 | common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags); | 1153 | common_flags = soc_mbus_config_compatible(&cfg, |
| 1168 | if (!common_flags) | 1154 | bus_flags); |
| 1169 | return -EINVAL; | 1155 | if (!common_flags) { |
| 1156 | dev_warn(icd->parent, | ||
| 1157 | "Flags incompatible: camera 0x%x, host 0x%lx\n", | ||
| 1158 | cfg.flags, bus_flags); | ||
| 1159 | return -EINVAL; | ||
| 1160 | } | ||
| 1161 | } else if (ret != -ENOIOCTLCMD) { | ||
| 1162 | return ret; | ||
| 1163 | } else { | ||
| 1164 | common_flags = bus_flags; | ||
| 1165 | } | ||
| 1170 | 1166 | ||
| 1171 | pcdev->channels = 1; | 1167 | pcdev->channels = 1; |
| 1172 | 1168 | ||
| 1173 | /* Make choises, based on platform preferences */ | 1169 | /* Make choises, based on platform preferences */ |
| 1174 | if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && | 1170 | if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && |
| 1175 | (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { | 1171 | (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { |
| 1176 | if (pcdev->platform_flags & PXA_CAMERA_HSP) | 1172 | if (pcdev->platform_flags & PXA_CAMERA_HSP) |
| 1177 | common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; | 1173 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; |
| 1178 | else | 1174 | else |
| 1179 | common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; | 1175 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; |
| 1180 | } | 1176 | } |
| 1181 | 1177 | ||
| 1182 | if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && | 1178 | if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && |
| 1183 | (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { | 1179 | (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { |
| 1184 | if (pcdev->platform_flags & PXA_CAMERA_VSP) | 1180 | if (pcdev->platform_flags & PXA_CAMERA_VSP) |
| 1185 | common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; | 1181 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; |
| 1186 | else | 1182 | else |
| 1187 | common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; | 1183 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; |
| 1188 | } | 1184 | } |
| 1189 | 1185 | ||
| 1190 | if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) && | 1186 | if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && |
| 1191 | (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) { | 1187 | (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { |
| 1192 | if (pcdev->platform_flags & PXA_CAMERA_PCP) | 1188 | if (pcdev->platform_flags & PXA_CAMERA_PCP) |
| 1193 | common_flags &= ~SOCAM_PCLK_SAMPLE_RISING; | 1189 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; |
| 1194 | else | 1190 | else |
| 1195 | common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; | 1191 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; |
| 1196 | } | 1192 | } |
| 1197 | 1193 | ||
| 1198 | cam->flags = common_flags; | 1194 | cfg.flags = common_flags; |
| 1199 | 1195 | ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); | |
| 1200 | ret = icd->ops->set_bus_param(icd, common_flags); | 1196 | if (ret < 0 && ret != -ENOIOCTLCMD) { |
| 1201 | if (ret < 0) | 1197 | dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n", |
| 1198 | common_flags, ret); | ||
| 1202 | return ret; | 1199 | return ret; |
| 1200 | } | ||
| 1201 | |||
| 1202 | cam->flags = common_flags; | ||
| 1203 | 1203 | ||
| 1204 | pxa_camera_setup_cicr(icd, common_flags, pixfmt); | 1204 | pxa_camera_setup_cicr(icd, common_flags, pixfmt); |
| 1205 | 1205 | ||
| @@ -1209,17 +1209,31 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) | |||
| 1209 | static int pxa_camera_try_bus_param(struct soc_camera_device *icd, | 1209 | static int pxa_camera_try_bus_param(struct soc_camera_device *icd, |
| 1210 | unsigned char buswidth) | 1210 | unsigned char buswidth) |
| 1211 | { | 1211 | { |
| 1212 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
| 1212 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 1213 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
| 1213 | struct pxa_camera_dev *pcdev = ici->priv; | 1214 | struct pxa_camera_dev *pcdev = ici->priv; |
| 1214 | unsigned long bus_flags, camera_flags; | 1215 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; |
| 1216 | unsigned long bus_flags, common_flags; | ||
| 1215 | int ret = test_platform_param(pcdev, buswidth, &bus_flags); | 1217 | int ret = test_platform_param(pcdev, buswidth, &bus_flags); |
| 1216 | 1218 | ||
| 1217 | if (ret < 0) | 1219 | if (ret < 0) |
| 1218 | return ret; | 1220 | return ret; |
| 1219 | 1221 | ||
| 1220 | camera_flags = icd->ops->query_bus_param(icd); | 1222 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); |
| 1223 | if (!ret) { | ||
| 1224 | common_flags = soc_mbus_config_compatible(&cfg, | ||
| 1225 | bus_flags); | ||
| 1226 | if (!common_flags) { | ||
| 1227 | dev_warn(icd->parent, | ||
| 1228 | "Flags incompatible: camera 0x%x, host 0x%lx\n", | ||
| 1229 | cfg.flags, bus_flags); | ||
| 1230 | return -EINVAL; | ||
| 1231 | } | ||
| 1232 | } else if (ret == -ENOIOCTLCMD) { | ||
| 1233 | ret = 0; | ||
| 1234 | } | ||
| 1221 | 1235 | ||
| 1222 | return soc_camera_bus_param_compatible(camera_flags, bus_flags) ? 0 : -EINVAL; | 1236 | return ret; |
| 1223 | } | 1237 | } |
| 1224 | 1238 | ||
| 1225 | static const struct soc_mbus_pixelfmt pxa_camera_formats[] = { | 1239 | static const struct soc_mbus_pixelfmt pxa_camera_formats[] = { |
| @@ -1687,6 +1701,12 @@ static int __devinit pxa_camera_probe(struct platform_device *pdev) | |||
| 1687 | "data widths, using default 10 bit\n"); | 1701 | "data widths, using default 10 bit\n"); |
| 1688 | pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_10; | 1702 | pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_10; |
| 1689 | } | 1703 | } |
| 1704 | if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8) | ||
| 1705 | pcdev->width_flags = 1 << 7; | ||
| 1706 | if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9) | ||
| 1707 | pcdev->width_flags |= 1 << 8; | ||
| 1708 | if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10) | ||
| 1709 | pcdev->width_flags |= 1 << 9; | ||
| 1690 | pcdev->mclk = pcdev->pdata->mclk_10khz * 10000; | 1710 | pcdev->mclk = pcdev->pdata->mclk_10khz * 10000; |
| 1691 | if (!pcdev->mclk) { | 1711 | if (!pcdev->mclk) { |
| 1692 | dev_warn(&pdev->dev, | 1712 | dev_warn(&pdev->dev, |
diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c index 847ccc067e87..6afc61689549 100644 --- a/drivers/media/video/rj54n1cb0c.c +++ b/drivers/media/video/rj54n1cb0c.c | |||
| @@ -11,13 +11,14 @@ | |||
| 11 | #include <linux/delay.h> | 11 | #include <linux/delay.h> |
| 12 | #include <linux/i2c.h> | 12 | #include <linux/i2c.h> |
| 13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
| 14 | #include <linux/v4l2-mediabus.h> | ||
| 14 | #include <linux/videodev2.h> | 15 | #include <linux/videodev2.h> |
| 15 | 16 | ||
| 16 | #include <media/rj54n1cb0c.h> | 17 | #include <media/rj54n1cb0c.h> |
| 17 | #include <media/soc_camera.h> | 18 | #include <media/soc_camera.h> |
| 18 | #include <media/soc_mediabus.h> | ||
| 19 | #include <media/v4l2-subdev.h> | 19 | #include <media/v4l2-subdev.h> |
| 20 | #include <media/v4l2-chip-ident.h> | 20 | #include <media/v4l2-chip-ident.h> |
| 21 | #include <media/v4l2-ctrls.h> | ||
| 21 | 22 | ||
| 22 | #define RJ54N1_DEV_CODE 0x0400 | 23 | #define RJ54N1_DEV_CODE 0x0400 |
| 23 | #define RJ54N1_DEV_CODE2 0x0401 | 24 | #define RJ54N1_DEV_CODE2 0x0401 |
| @@ -148,6 +149,7 @@ struct rj54n1_clock_div { | |||
| 148 | 149 | ||
| 149 | struct rj54n1 { | 150 | struct rj54n1 { |
| 150 | struct v4l2_subdev subdev; | 151 | struct v4l2_subdev subdev; |
| 152 | struct v4l2_ctrl_handler hdl; | ||
| 151 | struct rj54n1_clock_div clk_div; | 153 | struct rj54n1_clock_div clk_div; |
| 152 | const struct rj54n1_datafmt *fmt; | 154 | const struct rj54n1_datafmt *fmt; |
| 153 | struct v4l2_rect rect; /* Sensor window */ | 155 | struct v4l2_rect rect; /* Sensor window */ |
| @@ -499,31 +501,6 @@ static int rj54n1_s_stream(struct v4l2_subdev *sd, int enable) | |||
| 499 | return reg_set(client, RJ54N1_STILL_CONTROL, (!enable) << 7, 0x80); | 501 | return reg_set(client, RJ54N1_STILL_CONTROL, (!enable) << 7, 0x80); |
| 500 | } | 502 | } |
| 501 | 503 | ||
| 502 | static int rj54n1_set_bus_param(struct soc_camera_device *icd, | ||
| 503 | unsigned long flags) | ||
| 504 | { | ||
| 505 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
| 506 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 507 | /* Figures 2.5-1 to 2.5-3 - default falling pixclk edge */ | ||
| 508 | |||
| 509 | if (flags & SOCAM_PCLK_SAMPLE_RISING) | ||
| 510 | return reg_write(client, RJ54N1_OUT_SIGPO, 1 << 4); | ||
| 511 | else | ||
| 512 | return reg_write(client, RJ54N1_OUT_SIGPO, 0); | ||
| 513 | } | ||
| 514 | |||
| 515 | static unsigned long rj54n1_query_bus_param(struct soc_camera_device *icd) | ||
| 516 | { | ||
| 517 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
| 518 | const unsigned long flags = | ||
| 519 | SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING | | ||
| 520 | SOCAM_MASTER | SOCAM_DATAWIDTH_8 | | ||
| 521 | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | | ||
| 522 | SOCAM_DATA_ACTIVE_HIGH; | ||
| 523 | |||
| 524 | return soc_camera_apply_sensor_flags(icl, flags); | ||
| 525 | } | ||
| 526 | |||
| 527 | static int rj54n1_set_rect(struct i2c_client *client, | 504 | static int rj54n1_set_rect(struct i2c_client *client, |
| 528 | u16 reg_x, u16 reg_y, u16 reg_xy, | 505 | u16 reg_x, u16 reg_y, u16 reg_xy, |
| 529 | u32 width, u32 height) | 506 | u32 width, u32 height) |
| @@ -1202,134 +1179,51 @@ static int rj54n1_s_register(struct v4l2_subdev *sd, | |||
| 1202 | } | 1179 | } |
| 1203 | #endif | 1180 | #endif |
| 1204 | 1181 | ||
| 1205 | static const struct v4l2_queryctrl rj54n1_controls[] = { | 1182 | static int rj54n1_s_ctrl(struct v4l2_ctrl *ctrl) |
| 1206 | { | ||
| 1207 | .id = V4L2_CID_VFLIP, | ||
| 1208 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 1209 | .name = "Flip Vertically", | ||
| 1210 | .minimum = 0, | ||
| 1211 | .maximum = 1, | ||
| 1212 | .step = 1, | ||
| 1213 | .default_value = 0, | ||
| 1214 | }, { | ||
| 1215 | .id = V4L2_CID_HFLIP, | ||
| 1216 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 1217 | .name = "Flip Horizontally", | ||
| 1218 | .minimum = 0, | ||
| 1219 | .maximum = 1, | ||
| 1220 | .step = 1, | ||
| 1221 | .default_value = 0, | ||
| 1222 | }, { | ||
| 1223 | .id = V4L2_CID_GAIN, | ||
| 1224 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 1225 | .name = "Gain", | ||
| 1226 | .minimum = 0, | ||
| 1227 | .maximum = 127, | ||
| 1228 | .step = 1, | ||
| 1229 | .default_value = 66, | ||
| 1230 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
| 1231 | }, { | ||
| 1232 | .id = V4L2_CID_AUTO_WHITE_BALANCE, | ||
| 1233 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 1234 | .name = "Auto white balance", | ||
| 1235 | .minimum = 0, | ||
| 1236 | .maximum = 1, | ||
| 1237 | .step = 1, | ||
| 1238 | .default_value = 1, | ||
| 1239 | }, | ||
| 1240 | }; | ||
| 1241 | |||
| 1242 | static struct soc_camera_ops rj54n1_ops = { | ||
| 1243 | .set_bus_param = rj54n1_set_bus_param, | ||
| 1244 | .query_bus_param = rj54n1_query_bus_param, | ||
| 1245 | .controls = rj54n1_controls, | ||
| 1246 | .num_controls = ARRAY_SIZE(rj54n1_controls), | ||
| 1247 | }; | ||
| 1248 | |||
| 1249 | static int rj54n1_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
| 1250 | { | 1183 | { |
| 1184 | struct rj54n1 *rj54n1 = container_of(ctrl->handler, struct rj54n1, hdl); | ||
| 1185 | struct v4l2_subdev *sd = &rj54n1->subdev; | ||
| 1251 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 1186 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 1252 | struct rj54n1 *rj54n1 = to_rj54n1(client); | ||
| 1253 | int data; | 1187 | int data; |
| 1254 | 1188 | ||
| 1255 | switch (ctrl->id) { | 1189 | switch (ctrl->id) { |
| 1256 | case V4L2_CID_VFLIP: | 1190 | case V4L2_CID_VFLIP: |
| 1257 | data = reg_read(client, RJ54N1_MIRROR_STILL_MODE); | 1191 | if (ctrl->val) |
| 1258 | if (data < 0) | ||
| 1259 | return -EIO; | ||
| 1260 | ctrl->value = !(data & 1); | ||
| 1261 | break; | ||
| 1262 | case V4L2_CID_HFLIP: | ||
| 1263 | data = reg_read(client, RJ54N1_MIRROR_STILL_MODE); | ||
| 1264 | if (data < 0) | ||
| 1265 | return -EIO; | ||
| 1266 | ctrl->value = !(data & 2); | ||
| 1267 | break; | ||
| 1268 | case V4L2_CID_GAIN: | ||
| 1269 | data = reg_read(client, RJ54N1_Y_GAIN); | ||
| 1270 | if (data < 0) | ||
| 1271 | return -EIO; | ||
| 1272 | |||
| 1273 | ctrl->value = data / 2; | ||
| 1274 | break; | ||
| 1275 | case V4L2_CID_AUTO_WHITE_BALANCE: | ||
| 1276 | ctrl->value = rj54n1->auto_wb; | ||
| 1277 | break; | ||
| 1278 | } | ||
| 1279 | |||
| 1280 | return 0; | ||
| 1281 | } | ||
| 1282 | |||
| 1283 | static int rj54n1_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
| 1284 | { | ||
| 1285 | int data; | ||
| 1286 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 1287 | struct rj54n1 *rj54n1 = to_rj54n1(client); | ||
| 1288 | const struct v4l2_queryctrl *qctrl; | ||
| 1289 | |||
| 1290 | qctrl = soc_camera_find_qctrl(&rj54n1_ops, ctrl->id); | ||
| 1291 | if (!qctrl) | ||
| 1292 | return -EINVAL; | ||
| 1293 | |||
| 1294 | switch (ctrl->id) { | ||
| 1295 | case V4L2_CID_VFLIP: | ||
| 1296 | if (ctrl->value) | ||
| 1297 | data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 0, 1); | 1192 | data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 0, 1); |
| 1298 | else | 1193 | else |
| 1299 | data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 1, 1); | 1194 | data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 1, 1); |
| 1300 | if (data < 0) | 1195 | if (data < 0) |
| 1301 | return -EIO; | 1196 | return -EIO; |
| 1302 | break; | 1197 | return 0; |
| 1303 | case V4L2_CID_HFLIP: | 1198 | case V4L2_CID_HFLIP: |
| 1304 | if (ctrl->value) | 1199 | if (ctrl->val) |
| 1305 | data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 0, 2); | 1200 | data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 0, 2); |
| 1306 | else | 1201 | else |
| 1307 | data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 2, 2); | 1202 | data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 2, 2); |
| 1308 | if (data < 0) | 1203 | if (data < 0) |
| 1309 | return -EIO; | 1204 | return -EIO; |
| 1310 | break; | 1205 | return 0; |
| 1311 | case V4L2_CID_GAIN: | 1206 | case V4L2_CID_GAIN: |
| 1312 | if (ctrl->value > qctrl->maximum || | 1207 | if (reg_write(client, RJ54N1_Y_GAIN, ctrl->val * 2) < 0) |
| 1313 | ctrl->value < qctrl->minimum) | ||
| 1314 | return -EINVAL; | ||
| 1315 | else if (reg_write(client, RJ54N1_Y_GAIN, ctrl->value * 2) < 0) | ||
| 1316 | return -EIO; | 1208 | return -EIO; |
| 1317 | break; | 1209 | return 0; |
| 1318 | case V4L2_CID_AUTO_WHITE_BALANCE: | 1210 | case V4L2_CID_AUTO_WHITE_BALANCE: |
| 1319 | /* Auto WB area - whole image */ | 1211 | /* Auto WB area - whole image */ |
| 1320 | if (reg_set(client, RJ54N1_WB_SEL_WEIGHT_I, ctrl->value << 7, | 1212 | if (reg_set(client, RJ54N1_WB_SEL_WEIGHT_I, ctrl->val << 7, |
| 1321 | 0x80) < 0) | 1213 | 0x80) < 0) |
| 1322 | return -EIO; | 1214 | return -EIO; |
| 1323 | rj54n1->auto_wb = ctrl->value; | 1215 | rj54n1->auto_wb = ctrl->val; |
| 1324 | break; | 1216 | return 0; |
| 1325 | } | 1217 | } |
| 1326 | 1218 | ||
| 1327 | return 0; | 1219 | return -EINVAL; |
| 1328 | } | 1220 | } |
| 1329 | 1221 | ||
| 1222 | static const struct v4l2_ctrl_ops rj54n1_ctrl_ops = { | ||
| 1223 | .s_ctrl = rj54n1_s_ctrl, | ||
| 1224 | }; | ||
| 1225 | |||
| 1330 | static struct v4l2_subdev_core_ops rj54n1_subdev_core_ops = { | 1226 | static struct v4l2_subdev_core_ops rj54n1_subdev_core_ops = { |
| 1331 | .g_ctrl = rj54n1_g_ctrl, | ||
| 1332 | .s_ctrl = rj54n1_s_ctrl, | ||
| 1333 | .g_chip_ident = rj54n1_g_chip_ident, | 1227 | .g_chip_ident = rj54n1_g_chip_ident, |
| 1334 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 1228 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
| 1335 | .g_register = rj54n1_g_register, | 1229 | .g_register = rj54n1_g_register, |
| @@ -1337,6 +1231,36 @@ static struct v4l2_subdev_core_ops rj54n1_subdev_core_ops = { | |||
| 1337 | #endif | 1231 | #endif |
| 1338 | }; | 1232 | }; |
| 1339 | 1233 | ||
| 1234 | static int rj54n1_g_mbus_config(struct v4l2_subdev *sd, | ||
| 1235 | struct v4l2_mbus_config *cfg) | ||
| 1236 | { | ||
| 1237 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 1238 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
| 1239 | |||
| 1240 | cfg->flags = | ||
| 1241 | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | | ||
| 1242 | V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH | | ||
| 1243 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH; | ||
| 1244 | cfg->type = V4L2_MBUS_PARALLEL; | ||
| 1245 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | ||
| 1246 | |||
| 1247 | return 0; | ||
| 1248 | } | ||
| 1249 | |||
| 1250 | static int rj54n1_s_mbus_config(struct v4l2_subdev *sd, | ||
| 1251 | const struct v4l2_mbus_config *cfg) | ||
| 1252 | { | ||
| 1253 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 1254 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
| 1255 | |||
| 1256 | /* Figures 2.5-1 to 2.5-3 - default falling pixclk edge */ | ||
| 1257 | if (soc_camera_apply_board_flags(icl, cfg) & | ||
| 1258 | V4L2_MBUS_PCLK_SAMPLE_RISING) | ||
| 1259 | return reg_write(client, RJ54N1_OUT_SIGPO, 1 << 4); | ||
| 1260 | else | ||
| 1261 | return reg_write(client, RJ54N1_OUT_SIGPO, 0); | ||
| 1262 | } | ||
| 1263 | |||
| 1340 | static struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = { | 1264 | static struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = { |
| 1341 | .s_stream = rj54n1_s_stream, | 1265 | .s_stream = rj54n1_s_stream, |
| 1342 | .s_mbus_fmt = rj54n1_s_fmt, | 1266 | .s_mbus_fmt = rj54n1_s_fmt, |
| @@ -1346,6 +1270,8 @@ static struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = { | |||
| 1346 | .g_crop = rj54n1_g_crop, | 1270 | .g_crop = rj54n1_g_crop, |
| 1347 | .s_crop = rj54n1_s_crop, | 1271 | .s_crop = rj54n1_s_crop, |
| 1348 | .cropcap = rj54n1_cropcap, | 1272 | .cropcap = rj54n1_cropcap, |
| 1273 | .g_mbus_config = rj54n1_g_mbus_config, | ||
| 1274 | .s_mbus_config = rj54n1_s_mbus_config, | ||
| 1349 | }; | 1275 | }; |
| 1350 | 1276 | ||
| 1351 | static struct v4l2_subdev_ops rj54n1_subdev_ops = { | 1277 | static struct v4l2_subdev_ops rj54n1_subdev_ops = { |
| @@ -1357,17 +1283,12 @@ static struct v4l2_subdev_ops rj54n1_subdev_ops = { | |||
| 1357 | * Interface active, can use i2c. If it fails, it can indeed mean, that | 1283 | * Interface active, can use i2c. If it fails, it can indeed mean, that |
| 1358 | * this wasn't our capture interface, so, we wait for the right one | 1284 | * this wasn't our capture interface, so, we wait for the right one |
| 1359 | */ | 1285 | */ |
| 1360 | static int rj54n1_video_probe(struct soc_camera_device *icd, | 1286 | static int rj54n1_video_probe(struct i2c_client *client, |
| 1361 | struct i2c_client *client, | ||
| 1362 | struct rj54n1_pdata *priv) | 1287 | struct rj54n1_pdata *priv) |
| 1363 | { | 1288 | { |
| 1364 | int data1, data2; | 1289 | int data1, data2; |
| 1365 | int ret; | 1290 | int ret; |
| 1366 | 1291 | ||
| 1367 | /* We must have a parent by now. And it cannot be a wrong one. */ | ||
| 1368 | BUG_ON(!icd->parent || | ||
| 1369 | to_soc_camera_host(icd->parent)->nr != icd->iface); | ||
| 1370 | |||
| 1371 | /* Read out the chip version register */ | 1292 | /* Read out the chip version register */ |
| 1372 | data1 = reg_read(client, RJ54N1_DEV_CODE); | 1293 | data1 = reg_read(client, RJ54N1_DEV_CODE); |
| 1373 | data2 = reg_read(client, RJ54N1_DEV_CODE2); | 1294 | data2 = reg_read(client, RJ54N1_DEV_CODE2); |
| @@ -1395,18 +1316,11 @@ static int rj54n1_probe(struct i2c_client *client, | |||
| 1395 | const struct i2c_device_id *did) | 1316 | const struct i2c_device_id *did) |
| 1396 | { | 1317 | { |
| 1397 | struct rj54n1 *rj54n1; | 1318 | struct rj54n1 *rj54n1; |
| 1398 | struct soc_camera_device *icd = client->dev.platform_data; | 1319 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
| 1399 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 1320 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
| 1400 | struct soc_camera_link *icl; | ||
| 1401 | struct rj54n1_pdata *rj54n1_priv; | 1321 | struct rj54n1_pdata *rj54n1_priv; |
| 1402 | int ret; | 1322 | int ret; |
| 1403 | 1323 | ||
| 1404 | if (!icd) { | ||
| 1405 | dev_err(&client->dev, "RJ54N1CB0C: missing soc-camera data!\n"); | ||
| 1406 | return -EINVAL; | ||
| 1407 | } | ||
| 1408 | |||
| 1409 | icl = to_soc_camera_link(icd); | ||
| 1410 | if (!icl || !icl->priv) { | 1324 | if (!icl || !icl->priv) { |
| 1411 | dev_err(&client->dev, "RJ54N1CB0C: missing platform data!\n"); | 1325 | dev_err(&client->dev, "RJ54N1CB0C: missing platform data!\n"); |
| 1412 | return -EINVAL; | 1326 | return -EINVAL; |
| @@ -1425,8 +1339,22 @@ static int rj54n1_probe(struct i2c_client *client, | |||
| 1425 | return -ENOMEM; | 1339 | return -ENOMEM; |
| 1426 | 1340 | ||
| 1427 | v4l2_i2c_subdev_init(&rj54n1->subdev, client, &rj54n1_subdev_ops); | 1341 | v4l2_i2c_subdev_init(&rj54n1->subdev, client, &rj54n1_subdev_ops); |
| 1342 | v4l2_ctrl_handler_init(&rj54n1->hdl, 4); | ||
| 1343 | v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops, | ||
| 1344 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
| 1345 | v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops, | ||
| 1346 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
| 1347 | v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops, | ||
| 1348 | V4L2_CID_GAIN, 0, 127, 1, 66); | ||
| 1349 | v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops, | ||
| 1350 | V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); | ||
| 1351 | rj54n1->subdev.ctrl_handler = &rj54n1->hdl; | ||
| 1352 | if (rj54n1->hdl.error) { | ||
| 1353 | int err = rj54n1->hdl.error; | ||
| 1428 | 1354 | ||
| 1429 | icd->ops = &rj54n1_ops; | 1355 | kfree(rj54n1); |
| 1356 | return err; | ||
| 1357 | } | ||
| 1430 | 1358 | ||
| 1431 | rj54n1->clk_div = clk_div; | 1359 | rj54n1->clk_div = clk_div; |
| 1432 | rj54n1->rect.left = RJ54N1_COLUMN_SKIP; | 1360 | rj54n1->rect.left = RJ54N1_COLUMN_SKIP; |
| @@ -1440,25 +1368,24 @@ static int rj54n1_probe(struct i2c_client *client, | |||
| 1440 | rj54n1->tgclk_mhz = (rj54n1_priv->mclk_freq / PLL_L * PLL_N) / | 1368 | rj54n1->tgclk_mhz = (rj54n1_priv->mclk_freq / PLL_L * PLL_N) / |
| 1441 | (clk_div.ratio_tg + 1) / (clk_div.ratio_t + 1); | 1369 | (clk_div.ratio_tg + 1) / (clk_div.ratio_t + 1); |
| 1442 | 1370 | ||
| 1443 | ret = rj54n1_video_probe(icd, client, rj54n1_priv); | 1371 | ret = rj54n1_video_probe(client, rj54n1_priv); |
| 1444 | if (ret < 0) { | 1372 | if (ret < 0) { |
| 1445 | icd->ops = NULL; | 1373 | v4l2_ctrl_handler_free(&rj54n1->hdl); |
| 1446 | kfree(rj54n1); | 1374 | kfree(rj54n1); |
| 1447 | return ret; | 1375 | return ret; |
| 1448 | } | 1376 | } |
| 1449 | 1377 | return v4l2_ctrl_handler_setup(&rj54n1->hdl); | |
| 1450 | return ret; | ||
| 1451 | } | 1378 | } |
| 1452 | 1379 | ||
| 1453 | static int rj54n1_remove(struct i2c_client *client) | 1380 | static int rj54n1_remove(struct i2c_client *client) |
| 1454 | { | 1381 | { |
| 1455 | struct rj54n1 *rj54n1 = to_rj54n1(client); | 1382 | struct rj54n1 *rj54n1 = to_rj54n1(client); |
| 1456 | struct soc_camera_device *icd = client->dev.platform_data; | 1383 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
| 1457 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
| 1458 | 1384 | ||
| 1459 | icd->ops = NULL; | 1385 | v4l2_device_unregister_subdev(&rj54n1->subdev); |
| 1460 | if (icl->free_bus) | 1386 | if (icl->free_bus) |
| 1461 | icl->free_bus(icl); | 1387 | icl->free_bus(icl); |
| 1388 | v4l2_ctrl_handler_free(&rj54n1->hdl); | ||
| 1462 | kfree(rj54n1); | 1389 | kfree(rj54n1); |
| 1463 | 1390 | ||
| 1464 | return 0; | 1391 | return 0; |
diff --git a/drivers/media/video/s5k6aa.c b/drivers/media/video/s5k6aa.c new file mode 100644 index 000000000000..2446736b7871 --- /dev/null +++ b/drivers/media/video/s5k6aa.c | |||
| @@ -0,0 +1,1680 @@ | |||
| 1 | /* | ||
| 2 | * Driver for Samsung S5K6AAFX SXGA 1/6" 1.3M CMOS Image Sensor | ||
| 3 | * with embedded SoC ISP. | ||
| 4 | * | ||
| 5 | * Copyright (C) 2011, Samsung Electronics Co., Ltd. | ||
| 6 | * Sylwester Nawrocki <s.nawrocki@samsung.com> | ||
| 7 | * | ||
| 8 | * Based on a driver authored by Dongsoo Nathaniel Kim. | ||
| 9 | * Copyright (C) 2009, Dongsoo Nathaniel Kim <dongsoo45.kim@samsung.com> | ||
| 10 | * | ||
| 11 | * This program is free software; you can redistribute it and/or modify | ||
| 12 | * it under the terms of the GNU General Public License as published by | ||
| 13 | * the Free Software Foundation; either version 2 of the License, or | ||
| 14 | * (at your option) any later version. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/clk.h> | ||
| 18 | #include <linux/delay.h> | ||
| 19 | #include <linux/gpio.h> | ||
| 20 | #include <linux/i2c.h> | ||
| 21 | #include <linux/media.h> | ||
| 22 | #include <linux/regulator/consumer.h> | ||
| 23 | #include <linux/slab.h> | ||
| 24 | |||
| 25 | #include <media/media-entity.h> | ||
| 26 | #include <media/v4l2-ctrls.h> | ||
| 27 | #include <media/v4l2-device.h> | ||
| 28 | #include <media/v4l2-subdev.h> | ||
| 29 | #include <media/v4l2-mediabus.h> | ||
| 30 | #include <media/s5k6aa.h> | ||
| 31 | |||
| 32 | static int debug; | ||
| 33 | module_param(debug, int, 0644); | ||
| 34 | |||
| 35 | #define DRIVER_NAME "S5K6AA" | ||
| 36 | |||
| 37 | /* The token to indicate array termination */ | ||
| 38 | #define S5K6AA_TERM 0xffff | ||
| 39 | #define S5K6AA_OUT_WIDTH_DEF 640 | ||
| 40 | #define S5K6AA_OUT_HEIGHT_DEF 480 | ||
| 41 | #define S5K6AA_WIN_WIDTH_MAX 1280 | ||
| 42 | #define S5K6AA_WIN_HEIGHT_MAX 1024 | ||
| 43 | #define S5K6AA_WIN_WIDTH_MIN 8 | ||
| 44 | #define S5K6AA_WIN_HEIGHT_MIN 8 | ||
| 45 | |||
| 46 | /* | ||
| 47 | * H/W register Interface (0xD0000000 - 0xD0000FFF) | ||
| 48 | */ | ||
| 49 | #define AHB_MSB_ADDR_PTR 0xfcfc | ||
| 50 | #define GEN_REG_OFFSH 0xd000 | ||
| 51 | #define REG_CMDWR_ADDRH 0x0028 | ||
| 52 | #define REG_CMDWR_ADDRL 0x002a | ||
| 53 | #define REG_CMDRD_ADDRH 0x002c | ||
| 54 | #define REG_CMDRD_ADDRL 0x002e | ||
| 55 | #define REG_CMDBUF0_ADDR 0x0f12 | ||
| 56 | #define REG_CMDBUF1_ADDR 0x0f10 | ||
| 57 | |||
| 58 | /* | ||
| 59 | * Host S/W Register interface (0x70000000 - 0x70002000) | ||
| 60 | * The value of the two most significant address bytes is 0x7000, | ||
| 61 | * (HOST_SWIF_OFFS_H). The register addresses below specify 2 LSBs. | ||
| 62 | */ | ||
| 63 | #define HOST_SWIF_OFFSH 0x7000 | ||
| 64 | |||
| 65 | /* Initialization parameters */ | ||
| 66 | /* Master clock frequency in KHz */ | ||
| 67 | #define REG_I_INCLK_FREQ_L 0x01b8 | ||
| 68 | #define REG_I_INCLK_FREQ_H 0x01ba | ||
| 69 | #define MIN_MCLK_FREQ_KHZ 6000U | ||
| 70 | #define MAX_MCLK_FREQ_KHZ 27000U | ||
| 71 | #define REG_I_USE_NPVI_CLOCKS 0x01c6 | ||
| 72 | #define REG_I_USE_NMIPI_CLOCKS 0x01c8 | ||
| 73 | |||
| 74 | /* Clock configurations, n = 0..2. REG_I_* frequency unit is 4 kHz. */ | ||
| 75 | #define REG_I_OPCLK_4KHZ(n) ((n) * 6 + 0x01cc) | ||
| 76 | #define REG_I_MIN_OUTRATE_4KHZ(n) ((n) * 6 + 0x01ce) | ||
| 77 | #define REG_I_MAX_OUTRATE_4KHZ(n) ((n) * 6 + 0x01d0) | ||
| 78 | #define SYS_PLL_OUT_FREQ (48000000 / 4000) | ||
| 79 | #define PCLK_FREQ_MIN (24000000 / 4000) | ||
| 80 | #define PCLK_FREQ_MAX (48000000 / 4000) | ||
| 81 | #define REG_I_INIT_PARAMS_UPDATED 0x01e0 | ||
| 82 | #define REG_I_ERROR_INFO 0x01e2 | ||
| 83 | |||
| 84 | /* General purpose parameters */ | ||
| 85 | #define REG_USER_BRIGHTNESS 0x01e4 | ||
| 86 | #define REG_USER_CONTRAST 0x01e6 | ||
| 87 | #define REG_USER_SATURATION 0x01e8 | ||
| 88 | #define REG_USER_SHARPBLUR 0x01ea | ||
| 89 | |||
| 90 | #define REG_G_SPEC_EFFECTS 0x01ee | ||
| 91 | #define REG_G_ENABLE_PREV 0x01f0 | ||
| 92 | #define REG_G_ENABLE_PREV_CHG 0x01f2 | ||
| 93 | #define REG_G_NEW_CFG_SYNC 0x01f8 | ||
| 94 | #define REG_G_PREVZOOM_IN_WIDTH 0x020a | ||
| 95 | #define REG_G_PREVZOOM_IN_HEIGHT 0x020c | ||
| 96 | #define REG_G_PREVZOOM_IN_XOFFS 0x020e | ||
| 97 | #define REG_G_PREVZOOM_IN_YOFFS 0x0210 | ||
| 98 | #define REG_G_INPUTS_CHANGE_REQ 0x021a | ||
| 99 | #define REG_G_ACTIVE_PREV_CFG 0x021c | ||
| 100 | #define REG_G_PREV_CFG_CHG 0x021e | ||
| 101 | #define REG_G_PREV_OPEN_AFTER_CH 0x0220 | ||
| 102 | #define REG_G_PREV_CFG_ERROR 0x0222 | ||
| 103 | |||
| 104 | /* Preview control section. n = 0...4. */ | ||
| 105 | #define PREG(n, x) ((n) * 0x26 + x) | ||
| 106 | #define REG_P_OUT_WIDTH(n) PREG(n, 0x0242) | ||
| 107 | #define REG_P_OUT_HEIGHT(n) PREG(n, 0x0244) | ||
| 108 | #define REG_P_FMT(n) PREG(n, 0x0246) | ||
| 109 | #define REG_P_MAX_OUT_RATE(n) PREG(n, 0x0248) | ||
| 110 | #define REG_P_MIN_OUT_RATE(n) PREG(n, 0x024a) | ||
| 111 | #define REG_P_PVI_MASK(n) PREG(n, 0x024c) | ||
| 112 | #define REG_P_CLK_INDEX(n) PREG(n, 0x024e) | ||
| 113 | #define REG_P_FR_RATE_TYPE(n) PREG(n, 0x0250) | ||
| 114 | #define FR_RATE_DYNAMIC 0 | ||
| 115 | #define FR_RATE_FIXED 1 | ||
| 116 | #define FR_RATE_FIXED_ACCURATE 2 | ||
| 117 | #define REG_P_FR_RATE_Q_TYPE(n) PREG(n, 0x0252) | ||
| 118 | #define FR_RATE_Q_BEST_FRRATE 1 /* Binning enabled */ | ||
| 119 | #define FR_RATE_Q_BEST_QUALITY 2 /* Binning disabled */ | ||
| 120 | /* Frame period in 0.1 ms units */ | ||
| 121 | #define REG_P_MAX_FR_TIME(n) PREG(n, 0x0254) | ||
| 122 | #define REG_P_MIN_FR_TIME(n) PREG(n, 0x0256) | ||
| 123 | /* Conversion to REG_P_[MAX/MIN]_FR_TIME value; __t: time in us */ | ||
| 124 | #define US_TO_FR_TIME(__t) ((__t) / 100) | ||
| 125 | #define S5K6AA_MIN_FR_TIME 33300 /* us */ | ||
| 126 | #define S5K6AA_MAX_FR_TIME 650000 /* us */ | ||
| 127 | #define S5K6AA_MAX_HIGHRES_FR_TIME 666 /* x100 us */ | ||
| 128 | /* The below 5 registers are for "device correction" values */ | ||
| 129 | #define REG_P_COLORTEMP(n) PREG(n, 0x025e) | ||
| 130 | #define REG_P_PREV_MIRROR(n) PREG(n, 0x0262) | ||
| 131 | |||
| 132 | /* Extended image property controls */ | ||
| 133 | /* Exposure time in 10 us units */ | ||
| 134 | #define REG_SF_USR_EXPOSURE_L 0x03c6 | ||
| 135 | #define REG_SF_USR_EXPOSURE_H 0x03c8 | ||
| 136 | #define REG_SF_USR_EXPOSURE_CHG 0x03ca | ||
| 137 | #define REG_SF_USR_TOT_GAIN 0x03cc | ||
| 138 | #define REG_SF_USR_TOT_GAIN_CHG 0x03ce | ||
| 139 | #define REG_SF_RGAIN 0x03d0 | ||
| 140 | #define REG_SF_RGAIN_CHG 0x03d2 | ||
| 141 | #define REG_SF_GGAIN 0x03d4 | ||
| 142 | #define REG_SF_GGAIN_CHG 0x03d6 | ||
| 143 | #define REG_SF_BGAIN 0x03d8 | ||
| 144 | #define REG_SF_BGAIN_CHG 0x03da | ||
| 145 | #define REG_SF_FLICKER_QUANT 0x03dc | ||
| 146 | #define REG_SF_FLICKER_QUANT_CHG 0x03de | ||
| 147 | |||
| 148 | /* Output interface (parallel/MIPI) setup */ | ||
| 149 | #define REG_OIF_EN_MIPI_LANES 0x03fa | ||
| 150 | #define REG_OIF_EN_PACKETS 0x03fc | ||
| 151 | #define REG_OIF_CFG_CHG 0x03fe | ||
| 152 | |||
| 153 | /* Auto-algorithms enable mask */ | ||
| 154 | #define REG_DBG_AUTOALG_EN 0x0400 | ||
| 155 | #define AALG_ALL_EN_MASK (1 << 0) | ||
| 156 | #define AALG_AE_EN_MASK (1 << 1) | ||
| 157 | #define AALG_DIVLEI_EN_MASK (1 << 2) | ||
| 158 | #define AALG_WB_EN_MASK (1 << 3) | ||
| 159 | #define AALG_FLICKER_EN_MASK (1 << 5) | ||
| 160 | #define AALG_FIT_EN_MASK (1 << 6) | ||
| 161 | #define AALG_WRHW_EN_MASK (1 << 7) | ||
| 162 | |||
| 163 | /* Firmware revision information */ | ||
| 164 | #define REG_FW_APIVER 0x012e | ||
| 165 | #define S5K6AAFX_FW_APIVER 0x0001 | ||
| 166 | #define REG_FW_REVISION 0x0130 | ||
| 167 | |||
| 168 | /* For now we use only one user configuration register set */ | ||
| 169 | #define S5K6AA_MAX_PRESETS 1 | ||
| 170 | |||
| 171 | static const char * const s5k6aa_supply_names[] = { | ||
| 172 | "vdd_core", /* Digital core supply 1.5V (1.4V to 1.6V) */ | ||
| 173 | "vdda", /* Analog power supply 2.8V (2.6V to 3.0V) */ | ||
| 174 | "vdd_reg", /* Regulator input power 1.8V (1.7V to 1.9V) | ||
| 175 | or 2.8V (2.6V to 3.0) */ | ||
| 176 | "vddio", /* I/O supply 1.8V (1.65V to 1.95V) | ||
| 177 | or 2.8V (2.5V to 3.1V) */ | ||
| 178 | }; | ||
| 179 | #define S5K6AA_NUM_SUPPLIES ARRAY_SIZE(s5k6aa_supply_names) | ||
| 180 | |||
| 181 | enum s5k6aa_gpio_id { | ||
| 182 | STBY, | ||
| 183 | RST, | ||
| 184 | GPIO_NUM, | ||
| 185 | }; | ||
| 186 | |||
| 187 | struct s5k6aa_regval { | ||
| 188 | u16 addr; | ||
| 189 | u16 val; | ||
| 190 | }; | ||
| 191 | |||
| 192 | struct s5k6aa_pixfmt { | ||
| 193 | enum v4l2_mbus_pixelcode code; | ||
| 194 | u32 colorspace; | ||
| 195 | /* REG_P_FMT(x) register value */ | ||
| 196 | u16 reg_p_fmt; | ||
| 197 | }; | ||
| 198 | |||
| 199 | struct s5k6aa_preset { | ||
| 200 | /* output pixel format and resolution */ | ||
| 201 | struct v4l2_mbus_framefmt mbus_fmt; | ||
| 202 | u8 clk_id; | ||
| 203 | u8 index; | ||
| 204 | }; | ||
| 205 | |||
| 206 | struct s5k6aa_ctrls { | ||
| 207 | struct v4l2_ctrl_handler handler; | ||
| 208 | /* Auto / manual white balance cluster */ | ||
| 209 | struct v4l2_ctrl *awb; | ||
| 210 | struct v4l2_ctrl *gain_red; | ||
| 211 | struct v4l2_ctrl *gain_blue; | ||
| 212 | struct v4l2_ctrl *gain_green; | ||
| 213 | /* Mirror cluster */ | ||
| 214 | struct v4l2_ctrl *hflip; | ||
| 215 | struct v4l2_ctrl *vflip; | ||
| 216 | /* Auto exposure / manual exposure and gain cluster */ | ||
| 217 | struct v4l2_ctrl *auto_exp; | ||
| 218 | struct v4l2_ctrl *exposure; | ||
| 219 | struct v4l2_ctrl *gain; | ||
| 220 | }; | ||
| 221 | |||
| 222 | struct s5k6aa_interval { | ||
| 223 | u16 reg_fr_time; | ||
| 224 | struct v4l2_fract interval; | ||
| 225 | /* Maximum rectangle for the interval */ | ||
| 226 | struct v4l2_frmsize_discrete size; | ||
| 227 | }; | ||
| 228 | |||
| 229 | struct s5k6aa { | ||
| 230 | struct v4l2_subdev sd; | ||
| 231 | struct media_pad pad; | ||
| 232 | |||
| 233 | enum v4l2_mbus_type bus_type; | ||
| 234 | u8 mipi_lanes; | ||
| 235 | |||
| 236 | int (*s_power)(int enable); | ||
| 237 | struct regulator_bulk_data supplies[S5K6AA_NUM_SUPPLIES]; | ||
| 238 | struct s5k6aa_gpio gpio[GPIO_NUM]; | ||
| 239 | |||
| 240 | /* external master clock frequency */ | ||
| 241 | unsigned long mclk_frequency; | ||
| 242 | /* ISP internal master clock frequency */ | ||
| 243 | u16 clk_fop; | ||
| 244 | /* output pixel clock frequency range */ | ||
| 245 | u16 pclk_fmin; | ||
| 246 | u16 pclk_fmax; | ||
| 247 | |||
| 248 | unsigned int inv_hflip:1; | ||
| 249 | unsigned int inv_vflip:1; | ||
| 250 | |||
| 251 | /* protects the struct members below */ | ||
| 252 | struct mutex lock; | ||
| 253 | |||
| 254 | /* sensor matrix scan window */ | ||
| 255 | struct v4l2_rect ccd_rect; | ||
| 256 | |||
| 257 | struct s5k6aa_ctrls ctrls; | ||
| 258 | struct s5k6aa_preset presets[S5K6AA_MAX_PRESETS]; | ||
| 259 | struct s5k6aa_preset *preset; | ||
| 260 | const struct s5k6aa_interval *fiv; | ||
| 261 | |||
| 262 | unsigned int streaming:1; | ||
| 263 | unsigned int apply_cfg:1; | ||
| 264 | unsigned int apply_crop:1; | ||
| 265 | unsigned int power; | ||
| 266 | }; | ||
| 267 | |||
| 268 | static struct s5k6aa_regval s5k6aa_analog_config[] = { | ||
| 269 | /* Analog settings */ | ||
| 270 | { 0x112a, 0x0000 }, { 0x1132, 0x0000 }, | ||
| 271 | { 0x113e, 0x0000 }, { 0x115c, 0x0000 }, | ||
| 272 | { 0x1164, 0x0000 }, { 0x1174, 0x0000 }, | ||
| 273 | { 0x1178, 0x0000 }, { 0x077a, 0x0000 }, | ||
| 274 | { 0x077c, 0x0000 }, { 0x077e, 0x0000 }, | ||
| 275 | { 0x0780, 0x0000 }, { 0x0782, 0x0000 }, | ||
| 276 | { 0x0784, 0x0000 }, { 0x0786, 0x0000 }, | ||
| 277 | { 0x0788, 0x0000 }, { 0x07a2, 0x0000 }, | ||
| 278 | { 0x07a4, 0x0000 }, { 0x07a6, 0x0000 }, | ||
| 279 | { 0x07a8, 0x0000 }, { 0x07b6, 0x0000 }, | ||
| 280 | { 0x07b8, 0x0002 }, { 0x07ba, 0x0004 }, | ||
| 281 | { 0x07bc, 0x0004 }, { 0x07be, 0x0005 }, | ||
| 282 | { 0x07c0, 0x0005 }, { S5K6AA_TERM, 0 }, | ||
| 283 | }; | ||
| 284 | |||
| 285 | /* TODO: Add RGB888 and Bayer format */ | ||
| 286 | static const struct s5k6aa_pixfmt s5k6aa_formats[] = { | ||
| 287 | { V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG, 5 }, | ||
| 288 | /* range 16-240 */ | ||
| 289 | { V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_REC709, 6 }, | ||
| 290 | { V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_JPEG, 0 }, | ||
| 291 | }; | ||
| 292 | |||
| 293 | static const struct s5k6aa_interval s5k6aa_intervals[] = { | ||
| 294 | { 1000, {10000, 1000000}, {1280, 1024} }, /* 10 fps */ | ||
| 295 | { 666, {15000, 1000000}, {1280, 1024} }, /* 15 fps */ | ||
| 296 | { 500, {20000, 1000000}, {1280, 720} }, /* 20 fps */ | ||
| 297 | { 400, {25000, 1000000}, {640, 480} }, /* 25 fps */ | ||
| 298 | { 333, {33300, 1000000}, {640, 480} }, /* 30 fps */ | ||
| 299 | }; | ||
| 300 | |||
| 301 | #define S5K6AA_INTERVAL_DEF_INDEX 1 /* 15 fps */ | ||
| 302 | |||
| 303 | static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) | ||
| 304 | { | ||
| 305 | return &container_of(ctrl->handler, struct s5k6aa, ctrls.handler)->sd; | ||
| 306 | } | ||
| 307 | |||
| 308 | static inline struct s5k6aa *to_s5k6aa(struct v4l2_subdev *sd) | ||
| 309 | { | ||
| 310 | return container_of(sd, struct s5k6aa, sd); | ||
| 311 | } | ||
| 312 | |||
| 313 | /* Set initial values for all preview presets */ | ||
| 314 | static void s5k6aa_presets_data_init(struct s5k6aa *s5k6aa) | ||
| 315 | { | ||
| 316 | struct s5k6aa_preset *preset = &s5k6aa->presets[0]; | ||
| 317 | int i; | ||
| 318 | |||
| 319 | for (i = 0; i < S5K6AA_MAX_PRESETS; i++) { | ||
| 320 | preset->mbus_fmt.width = S5K6AA_OUT_WIDTH_DEF; | ||
| 321 | preset->mbus_fmt.height = S5K6AA_OUT_HEIGHT_DEF; | ||
| 322 | preset->mbus_fmt.code = s5k6aa_formats[0].code; | ||
| 323 | preset->index = i; | ||
| 324 | preset->clk_id = 0; | ||
| 325 | preset++; | ||
| 326 | } | ||
| 327 | |||
| 328 | s5k6aa->fiv = &s5k6aa_intervals[S5K6AA_INTERVAL_DEF_INDEX]; | ||
| 329 | s5k6aa->preset = &s5k6aa->presets[0]; | ||
| 330 | } | ||
| 331 | |||
| 332 | static int s5k6aa_i2c_read(struct i2c_client *client, u16 addr, u16 *val) | ||
| 333 | { | ||
| 334 | u8 wbuf[2] = {addr >> 8, addr & 0xFF}; | ||
| 335 | struct i2c_msg msg[2]; | ||
| 336 | u8 rbuf[2]; | ||
| 337 | int ret; | ||
| 338 | |||
| 339 | msg[0].addr = client->addr; | ||
| 340 | msg[0].flags = 0; | ||
| 341 | msg[0].len = 2; | ||
| 342 | msg[0].buf = wbuf; | ||
| 343 | |||
| 344 | msg[1].addr = client->addr; | ||
| 345 | msg[1].flags = I2C_M_RD; | ||
| 346 | msg[1].len = 2; | ||
| 347 | msg[1].buf = rbuf; | ||
| 348 | |||
| 349 | ret = i2c_transfer(client->adapter, msg, 2); | ||
| 350 | *val = be16_to_cpu(*((u16 *)rbuf)); | ||
| 351 | |||
| 352 | v4l2_dbg(3, debug, client, "i2c_read: 0x%04X : 0x%04x\n", addr, *val); | ||
| 353 | |||
| 354 | return ret == 2 ? 0 : ret; | ||
| 355 | } | ||
| 356 | |||
| 357 | static int s5k6aa_i2c_write(struct i2c_client *client, u16 addr, u16 val) | ||
| 358 | { | ||
| 359 | u8 buf[4] = {addr >> 8, addr & 0xFF, val >> 8, val & 0xFF}; | ||
| 360 | |||
| 361 | int ret = i2c_master_send(client, buf, 4); | ||
| 362 | v4l2_dbg(3, debug, client, "i2c_write: 0x%04X : 0x%04x\n", addr, val); | ||
| 363 | |||
| 364 | return ret == 4 ? 0 : ret; | ||
| 365 | } | ||
| 366 | |||
| 367 | /* The command register write, assumes Command_Wr_addH = 0x7000. */ | ||
| 368 | static int s5k6aa_write(struct i2c_client *c, u16 addr, u16 val) | ||
| 369 | { | ||
| 370 | int ret = s5k6aa_i2c_write(c, REG_CMDWR_ADDRL, addr); | ||
| 371 | if (ret) | ||
| 372 | return ret; | ||
| 373 | return s5k6aa_i2c_write(c, REG_CMDBUF0_ADDR, val); | ||
| 374 | } | ||
| 375 | |||
| 376 | /* The command register read, assumes Command_Rd_addH = 0x7000. */ | ||
| 377 | static int s5k6aa_read(struct i2c_client *client, u16 addr, u16 *val) | ||
| 378 | { | ||
| 379 | int ret = s5k6aa_i2c_write(client, REG_CMDRD_ADDRL, addr); | ||
| 380 | if (ret) | ||
| 381 | return ret; | ||
| 382 | return s5k6aa_i2c_read(client, REG_CMDBUF0_ADDR, val); | ||
| 383 | } | ||
| 384 | |||
| 385 | static int s5k6aa_write_array(struct v4l2_subdev *sd, | ||
| 386 | const struct s5k6aa_regval *msg) | ||
| 387 | { | ||
| 388 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 389 | u16 addr_incr = 0; | ||
| 390 | int ret = 0; | ||
| 391 | |||
| 392 | while (msg->addr != S5K6AA_TERM) { | ||
| 393 | if (addr_incr != 2) | ||
| 394 | ret = s5k6aa_i2c_write(client, REG_CMDWR_ADDRL, | ||
| 395 | msg->addr); | ||
| 396 | if (ret) | ||
| 397 | break; | ||
| 398 | ret = s5k6aa_i2c_write(client, REG_CMDBUF0_ADDR, msg->val); | ||
| 399 | if (ret) | ||
| 400 | break; | ||
| 401 | /* Assume that msg->addr is always less than 0xfffc */ | ||
| 402 | addr_incr = (msg + 1)->addr - msg->addr; | ||
| 403 | msg++; | ||
| 404 | } | ||
| 405 | |||
| 406 | return ret; | ||
| 407 | } | ||
| 408 | |||
| 409 | /* Configure the AHB high address bytes for GTG registers access */ | ||
| 410 | static int s5k6aa_set_ahb_address(struct i2c_client *client) | ||
| 411 | { | ||
| 412 | int ret = s5k6aa_i2c_write(client, AHB_MSB_ADDR_PTR, GEN_REG_OFFSH); | ||
| 413 | if (ret) | ||
| 414 | return ret; | ||
| 415 | ret = s5k6aa_i2c_write(client, REG_CMDRD_ADDRH, HOST_SWIF_OFFSH); | ||
| 416 | if (ret) | ||
| 417 | return ret; | ||
| 418 | return s5k6aa_i2c_write(client, REG_CMDWR_ADDRH, HOST_SWIF_OFFSH); | ||
| 419 | } | ||
| 420 | |||
| 421 | /** | ||
| 422 | * s5k6aa_configure_pixel_clock - apply ISP main clock/PLL configuration | ||
| 423 | * | ||
| 424 | * Configure the internal ISP PLL for the required output frequency. | ||
| 425 | * Locking: called with s5k6aa.lock mutex held. | ||
| 426 | */ | ||
| 427 | static int s5k6aa_configure_pixel_clocks(struct s5k6aa *s5k6aa) | ||
| 428 | { | ||
| 429 | struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd); | ||
| 430 | unsigned long fmclk = s5k6aa->mclk_frequency / 1000; | ||
| 431 | u16 status; | ||
| 432 | int ret; | ||
| 433 | |||
| 434 | if (WARN(fmclk < MIN_MCLK_FREQ_KHZ || fmclk > MAX_MCLK_FREQ_KHZ, | ||
| 435 | "Invalid clock frequency: %ld\n", fmclk)) | ||
| 436 | return -EINVAL; | ||
| 437 | |||
| 438 | s5k6aa->pclk_fmin = PCLK_FREQ_MIN; | ||
| 439 | s5k6aa->pclk_fmax = PCLK_FREQ_MAX; | ||
| 440 | s5k6aa->clk_fop = SYS_PLL_OUT_FREQ; | ||
| 441 | |||
| 442 | /* External input clock frequency in kHz */ | ||
| 443 | ret = s5k6aa_write(c, REG_I_INCLK_FREQ_H, fmclk >> 16); | ||
| 444 | if (!ret) | ||
| 445 | ret = s5k6aa_write(c, REG_I_INCLK_FREQ_L, fmclk & 0xFFFF); | ||
| 446 | if (!ret) | ||
| 447 | ret = s5k6aa_write(c, REG_I_USE_NPVI_CLOCKS, 1); | ||
| 448 | /* Internal PLL frequency */ | ||
| 449 | if (!ret) | ||
| 450 | ret = s5k6aa_write(c, REG_I_OPCLK_4KHZ(0), s5k6aa->clk_fop); | ||
| 451 | if (!ret) | ||
| 452 | ret = s5k6aa_write(c, REG_I_MIN_OUTRATE_4KHZ(0), | ||
| 453 | s5k6aa->pclk_fmin); | ||
| 454 | if (!ret) | ||
| 455 | ret = s5k6aa_write(c, REG_I_MAX_OUTRATE_4KHZ(0), | ||
| 456 | s5k6aa->pclk_fmax); | ||
| 457 | if (!ret) | ||
| 458 | ret = s5k6aa_write(c, REG_I_INIT_PARAMS_UPDATED, 1); | ||
| 459 | if (!ret) | ||
| 460 | ret = s5k6aa_read(c, REG_I_ERROR_INFO, &status); | ||
| 461 | |||
| 462 | return ret ? ret : (status ? -EINVAL : 0); | ||
| 463 | } | ||
| 464 | |||
| 465 | /* Set horizontal and vertical image flipping */ | ||
| 466 | static int s5k6aa_set_mirror(struct s5k6aa *s5k6aa, int horiz_flip) | ||
| 467 | { | ||
| 468 | struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); | ||
| 469 | int index = s5k6aa->preset->index; | ||
| 470 | |||
| 471 | unsigned int vflip = s5k6aa->ctrls.vflip->val ^ s5k6aa->inv_vflip; | ||
| 472 | unsigned int flip = (horiz_flip ^ s5k6aa->inv_hflip) | (vflip << 1); | ||
| 473 | |||
| 474 | return s5k6aa_write(client, REG_P_PREV_MIRROR(index), flip); | ||
| 475 | } | ||
| 476 | |||
| 477 | /* Configure auto/manual white balance and R/G/B gains */ | ||
| 478 | static int s5k6aa_set_awb(struct s5k6aa *s5k6aa, int awb) | ||
| 479 | { | ||
| 480 | struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd); | ||
| 481 | struct s5k6aa_ctrls *ctrls = &s5k6aa->ctrls; | ||
| 482 | u16 reg; | ||
| 483 | |||
| 484 | int ret = s5k6aa_read(c, REG_DBG_AUTOALG_EN, ®); | ||
| 485 | |||
| 486 | if (!ret && !awb) { | ||
| 487 | ret = s5k6aa_write(c, REG_SF_RGAIN, ctrls->gain_red->val); | ||
| 488 | if (!ret) | ||
| 489 | ret = s5k6aa_write(c, REG_SF_RGAIN_CHG, 1); | ||
| 490 | if (ret) | ||
| 491 | return ret; | ||
| 492 | |||
| 493 | ret = s5k6aa_write(c, REG_SF_GGAIN, ctrls->gain_green->val); | ||
| 494 | if (!ret) | ||
| 495 | ret = s5k6aa_write(c, REG_SF_GGAIN_CHG, 1); | ||
| 496 | if (ret) | ||
| 497 | return ret; | ||
| 498 | |||
| 499 | ret = s5k6aa_write(c, REG_SF_BGAIN, ctrls->gain_blue->val); | ||
| 500 | if (!ret) | ||
| 501 | ret = s5k6aa_write(c, REG_SF_BGAIN_CHG, 1); | ||
| 502 | } | ||
| 503 | if (!ret) { | ||
| 504 | reg = awb ? reg | AALG_WB_EN_MASK : reg & ~AALG_WB_EN_MASK; | ||
| 505 | ret = s5k6aa_write(c, REG_DBG_AUTOALG_EN, reg); | ||
| 506 | } | ||
| 507 | |||
| 508 | return ret; | ||
| 509 | } | ||
| 510 | |||
| 511 | /* Program FW with exposure time, 'exposure' in us units */ | ||
| 512 | static int s5k6aa_set_user_exposure(struct i2c_client *client, int exposure) | ||
| 513 | { | ||
| 514 | unsigned int time = exposure / 10; | ||
| 515 | |||
| 516 | int ret = s5k6aa_write(client, REG_SF_USR_EXPOSURE_L, time & 0xffff); | ||
| 517 | if (!ret) | ||
| 518 | ret = s5k6aa_write(client, REG_SF_USR_EXPOSURE_H, time >> 16); | ||
| 519 | if (ret) | ||
| 520 | return ret; | ||
| 521 | return s5k6aa_write(client, REG_SF_USR_EXPOSURE_CHG, 1); | ||
| 522 | } | ||
| 523 | |||
| 524 | static int s5k6aa_set_user_gain(struct i2c_client *client, int gain) | ||
| 525 | { | ||
| 526 | int ret = s5k6aa_write(client, REG_SF_USR_TOT_GAIN, gain); | ||
| 527 | if (ret) | ||
| 528 | return ret; | ||
| 529 | return s5k6aa_write(client, REG_SF_USR_TOT_GAIN_CHG, 1); | ||
| 530 | } | ||
| 531 | |||
| 532 | /* Set auto/manual exposure and total gain */ | ||
| 533 | static int s5k6aa_set_auto_exposure(struct s5k6aa *s5k6aa, int value) | ||
| 534 | { | ||
| 535 | struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd); | ||
| 536 | unsigned int exp_time = s5k6aa->ctrls.exposure->val; | ||
| 537 | u16 auto_alg; | ||
| 538 | |||
| 539 | int ret = s5k6aa_read(c, REG_DBG_AUTOALG_EN, &auto_alg); | ||
| 540 | if (ret) | ||
| 541 | return ret; | ||
| 542 | |||
| 543 | v4l2_dbg(1, debug, c, "man_exp: %d, auto_exp: %d, a_alg: 0x%x\n", | ||
| 544 | exp_time, value, auto_alg); | ||
| 545 | |||
| 546 | if (value == V4L2_EXPOSURE_AUTO) { | ||
| 547 | auto_alg |= AALG_AE_EN_MASK | AALG_DIVLEI_EN_MASK; | ||
| 548 | } else { | ||
| 549 | ret = s5k6aa_set_user_exposure(c, exp_time); | ||
| 550 | if (ret) | ||
| 551 | return ret; | ||
| 552 | ret = s5k6aa_set_user_gain(c, s5k6aa->ctrls.gain->val); | ||
| 553 | if (ret) | ||
| 554 | return ret; | ||
| 555 | auto_alg &= ~(AALG_AE_EN_MASK | AALG_DIVLEI_EN_MASK); | ||
| 556 | } | ||
| 557 | |||
| 558 | return s5k6aa_write(c, REG_DBG_AUTOALG_EN, auto_alg); | ||
| 559 | } | ||
| 560 | |||
| 561 | static int s5k6aa_set_anti_flicker(struct s5k6aa *s5k6aa, int value) | ||
| 562 | { | ||
| 563 | struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); | ||
| 564 | u16 auto_alg; | ||
| 565 | int ret; | ||
| 566 | |||
| 567 | ret = s5k6aa_read(client, REG_DBG_AUTOALG_EN, &auto_alg); | ||
| 568 | if (ret) | ||
| 569 | return ret; | ||
| 570 | |||
| 571 | if (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) { | ||
| 572 | auto_alg |= AALG_FLICKER_EN_MASK; | ||
| 573 | } else { | ||
| 574 | auto_alg &= ~AALG_FLICKER_EN_MASK; | ||
| 575 | /* The V4L2_CID_LINE_FREQUENCY control values match | ||
| 576 | * the register values */ | ||
| 577 | ret = s5k6aa_write(client, REG_SF_FLICKER_QUANT, value); | ||
| 578 | if (ret) | ||
| 579 | return ret; | ||
| 580 | ret = s5k6aa_write(client, REG_SF_FLICKER_QUANT_CHG, 1); | ||
| 581 | if (ret) | ||
| 582 | return ret; | ||
| 583 | } | ||
| 584 | |||
| 585 | return s5k6aa_write(client, REG_DBG_AUTOALG_EN, auto_alg); | ||
| 586 | } | ||
| 587 | |||
| 588 | static int s5k6aa_set_colorfx(struct s5k6aa *s5k6aa, int val) | ||
| 589 | { | ||
| 590 | struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); | ||
| 591 | static const struct v4l2_control colorfx[] = { | ||
| 592 | { V4L2_COLORFX_NONE, 0 }, | ||
| 593 | { V4L2_COLORFX_BW, 1 }, | ||
| 594 | { V4L2_COLORFX_NEGATIVE, 2 }, | ||
| 595 | { V4L2_COLORFX_SEPIA, 3 }, | ||
| 596 | { V4L2_COLORFX_SKY_BLUE, 4 }, | ||
| 597 | { V4L2_COLORFX_SKETCH, 5 }, | ||
| 598 | }; | ||
| 599 | int i; | ||
| 600 | |||
| 601 | for (i = 0; i < ARRAY_SIZE(colorfx); i++) { | ||
| 602 | if (colorfx[i].id == val) | ||
| 603 | return s5k6aa_write(client, REG_G_SPEC_EFFECTS, | ||
| 604 | colorfx[i].value); | ||
| 605 | } | ||
| 606 | return -EINVAL; | ||
| 607 | } | ||
| 608 | |||
| 609 | static int s5k6aa_preview_config_status(struct i2c_client *client) | ||
| 610 | { | ||
| 611 | u16 error = 0; | ||
| 612 | int ret = s5k6aa_read(client, REG_G_PREV_CFG_ERROR, &error); | ||
| 613 | |||
| 614 | v4l2_dbg(1, debug, client, "error: 0x%x (%d)\n", error, ret); | ||
| 615 | return ret ? ret : (error ? -EINVAL : 0); | ||
| 616 | } | ||
| 617 | |||
| 618 | static int s5k6aa_get_pixfmt_index(struct s5k6aa *s5k6aa, | ||
| 619 | struct v4l2_mbus_framefmt *mf) | ||
| 620 | { | ||
| 621 | unsigned int i; | ||
| 622 | |||
| 623 | for (i = 0; i < ARRAY_SIZE(s5k6aa_formats); i++) | ||
| 624 | if (mf->colorspace == s5k6aa_formats[i].colorspace && | ||
| 625 | mf->code == s5k6aa_formats[i].code) | ||
| 626 | return i; | ||
| 627 | return 0; | ||
| 628 | } | ||
| 629 | |||
| 630 | static int s5k6aa_set_output_framefmt(struct s5k6aa *s5k6aa, | ||
| 631 | struct s5k6aa_preset *preset) | ||
| 632 | { | ||
| 633 | struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); | ||
| 634 | int fmt_index = s5k6aa_get_pixfmt_index(s5k6aa, &preset->mbus_fmt); | ||
| 635 | int ret; | ||
| 636 | |||
| 637 | ret = s5k6aa_write(client, REG_P_OUT_WIDTH(preset->index), | ||
| 638 | preset->mbus_fmt.width); | ||
| 639 | if (!ret) | ||
| 640 | ret = s5k6aa_write(client, REG_P_OUT_HEIGHT(preset->index), | ||
| 641 | preset->mbus_fmt.height); | ||
| 642 | if (!ret) | ||
| 643 | ret = s5k6aa_write(client, REG_P_FMT(preset->index), | ||
| 644 | s5k6aa_formats[fmt_index].reg_p_fmt); | ||
| 645 | return ret; | ||
| 646 | } | ||
| 647 | |||
| 648 | static int s5k6aa_set_input_params(struct s5k6aa *s5k6aa) | ||
| 649 | { | ||
| 650 | struct i2c_client *c = v4l2_get_subdevdata(&s5k6aa->sd); | ||
| 651 | struct v4l2_rect *r = &s5k6aa->ccd_rect; | ||
| 652 | int ret; | ||
| 653 | |||
| 654 | ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_WIDTH, r->width); | ||
| 655 | if (!ret) | ||
| 656 | ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_HEIGHT, r->height); | ||
| 657 | if (!ret) | ||
| 658 | ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_XOFFS, r->left); | ||
| 659 | if (!ret) | ||
| 660 | ret = s5k6aa_write(c, REG_G_PREVZOOM_IN_YOFFS, r->top); | ||
| 661 | if (!ret) | ||
| 662 | ret = s5k6aa_write(c, REG_G_INPUTS_CHANGE_REQ, 1); | ||
| 663 | if (!ret) | ||
| 664 | s5k6aa->apply_crop = 0; | ||
| 665 | |||
| 666 | return ret; | ||
| 667 | } | ||
| 668 | |||
| 669 | /** | ||
| 670 | * s5k6aa_configure_video_bus - configure the video output interface | ||
| 671 | * @bus_type: video bus type: parallel or MIPI-CSI | ||
| 672 | * @nlanes: number of MIPI lanes to be used (MIPI-CSI only) | ||
| 673 | * | ||
| 674 | * Note: Only parallel bus operation has been tested. | ||
| 675 | */ | ||
| 676 | static int s5k6aa_configure_video_bus(struct s5k6aa *s5k6aa, | ||
| 677 | enum v4l2_mbus_type bus_type, int nlanes) | ||
| 678 | { | ||
| 679 | struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); | ||
| 680 | u16 cfg = 0; | ||
| 681 | int ret; | ||
| 682 | |||
| 683 | /* | ||
| 684 | * TODO: The sensor is supposed to support BT.601 and BT.656 | ||
| 685 | * but there is nothing indicating how to switch between both | ||
| 686 | * in the datasheet. For now default BT.601 interface is assumed. | ||
| 687 | */ | ||
| 688 | if (bus_type == V4L2_MBUS_CSI2) | ||
| 689 | cfg = nlanes; | ||
| 690 | else if (bus_type != V4L2_MBUS_PARALLEL) | ||
| 691 | return -EINVAL; | ||
| 692 | |||
| 693 | ret = s5k6aa_write(client, REG_OIF_EN_MIPI_LANES, cfg); | ||
| 694 | if (ret) | ||
| 695 | return ret; | ||
| 696 | return s5k6aa_write(client, REG_OIF_CFG_CHG, 1); | ||
| 697 | } | ||
| 698 | |||
| 699 | /* This function should be called when switching to new user configuration set*/ | ||
| 700 | static int s5k6aa_new_config_sync(struct i2c_client *client, int timeout, | ||
| 701 | int cid) | ||
| 702 | { | ||
| 703 | unsigned long end = jiffies + msecs_to_jiffies(timeout); | ||
| 704 | u16 reg = 1; | ||
| 705 | int ret; | ||
| 706 | |||
| 707 | ret = s5k6aa_write(client, REG_G_ACTIVE_PREV_CFG, cid); | ||
| 708 | if (!ret) | ||
| 709 | ret = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1); | ||
| 710 | if (!ret) | ||
| 711 | ret = s5k6aa_write(client, REG_G_NEW_CFG_SYNC, 1); | ||
| 712 | if (timeout == 0) | ||
| 713 | return ret; | ||
| 714 | |||
| 715 | while (ret >= 0 && time_is_after_jiffies(end)) { | ||
| 716 | ret = s5k6aa_read(client, REG_G_NEW_CFG_SYNC, ®); | ||
| 717 | if (!reg) | ||
| 718 | return 0; | ||
| 719 | usleep_range(1000, 5000); | ||
| 720 | } | ||
| 721 | return ret ? ret : -ETIMEDOUT; | ||
| 722 | } | ||
| 723 | |||
| 724 | /** | ||
| 725 | * s5k6aa_set_prev_config - write user preview register set | ||
| 726 | * | ||
| 727 | * Configure output resolution and color fromat, pixel clock | ||
| 728 | * frequency range, device frame rate type and frame period range. | ||
| 729 | */ | ||
| 730 | static int s5k6aa_set_prev_config(struct s5k6aa *s5k6aa, | ||
| 731 | struct s5k6aa_preset *preset) | ||
| 732 | { | ||
| 733 | struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); | ||
| 734 | int idx = preset->index; | ||
| 735 | u16 frame_rate_q; | ||
| 736 | int ret; | ||
| 737 | |||
| 738 | if (s5k6aa->fiv->reg_fr_time >= S5K6AA_MAX_HIGHRES_FR_TIME) | ||
| 739 | frame_rate_q = FR_RATE_Q_BEST_FRRATE; | ||
| 740 | else | ||
| 741 | frame_rate_q = FR_RATE_Q_BEST_QUALITY; | ||
| 742 | |||
| 743 | ret = s5k6aa_set_output_framefmt(s5k6aa, preset); | ||
| 744 | if (!ret) | ||
| 745 | ret = s5k6aa_write(client, REG_P_MAX_OUT_RATE(idx), | ||
| 746 | s5k6aa->pclk_fmax); | ||
| 747 | if (!ret) | ||
| 748 | ret = s5k6aa_write(client, REG_P_MIN_OUT_RATE(idx), | ||
| 749 | s5k6aa->pclk_fmin); | ||
| 750 | if (!ret) | ||
| 751 | ret = s5k6aa_write(client, REG_P_CLK_INDEX(idx), | ||
| 752 | preset->clk_id); | ||
| 753 | if (!ret) | ||
| 754 | ret = s5k6aa_write(client, REG_P_FR_RATE_TYPE(idx), | ||
| 755 | FR_RATE_DYNAMIC); | ||
| 756 | if (!ret) | ||
| 757 | ret = s5k6aa_write(client, REG_P_FR_RATE_Q_TYPE(idx), | ||
| 758 | frame_rate_q); | ||
| 759 | if (!ret) | ||
| 760 | ret = s5k6aa_write(client, REG_P_MAX_FR_TIME(idx), | ||
| 761 | s5k6aa->fiv->reg_fr_time + 33); | ||
| 762 | if (!ret) | ||
| 763 | ret = s5k6aa_write(client, REG_P_MIN_FR_TIME(idx), | ||
| 764 | s5k6aa->fiv->reg_fr_time - 33); | ||
| 765 | if (!ret) | ||
| 766 | ret = s5k6aa_new_config_sync(client, 250, idx); | ||
| 767 | if (!ret) | ||
| 768 | ret = s5k6aa_preview_config_status(client); | ||
| 769 | if (!ret) | ||
| 770 | s5k6aa->apply_cfg = 0; | ||
| 771 | |||
| 772 | v4l2_dbg(1, debug, client, "Frame interval: %d +/- 3.3ms. (%d)\n", | ||
| 773 | s5k6aa->fiv->reg_fr_time, ret); | ||
| 774 | return ret; | ||
| 775 | } | ||
| 776 | |||
| 777 | /** | ||
| 778 | * s5k6aa_initialize_isp - basic ISP MCU initialization | ||
| 779 | * | ||
| 780 | * Configure AHB addresses for registers read/write; configure PLLs for | ||
| 781 | * required output pixel clock. The ISP power supply needs to be already | ||
| 782 | * enabled, with an optional H/W reset. | ||
| 783 | * Locking: called with s5k6aa.lock mutex held. | ||
| 784 | */ | ||
| 785 | static int s5k6aa_initialize_isp(struct v4l2_subdev *sd) | ||
| 786 | { | ||
| 787 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 788 | struct s5k6aa *s5k6aa = to_s5k6aa(sd); | ||
| 789 | int ret; | ||
| 790 | |||
| 791 | s5k6aa->apply_crop = 1; | ||
| 792 | s5k6aa->apply_cfg = 1; | ||
| 793 | msleep(100); | ||
| 794 | |||
| 795 | ret = s5k6aa_set_ahb_address(client); | ||
| 796 | if (ret) | ||
| 797 | return ret; | ||
| 798 | ret = s5k6aa_configure_video_bus(s5k6aa, s5k6aa->bus_type, | ||
| 799 | s5k6aa->mipi_lanes); | ||
| 800 | if (ret) | ||
| 801 | return ret; | ||
| 802 | ret = s5k6aa_write_array(sd, s5k6aa_analog_config); | ||
| 803 | if (ret) | ||
| 804 | return ret; | ||
| 805 | msleep(20); | ||
| 806 | |||
| 807 | return s5k6aa_configure_pixel_clocks(s5k6aa); | ||
| 808 | } | ||
| 809 | |||
| 810 | static int s5k6aa_gpio_set_value(struct s5k6aa *priv, int id, u32 val) | ||
| 811 | { | ||
| 812 | if (!gpio_is_valid(priv->gpio[id].gpio)) | ||
| 813 | return 0; | ||
| 814 | gpio_set_value(priv->gpio[id].gpio, !!val); | ||
| 815 | return 1; | ||
| 816 | } | ||
| 817 | |||
| 818 | static int s5k6aa_gpio_assert(struct s5k6aa *priv, int id) | ||
| 819 | { | ||
| 820 | return s5k6aa_gpio_set_value(priv, id, priv->gpio[id].level); | ||
| 821 | } | ||
| 822 | |||
| 823 | static int s5k6aa_gpio_deassert(struct s5k6aa *priv, int id) | ||
| 824 | { | ||
| 825 | return s5k6aa_gpio_set_value(priv, id, !priv->gpio[id].level); | ||
| 826 | } | ||
| 827 | |||
| 828 | static int __s5k6aa_power_on(struct s5k6aa *s5k6aa) | ||
| 829 | { | ||
| 830 | int ret; | ||
| 831 | |||
| 832 | ret = regulator_bulk_enable(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies); | ||
| 833 | if (ret) | ||
| 834 | return ret; | ||
| 835 | if (s5k6aa_gpio_deassert(s5k6aa, STBY)) | ||
| 836 | usleep_range(150, 200); | ||
| 837 | |||
| 838 | if (s5k6aa->s_power) | ||
| 839 | ret = s5k6aa->s_power(1); | ||
| 840 | usleep_range(4000, 4000); | ||
| 841 | |||
| 842 | if (s5k6aa_gpio_deassert(s5k6aa, RST)) | ||
| 843 | msleep(20); | ||
| 844 | |||
| 845 | return ret; | ||
| 846 | } | ||
| 847 | |||
| 848 | static int __s5k6aa_power_off(struct s5k6aa *s5k6aa) | ||
| 849 | { | ||
| 850 | int ret; | ||
| 851 | |||
| 852 | if (s5k6aa_gpio_assert(s5k6aa, RST)) | ||
| 853 | usleep_range(100, 150); | ||
| 854 | |||
| 855 | if (s5k6aa->s_power) { | ||
| 856 | ret = s5k6aa->s_power(0); | ||
| 857 | if (ret) | ||
| 858 | return ret; | ||
| 859 | } | ||
| 860 | if (s5k6aa_gpio_assert(s5k6aa, STBY)) | ||
| 861 | usleep_range(50, 100); | ||
| 862 | s5k6aa->streaming = 0; | ||
| 863 | |||
| 864 | return regulator_bulk_disable(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies); | ||
| 865 | } | ||
| 866 | |||
| 867 | /* | ||
| 868 | * V4L2 subdev core and video operations | ||
| 869 | */ | ||
| 870 | static int s5k6aa_set_power(struct v4l2_subdev *sd, int on) | ||
| 871 | { | ||
| 872 | struct s5k6aa *s5k6aa = to_s5k6aa(sd); | ||
| 873 | int ret = 0; | ||
| 874 | |||
| 875 | mutex_lock(&s5k6aa->lock); | ||
| 876 | |||
| 877 | if (!on == s5k6aa->power) { | ||
| 878 | if (on) { | ||
| 879 | ret = __s5k6aa_power_on(s5k6aa); | ||
| 880 | if (!ret) | ||
| 881 | ret = s5k6aa_initialize_isp(sd); | ||
| 882 | } else { | ||
| 883 | ret = __s5k6aa_power_off(s5k6aa); | ||
| 884 | } | ||
| 885 | |||
| 886 | if (!ret) | ||
| 887 | s5k6aa->power += on ? 1 : -1; | ||
| 888 | } | ||
| 889 | |||
| 890 | mutex_unlock(&s5k6aa->lock); | ||
| 891 | |||
| 892 | if (!on || ret || s5k6aa->power != 1) | ||
| 893 | return ret; | ||
| 894 | |||
| 895 | return v4l2_ctrl_handler_setup(sd->ctrl_handler); | ||
| 896 | } | ||
| 897 | |||
| 898 | static int __s5k6aa_stream(struct s5k6aa *s5k6aa, int enable) | ||
| 899 | { | ||
| 900 | struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); | ||
| 901 | int ret = 0; | ||
| 902 | |||
| 903 | ret = s5k6aa_write(client, REG_G_ENABLE_PREV, enable); | ||
| 904 | if (!ret) | ||
| 905 | ret = s5k6aa_write(client, REG_G_ENABLE_PREV_CHG, 1); | ||
| 906 | if (!ret) | ||
| 907 | s5k6aa->streaming = enable; | ||
| 908 | |||
| 909 | return ret; | ||
| 910 | } | ||
| 911 | |||
| 912 | static int s5k6aa_s_stream(struct v4l2_subdev *sd, int on) | ||
| 913 | { | ||
| 914 | struct s5k6aa *s5k6aa = to_s5k6aa(sd); | ||
| 915 | int ret = 0; | ||
| 916 | |||
| 917 | mutex_lock(&s5k6aa->lock); | ||
| 918 | |||
| 919 | if (s5k6aa->streaming == !on) { | ||
| 920 | if (!ret && s5k6aa->apply_cfg) | ||
| 921 | ret = s5k6aa_set_prev_config(s5k6aa, s5k6aa->preset); | ||
| 922 | if (s5k6aa->apply_crop) | ||
| 923 | ret = s5k6aa_set_input_params(s5k6aa); | ||
| 924 | if (!ret) | ||
| 925 | ret = __s5k6aa_stream(s5k6aa, !!on); | ||
| 926 | } | ||
| 927 | mutex_unlock(&s5k6aa->lock); | ||
| 928 | |||
| 929 | return ret; | ||
| 930 | } | ||
| 931 | |||
| 932 | static int s5k6aa_g_frame_interval(struct v4l2_subdev *sd, | ||
| 933 | struct v4l2_subdev_frame_interval *fi) | ||
| 934 | { | ||
| 935 | struct s5k6aa *s5k6aa = to_s5k6aa(sd); | ||
| 936 | |||
| 937 | mutex_lock(&s5k6aa->lock); | ||
| 938 | fi->interval = s5k6aa->fiv->interval; | ||
| 939 | mutex_unlock(&s5k6aa->lock); | ||
| 940 | |||
| 941 | return 0; | ||
| 942 | } | ||
| 943 | |||
| 944 | static int __s5k6aa_set_frame_interval(struct s5k6aa *s5k6aa, | ||
| 945 | struct v4l2_subdev_frame_interval *fi) | ||
| 946 | { | ||
| 947 | struct v4l2_mbus_framefmt *mbus_fmt = &s5k6aa->preset->mbus_fmt; | ||
| 948 | const struct s5k6aa_interval *fiv = &s5k6aa_intervals[0]; | ||
| 949 | unsigned int err, min_err = UINT_MAX; | ||
| 950 | unsigned int i, fr_time; | ||
| 951 | |||
| 952 | if (fi->interval.denominator == 0) | ||
| 953 | return -EINVAL; | ||
| 954 | |||
| 955 | fr_time = fi->interval.numerator * 10000 / fi->interval.denominator; | ||
| 956 | |||
| 957 | for (i = 0; i < ARRAY_SIZE(s5k6aa_intervals); i++) { | ||
| 958 | const struct s5k6aa_interval *iv = &s5k6aa_intervals[i]; | ||
| 959 | |||
| 960 | if (mbus_fmt->width > iv->size.width || | ||
| 961 | mbus_fmt->height > iv->size.height) | ||
| 962 | continue; | ||
| 963 | |||
| 964 | err = abs(iv->reg_fr_time - fr_time); | ||
| 965 | if (err < min_err) { | ||
| 966 | fiv = iv; | ||
| 967 | min_err = err; | ||
| 968 | } | ||
| 969 | } | ||
| 970 | s5k6aa->fiv = fiv; | ||
| 971 | |||
| 972 | v4l2_dbg(1, debug, &s5k6aa->sd, "Changed frame interval to %d us\n", | ||
| 973 | fiv->reg_fr_time * 100); | ||
| 974 | return 0; | ||
| 975 | } | ||
| 976 | |||
| 977 | static int s5k6aa_s_frame_interval(struct v4l2_subdev *sd, | ||
| 978 | struct v4l2_subdev_frame_interval *fi) | ||
| 979 | { | ||
| 980 | struct s5k6aa *s5k6aa = to_s5k6aa(sd); | ||
| 981 | int ret; | ||
| 982 | |||
| 983 | v4l2_dbg(1, debug, sd, "Setting %d/%d frame interval\n", | ||
| 984 | fi->interval.numerator, fi->interval.denominator); | ||
| 985 | |||
| 986 | mutex_lock(&s5k6aa->lock); | ||
| 987 | ret = __s5k6aa_set_frame_interval(s5k6aa, fi); | ||
| 988 | s5k6aa->apply_cfg = 1; | ||
| 989 | |||
| 990 | mutex_unlock(&s5k6aa->lock); | ||
| 991 | return ret; | ||
| 992 | } | ||
| 993 | |||
| 994 | /* | ||
| 995 | * V4L2 subdev pad level and video operations | ||
| 996 | */ | ||
| 997 | static int s5k6aa_enum_frame_interval(struct v4l2_subdev *sd, | ||
| 998 | struct v4l2_subdev_fh *fh, | ||
| 999 | struct v4l2_subdev_frame_interval_enum *fie) | ||
| 1000 | { | ||
| 1001 | struct s5k6aa *s5k6aa = to_s5k6aa(sd); | ||
| 1002 | const struct s5k6aa_interval *fi; | ||
| 1003 | int ret = 0; | ||
| 1004 | |||
| 1005 | if (fie->index > ARRAY_SIZE(s5k6aa_intervals)) | ||
| 1006 | return -EINVAL; | ||
| 1007 | |||
| 1008 | v4l_bound_align_image(&fie->width, S5K6AA_WIN_WIDTH_MIN, | ||
| 1009 | S5K6AA_WIN_WIDTH_MAX, 1, | ||
| 1010 | &fie->height, S5K6AA_WIN_HEIGHT_MIN, | ||
| 1011 | S5K6AA_WIN_HEIGHT_MAX, 1, 0); | ||
| 1012 | |||
| 1013 | mutex_lock(&s5k6aa->lock); | ||
| 1014 | fi = &s5k6aa_intervals[fie->index]; | ||
| 1015 | if (fie->width > fi->size.width || fie->height > fi->size.height) | ||
| 1016 | ret = -EINVAL; | ||
| 1017 | else | ||
| 1018 | fie->interval = fi->interval; | ||
| 1019 | mutex_unlock(&s5k6aa->lock); | ||
| 1020 | |||
| 1021 | return ret; | ||
| 1022 | } | ||
| 1023 | |||
| 1024 | static int s5k6aa_enum_mbus_code(struct v4l2_subdev *sd, | ||
| 1025 | struct v4l2_subdev_fh *fh, | ||
| 1026 | struct v4l2_subdev_mbus_code_enum *code) | ||
| 1027 | { | ||
| 1028 | if (code->index >= ARRAY_SIZE(s5k6aa_formats)) | ||
| 1029 | return -EINVAL; | ||
| 1030 | |||
| 1031 | code->code = s5k6aa_formats[code->index].code; | ||
| 1032 | return 0; | ||
| 1033 | } | ||
| 1034 | |||
| 1035 | static int s5k6aa_enum_frame_size(struct v4l2_subdev *sd, | ||
| 1036 | struct v4l2_subdev_fh *fh, | ||
| 1037 | struct v4l2_subdev_frame_size_enum *fse) | ||
| 1038 | { | ||
| 1039 | int i = ARRAY_SIZE(s5k6aa_formats); | ||
| 1040 | |||
| 1041 | if (fse->index > 0) | ||
| 1042 | return -EINVAL; | ||
| 1043 | |||
| 1044 | while (--i) | ||
| 1045 | if (fse->code == s5k6aa_formats[i].code) | ||
| 1046 | break; | ||
| 1047 | |||
| 1048 | fse->code = s5k6aa_formats[i].code; | ||
| 1049 | fse->min_width = S5K6AA_WIN_WIDTH_MIN; | ||
| 1050 | fse->max_width = S5K6AA_WIN_WIDTH_MAX; | ||
| 1051 | fse->max_height = S5K6AA_WIN_HEIGHT_MIN; | ||
| 1052 | fse->min_height = S5K6AA_WIN_HEIGHT_MAX; | ||
| 1053 | |||
| 1054 | return 0; | ||
| 1055 | } | ||
| 1056 | |||
| 1057 | static struct v4l2_rect * | ||
| 1058 | __s5k6aa_get_crop_rect(struct s5k6aa *s5k6aa, struct v4l2_subdev_fh *fh, | ||
| 1059 | enum v4l2_subdev_format_whence which) | ||
| 1060 | { | ||
| 1061 | if (which == V4L2_SUBDEV_FORMAT_ACTIVE) | ||
| 1062 | return &s5k6aa->ccd_rect; | ||
| 1063 | if (which == V4L2_SUBDEV_FORMAT_TRY) | ||
| 1064 | return v4l2_subdev_get_try_crop(fh, 0); | ||
| 1065 | |||
| 1066 | return NULL; | ||
| 1067 | } | ||
| 1068 | |||
| 1069 | static void s5k6aa_try_format(struct s5k6aa *s5k6aa, | ||
| 1070 | struct v4l2_mbus_framefmt *mf) | ||
| 1071 | { | ||
| 1072 | unsigned int index; | ||
| 1073 | |||
| 1074 | v4l_bound_align_image(&mf->width, S5K6AA_WIN_WIDTH_MIN, | ||
| 1075 | S5K6AA_WIN_WIDTH_MAX, 1, | ||
| 1076 | &mf->height, S5K6AA_WIN_HEIGHT_MIN, | ||
| 1077 | S5K6AA_WIN_HEIGHT_MAX, 1, 0); | ||
| 1078 | |||
| 1079 | if (mf->colorspace != V4L2_COLORSPACE_JPEG && | ||
| 1080 | mf->colorspace != V4L2_COLORSPACE_REC709) | ||
| 1081 | mf->colorspace = V4L2_COLORSPACE_JPEG; | ||
| 1082 | |||
| 1083 | index = s5k6aa_get_pixfmt_index(s5k6aa, mf); | ||
| 1084 | |||
| 1085 | mf->colorspace = s5k6aa_formats[index].colorspace; | ||
| 1086 | mf->code = s5k6aa_formats[index].code; | ||
| 1087 | mf->field = V4L2_FIELD_NONE; | ||
| 1088 | } | ||
| 1089 | |||
| 1090 | static int s5k6aa_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
| 1091 | struct v4l2_subdev_format *fmt) | ||
| 1092 | { | ||
| 1093 | struct s5k6aa *s5k6aa = to_s5k6aa(sd); | ||
| 1094 | struct v4l2_mbus_framefmt *mf; | ||
| 1095 | |||
| 1096 | memset(fmt->reserved, 0, sizeof(fmt->reserved)); | ||
| 1097 | |||
| 1098 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | ||
| 1099 | mf = v4l2_subdev_get_try_format(fh, 0); | ||
| 1100 | fmt->format = *mf; | ||
| 1101 | return 0; | ||
| 1102 | } | ||
| 1103 | |||
| 1104 | mutex_lock(&s5k6aa->lock); | ||
| 1105 | fmt->format = s5k6aa->preset->mbus_fmt; | ||
| 1106 | mutex_unlock(&s5k6aa->lock); | ||
| 1107 | |||
| 1108 | return 0; | ||
| 1109 | } | ||
| 1110 | |||
| 1111 | static int s5k6aa_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
| 1112 | struct v4l2_subdev_format *fmt) | ||
| 1113 | { | ||
| 1114 | struct s5k6aa *s5k6aa = to_s5k6aa(sd); | ||
| 1115 | struct s5k6aa_preset *preset = s5k6aa->preset; | ||
| 1116 | struct v4l2_mbus_framefmt *mf; | ||
| 1117 | struct v4l2_rect *crop; | ||
| 1118 | int ret = 0; | ||
| 1119 | |||
| 1120 | mutex_lock(&s5k6aa->lock); | ||
| 1121 | s5k6aa_try_format(s5k6aa, &fmt->format); | ||
| 1122 | |||
| 1123 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | ||
| 1124 | mf = v4l2_subdev_get_try_format(fh, fmt->pad); | ||
| 1125 | crop = v4l2_subdev_get_try_crop(fh, 0); | ||
| 1126 | } else { | ||
| 1127 | if (s5k6aa->streaming) { | ||
| 1128 | ret = -EBUSY; | ||
| 1129 | } else { | ||
| 1130 | mf = &preset->mbus_fmt; | ||
| 1131 | crop = &s5k6aa->ccd_rect; | ||
| 1132 | s5k6aa->apply_cfg = 1; | ||
| 1133 | } | ||
| 1134 | } | ||
| 1135 | |||
| 1136 | if (ret == 0) { | ||
| 1137 | struct v4l2_subdev_frame_interval fiv = { | ||
| 1138 | .interval = {0, 1} | ||
| 1139 | }; | ||
| 1140 | |||
| 1141 | *mf = fmt->format; | ||
| 1142 | /* | ||
| 1143 | * Make sure the crop window is valid, i.e. its size is | ||
| 1144 | * greater than the output window, as the ISP supports | ||
| 1145 | * only down-scaling. | ||
| 1146 | */ | ||
| 1147 | crop->width = clamp_t(unsigned int, crop->width, mf->width, | ||
| 1148 | S5K6AA_WIN_WIDTH_MAX); | ||
| 1149 | crop->height = clamp_t(unsigned int, crop->height, mf->height, | ||
| 1150 | S5K6AA_WIN_HEIGHT_MAX); | ||
| 1151 | crop->left = clamp_t(unsigned int, crop->left, 0, | ||
| 1152 | S5K6AA_WIN_WIDTH_MAX - crop->width); | ||
| 1153 | crop->top = clamp_t(unsigned int, crop->top, 0, | ||
| 1154 | S5K6AA_WIN_HEIGHT_MAX - crop->height); | ||
| 1155 | |||
| 1156 | /* Reset to minimum possible frame interval */ | ||
| 1157 | ret = __s5k6aa_set_frame_interval(s5k6aa, &fiv); | ||
| 1158 | } | ||
| 1159 | mutex_unlock(&s5k6aa->lock); | ||
| 1160 | |||
| 1161 | return ret; | ||
| 1162 | } | ||
| 1163 | |||
| 1164 | static int s5k6aa_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
| 1165 | struct v4l2_subdev_crop *crop) | ||
| 1166 | { | ||
| 1167 | struct s5k6aa *s5k6aa = to_s5k6aa(sd); | ||
| 1168 | struct v4l2_rect *rect; | ||
| 1169 | |||
| 1170 | memset(crop->reserved, 0, sizeof(crop->reserved)); | ||
| 1171 | mutex_lock(&s5k6aa->lock); | ||
| 1172 | |||
| 1173 | rect = __s5k6aa_get_crop_rect(s5k6aa, fh, crop->which); | ||
| 1174 | if (rect) | ||
| 1175 | crop->rect = *rect; | ||
| 1176 | |||
| 1177 | mutex_unlock(&s5k6aa->lock); | ||
| 1178 | |||
| 1179 | v4l2_dbg(1, debug, sd, "Current crop rectangle: (%d,%d)/%dx%d\n", | ||
| 1180 | rect->left, rect->top, rect->width, rect->height); | ||
| 1181 | |||
| 1182 | return 0; | ||
| 1183 | } | ||
| 1184 | |||
| 1185 | static int s5k6aa_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
| 1186 | struct v4l2_subdev_crop *crop) | ||
| 1187 | { | ||
| 1188 | struct s5k6aa *s5k6aa = to_s5k6aa(sd); | ||
| 1189 | struct v4l2_mbus_framefmt *mf; | ||
| 1190 | unsigned int max_x, max_y; | ||
| 1191 | struct v4l2_rect *crop_r; | ||
| 1192 | |||
| 1193 | mutex_lock(&s5k6aa->lock); | ||
| 1194 | crop_r = __s5k6aa_get_crop_rect(s5k6aa, fh, crop->which); | ||
| 1195 | |||
| 1196 | if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) { | ||
| 1197 | mf = &s5k6aa->preset->mbus_fmt; | ||
| 1198 | s5k6aa->apply_crop = 1; | ||
| 1199 | } else { | ||
| 1200 | mf = v4l2_subdev_get_try_format(fh, 0); | ||
| 1201 | } | ||
| 1202 | v4l_bound_align_image(&crop->rect.width, mf->width, | ||
| 1203 | S5K6AA_WIN_WIDTH_MAX, 1, | ||
| 1204 | &crop->rect.height, mf->height, | ||
| 1205 | S5K6AA_WIN_HEIGHT_MAX, 1, 0); | ||
| 1206 | |||
| 1207 | max_x = (S5K6AA_WIN_WIDTH_MAX - crop->rect.width) & ~1; | ||
| 1208 | max_y = (S5K6AA_WIN_HEIGHT_MAX - crop->rect.height) & ~1; | ||
| 1209 | |||
| 1210 | crop->rect.left = clamp_t(unsigned int, crop->rect.left, 0, max_x); | ||
| 1211 | crop->rect.top = clamp_t(unsigned int, crop->rect.top, 0, max_y); | ||
| 1212 | |||
| 1213 | *crop_r = crop->rect; | ||
| 1214 | |||
| 1215 | mutex_unlock(&s5k6aa->lock); | ||
| 1216 | |||
| 1217 | v4l2_dbg(1, debug, sd, "Set crop rectangle: (%d,%d)/%dx%d\n", | ||
| 1218 | crop_r->left, crop_r->top, crop_r->width, crop_r->height); | ||
| 1219 | |||
| 1220 | return 0; | ||
| 1221 | } | ||
| 1222 | |||
| 1223 | static const struct v4l2_subdev_pad_ops s5k6aa_pad_ops = { | ||
| 1224 | .enum_mbus_code = s5k6aa_enum_mbus_code, | ||
| 1225 | .enum_frame_size = s5k6aa_enum_frame_size, | ||
| 1226 | .enum_frame_interval = s5k6aa_enum_frame_interval, | ||
| 1227 | .get_fmt = s5k6aa_get_fmt, | ||
| 1228 | .set_fmt = s5k6aa_set_fmt, | ||
| 1229 | .get_crop = s5k6aa_get_crop, | ||
| 1230 | .set_crop = s5k6aa_set_crop, | ||
| 1231 | }; | ||
| 1232 | |||
| 1233 | static const struct v4l2_subdev_video_ops s5k6aa_video_ops = { | ||
| 1234 | .g_frame_interval = s5k6aa_g_frame_interval, | ||
| 1235 | .s_frame_interval = s5k6aa_s_frame_interval, | ||
| 1236 | .s_stream = s5k6aa_s_stream, | ||
| 1237 | }; | ||
| 1238 | |||
| 1239 | /* | ||
| 1240 | * V4L2 subdev controls | ||
| 1241 | */ | ||
| 1242 | |||
| 1243 | static int s5k6aa_s_ctrl(struct v4l2_ctrl *ctrl) | ||
| 1244 | { | ||
| 1245 | struct v4l2_subdev *sd = ctrl_to_sd(ctrl); | ||
| 1246 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 1247 | struct s5k6aa *s5k6aa = to_s5k6aa(sd); | ||
| 1248 | int idx, err = 0; | ||
| 1249 | |||
| 1250 | v4l2_dbg(1, debug, sd, "ctrl: 0x%x, value: %d\n", ctrl->id, ctrl->val); | ||
| 1251 | |||
| 1252 | mutex_lock(&s5k6aa->lock); | ||
| 1253 | /* | ||
| 1254 | * If the device is not powered up by the host driver do | ||
| 1255 | * not apply any controls to H/W at this time. Instead | ||
| 1256 | * the controls will be restored right after power-up. | ||
| 1257 | */ | ||
| 1258 | if (s5k6aa->power == 0) | ||
| 1259 | goto unlock; | ||
| 1260 | idx = s5k6aa->preset->index; | ||
| 1261 | |||
| 1262 | switch (ctrl->id) { | ||
| 1263 | case V4L2_CID_AUTO_WHITE_BALANCE: | ||
| 1264 | err = s5k6aa_set_awb(s5k6aa, ctrl->val); | ||
| 1265 | break; | ||
| 1266 | |||
| 1267 | case V4L2_CID_BRIGHTNESS: | ||
| 1268 | err = s5k6aa_write(client, REG_USER_BRIGHTNESS, ctrl->val); | ||
| 1269 | break; | ||
| 1270 | |||
| 1271 | case V4L2_CID_COLORFX: | ||
| 1272 | err = s5k6aa_set_colorfx(s5k6aa, ctrl->val); | ||
| 1273 | break; | ||
| 1274 | |||
| 1275 | case V4L2_CID_CONTRAST: | ||
| 1276 | err = s5k6aa_write(client, REG_USER_CONTRAST, ctrl->val); | ||
| 1277 | break; | ||
| 1278 | |||
| 1279 | case V4L2_CID_EXPOSURE_AUTO: | ||
| 1280 | err = s5k6aa_set_auto_exposure(s5k6aa, ctrl->val); | ||
| 1281 | break; | ||
| 1282 | |||
| 1283 | case V4L2_CID_HFLIP: | ||
| 1284 | err = s5k6aa_set_mirror(s5k6aa, ctrl->val); | ||
| 1285 | if (err) | ||
| 1286 | break; | ||
| 1287 | err = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1); | ||
| 1288 | break; | ||
| 1289 | |||
| 1290 | case V4L2_CID_POWER_LINE_FREQUENCY: | ||
| 1291 | err = s5k6aa_set_anti_flicker(s5k6aa, ctrl->val); | ||
| 1292 | break; | ||
| 1293 | |||
| 1294 | case V4L2_CID_SATURATION: | ||
| 1295 | err = s5k6aa_write(client, REG_USER_SATURATION, ctrl->val); | ||
| 1296 | break; | ||
| 1297 | |||
| 1298 | case V4L2_CID_SHARPNESS: | ||
| 1299 | err = s5k6aa_write(client, REG_USER_SHARPBLUR, ctrl->val); | ||
| 1300 | break; | ||
| 1301 | |||
| 1302 | case V4L2_CID_WHITE_BALANCE_TEMPERATURE: | ||
| 1303 | err = s5k6aa_write(client, REG_P_COLORTEMP(idx), ctrl->val); | ||
| 1304 | if (err) | ||
| 1305 | break; | ||
| 1306 | err = s5k6aa_write(client, REG_G_PREV_CFG_CHG, 1); | ||
| 1307 | break; | ||
| 1308 | } | ||
| 1309 | unlock: | ||
| 1310 | mutex_unlock(&s5k6aa->lock); | ||
| 1311 | return err; | ||
| 1312 | } | ||
| 1313 | |||
| 1314 | static const struct v4l2_ctrl_ops s5k6aa_ctrl_ops = { | ||
| 1315 | .s_ctrl = s5k6aa_s_ctrl, | ||
| 1316 | }; | ||
| 1317 | |||
| 1318 | static int s5k6aa_log_status(struct v4l2_subdev *sd) | ||
| 1319 | { | ||
| 1320 | v4l2_ctrl_handler_log_status(sd->ctrl_handler, sd->name); | ||
| 1321 | return 0; | ||
| 1322 | } | ||
| 1323 | |||
| 1324 | #define V4L2_CID_RED_GAIN (V4L2_CTRL_CLASS_CAMERA | 0x1001) | ||
| 1325 | #define V4L2_CID_GREEN_GAIN (V4L2_CTRL_CLASS_CAMERA | 0x1002) | ||
| 1326 | #define V4L2_CID_BLUE_GAIN (V4L2_CTRL_CLASS_CAMERA | 0x1003) | ||
| 1327 | |||
| 1328 | static const struct v4l2_ctrl_config s5k6aa_ctrls[] = { | ||
| 1329 | { | ||
| 1330 | .ops = &s5k6aa_ctrl_ops, | ||
| 1331 | .id = V4L2_CID_RED_GAIN, | ||
| 1332 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 1333 | .name = "Gain, Red", | ||
| 1334 | .min = 0, | ||
| 1335 | .max = 256, | ||
| 1336 | .def = 127, | ||
| 1337 | .step = 1, | ||
| 1338 | }, { | ||
| 1339 | .ops = &s5k6aa_ctrl_ops, | ||
| 1340 | .id = V4L2_CID_GREEN_GAIN, | ||
| 1341 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 1342 | .name = "Gain, Green", | ||
| 1343 | .min = 0, | ||
| 1344 | .max = 256, | ||
| 1345 | .def = 127, | ||
| 1346 | .step = 1, | ||
| 1347 | }, { | ||
| 1348 | .ops = &s5k6aa_ctrl_ops, | ||
| 1349 | .id = V4L2_CID_BLUE_GAIN, | ||
| 1350 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 1351 | .name = "Gain, Blue", | ||
| 1352 | .min = 0, | ||
| 1353 | .max = 256, | ||
| 1354 | .def = 127, | ||
| 1355 | .step = 1, | ||
| 1356 | }, | ||
| 1357 | }; | ||
| 1358 | |||
| 1359 | static int s5k6aa_initialize_ctrls(struct s5k6aa *s5k6aa) | ||
| 1360 | { | ||
| 1361 | const struct v4l2_ctrl_ops *ops = &s5k6aa_ctrl_ops; | ||
| 1362 | struct s5k6aa_ctrls *ctrls = &s5k6aa->ctrls; | ||
| 1363 | struct v4l2_ctrl_handler *hdl = &ctrls->handler; | ||
| 1364 | |||
| 1365 | int ret = v4l2_ctrl_handler_init(hdl, 16); | ||
| 1366 | if (ret) | ||
| 1367 | return ret; | ||
| 1368 | /* Auto white balance cluster */ | ||
| 1369 | ctrls->awb = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_WHITE_BALANCE, | ||
| 1370 | 0, 1, 1, 1); | ||
| 1371 | ctrls->gain_red = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[0], NULL); | ||
| 1372 | ctrls->gain_green = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[1], NULL); | ||
| 1373 | ctrls->gain_blue = v4l2_ctrl_new_custom(hdl, &s5k6aa_ctrls[2], NULL); | ||
| 1374 | v4l2_ctrl_auto_cluster(4, &ctrls->awb, 0, false); | ||
| 1375 | |||
| 1376 | ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
| 1377 | ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
| 1378 | v4l2_ctrl_cluster(2, &ctrls->hflip); | ||
| 1379 | |||
| 1380 | ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops, | ||
| 1381 | V4L2_CID_EXPOSURE_AUTO, | ||
| 1382 | V4L2_EXPOSURE_MANUAL, 0, V4L2_EXPOSURE_AUTO); | ||
| 1383 | /* Exposure time: x 1 us */ | ||
| 1384 | ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE, | ||
| 1385 | 0, 6000000U, 1, 100000U); | ||
| 1386 | /* Total gain: 256 <=> 1x */ | ||
| 1387 | ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN, | ||
| 1388 | 0, 256, 1, 256); | ||
| 1389 | v4l2_ctrl_auto_cluster(3, &ctrls->auto_exp, 0, false); | ||
| 1390 | |||
| 1391 | v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_POWER_LINE_FREQUENCY, | ||
| 1392 | V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0, | ||
| 1393 | V4L2_CID_POWER_LINE_FREQUENCY_AUTO); | ||
| 1394 | |||
| 1395 | v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_COLORFX, | ||
| 1396 | V4L2_COLORFX_SKY_BLUE, ~0x6f, V4L2_COLORFX_NONE); | ||
| 1397 | |||
| 1398 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_WHITE_BALANCE_TEMPERATURE, | ||
| 1399 | 0, 256, 1, 0); | ||
| 1400 | |||
| 1401 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, -127, 127, 1, 0); | ||
| 1402 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -127, 127, 1, 0); | ||
| 1403 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -127, 127, 1, 0); | ||
| 1404 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SHARPNESS, -127, 127, 1, 0); | ||
| 1405 | |||
| 1406 | if (hdl->error) { | ||
| 1407 | ret = hdl->error; | ||
| 1408 | v4l2_ctrl_handler_free(hdl); | ||
| 1409 | return ret; | ||
| 1410 | } | ||
| 1411 | |||
| 1412 | s5k6aa->sd.ctrl_handler = hdl; | ||
| 1413 | return 0; | ||
| 1414 | } | ||
| 1415 | |||
| 1416 | /* | ||
| 1417 | * V4L2 subdev internal operations | ||
| 1418 | */ | ||
| 1419 | static int s5k6aa_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | ||
| 1420 | { | ||
| 1421 | struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0); | ||
| 1422 | struct v4l2_rect *crop = v4l2_subdev_get_try_crop(fh, 0); | ||
| 1423 | |||
| 1424 | format->colorspace = s5k6aa_formats[0].colorspace; | ||
| 1425 | format->code = s5k6aa_formats[0].code; | ||
| 1426 | format->width = S5K6AA_OUT_WIDTH_DEF; | ||
| 1427 | format->height = S5K6AA_OUT_HEIGHT_DEF; | ||
| 1428 | format->field = V4L2_FIELD_NONE; | ||
| 1429 | |||
| 1430 | crop->width = S5K6AA_WIN_WIDTH_MAX; | ||
| 1431 | crop->height = S5K6AA_WIN_HEIGHT_MAX; | ||
| 1432 | crop->left = 0; | ||
| 1433 | crop->top = 0; | ||
| 1434 | |||
| 1435 | return 0; | ||
| 1436 | } | ||
| 1437 | |||
| 1438 | int s5k6aa_check_fw_revision(struct s5k6aa *s5k6aa) | ||
| 1439 | { | ||
| 1440 | struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd); | ||
| 1441 | u16 api_ver = 0, fw_rev = 0; | ||
| 1442 | |||
| 1443 | int ret = s5k6aa_set_ahb_address(client); | ||
| 1444 | |||
| 1445 | if (!ret) | ||
| 1446 | ret = s5k6aa_read(client, REG_FW_APIVER, &api_ver); | ||
| 1447 | if (!ret) | ||
| 1448 | ret = s5k6aa_read(client, REG_FW_REVISION, &fw_rev); | ||
| 1449 | if (ret) { | ||
| 1450 | v4l2_err(&s5k6aa->sd, "FW revision check failed!\n"); | ||
| 1451 | return ret; | ||
| 1452 | } | ||
| 1453 | |||
| 1454 | v4l2_info(&s5k6aa->sd, "FW API ver.: 0x%X, FW rev.: 0x%X\n", | ||
| 1455 | api_ver, fw_rev); | ||
| 1456 | |||
| 1457 | return api_ver == S5K6AAFX_FW_APIVER ? 0 : -ENODEV; | ||
| 1458 | } | ||
| 1459 | |||
| 1460 | static int s5k6aa_registered(struct v4l2_subdev *sd) | ||
| 1461 | { | ||
| 1462 | struct s5k6aa *s5k6aa = to_s5k6aa(sd); | ||
| 1463 | int ret; | ||
| 1464 | |||
| 1465 | mutex_lock(&s5k6aa->lock); | ||
| 1466 | ret = __s5k6aa_power_on(s5k6aa); | ||
| 1467 | if (!ret) { | ||
| 1468 | msleep(100); | ||
| 1469 | ret = s5k6aa_check_fw_revision(s5k6aa); | ||
| 1470 | __s5k6aa_power_off(s5k6aa); | ||
| 1471 | } | ||
| 1472 | mutex_unlock(&s5k6aa->lock); | ||
| 1473 | |||
| 1474 | return ret; | ||
| 1475 | } | ||
| 1476 | |||
| 1477 | static const struct v4l2_subdev_internal_ops s5k6aa_subdev_internal_ops = { | ||
| 1478 | .registered = s5k6aa_registered, | ||
| 1479 | .open = s5k6aa_open, | ||
| 1480 | }; | ||
| 1481 | |||
| 1482 | static const struct v4l2_subdev_core_ops s5k6aa_core_ops = { | ||
| 1483 | .s_power = s5k6aa_set_power, | ||
| 1484 | .log_status = s5k6aa_log_status, | ||
| 1485 | }; | ||
| 1486 | |||
| 1487 | static const struct v4l2_subdev_ops s5k6aa_subdev_ops = { | ||
| 1488 | .core = &s5k6aa_core_ops, | ||
| 1489 | .pad = &s5k6aa_pad_ops, | ||
| 1490 | .video = &s5k6aa_video_ops, | ||
| 1491 | }; | ||
| 1492 | |||
| 1493 | /* | ||
| 1494 | * GPIO setup | ||
| 1495 | */ | ||
| 1496 | static int s5k6aa_configure_gpio(int nr, int val, const char *name) | ||
| 1497 | { | ||
| 1498 | unsigned long flags = val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; | ||
| 1499 | int ret; | ||
| 1500 | |||
| 1501 | if (!gpio_is_valid(nr)) | ||
| 1502 | return 0; | ||
| 1503 | ret = gpio_request_one(nr, flags, name); | ||
| 1504 | if (!ret) | ||
| 1505 | gpio_export(nr, 0); | ||
| 1506 | return ret; | ||
| 1507 | } | ||
| 1508 | |||
| 1509 | static void s5k6aa_free_gpios(struct s5k6aa *s5k6aa) | ||
| 1510 | { | ||
| 1511 | int i; | ||
| 1512 | |||
| 1513 | for (i = 0; i < ARRAY_SIZE(s5k6aa->gpio); i++) { | ||
| 1514 | if (!gpio_is_valid(s5k6aa->gpio[i].gpio)) | ||
| 1515 | continue; | ||
| 1516 | gpio_free(s5k6aa->gpio[i].gpio); | ||
| 1517 | s5k6aa->gpio[i].gpio = -EINVAL; | ||
| 1518 | } | ||
| 1519 | } | ||
| 1520 | |||
| 1521 | static int s5k6aa_configure_gpios(struct s5k6aa *s5k6aa, | ||
| 1522 | const struct s5k6aa_platform_data *pdata) | ||
| 1523 | { | ||
| 1524 | const struct s5k6aa_gpio *gpio = &pdata->gpio_stby; | ||
| 1525 | int ret; | ||
| 1526 | |||
| 1527 | s5k6aa->gpio[STBY].gpio = -EINVAL; | ||
| 1528 | s5k6aa->gpio[RST].gpio = -EINVAL; | ||
| 1529 | |||
| 1530 | ret = s5k6aa_configure_gpio(gpio->gpio, gpio->level, "S5K6AA_STBY"); | ||
| 1531 | if (ret) { | ||
| 1532 | s5k6aa_free_gpios(s5k6aa); | ||
| 1533 | return ret; | ||
| 1534 | } | ||
| 1535 | s5k6aa->gpio[STBY] = *gpio; | ||
| 1536 | if (gpio_is_valid(gpio->gpio)) | ||
| 1537 | gpio_set_value(gpio->gpio, 0); | ||
| 1538 | |||
| 1539 | gpio = &pdata->gpio_reset; | ||
| 1540 | ret = s5k6aa_configure_gpio(gpio->gpio, gpio->level, "S5K6AA_RST"); | ||
| 1541 | if (ret) { | ||
| 1542 | s5k6aa_free_gpios(s5k6aa); | ||
| 1543 | return ret; | ||
| 1544 | } | ||
| 1545 | s5k6aa->gpio[RST] = *gpio; | ||
| 1546 | if (gpio_is_valid(gpio->gpio)) | ||
| 1547 | gpio_set_value(gpio->gpio, 0); | ||
| 1548 | |||
| 1549 | return 0; | ||
| 1550 | } | ||
| 1551 | |||
| 1552 | static int s5k6aa_probe(struct i2c_client *client, | ||
| 1553 | const struct i2c_device_id *id) | ||
| 1554 | { | ||
| 1555 | const struct s5k6aa_platform_data *pdata = client->dev.platform_data; | ||
| 1556 | struct v4l2_subdev *sd; | ||
| 1557 | struct s5k6aa *s5k6aa; | ||
| 1558 | int i, ret; | ||
| 1559 | |||
| 1560 | if (pdata == NULL) { | ||
| 1561 | dev_err(&client->dev, "Platform data not specified\n"); | ||
| 1562 | return -EINVAL; | ||
| 1563 | } | ||
| 1564 | |||
| 1565 | if (pdata->mclk_frequency == 0) { | ||
| 1566 | dev_err(&client->dev, "MCLK frequency not specified\n"); | ||
| 1567 | return -EINVAL; | ||
| 1568 | } | ||
| 1569 | |||
| 1570 | s5k6aa = kzalloc(sizeof(*s5k6aa), GFP_KERNEL); | ||
| 1571 | if (!s5k6aa) | ||
| 1572 | return -ENOMEM; | ||
| 1573 | |||
| 1574 | mutex_init(&s5k6aa->lock); | ||
| 1575 | |||
| 1576 | s5k6aa->mclk_frequency = pdata->mclk_frequency; | ||
| 1577 | s5k6aa->bus_type = pdata->bus_type; | ||
| 1578 | s5k6aa->mipi_lanes = pdata->nlanes; | ||
| 1579 | s5k6aa->s_power = pdata->set_power; | ||
| 1580 | s5k6aa->inv_hflip = pdata->horiz_flip; | ||
| 1581 | s5k6aa->inv_vflip = pdata->vert_flip; | ||
| 1582 | |||
| 1583 | sd = &s5k6aa->sd; | ||
| 1584 | strlcpy(sd->name, DRIVER_NAME, sizeof(sd->name)); | ||
| 1585 | v4l2_i2c_subdev_init(sd, client, &s5k6aa_subdev_ops); | ||
| 1586 | |||
| 1587 | sd->internal_ops = &s5k6aa_subdev_internal_ops; | ||
| 1588 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
| 1589 | |||
| 1590 | s5k6aa->pad.flags = MEDIA_PAD_FL_SOURCE; | ||
| 1591 | sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; | ||
| 1592 | ret = media_entity_init(&sd->entity, 1, &s5k6aa->pad, 0); | ||
| 1593 | if (ret) | ||
| 1594 | goto out_err1; | ||
| 1595 | |||
| 1596 | ret = s5k6aa_configure_gpios(s5k6aa, pdata); | ||
| 1597 | if (ret) | ||
| 1598 | goto out_err2; | ||
| 1599 | |||
| 1600 | for (i = 0; i < S5K6AA_NUM_SUPPLIES; i++) | ||
| 1601 | s5k6aa->supplies[i].supply = s5k6aa_supply_names[i]; | ||
| 1602 | |||
| 1603 | ret = regulator_bulk_get(&client->dev, S5K6AA_NUM_SUPPLIES, | ||
| 1604 | s5k6aa->supplies); | ||
| 1605 | if (ret) { | ||
| 1606 | dev_err(&client->dev, "Failed to get regulators\n"); | ||
| 1607 | goto out_err3; | ||
| 1608 | } | ||
| 1609 | |||
| 1610 | ret = s5k6aa_initialize_ctrls(s5k6aa); | ||
| 1611 | if (ret) | ||
| 1612 | goto out_err4; | ||
| 1613 | |||
| 1614 | s5k6aa_presets_data_init(s5k6aa); | ||
| 1615 | |||
| 1616 | s5k6aa->ccd_rect.width = S5K6AA_WIN_WIDTH_MAX; | ||
| 1617 | s5k6aa->ccd_rect.height = S5K6AA_WIN_HEIGHT_MAX; | ||
| 1618 | s5k6aa->ccd_rect.left = 0; | ||
| 1619 | s5k6aa->ccd_rect.top = 0; | ||
| 1620 | |||
| 1621 | return 0; | ||
| 1622 | |||
| 1623 | out_err4: | ||
| 1624 | regulator_bulk_free(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies); | ||
| 1625 | out_err3: | ||
| 1626 | s5k6aa_free_gpios(s5k6aa); | ||
| 1627 | out_err2: | ||
| 1628 | media_entity_cleanup(&s5k6aa->sd.entity); | ||
| 1629 | out_err1: | ||
| 1630 | kfree(s5k6aa); | ||
| 1631 | return ret; | ||
| 1632 | } | ||
| 1633 | |||
| 1634 | static int s5k6aa_remove(struct i2c_client *client) | ||
| 1635 | { | ||
| 1636 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | ||
| 1637 | struct s5k6aa *s5k6aa = to_s5k6aa(sd); | ||
| 1638 | |||
| 1639 | v4l2_device_unregister_subdev(sd); | ||
| 1640 | v4l2_ctrl_handler_free(sd->ctrl_handler); | ||
| 1641 | media_entity_cleanup(&sd->entity); | ||
| 1642 | regulator_bulk_free(S5K6AA_NUM_SUPPLIES, s5k6aa->supplies); | ||
| 1643 | s5k6aa_free_gpios(s5k6aa); | ||
| 1644 | kfree(s5k6aa); | ||
| 1645 | |||
| 1646 | return 0; | ||
| 1647 | } | ||
| 1648 | |||
| 1649 | static const struct i2c_device_id s5k6aa_id[] = { | ||
| 1650 | { DRIVER_NAME, 0 }, | ||
| 1651 | { }, | ||
| 1652 | }; | ||
| 1653 | MODULE_DEVICE_TABLE(i2c, s5k6aa_id); | ||
| 1654 | |||
| 1655 | |||
| 1656 | static struct i2c_driver s5k6aa_i2c_driver = { | ||
| 1657 | .driver = { | ||
| 1658 | .name = DRIVER_NAME | ||
| 1659 | }, | ||
| 1660 | .probe = s5k6aa_probe, | ||
| 1661 | .remove = s5k6aa_remove, | ||
| 1662 | .id_table = s5k6aa_id, | ||
| 1663 | }; | ||
| 1664 | |||
| 1665 | static int __init s5k6aa_init(void) | ||
| 1666 | { | ||
| 1667 | return i2c_add_driver(&s5k6aa_i2c_driver); | ||
| 1668 | } | ||
| 1669 | |||
| 1670 | static void __exit s5k6aa_exit(void) | ||
| 1671 | { | ||
| 1672 | i2c_del_driver(&s5k6aa_i2c_driver); | ||
| 1673 | } | ||
| 1674 | |||
| 1675 | module_init(s5k6aa_init); | ||
| 1676 | module_exit(s5k6aa_exit); | ||
| 1677 | |||
| 1678 | MODULE_DESCRIPTION("Samsung S5K6AA(FX) SXGA camera driver"); | ||
| 1679 | MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>"); | ||
| 1680 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 931f469604b0..c8d91b0cd9bd 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c | |||
| @@ -246,9 +246,9 @@ static unsigned int get_plane_size(struct fimc_frame *fr, unsigned int plane) | |||
| 246 | return fr->f_width * fr->f_height * fr->fmt->depth[plane] / 8; | 246 | return fr->f_width * fr->f_height * fr->fmt->depth[plane] / 8; |
| 247 | } | 247 | } |
| 248 | 248 | ||
| 249 | static int queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, | 249 | static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt, |
| 250 | unsigned int *num_planes, unsigned int sizes[], | 250 | unsigned int *num_buffers, unsigned int *num_planes, |
| 251 | void *allocators[]) | 251 | unsigned int sizes[], void *allocators[]) |
| 252 | { | 252 | { |
| 253 | struct fimc_ctx *ctx = vq->drv_priv; | 253 | struct fimc_ctx *ctx = vq->drv_priv; |
| 254 | struct fimc_fmt *fmt = ctx->d_frame.fmt; | 254 | struct fimc_fmt *fmt = ctx->d_frame.fmt; |
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 6c1c9cb55378..19ca6db38b2f 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c | |||
| @@ -670,9 +670,9 @@ static void fimc_job_abort(void *priv) | |||
| 670 | fimc_m2m_shutdown(priv); | 670 | fimc_m2m_shutdown(priv); |
| 671 | } | 671 | } |
| 672 | 672 | ||
| 673 | static int fimc_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, | 673 | static int fimc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, |
| 674 | unsigned int *num_planes, unsigned int sizes[], | 674 | unsigned int *num_buffers, unsigned int *num_planes, |
| 675 | void *allocators[]) | 675 | unsigned int sizes[], void *allocators[]) |
| 676 | { | 676 | { |
| 677 | struct fimc_ctx *ctx = vb2_get_drv_priv(vq); | 677 | struct fimc_ctx *ctx = vb2_get_drv_priv(vq); |
| 678 | struct fimc_frame *f; | 678 | struct fimc_frame *f; |
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c index 5f4da80051bb..f2481a85e0a2 100644 --- a/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c | |||
| @@ -38,7 +38,7 @@ int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev) | |||
| 38 | * into kernel. */ | 38 | * into kernel. */ |
| 39 | mfc_debug_enter(); | 39 | mfc_debug_enter(); |
| 40 | err = request_firmware((const struct firmware **)&fw_blob, | 40 | err = request_firmware((const struct firmware **)&fw_blob, |
| 41 | "s5pc110-mfc.fw", dev->v4l2_dev.dev); | 41 | "s5p-mfc.fw", dev->v4l2_dev.dev); |
| 42 | if (err != 0) { | 42 | if (err != 0) { |
| 43 | mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); | 43 | mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); |
| 44 | return -EINVAL; | 44 | return -EINVAL; |
| @@ -116,7 +116,7 @@ int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev) | |||
| 116 | * into kernel. */ | 116 | * into kernel. */ |
| 117 | mfc_debug_enter(); | 117 | mfc_debug_enter(); |
| 118 | err = request_firmware((const struct firmware **)&fw_blob, | 118 | err = request_firmware((const struct firmware **)&fw_blob, |
| 119 | "s5pc110-mfc.fw", dev->v4l2_dev.dev); | 119 | "s5p-mfc.fw", dev->v4l2_dev.dev); |
| 120 | if (err != 0) { | 120 | if (err != 0) { |
| 121 | mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); | 121 | mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); |
| 122 | return -EINVAL; | 122 | return -EINVAL; |
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_dec.c b/drivers/media/video/s5p-mfc/s5p_mfc_dec.c index bfbe08432050..725634d9736d 100644 --- a/drivers/media/video/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/video/s5p-mfc/s5p_mfc_dec.c | |||
| @@ -744,9 +744,10 @@ static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = { | |||
| 744 | .vidioc_g_crop = vidioc_g_crop, | 744 | .vidioc_g_crop = vidioc_g_crop, |
| 745 | }; | 745 | }; |
| 746 | 746 | ||
| 747 | static int s5p_mfc_queue_setup(struct vb2_queue *vq, unsigned int *buf_count, | 747 | static int s5p_mfc_queue_setup(struct vb2_queue *vq, |
| 748 | unsigned int *plane_count, unsigned int psize[], | 748 | const struct v4l2_format *fmt, unsigned int *buf_count, |
| 749 | void *allocators[]) | 749 | unsigned int *plane_count, unsigned int psize[], |
| 750 | void *allocators[]) | ||
| 750 | { | 751 | { |
| 751 | struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); | 752 | struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); |
| 752 | 753 | ||
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_enc.c b/drivers/media/video/s5p-mfc/s5p_mfc_enc.c index 4c90e53bd964..ecef127dbc66 100644 --- a/drivers/media/video/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/video/s5p-mfc/s5p_mfc_enc.c | |||
| @@ -1513,8 +1513,9 @@ static int check_vb_with_fmt(struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb) | |||
| 1513 | } | 1513 | } |
| 1514 | 1514 | ||
| 1515 | static int s5p_mfc_queue_setup(struct vb2_queue *vq, | 1515 | static int s5p_mfc_queue_setup(struct vb2_queue *vq, |
| 1516 | unsigned int *buf_count, unsigned int *plane_count, | 1516 | const struct v4l2_format *fmt, |
| 1517 | unsigned int psize[], void *allocators[]) | 1517 | unsigned int *buf_count, unsigned int *plane_count, |
| 1518 | unsigned int psize[], void *allocators[]) | ||
| 1518 | { | 1519 | { |
| 1519 | struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); | 1520 | struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); |
| 1520 | 1521 | ||
diff --git a/drivers/media/video/s5p-tv/mixer_video.c b/drivers/media/video/s5p-tv/mixer_video.c index 4917e2c2b321..e16d3a4bc1dc 100644 --- a/drivers/media/video/s5p-tv/mixer_video.c +++ b/drivers/media/video/s5p-tv/mixer_video.c | |||
| @@ -727,8 +727,8 @@ static const struct v4l2_file_operations mxr_fops = { | |||
| 727 | .unlocked_ioctl = video_ioctl2, | 727 | .unlocked_ioctl = video_ioctl2, |
| 728 | }; | 728 | }; |
| 729 | 729 | ||
| 730 | static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, | 730 | static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt, |
| 731 | unsigned int *nplanes, unsigned int sizes[], | 731 | unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], |
| 732 | void *alloc_ctxs[]) | 732 | void *alloc_ctxs[]) |
| 733 | { | 733 | { |
| 734 | struct mxr_layer *layer = vb2_get_drv_priv(vq); | 734 | struct mxr_layer *layer = vb2_get_drv_priv(vq); |
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index bc8d6bba8ee5..9b550687213a 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h | |||
| @@ -843,10 +843,10 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev); | |||
| 843 | int saa7134_ir_start(struct saa7134_dev *dev); | 843 | int saa7134_ir_start(struct saa7134_dev *dev); |
| 844 | void saa7134_ir_stop(struct saa7134_dev *dev); | 844 | void saa7134_ir_stop(struct saa7134_dev *dev); |
| 845 | #else | 845 | #else |
| 846 | #define saa7134_input_init1(dev) (0) | 846 | #define saa7134_input_init1(dev) ((void)0) |
| 847 | #define saa7134_input_fini(dev) (0) | 847 | #define saa7134_input_fini(dev) ((void)0) |
| 848 | #define saa7134_input_irq(dev) (0) | 848 | #define saa7134_input_irq(dev) ((void)0) |
| 849 | #define saa7134_probe_i2c_ir(dev) (0) | 849 | #define saa7134_probe_i2c_ir(dev) ((void)0) |
| 850 | #define saa7134_ir_start(dev) (0) | 850 | #define saa7134_ir_start(dev) ((void)0) |
| 851 | #define saa7134_ir_stop(dev) (0) | 851 | #define saa7134_ir_stop(dev) ((void)0) |
| 852 | #endif | 852 | #endif |
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 8615fb81775f..f390682629cf 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c | |||
| @@ -90,7 +90,6 @@ | |||
| 90 | struct sh_mobile_ceu_buffer { | 90 | struct sh_mobile_ceu_buffer { |
| 91 | struct vb2_buffer vb; /* v4l buffer must be first */ | 91 | struct vb2_buffer vb; /* v4l buffer must be first */ |
| 92 | struct list_head queue; | 92 | struct list_head queue; |
| 93 | enum v4l2_mbus_pixelcode code; | ||
| 94 | }; | 93 | }; |
| 95 | 94 | ||
| 96 | struct sh_mobile_ceu_dev { | 95 | struct sh_mobile_ceu_dev { |
| @@ -100,7 +99,8 @@ struct sh_mobile_ceu_dev { | |||
| 100 | 99 | ||
| 101 | unsigned int irq; | 100 | unsigned int irq; |
| 102 | void __iomem *base; | 101 | void __iomem *base; |
| 103 | unsigned long video_limit; | 102 | size_t video_limit; |
| 103 | size_t buf_total; | ||
| 104 | 104 | ||
| 105 | spinlock_t lock; /* Protects video buffer lists */ | 105 | spinlock_t lock; /* Protects video buffer lists */ |
| 106 | struct list_head capture; | 106 | struct list_head capture; |
| @@ -121,7 +121,7 @@ struct sh_mobile_ceu_dev { | |||
| 121 | }; | 121 | }; |
| 122 | 122 | ||
| 123 | struct sh_mobile_ceu_cam { | 123 | struct sh_mobile_ceu_cam { |
| 124 | /* CEU offsets within scaled by the CEU camera output */ | 124 | /* CEU offsets within the camera output, before the CEU scaler */ |
| 125 | unsigned int ceu_left; | 125 | unsigned int ceu_left; |
| 126 | unsigned int ceu_top; | 126 | unsigned int ceu_top; |
| 127 | /* Client output, as seen by the CEU */ | 127 | /* Client output, as seen by the CEU */ |
| @@ -144,30 +144,6 @@ static struct sh_mobile_ceu_buffer *to_ceu_vb(struct vb2_buffer *vb) | |||
| 144 | return container_of(vb, struct sh_mobile_ceu_buffer, vb); | 144 | return container_of(vb, struct sh_mobile_ceu_buffer, vb); |
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | static unsigned long make_bus_param(struct sh_mobile_ceu_dev *pcdev) | ||
| 148 | { | ||
| 149 | unsigned long flags; | ||
| 150 | |||
| 151 | flags = SOCAM_MASTER | | ||
| 152 | SOCAM_PCLK_SAMPLE_RISING | | ||
| 153 | SOCAM_HSYNC_ACTIVE_HIGH | | ||
| 154 | SOCAM_HSYNC_ACTIVE_LOW | | ||
| 155 | SOCAM_VSYNC_ACTIVE_HIGH | | ||
| 156 | SOCAM_VSYNC_ACTIVE_LOW | | ||
| 157 | SOCAM_DATA_ACTIVE_HIGH; | ||
| 158 | |||
| 159 | if (pcdev->pdata->flags & SH_CEU_FLAG_USE_8BIT_BUS) | ||
| 160 | flags |= SOCAM_DATAWIDTH_8; | ||
| 161 | |||
| 162 | if (pcdev->pdata->flags & SH_CEU_FLAG_USE_16BIT_BUS) | ||
| 163 | flags |= SOCAM_DATAWIDTH_16; | ||
| 164 | |||
| 165 | if (flags & SOCAM_DATAWIDTH_MASK) | ||
| 166 | return flags; | ||
| 167 | |||
| 168 | return 0; | ||
| 169 | } | ||
| 170 | |||
| 171 | static void ceu_write(struct sh_mobile_ceu_dev *priv, | 147 | static void ceu_write(struct sh_mobile_ceu_dev *priv, |
| 172 | unsigned long reg_offs, u32 data) | 148 | unsigned long reg_offs, u32 data) |
| 173 | { | 149 | { |
| @@ -216,33 +192,61 @@ static int sh_mobile_ceu_soft_reset(struct sh_mobile_ceu_dev *pcdev) | |||
| 216 | /* | 192 | /* |
| 217 | * Videobuf operations | 193 | * Videobuf operations |
| 218 | */ | 194 | */ |
| 195 | |||
| 196 | /* | ||
| 197 | * .queue_setup() is called to check, whether the driver can accept the | ||
| 198 | * requested number of buffers and to fill in plane sizes | ||
| 199 | * for the current frame format if required | ||
| 200 | */ | ||
| 219 | static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq, | 201 | static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq, |
| 202 | const struct v4l2_format *fmt, | ||
| 220 | unsigned int *count, unsigned int *num_planes, | 203 | unsigned int *count, unsigned int *num_planes, |
| 221 | unsigned int sizes[], void *alloc_ctxs[]) | 204 | unsigned int sizes[], void *alloc_ctxs[]) |
| 222 | { | 205 | { |
| 223 | struct soc_camera_device *icd = container_of(vq, struct soc_camera_device, vb2_vidq); | 206 | struct soc_camera_device *icd = container_of(vq, struct soc_camera_device, vb2_vidq); |
| 224 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 207 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
| 225 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | 208 | struct sh_mobile_ceu_dev *pcdev = ici->priv; |
| 226 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, | 209 | int bytes_per_line; |
| 227 | icd->current_fmt->host_fmt); | 210 | unsigned int height; |
| 228 | 211 | ||
| 212 | if (fmt) { | ||
| 213 | const struct soc_camera_format_xlate *xlate = soc_camera_xlate_by_fourcc(icd, | ||
| 214 | fmt->fmt.pix.pixelformat); | ||
| 215 | if (!xlate) | ||
| 216 | return -EINVAL; | ||
| 217 | bytes_per_line = soc_mbus_bytes_per_line(fmt->fmt.pix.width, | ||
| 218 | xlate->host_fmt); | ||
| 219 | height = fmt->fmt.pix.height; | ||
| 220 | } else { | ||
| 221 | /* Called from VIDIOC_REQBUFS or in compatibility mode */ | ||
| 222 | bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, | ||
| 223 | icd->current_fmt->host_fmt); | ||
| 224 | height = icd->user_height; | ||
| 225 | } | ||
| 229 | if (bytes_per_line < 0) | 226 | if (bytes_per_line < 0) |
| 230 | return bytes_per_line; | 227 | return bytes_per_line; |
| 231 | 228 | ||
| 232 | *num_planes = 1; | 229 | sizes[0] = bytes_per_line * height; |
| 233 | 230 | ||
| 234 | pcdev->sequence = 0; | ||
| 235 | sizes[0] = bytes_per_line * icd->user_height; | ||
| 236 | alloc_ctxs[0] = pcdev->alloc_ctx; | 231 | alloc_ctxs[0] = pcdev->alloc_ctx; |
| 237 | 232 | ||
| 233 | if (!vq->num_buffers) | ||
| 234 | pcdev->sequence = 0; | ||
| 235 | |||
| 238 | if (!*count) | 236 | if (!*count) |
| 239 | *count = 2; | 237 | *count = 2; |
| 240 | 238 | ||
| 241 | if (pcdev->video_limit) { | 239 | /* If *num_planes != 0, we have already verified *count. */ |
| 242 | if (PAGE_ALIGN(sizes[0]) * *count > pcdev->video_limit) | 240 | if (pcdev->video_limit && !*num_planes) { |
| 243 | *count = pcdev->video_limit / PAGE_ALIGN(sizes[0]); | 241 | size_t size = PAGE_ALIGN(sizes[0]) * *count; |
| 242 | |||
| 243 | if (size + pcdev->buf_total > pcdev->video_limit) | ||
| 244 | *count = (pcdev->video_limit - pcdev->buf_total) / | ||
| 245 | PAGE_ALIGN(sizes[0]); | ||
| 244 | } | 246 | } |
| 245 | 247 | ||
| 248 | *num_planes = 1; | ||
| 249 | |||
| 246 | dev_dbg(icd->parent, "count=%d, size=%u\n", *count, sizes[0]); | 250 | dev_dbg(icd->parent, "count=%d, size=%u\n", *count, sizes[0]); |
| 247 | 251 | ||
| 248 | return 0; | 252 | return 0; |
| @@ -267,6 +271,7 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) | |||
| 267 | unsigned long top1, top2; | 271 | unsigned long top1, top2; |
| 268 | unsigned long bottom1, bottom2; | 272 | unsigned long bottom1, bottom2; |
| 269 | u32 status; | 273 | u32 status; |
| 274 | bool planar; | ||
| 270 | int ret = 0; | 275 | int ret = 0; |
| 271 | 276 | ||
| 272 | /* | 277 | /* |
| @@ -314,17 +319,29 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) | |||
| 314 | 319 | ||
| 315 | phys_addr_top = vb2_dma_contig_plane_dma_addr(pcdev->active, 0); | 320 | phys_addr_top = vb2_dma_contig_plane_dma_addr(pcdev->active, 0); |
| 316 | 321 | ||
| 317 | ceu_write(pcdev, top1, phys_addr_top); | ||
| 318 | if (V4L2_FIELD_NONE != pcdev->field) { | ||
| 319 | phys_addr_bottom = phys_addr_top + icd->user_width; | ||
| 320 | ceu_write(pcdev, bottom1, phys_addr_bottom); | ||
| 321 | } | ||
| 322 | |||
| 323 | switch (icd->current_fmt->host_fmt->fourcc) { | 322 | switch (icd->current_fmt->host_fmt->fourcc) { |
| 324 | case V4L2_PIX_FMT_NV12: | 323 | case V4L2_PIX_FMT_NV12: |
| 325 | case V4L2_PIX_FMT_NV21: | 324 | case V4L2_PIX_FMT_NV21: |
| 326 | case V4L2_PIX_FMT_NV16: | 325 | case V4L2_PIX_FMT_NV16: |
| 327 | case V4L2_PIX_FMT_NV61: | 326 | case V4L2_PIX_FMT_NV61: |
| 327 | planar = true; | ||
| 328 | break; | ||
| 329 | default: | ||
| 330 | planar = false; | ||
| 331 | } | ||
| 332 | |||
| 333 | ceu_write(pcdev, top1, phys_addr_top); | ||
| 334 | if (V4L2_FIELD_NONE != pcdev->field) { | ||
| 335 | if (planar) | ||
| 336 | phys_addr_bottom = phys_addr_top + icd->user_width; | ||
| 337 | else | ||
| 338 | phys_addr_bottom = phys_addr_top + | ||
| 339 | soc_mbus_bytes_per_line(icd->user_width, | ||
| 340 | icd->current_fmt->host_fmt); | ||
| 341 | ceu_write(pcdev, bottom1, phys_addr_bottom); | ||
| 342 | } | ||
| 343 | |||
| 344 | if (planar) { | ||
| 328 | phys_addr_top += icd->user_width * | 345 | phys_addr_top += icd->user_width * |
| 329 | icd->user_height; | 346 | icd->user_height; |
| 330 | ceu_write(pcdev, top2, phys_addr_top); | 347 | ceu_write(pcdev, top2, phys_addr_top); |
| @@ -341,23 +358,40 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) | |||
| 341 | 358 | ||
| 342 | static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb) | 359 | static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb) |
| 343 | { | 360 | { |
| 361 | struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb); | ||
| 362 | |||
| 363 | /* Added list head initialization on alloc */ | ||
| 364 | WARN(!list_empty(&buf->queue), "Buffer %p on queue!\n", vb); | ||
| 365 | |||
| 366 | return 0; | ||
| 367 | } | ||
| 368 | |||
| 369 | static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb) | ||
| 370 | { | ||
| 344 | struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq); | 371 | struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq); |
| 345 | struct sh_mobile_ceu_buffer *buf; | 372 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
| 373 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
| 374 | struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb); | ||
| 375 | unsigned long size; | ||
| 346 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, | 376 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, |
| 347 | icd->current_fmt->host_fmt); | 377 | icd->current_fmt->host_fmt); |
| 348 | unsigned long size; | ||
| 349 | 378 | ||
| 350 | if (bytes_per_line < 0) | 379 | if (bytes_per_line < 0) |
| 351 | return bytes_per_line; | 380 | goto error; |
| 352 | 381 | ||
| 353 | buf = to_ceu_vb(vb); | 382 | size = icd->user_height * bytes_per_line; |
| 383 | |||
| 384 | if (vb2_plane_size(vb, 0) < size) { | ||
| 385 | dev_err(icd->parent, "Buffer #%d too small (%lu < %lu)\n", | ||
| 386 | vb->v4l2_buf.index, vb2_plane_size(vb, 0), size); | ||
| 387 | goto error; | ||
| 388 | } | ||
| 389 | |||
| 390 | vb2_set_plane_payload(vb, 0, size); | ||
| 354 | 391 | ||
| 355 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, | 392 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, |
| 356 | vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); | 393 | vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); |
| 357 | 394 | ||
| 358 | /* Added list head initialization on alloc */ | ||
| 359 | WARN(!list_empty(&buf->queue), "Buffer %p on queue!\n", vb); | ||
| 360 | |||
| 361 | #ifdef DEBUG | 395 | #ifdef DEBUG |
| 362 | /* | 396 | /* |
| 363 | * This can be useful if you want to see if we actually fill | 397 | * This can be useful if you want to see if we actually fill |
| @@ -367,31 +401,6 @@ static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb) | |||
| 367 | memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0)); | 401 | memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0)); |
| 368 | #endif | 402 | #endif |
| 369 | 403 | ||
| 370 | BUG_ON(NULL == icd->current_fmt); | ||
| 371 | |||
| 372 | size = icd->user_height * bytes_per_line; | ||
| 373 | |||
| 374 | if (vb2_plane_size(vb, 0) < size) { | ||
| 375 | dev_err(icd->parent, "Buffer too small (%lu < %lu)\n", | ||
| 376 | vb2_plane_size(vb, 0), size); | ||
| 377 | return -ENOBUFS; | ||
| 378 | } | ||
| 379 | |||
| 380 | vb2_set_plane_payload(vb, 0, size); | ||
| 381 | |||
| 382 | return 0; | ||
| 383 | } | ||
| 384 | |||
| 385 | static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb) | ||
| 386 | { | ||
| 387 | struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq); | ||
| 388 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
| 389 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
| 390 | struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb); | ||
| 391 | |||
| 392 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, | ||
| 393 | vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); | ||
| 394 | |||
| 395 | spin_lock_irq(&pcdev->lock); | 404 | spin_lock_irq(&pcdev->lock); |
| 396 | list_add_tail(&buf->queue, &pcdev->capture); | 405 | list_add_tail(&buf->queue, &pcdev->capture); |
| 397 | 406 | ||
| @@ -405,6 +414,11 @@ static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb) | |||
| 405 | sh_mobile_ceu_capture(pcdev); | 414 | sh_mobile_ceu_capture(pcdev); |
| 406 | } | 415 | } |
| 407 | spin_unlock_irq(&pcdev->lock); | 416 | spin_unlock_irq(&pcdev->lock); |
| 417 | |||
| 418 | return; | ||
| 419 | |||
| 420 | error: | ||
| 421 | vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); | ||
| 408 | } | 422 | } |
| 409 | 423 | ||
| 410 | static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb) | 424 | static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb) |
| @@ -429,11 +443,23 @@ static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb) | |||
| 429 | if (buf->queue.next) | 443 | if (buf->queue.next) |
| 430 | list_del_init(&buf->queue); | 444 | list_del_init(&buf->queue); |
| 431 | 445 | ||
| 446 | pcdev->buf_total -= PAGE_ALIGN(vb2_plane_size(vb, 0)); | ||
| 447 | dev_dbg(icd->parent, "%s() %zu bytes buffers\n", __func__, | ||
| 448 | pcdev->buf_total); | ||
| 449 | |||
| 432 | spin_unlock_irq(&pcdev->lock); | 450 | spin_unlock_irq(&pcdev->lock); |
| 433 | } | 451 | } |
| 434 | 452 | ||
| 435 | static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb) | 453 | static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb) |
| 436 | { | 454 | { |
| 455 | struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq); | ||
| 456 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
| 457 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
| 458 | |||
| 459 | pcdev->buf_total += PAGE_ALIGN(vb2_plane_size(vb, 0)); | ||
| 460 | dev_dbg(icd->parent, "%s() %zu bytes buffers\n", __func__, | ||
| 461 | pcdev->buf_total); | ||
| 462 | |||
| 437 | /* This is for locking debugging only */ | 463 | /* This is for locking debugging only */ |
| 438 | INIT_LIST_HEAD(&to_ceu_vb(vb)->queue); | 464 | INIT_LIST_HEAD(&to_ceu_vb(vb)->queue); |
| 439 | return 0; | 465 | return 0; |
| @@ -535,19 +561,29 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) | |||
| 535 | 561 | ||
| 536 | pm_runtime_get_sync(ici->v4l2_dev.dev); | 562 | pm_runtime_get_sync(ici->v4l2_dev.dev); |
| 537 | 563 | ||
| 564 | pcdev->buf_total = 0; | ||
| 565 | |||
| 538 | ret = sh_mobile_ceu_soft_reset(pcdev); | 566 | ret = sh_mobile_ceu_soft_reset(pcdev); |
| 539 | 567 | ||
| 540 | csi2_sd = find_csi2(pcdev); | 568 | csi2_sd = find_csi2(pcdev); |
| 569 | if (csi2_sd) | ||
| 570 | csi2_sd->grp_id = (long)icd; | ||
| 541 | 571 | ||
| 542 | ret = v4l2_subdev_call(csi2_sd, core, s_power, 1); | 572 | ret = v4l2_subdev_call(csi2_sd, core, s_power, 1); |
| 543 | if (ret != -ENODEV && ret != -ENOIOCTLCMD && ret < 0) { | 573 | if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) { |
| 544 | pm_runtime_put_sync(ici->v4l2_dev.dev); | 574 | pm_runtime_put_sync(ici->v4l2_dev.dev); |
| 545 | } else { | 575 | return ret; |
| 546 | pcdev->icd = icd; | ||
| 547 | ret = 0; | ||
| 548 | } | 576 | } |
| 549 | 577 | ||
| 550 | return ret; | 578 | /* |
| 579 | * -ENODEV is special: either csi2_sd == NULL or the CSI-2 driver | ||
| 580 | * has not found this soc-camera device among its clients | ||
| 581 | */ | ||
| 582 | if (ret == -ENODEV && csi2_sd) | ||
| 583 | csi2_sd->grp_id = 0; | ||
| 584 | pcdev->icd = icd; | ||
| 585 | |||
| 586 | return 0; | ||
| 551 | } | 587 | } |
| 552 | 588 | ||
| 553 | /* Called with .video_lock held */ | 589 | /* Called with .video_lock held */ |
| @@ -560,6 +596,8 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd) | |||
| 560 | BUG_ON(icd != pcdev->icd); | 596 | BUG_ON(icd != pcdev->icd); |
| 561 | 597 | ||
| 562 | v4l2_subdev_call(csi2_sd, core, s_power, 0); | 598 | v4l2_subdev_call(csi2_sd, core, s_power, 0); |
| 599 | if (csi2_sd) | ||
| 600 | csi2_sd->grp_id = 0; | ||
| 563 | /* disable capture, disable interrupts */ | 601 | /* disable capture, disable interrupts */ |
| 564 | ceu_write(pcdev, CEIER, 0); | 602 | ceu_write(pcdev, CEIER, 0); |
| 565 | sh_mobile_ceu_soft_reset(pcdev); | 603 | sh_mobile_ceu_soft_reset(pcdev); |
| @@ -628,22 +666,22 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd) | |||
| 628 | left_offset = cam->ceu_left; | 666 | left_offset = cam->ceu_left; |
| 629 | top_offset = cam->ceu_top; | 667 | top_offset = cam->ceu_top; |
| 630 | 668 | ||
| 631 | /* CEU cropping (CFSZR) is applied _after_ the scaling filter (CFLCR) */ | 669 | WARN_ON(icd->user_width & 3 || icd->user_height & 3); |
| 670 | |||
| 671 | width = icd->user_width; | ||
| 672 | |||
| 632 | if (pcdev->image_mode) { | 673 | if (pcdev->image_mode) { |
| 633 | in_width = cam->width; | 674 | in_width = cam->width; |
| 634 | if (!pcdev->is_16bit) { | 675 | if (!pcdev->is_16bit) { |
| 635 | in_width *= 2; | 676 | in_width *= 2; |
| 636 | left_offset *= 2; | 677 | left_offset *= 2; |
| 637 | } | 678 | } |
| 638 | width = icd->user_width; | 679 | cdwdr_width = width; |
| 639 | cdwdr_width = icd->user_width; | ||
| 640 | } else { | 680 | } else { |
| 641 | int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, | 681 | int bytes_per_line = soc_mbus_bytes_per_line(width, |
| 642 | icd->current_fmt->host_fmt); | 682 | icd->current_fmt->host_fmt); |
| 643 | unsigned int w_factor; | 683 | unsigned int w_factor; |
| 644 | 684 | ||
| 645 | width = icd->user_width; | ||
| 646 | |||
| 647 | switch (icd->current_fmt->host_fmt->packing) { | 685 | switch (icd->current_fmt->host_fmt->packing) { |
| 648 | case SOC_MBUS_PACKING_2X8_PADHI: | 686 | case SOC_MBUS_PACKING_2X8_PADHI: |
| 649 | w_factor = 2; | 687 | w_factor = 2; |
| @@ -653,10 +691,10 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd) | |||
| 653 | } | 691 | } |
| 654 | 692 | ||
| 655 | in_width = cam->width * w_factor; | 693 | in_width = cam->width * w_factor; |
| 656 | left_offset = left_offset * w_factor; | 694 | left_offset *= w_factor; |
| 657 | 695 | ||
| 658 | if (bytes_per_line < 0) | 696 | if (bytes_per_line < 0) |
| 659 | cdwdr_width = icd->user_width; | 697 | cdwdr_width = width; |
| 660 | else | 698 | else |
| 661 | cdwdr_width = bytes_per_line; | 699 | cdwdr_width = bytes_per_line; |
| 662 | } | 700 | } |
| @@ -664,7 +702,7 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd) | |||
| 664 | height = icd->user_height; | 702 | height = icd->user_height; |
| 665 | in_height = cam->height; | 703 | in_height = cam->height; |
| 666 | if (V4L2_FIELD_NONE != pcdev->field) { | 704 | if (V4L2_FIELD_NONE != pcdev->field) { |
| 667 | height /= 2; | 705 | height = (height / 2) & ~3; |
| 668 | in_height /= 2; | 706 | in_height /= 2; |
| 669 | top_offset /= 2; | 707 | top_offset /= 2; |
| 670 | cdwdr_width *= 2; | 708 | cdwdr_width *= 2; |
| @@ -686,6 +724,7 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd) | |||
| 686 | 724 | ||
| 687 | ceu_write(pcdev, CAMOR, camor); | 725 | ceu_write(pcdev, CAMOR, camor); |
| 688 | ceu_write(pcdev, CAPWR, (in_height << 16) | in_width); | 726 | ceu_write(pcdev, CAPWR, (in_height << 16) | in_width); |
| 727 | /* CFSZR clipping is applied _after_ the scaling filter (CFLCR) */ | ||
| 689 | ceu_write(pcdev, CFSZR, (height << 16) | width); | 728 | ceu_write(pcdev, CFSZR, (height << 16) | width); |
| 690 | ceu_write(pcdev, CDWDR, cdwdr_width); | 729 | ceu_write(pcdev, CDWDR, cdwdr_width); |
| 691 | } | 730 | } |
| @@ -723,66 +762,93 @@ static void capture_restore(struct sh_mobile_ceu_dev *pcdev, u32 capsr) | |||
| 723 | ceu_write(pcdev, CAPSR, capsr); | 762 | ceu_write(pcdev, CAPSR, capsr); |
| 724 | } | 763 | } |
| 725 | 764 | ||
| 765 | /* Find the bus subdevice driver, e.g., CSI2 */ | ||
| 766 | static struct v4l2_subdev *find_bus_subdev(struct sh_mobile_ceu_dev *pcdev, | ||
| 767 | struct soc_camera_device *icd) | ||
| 768 | { | ||
| 769 | if (pcdev->csi2_pdev) { | ||
| 770 | struct v4l2_subdev *csi2_sd = find_csi2(pcdev); | ||
| 771 | if (csi2_sd && csi2_sd->grp_id == (u32)icd) | ||
| 772 | return csi2_sd; | ||
| 773 | } | ||
| 774 | |||
| 775 | return soc_camera_to_subdev(icd); | ||
| 776 | } | ||
| 777 | |||
| 778 | #define CEU_BUS_FLAGS (V4L2_MBUS_MASTER | \ | ||
| 779 | V4L2_MBUS_PCLK_SAMPLE_RISING | \ | ||
| 780 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | \ | ||
| 781 | V4L2_MBUS_HSYNC_ACTIVE_LOW | \ | ||
| 782 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | \ | ||
| 783 | V4L2_MBUS_VSYNC_ACTIVE_LOW | \ | ||
| 784 | V4L2_MBUS_DATA_ACTIVE_HIGH) | ||
| 785 | |||
| 726 | /* Capture is not running, no interrupts, no locking needed */ | 786 | /* Capture is not running, no interrupts, no locking needed */ |
| 727 | static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, | 787 | static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, |
| 728 | __u32 pixfmt) | 788 | __u32 pixfmt) |
| 729 | { | 789 | { |
| 730 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 790 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
| 731 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | 791 | struct sh_mobile_ceu_dev *pcdev = ici->priv; |
| 732 | int ret; | 792 | struct v4l2_subdev *sd = find_bus_subdev(pcdev, icd); |
| 733 | unsigned long camera_flags, common_flags, value; | ||
| 734 | int yuv_lineskip; | ||
| 735 | struct sh_mobile_ceu_cam *cam = icd->host_priv; | 793 | struct sh_mobile_ceu_cam *cam = icd->host_priv; |
| 794 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; | ||
| 795 | unsigned long value, common_flags = CEU_BUS_FLAGS; | ||
| 736 | u32 capsr = capture_save_reset(pcdev); | 796 | u32 capsr = capture_save_reset(pcdev); |
| 797 | unsigned int yuv_lineskip; | ||
| 798 | int ret; | ||
| 737 | 799 | ||
| 738 | camera_flags = icd->ops->query_bus_param(icd); | 800 | /* |
| 739 | common_flags = soc_camera_bus_param_compatible(camera_flags, | 801 | * If the client doesn't implement g_mbus_config, we just use our |
| 740 | make_bus_param(pcdev)); | 802 | * platform data |
| 741 | if (!common_flags) | 803 | */ |
| 742 | return -EINVAL; | 804 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); |
| 805 | if (!ret) { | ||
| 806 | common_flags = soc_mbus_config_compatible(&cfg, | ||
| 807 | common_flags); | ||
| 808 | if (!common_flags) | ||
| 809 | return -EINVAL; | ||
| 810 | } else if (ret != -ENOIOCTLCMD) { | ||
| 811 | return ret; | ||
| 812 | } | ||
| 743 | 813 | ||
| 744 | /* Make choises, based on platform preferences */ | 814 | /* Make choises, based on platform preferences */ |
| 745 | if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && | 815 | if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && |
| 746 | (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { | 816 | (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { |
| 747 | if (pcdev->pdata->flags & SH_CEU_FLAG_HSYNC_LOW) | 817 | if (pcdev->pdata->flags & SH_CEU_FLAG_HSYNC_LOW) |
| 748 | common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; | 818 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; |
| 749 | else | 819 | else |
| 750 | common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; | 820 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; |
| 751 | } | 821 | } |
| 752 | 822 | ||
| 753 | if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && | 823 | if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && |
| 754 | (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { | 824 | (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { |
| 755 | if (pcdev->pdata->flags & SH_CEU_FLAG_VSYNC_LOW) | 825 | if (pcdev->pdata->flags & SH_CEU_FLAG_VSYNC_LOW) |
| 756 | common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; | 826 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; |
| 757 | else | 827 | else |
| 758 | common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; | 828 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; |
| 759 | } | 829 | } |
| 760 | 830 | ||
| 761 | ret = icd->ops->set_bus_param(icd, common_flags); | 831 | cfg.flags = common_flags; |
| 762 | if (ret < 0) | 832 | ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); |
| 833 | if (ret < 0 && ret != -ENOIOCTLCMD) | ||
| 763 | return ret; | 834 | return ret; |
| 764 | 835 | ||
| 765 | switch (common_flags & SOCAM_DATAWIDTH_MASK) { | 836 | if (icd->current_fmt->host_fmt->bits_per_sample > 8) |
| 766 | case SOCAM_DATAWIDTH_8: | ||
| 767 | pcdev->is_16bit = 0; | ||
| 768 | break; | ||
| 769 | case SOCAM_DATAWIDTH_16: | ||
| 770 | pcdev->is_16bit = 1; | 837 | pcdev->is_16bit = 1; |
| 771 | break; | 838 | else |
| 772 | default: | 839 | pcdev->is_16bit = 0; |
| 773 | return -EINVAL; | ||
| 774 | } | ||
| 775 | 840 | ||
| 776 | ceu_write(pcdev, CRCNTR, 0); | 841 | ceu_write(pcdev, CRCNTR, 0); |
| 777 | ceu_write(pcdev, CRCMPR, 0); | 842 | ceu_write(pcdev, CRCMPR, 0); |
| 778 | 843 | ||
| 779 | value = 0x00000010; /* data fetch by default */ | 844 | value = 0x00000010; /* data fetch by default */ |
| 780 | yuv_lineskip = 0; | 845 | yuv_lineskip = 0x10; |
| 781 | 846 | ||
| 782 | switch (icd->current_fmt->host_fmt->fourcc) { | 847 | switch (icd->current_fmt->host_fmt->fourcc) { |
| 783 | case V4L2_PIX_FMT_NV12: | 848 | case V4L2_PIX_FMT_NV12: |
| 784 | case V4L2_PIX_FMT_NV21: | 849 | case V4L2_PIX_FMT_NV21: |
| 785 | yuv_lineskip = 1; /* skip for NV12/21, no skip for NV16/61 */ | 850 | /* convert 4:2:2 -> 4:2:0 */ |
| 851 | yuv_lineskip = 0; /* skip for NV12/21, no skip for NV16/61 */ | ||
| 786 | /* fall-through */ | 852 | /* fall-through */ |
| 787 | case V4L2_PIX_FMT_NV16: | 853 | case V4L2_PIX_FMT_NV16: |
| 788 | case V4L2_PIX_FMT_NV61: | 854 | case V4L2_PIX_FMT_NV61: |
| @@ -808,8 +874,8 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, | |||
| 808 | icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_NV61) | 874 | icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_NV61) |
| 809 | value ^= 0x00000100; /* swap U, V to change from NV1x->NVx1 */ | 875 | value ^= 0x00000100; /* swap U, V to change from NV1x->NVx1 */ |
| 810 | 876 | ||
| 811 | value |= common_flags & SOCAM_VSYNC_ACTIVE_LOW ? 1 << 1 : 0; | 877 | value |= common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW ? 1 << 1 : 0; |
| 812 | value |= common_flags & SOCAM_HSYNC_ACTIVE_LOW ? 1 << 0 : 0; | 878 | value |= common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW ? 1 << 0 : 0; |
| 813 | value |= pcdev->is_16bit ? 1 << 12 : 0; | 879 | value |= pcdev->is_16bit ? 1 << 12 : 0; |
| 814 | 880 | ||
| 815 | /* CSI2 mode */ | 881 | /* CSI2 mode */ |
| @@ -852,9 +918,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, | |||
| 852 | * using 7 we swap the data bytes to match the incoming order: | 918 | * using 7 we swap the data bytes to match the incoming order: |
| 853 | * D0, D1, D2, D3, D4, D5, D6, D7 | 919 | * D0, D1, D2, D3, D4, D5, D6, D7 |
| 854 | */ | 920 | */ |
| 855 | value = 0x00000017; | 921 | value = 0x00000007 | yuv_lineskip; |
| 856 | if (yuv_lineskip) | ||
| 857 | value &= ~0x00000010; /* convert 4:2:2 -> 4:2:0 */ | ||
| 858 | 922 | ||
| 859 | ceu_write(pcdev, CDOCR, value); | 923 | ceu_write(pcdev, CDOCR, value); |
| 860 | ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */ | 924 | ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */ |
| @@ -875,13 +939,19 @@ static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd, | |||
| 875 | { | 939 | { |
| 876 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | 940 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); |
| 877 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | 941 | struct sh_mobile_ceu_dev *pcdev = ici->priv; |
| 878 | unsigned long camera_flags, common_flags; | 942 | struct v4l2_subdev *sd = find_bus_subdev(pcdev, icd); |
| 943 | unsigned long common_flags = CEU_BUS_FLAGS; | ||
| 944 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; | ||
| 945 | int ret; | ||
| 879 | 946 | ||
| 880 | camera_flags = icd->ops->query_bus_param(icd); | 947 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); |
| 881 | common_flags = soc_camera_bus_param_compatible(camera_flags, | 948 | if (!ret) |
| 882 | make_bus_param(pcdev)); | 949 | common_flags = soc_mbus_config_compatible(&cfg, |
| 883 | if (!common_flags || buswidth > 16 || | 950 | common_flags); |
| 884 | (buswidth > 8 && !(common_flags & SOCAM_DATAWIDTH_16))) | 951 | else if (ret != -ENOIOCTLCMD) |
| 952 | return ret; | ||
| 953 | |||
| 954 | if (!common_flags || buswidth > 16) | ||
| 885 | return -EINVAL; | 955 | return -EINVAL; |
| 886 | 956 | ||
| 887 | return 0; | 957 | return 0; |
| @@ -891,26 +961,26 @@ static const struct soc_mbus_pixelfmt sh_mobile_ceu_formats[] = { | |||
| 891 | { | 961 | { |
| 892 | .fourcc = V4L2_PIX_FMT_NV12, | 962 | .fourcc = V4L2_PIX_FMT_NV12, |
| 893 | .name = "NV12", | 963 | .name = "NV12", |
| 894 | .bits_per_sample = 12, | 964 | .bits_per_sample = 8, |
| 895 | .packing = SOC_MBUS_PACKING_NONE, | 965 | .packing = SOC_MBUS_PACKING_1_5X8, |
| 896 | .order = SOC_MBUS_ORDER_LE, | 966 | .order = SOC_MBUS_ORDER_LE, |
| 897 | }, { | 967 | }, { |
| 898 | .fourcc = V4L2_PIX_FMT_NV21, | 968 | .fourcc = V4L2_PIX_FMT_NV21, |
| 899 | .name = "NV21", | 969 | .name = "NV21", |
| 900 | .bits_per_sample = 12, | 970 | .bits_per_sample = 8, |
| 901 | .packing = SOC_MBUS_PACKING_NONE, | 971 | .packing = SOC_MBUS_PACKING_1_5X8, |
| 902 | .order = SOC_MBUS_ORDER_LE, | 972 | .order = SOC_MBUS_ORDER_LE, |
| 903 | }, { | 973 | }, { |
| 904 | .fourcc = V4L2_PIX_FMT_NV16, | 974 | .fourcc = V4L2_PIX_FMT_NV16, |
| 905 | .name = "NV16", | 975 | .name = "NV16", |
| 906 | .bits_per_sample = 16, | 976 | .bits_per_sample = 8, |
| 907 | .packing = SOC_MBUS_PACKING_NONE, | 977 | .packing = SOC_MBUS_PACKING_2X8_PADHI, |
| 908 | .order = SOC_MBUS_ORDER_LE, | 978 | .order = SOC_MBUS_ORDER_LE, |
| 909 | }, { | 979 | }, { |
| 910 | .fourcc = V4L2_PIX_FMT_NV61, | 980 | .fourcc = V4L2_PIX_FMT_NV61, |
| 911 | .name = "NV61", | 981 | .name = "NV61", |
| 912 | .bits_per_sample = 16, | 982 | .bits_per_sample = 8, |
| 913 | .packing = SOC_MBUS_PACKING_NONE, | 983 | .packing = SOC_MBUS_PACKING_2X8_PADHI, |
| 914 | .order = SOC_MBUS_ORDER_LE, | 984 | .order = SOC_MBUS_ORDER_LE, |
| 915 | }, | 985 | }, |
| 916 | }; | 986 | }; |
| @@ -920,6 +990,8 @@ static bool sh_mobile_ceu_packing_supported(const struct soc_mbus_pixelfmt *fmt) | |||
| 920 | { | 990 | { |
| 921 | return fmt->packing == SOC_MBUS_PACKING_NONE || | 991 | return fmt->packing == SOC_MBUS_PACKING_NONE || |
| 922 | (fmt->bits_per_sample == 8 && | 992 | (fmt->bits_per_sample == 8 && |
| 993 | fmt->packing == SOC_MBUS_PACKING_1_5X8) || | ||
| 994 | (fmt->bits_per_sample == 8 && | ||
| 923 | fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) || | 995 | fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) || |
| 924 | (fmt->bits_per_sample > 8 && | 996 | (fmt->bits_per_sample > 8 && |
| 925 | fmt->packing == SOC_MBUS_PACKING_EXTEND16); | 997 | fmt->packing == SOC_MBUS_PACKING_EXTEND16); |
| @@ -927,6 +999,38 @@ static bool sh_mobile_ceu_packing_supported(const struct soc_mbus_pixelfmt *fmt) | |||
| 927 | 999 | ||
| 928 | static int client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect); | 1000 | static int client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect); |
| 929 | 1001 | ||
| 1002 | static struct soc_camera_device *ctrl_to_icd(struct v4l2_ctrl *ctrl) | ||
| 1003 | { | ||
| 1004 | return container_of(ctrl->handler, struct soc_camera_device, | ||
| 1005 | ctrl_handler); | ||
| 1006 | } | ||
| 1007 | |||
| 1008 | static int sh_mobile_ceu_s_ctrl(struct v4l2_ctrl *ctrl) | ||
| 1009 | { | ||
| 1010 | struct soc_camera_device *icd = ctrl_to_icd(ctrl); | ||
| 1011 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
| 1012 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
| 1013 | |||
| 1014 | switch (ctrl->id) { | ||
| 1015 | case V4L2_CID_SHARPNESS: | ||
| 1016 | switch (icd->current_fmt->host_fmt->fourcc) { | ||
| 1017 | case V4L2_PIX_FMT_NV12: | ||
| 1018 | case V4L2_PIX_FMT_NV21: | ||
| 1019 | case V4L2_PIX_FMT_NV16: | ||
| 1020 | case V4L2_PIX_FMT_NV61: | ||
| 1021 | ceu_write(pcdev, CLFCR, !ctrl->val); | ||
| 1022 | return 0; | ||
| 1023 | } | ||
| 1024 | break; | ||
| 1025 | } | ||
| 1026 | |||
| 1027 | return -EINVAL; | ||
| 1028 | } | ||
| 1029 | |||
| 1030 | static const struct v4l2_ctrl_ops sh_mobile_ceu_ctrl_ops = { | ||
| 1031 | .s_ctrl = sh_mobile_ceu_s_ctrl, | ||
| 1032 | }; | ||
| 1033 | |||
| 930 | static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int idx, | 1034 | static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int idx, |
| 931 | struct soc_camera_format_xlate *xlate) | 1035 | struct soc_camera_format_xlate *xlate) |
| 932 | { | 1036 | { |
| @@ -952,6 +1056,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int | |||
| 952 | } | 1056 | } |
| 953 | 1057 | ||
| 954 | if (!pcdev->pdata->csi2) { | 1058 | if (!pcdev->pdata->csi2) { |
| 1059 | /* Are there any restrictions in the CSI-2 case? */ | ||
| 955 | ret = sh_mobile_ceu_try_bus_param(icd, fmt->bits_per_sample); | 1060 | ret = sh_mobile_ceu_try_bus_param(icd, fmt->bits_per_sample); |
| 956 | if (ret < 0) | 1061 | if (ret < 0) |
| 957 | return 0; | 1062 | return 0; |
| @@ -962,6 +1067,12 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int | |||
| 962 | struct v4l2_rect rect; | 1067 | struct v4l2_rect rect; |
| 963 | int shift = 0; | 1068 | int shift = 0; |
| 964 | 1069 | ||
| 1070 | /* Add our control */ | ||
| 1071 | v4l2_ctrl_new_std(&icd->ctrl_handler, &sh_mobile_ceu_ctrl_ops, | ||
| 1072 | V4L2_CID_SHARPNESS, 0, 1, 1, 0); | ||
| 1073 | if (icd->ctrl_handler.error) | ||
| 1074 | return icd->ctrl_handler.error; | ||
| 1075 | |||
| 965 | /* FIXME: subwindow is lost between close / open */ | 1076 | /* FIXME: subwindow is lost between close / open */ |
| 966 | 1077 | ||
| 967 | /* Cache current client geometry */ | 1078 | /* Cache current client geometry */ |
| @@ -1004,9 +1115,6 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int | |||
| 1004 | cam->width = mf.width; | 1115 | cam->width = mf.width; |
| 1005 | cam->height = mf.height; | 1116 | cam->height = mf.height; |
| 1006 | 1117 | ||
| 1007 | cam->width = mf.width; | ||
| 1008 | cam->height = mf.height; | ||
| 1009 | |||
| 1010 | icd->host_priv = cam; | 1118 | icd->host_priv = cam; |
| 1011 | } else { | 1119 | } else { |
| 1012 | cam = icd->host_priv; | 1120 | cam = icd->host_priv; |
| @@ -1278,6 +1386,7 @@ static int client_s_fmt(struct soc_camera_device *icd, | |||
| 1278 | unsigned int width = mf->width, height = mf->height, tmp_w, tmp_h; | 1386 | unsigned int width = mf->width, height = mf->height, tmp_w, tmp_h; |
| 1279 | unsigned int max_width, max_height; | 1387 | unsigned int max_width, max_height; |
| 1280 | struct v4l2_cropcap cap; | 1388 | struct v4l2_cropcap cap; |
| 1389 | bool ceu_1to1; | ||
| 1281 | int ret; | 1390 | int ret; |
| 1282 | 1391 | ||
| 1283 | ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, | 1392 | ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, |
| @@ -1287,7 +1396,14 @@ static int client_s_fmt(struct soc_camera_device *icd, | |||
| 1287 | 1396 | ||
| 1288 | dev_geo(dev, "camera scaled to %ux%u\n", mf->width, mf->height); | 1397 | dev_geo(dev, "camera scaled to %ux%u\n", mf->width, mf->height); |
| 1289 | 1398 | ||
| 1290 | if ((width == mf->width && height == mf->height) || !ceu_can_scale) | 1399 | if (width == mf->width && height == mf->height) { |
| 1400 | /* Perfect! The client has done it all. */ | ||
| 1401 | ceu_1to1 = true; | ||
| 1402 | goto update_cache; | ||
| 1403 | } | ||
| 1404 | |||
| 1405 | ceu_1to1 = false; | ||
| 1406 | if (!ceu_can_scale) | ||
| 1291 | goto update_cache; | 1407 | goto update_cache; |
| 1292 | 1408 | ||
| 1293 | cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 1409 | cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| @@ -1327,7 +1443,10 @@ update_cache: | |||
| 1327 | if (ret < 0) | 1443 | if (ret < 0) |
| 1328 | return ret; | 1444 | return ret; |
| 1329 | 1445 | ||
| 1330 | update_subrect(cam); | 1446 | if (ceu_1to1) |
| 1447 | cam->subrect = cam->rect; | ||
| 1448 | else | ||
| 1449 | update_subrect(cam); | ||
| 1331 | 1450 | ||
| 1332 | return 0; | 1451 | return 0; |
| 1333 | } | 1452 | } |
| @@ -1414,7 +1533,10 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, | |||
| 1414 | capsr = capture_save_reset(pcdev); | 1533 | capsr = capture_save_reset(pcdev); |
| 1415 | dev_dbg(dev, "CAPSR 0x%x, CFLCR 0x%x\n", capsr, pcdev->cflcr); | 1534 | dev_dbg(dev, "CAPSR 0x%x, CFLCR 0x%x\n", capsr, pcdev->cflcr); |
| 1416 | 1535 | ||
| 1417 | /* 1. - 2. Apply iterative camera S_CROP for new input window. */ | 1536 | /* |
| 1537 | * 1. - 2. Apply iterative camera S_CROP for new input window, read back | ||
| 1538 | * actual camera rectangle. | ||
| 1539 | */ | ||
| 1418 | ret = client_s_crop(icd, a, &cam_crop); | 1540 | ret = client_s_crop(icd, a, &cam_crop); |
| 1419 | if (ret < 0) | 1541 | if (ret < 0) |
| 1420 | return ret; | 1542 | return ret; |
| @@ -1498,8 +1620,9 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, | |||
| 1498 | ceu_write(pcdev, CFLCR, cflcr); | 1620 | ceu_write(pcdev, CFLCR, cflcr); |
| 1499 | } | 1621 | } |
| 1500 | 1622 | ||
| 1501 | icd->user_width = out_width; | 1623 | icd->user_width = out_width & ~3; |
| 1502 | icd->user_height = out_height; | 1624 | icd->user_height = out_height & ~3; |
| 1625 | /* Offsets are applied at the CEU scaling filter input */ | ||
| 1503 | cam->ceu_left = scale_down(rect->left - cam_rect->left, scale_cam_h) & ~1; | 1626 | cam->ceu_left = scale_down(rect->left - cam_rect->left, scale_cam_h) & ~1; |
| 1504 | cam->ceu_top = scale_down(rect->top - cam_rect->top, scale_cam_v) & ~1; | 1627 | cam->ceu_top = scale_down(rect->top - cam_rect->top, scale_cam_v) & ~1; |
| 1505 | 1628 | ||
| @@ -1538,7 +1661,7 @@ static int sh_mobile_ceu_get_crop(struct soc_camera_device *icd, | |||
| 1538 | * CEU crop, mapped backed onto the client input (subrect). | 1661 | * CEU crop, mapped backed onto the client input (subrect). |
| 1539 | */ | 1662 | */ |
| 1540 | static void calculate_client_output(struct soc_camera_device *icd, | 1663 | static void calculate_client_output(struct soc_camera_device *icd, |
| 1541 | struct v4l2_pix_format *pix, struct v4l2_mbus_framefmt *mf) | 1664 | const struct v4l2_pix_format *pix, struct v4l2_mbus_framefmt *mf) |
| 1542 | { | 1665 | { |
| 1543 | struct sh_mobile_ceu_cam *cam = icd->host_priv; | 1666 | struct sh_mobile_ceu_cam *cam = icd->host_priv; |
| 1544 | struct device *dev = icd->parent; | 1667 | struct device *dev = icd->parent; |
| @@ -1574,8 +1697,8 @@ static void calculate_client_output(struct soc_camera_device *icd, | |||
| 1574 | dev_geo(dev, "3: scales %u:%u\n", scale_h, scale_v); | 1697 | dev_geo(dev, "3: scales %u:%u\n", scale_h, scale_v); |
| 1575 | 1698 | ||
| 1576 | /* | 1699 | /* |
| 1577 | * 4. Calculate client output window by applying combined scales to real | 1700 | * 4. Calculate desired client output window by applying combined scales |
| 1578 | * input window. | 1701 | * to client (real) input window. |
| 1579 | */ | 1702 | */ |
| 1580 | mf->width = scale_down(cam->rect.width, scale_h); | 1703 | mf->width = scale_down(cam->rect.width, scale_h); |
| 1581 | mf->height = scale_down(cam->rect.height, scale_v); | 1704 | mf->height = scale_down(cam->rect.height, scale_v); |
| @@ -1600,8 +1723,6 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, | |||
| 1600 | bool image_mode; | 1723 | bool image_mode; |
| 1601 | enum v4l2_field field; | 1724 | enum v4l2_field field; |
| 1602 | 1725 | ||
| 1603 | dev_geo(dev, "S_FMT(pix=0x%x, %ux%u)\n", pixfmt, pix->width, pix->height); | ||
| 1604 | |||
| 1605 | switch (pix->field) { | 1726 | switch (pix->field) { |
| 1606 | default: | 1727 | default: |
| 1607 | pix->field = V4L2_FIELD_NONE; | 1728 | pix->field = V4L2_FIELD_NONE; |
| @@ -1622,8 +1743,8 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, | |||
| 1622 | return -EINVAL; | 1743 | return -EINVAL; |
| 1623 | } | 1744 | } |
| 1624 | 1745 | ||
| 1625 | /* 1.-4. Calculate client output geometry */ | 1746 | /* 1.-4. Calculate desired client output geometry */ |
| 1626 | calculate_client_output(icd, &f->fmt.pix, &mf); | 1747 | calculate_client_output(icd, pix, &mf); |
| 1627 | mf.field = pix->field; | 1748 | mf.field = pix->field; |
| 1628 | mf.colorspace = pix->colorspace; | 1749 | mf.colorspace = pix->colorspace; |
| 1629 | mf.code = xlate->code; | 1750 | mf.code = xlate->code; |
| @@ -1639,6 +1760,9 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, | |||
| 1639 | image_mode = false; | 1760 | image_mode = false; |
| 1640 | } | 1761 | } |
| 1641 | 1762 | ||
| 1763 | dev_geo(dev, "S_FMT(pix=0x%x, fld 0x%x, code 0x%x, %ux%u)\n", pixfmt, mf.field, mf.code, | ||
| 1764 | pix->width, pix->height); | ||
| 1765 | |||
| 1642 | dev_geo(dev, "4: request camera output %ux%u\n", mf.width, mf.height); | 1766 | dev_geo(dev, "4: request camera output %ux%u\n", mf.width, mf.height); |
| 1643 | 1767 | ||
| 1644 | /* 5. - 9. */ | 1768 | /* 5. - 9. */ |
| @@ -1700,6 +1824,10 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, | |||
| 1700 | pcdev->field = field; | 1824 | pcdev->field = field; |
| 1701 | pcdev->image_mode = image_mode; | 1825 | pcdev->image_mode = image_mode; |
| 1702 | 1826 | ||
| 1827 | /* CFSZR requirement */ | ||
| 1828 | pix->width &= ~3; | ||
| 1829 | pix->height &= ~3; | ||
| 1830 | |||
| 1703 | return 0; | 1831 | return 0; |
| 1704 | } | 1832 | } |
| 1705 | 1833 | ||
| @@ -1725,7 +1853,8 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, | |||
| 1725 | 1853 | ||
| 1726 | /* FIXME: calculate using depth and bus width */ | 1854 | /* FIXME: calculate using depth and bus width */ |
| 1727 | 1855 | ||
| 1728 | v4l_bound_align_image(&pix->width, 2, 2560, 1, | 1856 | /* CFSZR requires height and width to be 4-pixel aligned */ |
| 1857 | v4l_bound_align_image(&pix->width, 2, 2560, 2, | ||
| 1729 | &pix->height, 4, 1920, 2, 0); | 1858 | &pix->height, 4, 1920, 2, 0); |
| 1730 | 1859 | ||
| 1731 | width = pix->width; | 1860 | width = pix->width; |
| @@ -1778,6 +1907,9 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, | |||
| 1778 | pix->height = height; | 1907 | pix->height = height; |
| 1779 | } | 1908 | } |
| 1780 | 1909 | ||
| 1910 | pix->width &= ~3; | ||
| 1911 | pix->height &= ~3; | ||
| 1912 | |||
| 1781 | dev_geo(icd->parent, "%s(): return %d, fmt 0x%x, %ux%u\n", | 1913 | dev_geo(icd->parent, "%s(): return %d, fmt 0x%x, %ux%u\n", |
| 1782 | __func__, ret, pix->pixelformat, pix->width, pix->height); | 1914 | __func__, ret, pix->pixelformat, pix->width, pix->height); |
| 1783 | 1915 | ||
| @@ -1824,8 +1956,8 @@ static int sh_mobile_ceu_set_livecrop(struct soc_camera_device *icd, | |||
| 1824 | out_height != f.fmt.pix.height)) | 1956 | out_height != f.fmt.pix.height)) |
| 1825 | ret = -EINVAL; | 1957 | ret = -EINVAL; |
| 1826 | if (!ret) { | 1958 | if (!ret) { |
| 1827 | icd->user_width = out_width; | 1959 | icd->user_width = out_width & ~3; |
| 1828 | icd->user_height = out_height; | 1960 | icd->user_height = out_height & ~3; |
| 1829 | ret = sh_mobile_ceu_set_bus_param(icd, | 1961 | ret = sh_mobile_ceu_set_bus_param(icd, |
| 1830 | icd->current_fmt->host_fmt->fourcc); | 1962 | icd->current_fmt->host_fmt->fourcc); |
| 1831 | } | 1963 | } |
| @@ -1869,55 +2001,6 @@ static int sh_mobile_ceu_init_videobuf(struct vb2_queue *q, | |||
| 1869 | return vb2_queue_init(q); | 2001 | return vb2_queue_init(q); |
| 1870 | } | 2002 | } |
| 1871 | 2003 | ||
| 1872 | static int sh_mobile_ceu_get_ctrl(struct soc_camera_device *icd, | ||
| 1873 | struct v4l2_control *ctrl) | ||
| 1874 | { | ||
| 1875 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
| 1876 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
| 1877 | u32 val; | ||
| 1878 | |||
| 1879 | switch (ctrl->id) { | ||
| 1880 | case V4L2_CID_SHARPNESS: | ||
| 1881 | val = ceu_read(pcdev, CLFCR); | ||
| 1882 | ctrl->value = val ^ 1; | ||
| 1883 | return 0; | ||
| 1884 | } | ||
| 1885 | return -ENOIOCTLCMD; | ||
| 1886 | } | ||
| 1887 | |||
| 1888 | static int sh_mobile_ceu_set_ctrl(struct soc_camera_device *icd, | ||
| 1889 | struct v4l2_control *ctrl) | ||
| 1890 | { | ||
| 1891 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
| 1892 | struct sh_mobile_ceu_dev *pcdev = ici->priv; | ||
| 1893 | |||
| 1894 | switch (ctrl->id) { | ||
| 1895 | case V4L2_CID_SHARPNESS: | ||
| 1896 | switch (icd->current_fmt->host_fmt->fourcc) { | ||
| 1897 | case V4L2_PIX_FMT_NV12: | ||
| 1898 | case V4L2_PIX_FMT_NV21: | ||
| 1899 | case V4L2_PIX_FMT_NV16: | ||
| 1900 | case V4L2_PIX_FMT_NV61: | ||
| 1901 | ceu_write(pcdev, CLFCR, !ctrl->value); | ||
| 1902 | return 0; | ||
| 1903 | } | ||
| 1904 | return -EINVAL; | ||
| 1905 | } | ||
| 1906 | return -ENOIOCTLCMD; | ||
| 1907 | } | ||
| 1908 | |||
| 1909 | static const struct v4l2_queryctrl sh_mobile_ceu_controls[] = { | ||
| 1910 | { | ||
| 1911 | .id = V4L2_CID_SHARPNESS, | ||
| 1912 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
| 1913 | .name = "Low-pass filter", | ||
| 1914 | .minimum = 0, | ||
| 1915 | .maximum = 1, | ||
| 1916 | .step = 1, | ||
| 1917 | .default_value = 0, | ||
| 1918 | }, | ||
| 1919 | }; | ||
| 1920 | |||
| 1921 | static struct soc_camera_host_ops sh_mobile_ceu_host_ops = { | 2004 | static struct soc_camera_host_ops sh_mobile_ceu_host_ops = { |
| 1922 | .owner = THIS_MODULE, | 2005 | .owner = THIS_MODULE, |
| 1923 | .add = sh_mobile_ceu_add_device, | 2006 | .add = sh_mobile_ceu_add_device, |
| @@ -1929,14 +2012,10 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = { | |||
| 1929 | .set_livecrop = sh_mobile_ceu_set_livecrop, | 2012 | .set_livecrop = sh_mobile_ceu_set_livecrop, |
| 1930 | .set_fmt = sh_mobile_ceu_set_fmt, | 2013 | .set_fmt = sh_mobile_ceu_set_fmt, |
| 1931 | .try_fmt = sh_mobile_ceu_try_fmt, | 2014 | .try_fmt = sh_mobile_ceu_try_fmt, |
| 1932 | .set_ctrl = sh_mobile_ceu_set_ctrl, | ||
| 1933 | .get_ctrl = sh_mobile_ceu_get_ctrl, | ||
| 1934 | .poll = sh_mobile_ceu_poll, | 2015 | .poll = sh_mobile_ceu_poll, |
| 1935 | .querycap = sh_mobile_ceu_querycap, | 2016 | .querycap = sh_mobile_ceu_querycap, |
| 1936 | .set_bus_param = sh_mobile_ceu_set_bus_param, | 2017 | .set_bus_param = sh_mobile_ceu_set_bus_param, |
| 1937 | .init_videobuf2 = sh_mobile_ceu_init_videobuf, | 2018 | .init_videobuf2 = sh_mobile_ceu_init_videobuf, |
| 1938 | .controls = sh_mobile_ceu_controls, | ||
| 1939 | .num_controls = ARRAY_SIZE(sh_mobile_ceu_controls), | ||
| 1940 | }; | 2019 | }; |
| 1941 | 2020 | ||
| 1942 | struct bus_wait { | 2021 | struct bus_wait { |
diff --git a/drivers/media/video/sh_mobile_csi2.c b/drivers/media/video/sh_mobile_csi2.c index 2893a0134c7e..37706eb81f25 100644 --- a/drivers/media/video/sh_mobile_csi2.c +++ b/drivers/media/video/sh_mobile_csi2.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include <media/sh_mobile_ceu.h> | 19 | #include <media/sh_mobile_ceu.h> |
| 20 | #include <media/sh_mobile_csi2.h> | 20 | #include <media/sh_mobile_csi2.h> |
| 21 | #include <media/soc_camera.h> | 21 | #include <media/soc_camera.h> |
| 22 | #include <media/soc_mediabus.h> | ||
| 22 | #include <media/v4l2-common.h> | 23 | #include <media/v4l2-common.h> |
| 23 | #include <media/v4l2-dev.h> | 24 | #include <media/v4l2-dev.h> |
| 24 | #include <media/v4l2-device.h> | 25 | #include <media/v4l2-device.h> |
| @@ -35,11 +36,10 @@ struct sh_csi2 { | |||
| 35 | struct v4l2_subdev subdev; | 36 | struct v4l2_subdev subdev; |
| 36 | struct list_head list; | 37 | struct list_head list; |
| 37 | unsigned int irq; | 38 | unsigned int irq; |
| 39 | unsigned long mipi_flags; | ||
| 38 | void __iomem *base; | 40 | void __iomem *base; |
| 39 | struct platform_device *pdev; | 41 | struct platform_device *pdev; |
| 40 | struct sh_csi2_client_config *client; | 42 | struct sh_csi2_client_config *client; |
| 41 | unsigned long (*query_bus_param)(struct soc_camera_device *); | ||
| 42 | int (*set_bus_param)(struct soc_camera_device *, unsigned long); | ||
| 43 | }; | 43 | }; |
| 44 | 44 | ||
| 45 | static int sh_csi2_try_fmt(struct v4l2_subdev *sd, | 45 | static int sh_csi2_try_fmt(struct v4l2_subdev *sd, |
| @@ -127,9 +127,34 @@ static int sh_csi2_s_fmt(struct v4l2_subdev *sd, | |||
| 127 | return 0; | 127 | return 0; |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | static int sh_csi2_g_mbus_config(struct v4l2_subdev *sd, | ||
| 131 | struct v4l2_mbus_config *cfg) | ||
| 132 | { | ||
| 133 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | | ||
| 134 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | | ||
| 135 | V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH; | ||
| 136 | cfg->type = V4L2_MBUS_PARALLEL; | ||
| 137 | |||
| 138 | return 0; | ||
| 139 | } | ||
| 140 | |||
| 141 | static int sh_csi2_s_mbus_config(struct v4l2_subdev *sd, | ||
| 142 | const struct v4l2_mbus_config *cfg) | ||
| 143 | { | ||
| 144 | struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev); | ||
| 145 | struct soc_camera_device *icd = (struct soc_camera_device *)sd->grp_id; | ||
| 146 | struct v4l2_subdev *client_sd = soc_camera_to_subdev(icd); | ||
| 147 | struct v4l2_mbus_config client_cfg = {.type = V4L2_MBUS_CSI2, | ||
| 148 | .flags = priv->mipi_flags}; | ||
| 149 | |||
| 150 | return v4l2_subdev_call(client_sd, video, s_mbus_config, &client_cfg); | ||
| 151 | } | ||
| 152 | |||
| 130 | static struct v4l2_subdev_video_ops sh_csi2_subdev_video_ops = { | 153 | static struct v4l2_subdev_video_ops sh_csi2_subdev_video_ops = { |
| 131 | .s_mbus_fmt = sh_csi2_s_fmt, | 154 | .s_mbus_fmt = sh_csi2_s_fmt, |
| 132 | .try_mbus_fmt = sh_csi2_try_fmt, | 155 | .try_mbus_fmt = sh_csi2_try_fmt, |
| 156 | .g_mbus_config = sh_csi2_g_mbus_config, | ||
| 157 | .s_mbus_config = sh_csi2_s_mbus_config, | ||
| 133 | }; | 158 | }; |
| 134 | 159 | ||
| 135 | static void sh_csi2_hwinit(struct sh_csi2 *priv) | 160 | static void sh_csi2_hwinit(struct sh_csi2 *priv) |
| @@ -144,11 +169,21 @@ static void sh_csi2_hwinit(struct sh_csi2 *priv) | |||
| 144 | udelay(5); | 169 | udelay(5); |
| 145 | iowrite32(0x00000000, priv->base + SH_CSI2_SRST); | 170 | iowrite32(0x00000000, priv->base + SH_CSI2_SRST); |
| 146 | 171 | ||
| 147 | if (priv->client->lanes & 3) | 172 | switch (pdata->type) { |
| 148 | tmp |= priv->client->lanes & 3; | 173 | case SH_CSI2C: |
| 149 | else | 174 | if (priv->client->lanes == 1) |
| 150 | /* Default - both lanes */ | 175 | tmp |= 1; |
| 151 | tmp |= 3; | 176 | else |
| 177 | /* Default - both lanes */ | ||
| 178 | tmp |= 3; | ||
| 179 | break; | ||
| 180 | case SH_CSI2I: | ||
| 181 | if (!priv->client->lanes || priv->client->lanes > 4) | ||
| 182 | /* Default - all 4 lanes */ | ||
| 183 | tmp |= 0xf; | ||
| 184 | else | ||
| 185 | tmp |= (1 << priv->client->lanes) - 1; | ||
| 186 | } | ||
| 152 | 187 | ||
| 153 | if (priv->client->phy == SH_CSI2_PHY_MAIN) | 188 | if (priv->client->phy == SH_CSI2_PHY_MAIN) |
| 154 | tmp |= 0x8000; | 189 | tmp |= 0x8000; |
| @@ -163,38 +198,18 @@ static void sh_csi2_hwinit(struct sh_csi2 *priv) | |||
| 163 | iowrite32(tmp, priv->base + SH_CSI2_CHKSUM); | 198 | iowrite32(tmp, priv->base + SH_CSI2_CHKSUM); |
| 164 | } | 199 | } |
| 165 | 200 | ||
| 166 | static int sh_csi2_set_bus_param(struct soc_camera_device *icd, | ||
| 167 | unsigned long flags) | ||
| 168 | { | ||
| 169 | return 0; | ||
| 170 | } | ||
| 171 | |||
| 172 | static unsigned long sh_csi2_query_bus_param(struct soc_camera_device *icd) | ||
| 173 | { | ||
| 174 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
| 175 | const unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | | ||
| 176 | SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | | ||
| 177 | SOCAM_MASTER | SOCAM_DATAWIDTH_8 | SOCAM_DATA_ACTIVE_HIGH; | ||
| 178 | |||
| 179 | return soc_camera_apply_sensor_flags(icl, flags); | ||
| 180 | } | ||
| 181 | |||
| 182 | static int sh_csi2_client_connect(struct sh_csi2 *priv) | 201 | static int sh_csi2_client_connect(struct sh_csi2 *priv) |
| 183 | { | 202 | { |
| 184 | struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data; | 203 | struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data; |
| 185 | struct v4l2_subdev *sd, *csi2_sd = &priv->subdev; | 204 | struct soc_camera_device *icd = (struct soc_camera_device *)priv->subdev.grp_id; |
| 186 | struct soc_camera_device *icd = NULL; | 205 | struct v4l2_subdev *client_sd = soc_camera_to_subdev(icd); |
| 187 | struct device *dev = v4l2_get_subdevdata(&priv->subdev); | 206 | struct device *dev = v4l2_get_subdevdata(&priv->subdev); |
| 188 | int i; | 207 | struct v4l2_mbus_config cfg; |
| 208 | unsigned long common_flags, csi2_flags; | ||
| 209 | int i, ret; | ||
| 189 | 210 | ||
| 190 | v4l2_device_for_each_subdev(sd, csi2_sd->v4l2_dev) | 211 | if (priv->client) |
| 191 | if (sd->grp_id) { | 212 | return -EBUSY; |
| 192 | icd = (struct soc_camera_device *)sd->grp_id; | ||
| 193 | break; | ||
| 194 | } | ||
| 195 | |||
| 196 | if (!icd) | ||
| 197 | return -EINVAL; | ||
| 198 | 213 | ||
| 199 | for (i = 0; i < pdata->num_clients; i++) | 214 | for (i = 0; i < pdata->num_clients; i++) |
| 200 | if (&pdata->clients[i].pdev->dev == icd->pdev) | 215 | if (&pdata->clients[i].pdev->dev == icd->pdev) |
| @@ -205,14 +220,41 @@ static int sh_csi2_client_connect(struct sh_csi2 *priv) | |||
| 205 | if (i == pdata->num_clients) | 220 | if (i == pdata->num_clients) |
| 206 | return -ENODEV; | 221 | return -ENODEV; |
| 207 | 222 | ||
| 208 | priv->client = pdata->clients + i; | 223 | /* Check if we can support this camera */ |
| 224 | csi2_flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK | V4L2_MBUS_CSI2_1_LANE; | ||
| 225 | |||
| 226 | switch (pdata->type) { | ||
| 227 | case SH_CSI2C: | ||
| 228 | if (pdata->clients[i].lanes != 1) | ||
| 229 | csi2_flags |= V4L2_MBUS_CSI2_2_LANE; | ||
| 230 | break; | ||
| 231 | case SH_CSI2I: | ||
| 232 | switch (pdata->clients[i].lanes) { | ||
| 233 | default: | ||
| 234 | csi2_flags |= V4L2_MBUS_CSI2_4_LANE; | ||
| 235 | case 3: | ||
| 236 | csi2_flags |= V4L2_MBUS_CSI2_3_LANE; | ||
| 237 | case 2: | ||
| 238 | csi2_flags |= V4L2_MBUS_CSI2_2_LANE; | ||
| 239 | } | ||
| 240 | } | ||
| 209 | 241 | ||
| 210 | priv->set_bus_param = icd->ops->set_bus_param; | 242 | cfg.type = V4L2_MBUS_CSI2; |
| 211 | priv->query_bus_param = icd->ops->query_bus_param; | 243 | ret = v4l2_subdev_call(client_sd, video, g_mbus_config, &cfg); |
| 212 | icd->ops->set_bus_param = sh_csi2_set_bus_param; | 244 | if (ret == -ENOIOCTLCMD) |
| 213 | icd->ops->query_bus_param = sh_csi2_query_bus_param; | 245 | common_flags = csi2_flags; |
| 246 | else if (!ret) | ||
| 247 | common_flags = soc_mbus_config_compatible(&cfg, | ||
| 248 | csi2_flags); | ||
| 249 | else | ||
| 250 | common_flags = 0; | ||
| 214 | 251 | ||
| 215 | csi2_sd->grp_id = (long)icd; | 252 | if (!common_flags) |
| 253 | return -EINVAL; | ||
| 254 | |||
| 255 | /* All good: camera MIPI configuration supported */ | ||
| 256 | priv->mipi_flags = common_flags; | ||
| 257 | priv->client = pdata->clients + i; | ||
| 216 | 258 | ||
| 217 | pm_runtime_get_sync(dev); | 259 | pm_runtime_get_sync(dev); |
| 218 | 260 | ||
| @@ -223,16 +265,10 @@ static int sh_csi2_client_connect(struct sh_csi2 *priv) | |||
| 223 | 265 | ||
| 224 | static void sh_csi2_client_disconnect(struct sh_csi2 *priv) | 266 | static void sh_csi2_client_disconnect(struct sh_csi2 *priv) |
| 225 | { | 267 | { |
| 226 | struct soc_camera_device *icd = (struct soc_camera_device *)priv->subdev.grp_id; | 268 | if (!priv->client) |
| 269 | return; | ||
| 227 | 270 | ||
| 228 | priv->client = NULL; | 271 | priv->client = NULL; |
| 229 | priv->subdev.grp_id = 0; | ||
| 230 | |||
| 231 | /* Driver is about to be unbound */ | ||
| 232 | icd->ops->set_bus_param = priv->set_bus_param; | ||
| 233 | icd->ops->query_bus_param = priv->query_bus_param; | ||
| 234 | priv->set_bus_param = NULL; | ||
| 235 | priv->query_bus_param = NULL; | ||
| 236 | 272 | ||
| 237 | pm_runtime_put(v4l2_get_subdevdata(&priv->subdev)); | 273 | pm_runtime_put(v4l2_get_subdevdata(&priv->subdev)); |
| 238 | } | 274 | } |
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 5bdfe7e16bc1..b72580c38957 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c | |||
| @@ -50,49 +50,65 @@ static LIST_HEAD(hosts); | |||
| 50 | static LIST_HEAD(devices); | 50 | static LIST_HEAD(devices); |
| 51 | static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */ | 51 | static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */ |
| 52 | 52 | ||
| 53 | static int soc_camera_power_set(struct soc_camera_device *icd, | 53 | static int soc_camera_power_on(struct soc_camera_device *icd, |
| 54 | struct soc_camera_link *icl, | 54 | struct soc_camera_link *icl) |
| 55 | int power_on) | ||
| 56 | { | 55 | { |
| 57 | int ret; | 56 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
| 58 | 57 | int ret = regulator_bulk_enable(icl->num_regulators, | |
| 59 | if (power_on) { | 58 | icl->regulators); |
| 60 | ret = regulator_bulk_enable(icl->num_regulators, | 59 | if (ret < 0) { |
| 61 | icl->regulators); | 60 | dev_err(icd->pdev, "Cannot enable regulators\n"); |
| 62 | if (ret < 0) { | 61 | return ret; |
| 63 | dev_err(icd->pdev, "Cannot enable regulators\n"); | 62 | } |
| 64 | return ret; | ||
| 65 | } | ||
| 66 | 63 | ||
| 67 | if (icl->power) | 64 | if (icl->power) { |
| 68 | ret = icl->power(icd->pdev, power_on); | 65 | ret = icl->power(icd->pdev, 1); |
| 69 | if (ret < 0) { | 66 | if (ret < 0) { |
| 70 | dev_err(icd->pdev, | 67 | dev_err(icd->pdev, |
| 71 | "Platform failed to power-on the camera.\n"); | 68 | "Platform failed to power-on the camera.\n"); |
| 72 | 69 | goto elinkpwr; | |
| 73 | regulator_bulk_disable(icl->num_regulators, | ||
| 74 | icl->regulators); | ||
| 75 | return ret; | ||
| 76 | } | 70 | } |
| 77 | } else { | 71 | } |
| 78 | ret = 0; | 72 | |
| 79 | if (icl->power) | 73 | ret = v4l2_subdev_call(sd, core, s_power, 1); |
| 80 | ret = icl->power(icd->pdev, 0); | 74 | if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) |
| 75 | goto esdpwr; | ||
| 76 | |||
| 77 | return 0; | ||
| 78 | |||
| 79 | esdpwr: | ||
| 80 | if (icl->power) | ||
| 81 | icl->power(icd->pdev, 0); | ||
| 82 | elinkpwr: | ||
| 83 | regulator_bulk_disable(icl->num_regulators, | ||
| 84 | icl->regulators); | ||
| 85 | return ret; | ||
| 86 | } | ||
| 87 | |||
| 88 | static int soc_camera_power_off(struct soc_camera_device *icd, | ||
| 89 | struct soc_camera_link *icl) | ||
| 90 | { | ||
| 91 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
| 92 | int ret = v4l2_subdev_call(sd, core, s_power, 0); | ||
| 93 | |||
| 94 | if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) | ||
| 95 | return ret; | ||
| 96 | |||
| 97 | if (icl->power) { | ||
| 98 | ret = icl->power(icd->pdev, 0); | ||
| 81 | if (ret < 0) { | 99 | if (ret < 0) { |
| 82 | dev_err(icd->pdev, | 100 | dev_err(icd->pdev, |
| 83 | "Platform failed to power-off the camera.\n"); | 101 | "Platform failed to power-off the camera.\n"); |
| 84 | return ret; | 102 | return ret; |
| 85 | } | 103 | } |
| 86 | |||
| 87 | ret = regulator_bulk_disable(icl->num_regulators, | ||
| 88 | icl->regulators); | ||
| 89 | if (ret < 0) { | ||
| 90 | dev_err(icd->pdev, "Cannot disable regulators\n"); | ||
| 91 | return ret; | ||
| 92 | } | ||
| 93 | } | 104 | } |
| 94 | 105 | ||
| 95 | return 0; | 106 | ret = regulator_bulk_disable(icl->num_regulators, |
| 107 | icl->regulators); | ||
| 108 | if (ret < 0) | ||
| 109 | dev_err(icd->pdev, "Cannot disable regulators\n"); | ||
| 110 | |||
| 111 | return ret; | ||
| 96 | } | 112 | } |
| 97 | 113 | ||
| 98 | const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc( | 114 | const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc( |
| @@ -108,38 +124,38 @@ const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc( | |||
| 108 | EXPORT_SYMBOL(soc_camera_xlate_by_fourcc); | 124 | EXPORT_SYMBOL(soc_camera_xlate_by_fourcc); |
| 109 | 125 | ||
| 110 | /** | 126 | /** |
| 111 | * soc_camera_apply_sensor_flags() - apply platform SOCAM_SENSOR_INVERT_* flags | 127 | * soc_camera_apply_board_flags() - apply platform SOCAM_SENSOR_INVERT_* flags |
| 112 | * @icl: camera platform parameters | 128 | * @icl: camera platform parameters |
| 113 | * @flags: flags to be inverted according to platform configuration | 129 | * @cfg: media bus configuration |
| 114 | * @return: resulting flags | 130 | * @return: resulting flags |
| 115 | */ | 131 | */ |
| 116 | unsigned long soc_camera_apply_sensor_flags(struct soc_camera_link *icl, | 132 | unsigned long soc_camera_apply_board_flags(struct soc_camera_link *icl, |
| 117 | unsigned long flags) | 133 | const struct v4l2_mbus_config *cfg) |
| 118 | { | 134 | { |
| 119 | unsigned long f; | 135 | unsigned long f, flags = cfg->flags; |
| 120 | 136 | ||
| 121 | /* If only one of the two polarities is supported, switch to the opposite */ | 137 | /* If only one of the two polarities is supported, switch to the opposite */ |
| 122 | if (icl->flags & SOCAM_SENSOR_INVERT_HSYNC) { | 138 | if (icl->flags & SOCAM_SENSOR_INVERT_HSYNC) { |
| 123 | f = flags & (SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW); | 139 | f = flags & (V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW); |
| 124 | if (f == SOCAM_HSYNC_ACTIVE_HIGH || f == SOCAM_HSYNC_ACTIVE_LOW) | 140 | if (f == V4L2_MBUS_HSYNC_ACTIVE_HIGH || f == V4L2_MBUS_HSYNC_ACTIVE_LOW) |
| 125 | flags ^= SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW; | 141 | flags ^= V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW; |
| 126 | } | 142 | } |
| 127 | 143 | ||
| 128 | if (icl->flags & SOCAM_SENSOR_INVERT_VSYNC) { | 144 | if (icl->flags & SOCAM_SENSOR_INVERT_VSYNC) { |
| 129 | f = flags & (SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW); | 145 | f = flags & (V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW); |
| 130 | if (f == SOCAM_VSYNC_ACTIVE_HIGH || f == SOCAM_VSYNC_ACTIVE_LOW) | 146 | if (f == V4L2_MBUS_VSYNC_ACTIVE_HIGH || f == V4L2_MBUS_VSYNC_ACTIVE_LOW) |
| 131 | flags ^= SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW; | 147 | flags ^= V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW; |
| 132 | } | 148 | } |
| 133 | 149 | ||
| 134 | if (icl->flags & SOCAM_SENSOR_INVERT_PCLK) { | 150 | if (icl->flags & SOCAM_SENSOR_INVERT_PCLK) { |
| 135 | f = flags & (SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING); | 151 | f = flags & (V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING); |
| 136 | if (f == SOCAM_PCLK_SAMPLE_RISING || f == SOCAM_PCLK_SAMPLE_FALLING) | 152 | if (f == V4L2_MBUS_PCLK_SAMPLE_RISING || f == V4L2_MBUS_PCLK_SAMPLE_FALLING) |
| 137 | flags ^= SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING; | 153 | flags ^= V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING; |
| 138 | } | 154 | } |
| 139 | 155 | ||
| 140 | return flags; | 156 | return flags; |
| 141 | } | 157 | } |
| 142 | EXPORT_SYMBOL(soc_camera_apply_sensor_flags); | 158 | EXPORT_SYMBOL(soc_camera_apply_board_flags); |
| 143 | 159 | ||
| 144 | #define pixfmtstr(x) (x) & 0xff, ((x) >> 8) & 0xff, ((x) >> 16) & 0xff, \ | 160 | #define pixfmtstr(x) (x) & 0xff, ((x) >> 8) & 0xff, ((x) >> 16) & 0xff, \ |
| 145 | ((x) >> 24) & 0xff | 161 | ((x) >> 24) & 0xff |
| @@ -233,6 +249,14 @@ static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a) | |||
| 233 | return v4l2_subdev_call(sd, core, s_std, *a); | 249 | return v4l2_subdev_call(sd, core, s_std, *a); |
| 234 | } | 250 | } |
| 235 | 251 | ||
| 252 | static int soc_camera_g_std(struct file *file, void *priv, v4l2_std_id *a) | ||
| 253 | { | ||
| 254 | struct soc_camera_device *icd = file->private_data; | ||
| 255 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
| 256 | |||
| 257 | return v4l2_subdev_call(sd, core, g_std, a); | ||
| 258 | } | ||
| 259 | |||
| 236 | static int soc_camera_enum_fsizes(struct file *file, void *fh, | 260 | static int soc_camera_enum_fsizes(struct file *file, void *fh, |
| 237 | struct v4l2_frmsizeenum *fsize) | 261 | struct v4l2_frmsizeenum *fsize) |
| 238 | { | 262 | { |
| @@ -318,6 +342,32 @@ static int soc_camera_dqbuf(struct file *file, void *priv, | |||
| 318 | return vb2_dqbuf(&icd->vb2_vidq, p, file->f_flags & O_NONBLOCK); | 342 | return vb2_dqbuf(&icd->vb2_vidq, p, file->f_flags & O_NONBLOCK); |
| 319 | } | 343 | } |
| 320 | 344 | ||
| 345 | static int soc_camera_create_bufs(struct file *file, void *priv, | ||
| 346 | struct v4l2_create_buffers *create) | ||
| 347 | { | ||
| 348 | struct soc_camera_device *icd = file->private_data; | ||
| 349 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
| 350 | |||
| 351 | /* videobuf2 only */ | ||
| 352 | if (ici->ops->init_videobuf) | ||
| 353 | return -EINVAL; | ||
| 354 | else | ||
| 355 | return vb2_create_bufs(&icd->vb2_vidq, create); | ||
| 356 | } | ||
| 357 | |||
| 358 | static int soc_camera_prepare_buf(struct file *file, void *priv, | ||
| 359 | struct v4l2_buffer *b) | ||
| 360 | { | ||
| 361 | struct soc_camera_device *icd = file->private_data; | ||
| 362 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
| 363 | |||
| 364 | /* videobuf2 only */ | ||
| 365 | if (ici->ops->init_videobuf) | ||
| 366 | return -EINVAL; | ||
| 367 | else | ||
| 368 | return vb2_prepare_buf(&icd->vb2_vidq, b); | ||
| 369 | } | ||
| 370 | |||
| 321 | /* Always entered with .video_lock held */ | 371 | /* Always entered with .video_lock held */ |
| 322 | static int soc_camera_init_user_formats(struct soc_camera_device *icd) | 372 | static int soc_camera_init_user_formats(struct soc_camera_device *icd) |
| 323 | { | 373 | { |
| @@ -448,7 +498,7 @@ static int soc_camera_open(struct file *file) | |||
| 448 | struct soc_camera_host *ici; | 498 | struct soc_camera_host *ici; |
| 449 | int ret; | 499 | int ret; |
| 450 | 500 | ||
| 451 | if (!icd->ops) | 501 | if (!to_soc_camera_control(icd)) |
| 452 | /* No device driver attached */ | 502 | /* No device driver attached */ |
| 453 | return -ENODEV; | 503 | return -ENODEV; |
| 454 | 504 | ||
| @@ -476,7 +526,7 @@ static int soc_camera_open(struct file *file) | |||
| 476 | }, | 526 | }, |
| 477 | }; | 527 | }; |
| 478 | 528 | ||
| 479 | ret = soc_camera_power_set(icd, icl, 1); | 529 | ret = soc_camera_power_on(icd, icl); |
| 480 | if (ret < 0) | 530 | if (ret < 0) |
| 481 | goto epower; | 531 | goto epower; |
| 482 | 532 | ||
| @@ -512,6 +562,7 @@ static int soc_camera_open(struct file *file) | |||
| 512 | if (ret < 0) | 562 | if (ret < 0) |
| 513 | goto einitvb; | 563 | goto einitvb; |
| 514 | } | 564 | } |
| 565 | v4l2_ctrl_handler_setup(&icd->ctrl_handler); | ||
| 515 | } | 566 | } |
| 516 | 567 | ||
| 517 | file->private_data = icd; | 568 | file->private_data = icd; |
| @@ -529,7 +580,7 @@ esfmt: | |||
| 529 | eresume: | 580 | eresume: |
| 530 | ici->ops->remove(icd); | 581 | ici->ops->remove(icd); |
| 531 | eiciadd: | 582 | eiciadd: |
| 532 | soc_camera_power_set(icd, icl, 0); | 583 | soc_camera_power_off(icd, icl); |
| 533 | epower: | 584 | epower: |
| 534 | icd->use_count--; | 585 | icd->use_count--; |
| 535 | module_put(ici->ops->owner); | 586 | module_put(ici->ops->owner); |
| @@ -553,7 +604,7 @@ static int soc_camera_close(struct file *file) | |||
| 553 | if (ici->ops->init_videobuf2) | 604 | if (ici->ops->init_videobuf2) |
| 554 | vb2_queue_release(&icd->vb2_vidq); | 605 | vb2_queue_release(&icd->vb2_vidq); |
| 555 | 606 | ||
| 556 | soc_camera_power_set(icd, icl, 0); | 607 | soc_camera_power_off(icd, icl); |
| 557 | } | 608 | } |
| 558 | 609 | ||
| 559 | if (icd->streamer == file) | 610 | if (icd->streamer == file) |
| @@ -781,75 +832,6 @@ static int soc_camera_streamoff(struct file *file, void *priv, | |||
| 781 | return 0; | 832 | return 0; |
| 782 | } | 833 | } |
| 783 | 834 | ||
| 784 | static int soc_camera_queryctrl(struct file *file, void *priv, | ||
| 785 | struct v4l2_queryctrl *qc) | ||
| 786 | { | ||
| 787 | struct soc_camera_device *icd = file->private_data; | ||
| 788 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
| 789 | int i; | ||
| 790 | |||
| 791 | WARN_ON(priv != file->private_data); | ||
| 792 | |||
| 793 | if (!qc->id) | ||
| 794 | return -EINVAL; | ||
| 795 | |||
| 796 | /* First check host controls */ | ||
| 797 | for (i = 0; i < ici->ops->num_controls; i++) | ||
| 798 | if (qc->id == ici->ops->controls[i].id) { | ||
| 799 | memcpy(qc, &(ici->ops->controls[i]), | ||
| 800 | sizeof(*qc)); | ||
| 801 | return 0; | ||
| 802 | } | ||
| 803 | |||
| 804 | /* Then device controls */ | ||
| 805 | for (i = 0; i < icd->ops->num_controls; i++) | ||
| 806 | if (qc->id == icd->ops->controls[i].id) { | ||
| 807 | memcpy(qc, &(icd->ops->controls[i]), | ||
| 808 | sizeof(*qc)); | ||
| 809 | return 0; | ||
| 810 | } | ||
| 811 | |||
| 812 | return -EINVAL; | ||
| 813 | } | ||
| 814 | |||
| 815 | static int soc_camera_g_ctrl(struct file *file, void *priv, | ||
| 816 | struct v4l2_control *ctrl) | ||
| 817 | { | ||
| 818 | struct soc_camera_device *icd = file->private_data; | ||
| 819 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
| 820 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
| 821 | int ret; | ||
| 822 | |||
| 823 | WARN_ON(priv != file->private_data); | ||
| 824 | |||
| 825 | if (ici->ops->get_ctrl) { | ||
| 826 | ret = ici->ops->get_ctrl(icd, ctrl); | ||
| 827 | if (ret != -ENOIOCTLCMD) | ||
| 828 | return ret; | ||
| 829 | } | ||
| 830 | |||
| 831 | return v4l2_subdev_call(sd, core, g_ctrl, ctrl); | ||
| 832 | } | ||
| 833 | |||
| 834 | static int soc_camera_s_ctrl(struct file *file, void *priv, | ||
| 835 | struct v4l2_control *ctrl) | ||
| 836 | { | ||
| 837 | struct soc_camera_device *icd = file->private_data; | ||
| 838 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
| 839 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
| 840 | int ret; | ||
| 841 | |||
| 842 | WARN_ON(priv != file->private_data); | ||
| 843 | |||
| 844 | if (ici->ops->set_ctrl) { | ||
| 845 | ret = ici->ops->set_ctrl(icd, ctrl); | ||
| 846 | if (ret != -ENOIOCTLCMD) | ||
| 847 | return ret; | ||
| 848 | } | ||
| 849 | |||
| 850 | return v4l2_subdev_call(sd, core, s_ctrl, ctrl); | ||
| 851 | } | ||
| 852 | |||
| 853 | static int soc_camera_cropcap(struct file *file, void *fh, | 835 | static int soc_camera_cropcap(struct file *file, void *fh, |
| 854 | struct v4l2_cropcap *a) | 836 | struct v4l2_cropcap *a) |
| 855 | { | 837 | { |
| @@ -1003,7 +985,7 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd, | |||
| 1003 | goto ei2cga; | 985 | goto ei2cga; |
| 1004 | } | 986 | } |
| 1005 | 987 | ||
| 1006 | icl->board_info->platform_data = icd; | 988 | icl->board_info->platform_data = icl; |
| 1007 | 989 | ||
| 1008 | subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap, | 990 | subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap, |
| 1009 | icl->board_info, NULL); | 991 | icl->board_info, NULL); |
| @@ -1052,12 +1034,29 @@ static int soc_camera_probe(struct soc_camera_device *icd) | |||
| 1052 | 1034 | ||
| 1053 | dev_info(icd->pdev, "Probing %s\n", dev_name(icd->pdev)); | 1035 | dev_info(icd->pdev, "Probing %s\n", dev_name(icd->pdev)); |
| 1054 | 1036 | ||
| 1037 | /* | ||
| 1038 | * Currently the subdev with the largest number of controls (13) is | ||
| 1039 | * ov6550. So let's pick 16 as a hint for the control handler. Note | ||
| 1040 | * that this is a hint only: too large and you waste some memory, too | ||
| 1041 | * small and there is a (very) small performance hit when looking up | ||
| 1042 | * controls in the internal hash. | ||
| 1043 | */ | ||
| 1044 | ret = v4l2_ctrl_handler_init(&icd->ctrl_handler, 16); | ||
| 1045 | if (ret < 0) | ||
| 1046 | return ret; | ||
| 1047 | |||
| 1055 | ret = regulator_bulk_get(icd->pdev, icl->num_regulators, | 1048 | ret = regulator_bulk_get(icd->pdev, icl->num_regulators, |
| 1056 | icl->regulators); | 1049 | icl->regulators); |
| 1057 | if (ret < 0) | 1050 | if (ret < 0) |
| 1058 | goto ereg; | 1051 | goto ereg; |
| 1059 | 1052 | ||
| 1060 | ret = soc_camera_power_set(icd, icl, 1); | 1053 | /* |
| 1054 | * This will not yet call v4l2_subdev_core_ops::s_power(1), because the | ||
| 1055 | * subdevice has not been initialised yet. We'll have to call it once | ||
| 1056 | * again after initialisation, even though it shouldn't be needed, we | ||
| 1057 | * don't do any IO here. | ||
| 1058 | */ | ||
| 1059 | ret = soc_camera_power_on(icd, icl); | ||
| 1061 | if (ret < 0) | 1060 | if (ret < 0) |
| 1062 | goto epower; | 1061 | goto epower; |
| 1063 | 1062 | ||
| @@ -1098,6 +1097,7 @@ static int soc_camera_probe(struct soc_camera_device *icd) | |||
| 1098 | if (!control || !control->driver || !dev_get_drvdata(control) || | 1097 | if (!control || !control->driver || !dev_get_drvdata(control) || |
| 1099 | !try_module_get(control->driver->owner)) { | 1098 | !try_module_get(control->driver->owner)) { |
| 1100 | icl->del_device(icd); | 1099 | icl->del_device(icd); |
| 1100 | ret = -ENODEV; | ||
| 1101 | goto enodrv; | 1101 | goto enodrv; |
| 1102 | } | 1102 | } |
| 1103 | } | 1103 | } |
| @@ -1105,6 +1105,9 @@ static int soc_camera_probe(struct soc_camera_device *icd) | |||
| 1105 | sd = soc_camera_to_subdev(icd); | 1105 | sd = soc_camera_to_subdev(icd); |
| 1106 | sd->grp_id = (long)icd; | 1106 | sd->grp_id = (long)icd; |
| 1107 | 1107 | ||
| 1108 | if (v4l2_ctrl_add_handler(&icd->ctrl_handler, sd->ctrl_handler)) | ||
| 1109 | goto ectrl; | ||
| 1110 | |||
| 1108 | /* At this point client .probe() should have run already */ | 1111 | /* At this point client .probe() should have run already */ |
| 1109 | ret = soc_camera_init_user_formats(icd); | 1112 | ret = soc_camera_init_user_formats(icd); |
| 1110 | if (ret < 0) | 1113 | if (ret < 0) |
| @@ -1123,6 +1126,10 @@ static int soc_camera_probe(struct soc_camera_device *icd) | |||
| 1123 | if (ret < 0) | 1126 | if (ret < 0) |
| 1124 | goto evidstart; | 1127 | goto evidstart; |
| 1125 | 1128 | ||
| 1129 | ret = v4l2_subdev_call(sd, core, s_power, 1); | ||
| 1130 | if (ret < 0 && ret != -ENOIOCTLCMD) | ||
| 1131 | goto esdpwr; | ||
| 1132 | |||
| 1126 | /* Try to improve our guess of a reasonable window format */ | 1133 | /* Try to improve our guess of a reasonable window format */ |
| 1127 | if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) { | 1134 | if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) { |
| 1128 | icd->user_width = mf.width; | 1135 | icd->user_width = mf.width; |
| @@ -1133,16 +1140,19 @@ static int soc_camera_probe(struct soc_camera_device *icd) | |||
| 1133 | 1140 | ||
| 1134 | ici->ops->remove(icd); | 1141 | ici->ops->remove(icd); |
| 1135 | 1142 | ||
| 1136 | soc_camera_power_set(icd, icl, 0); | 1143 | soc_camera_power_off(icd, icl); |
| 1137 | 1144 | ||
| 1138 | mutex_unlock(&icd->video_lock); | 1145 | mutex_unlock(&icd->video_lock); |
| 1139 | 1146 | ||
| 1140 | return 0; | 1147 | return 0; |
| 1141 | 1148 | ||
| 1149 | esdpwr: | ||
| 1150 | video_unregister_device(icd->vdev); | ||
| 1142 | evidstart: | 1151 | evidstart: |
| 1143 | mutex_unlock(&icd->video_lock); | 1152 | mutex_unlock(&icd->video_lock); |
| 1144 | soc_camera_free_user_formats(icd); | 1153 | soc_camera_free_user_formats(icd); |
| 1145 | eiufmt: | 1154 | eiufmt: |
| 1155 | ectrl: | ||
| 1146 | if (icl->board_info) { | 1156 | if (icl->board_info) { |
| 1147 | soc_camera_free_i2c(icd); | 1157 | soc_camera_free_i2c(icd); |
| 1148 | } else { | 1158 | } else { |
| @@ -1152,13 +1162,15 @@ eiufmt: | |||
| 1152 | enodrv: | 1162 | enodrv: |
| 1153 | eadddev: | 1163 | eadddev: |
| 1154 | video_device_release(icd->vdev); | 1164 | video_device_release(icd->vdev); |
| 1165 | icd->vdev = NULL; | ||
| 1155 | evdc: | 1166 | evdc: |
| 1156 | ici->ops->remove(icd); | 1167 | ici->ops->remove(icd); |
| 1157 | eadd: | 1168 | eadd: |
| 1158 | soc_camera_power_set(icd, icl, 0); | 1169 | soc_camera_power_off(icd, icl); |
| 1159 | epower: | 1170 | epower: |
| 1160 | regulator_bulk_free(icl->num_regulators, icl->regulators); | 1171 | regulator_bulk_free(icl->num_regulators, icl->regulators); |
| 1161 | ereg: | 1172 | ereg: |
| 1173 | v4l2_ctrl_handler_free(&icd->ctrl_handler); | ||
| 1162 | return ret; | 1174 | return ret; |
| 1163 | } | 1175 | } |
| 1164 | 1176 | ||
| @@ -1173,6 +1185,7 @@ static int soc_camera_remove(struct soc_camera_device *icd) | |||
| 1173 | 1185 | ||
| 1174 | BUG_ON(!icd->parent); | 1186 | BUG_ON(!icd->parent); |
| 1175 | 1187 | ||
| 1188 | v4l2_ctrl_handler_free(&icd->ctrl_handler); | ||
| 1176 | if (vdev) { | 1189 | if (vdev) { |
| 1177 | video_unregister_device(vdev); | 1190 | video_unregister_device(vdev); |
| 1178 | icd->vdev = NULL; | 1191 | icd->vdev = NULL; |
| @@ -1363,24 +1376,24 @@ static int soc_camera_device_register(struct soc_camera_device *icd) | |||
| 1363 | 1376 | ||
| 1364 | static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = { | 1377 | static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = { |
| 1365 | .vidioc_querycap = soc_camera_querycap, | 1378 | .vidioc_querycap = soc_camera_querycap, |
| 1379 | .vidioc_try_fmt_vid_cap = soc_camera_try_fmt_vid_cap, | ||
| 1366 | .vidioc_g_fmt_vid_cap = soc_camera_g_fmt_vid_cap, | 1380 | .vidioc_g_fmt_vid_cap = soc_camera_g_fmt_vid_cap, |
| 1367 | .vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap, | ||
| 1368 | .vidioc_s_fmt_vid_cap = soc_camera_s_fmt_vid_cap, | 1381 | .vidioc_s_fmt_vid_cap = soc_camera_s_fmt_vid_cap, |
| 1382 | .vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap, | ||
| 1369 | .vidioc_enum_input = soc_camera_enum_input, | 1383 | .vidioc_enum_input = soc_camera_enum_input, |
| 1370 | .vidioc_g_input = soc_camera_g_input, | 1384 | .vidioc_g_input = soc_camera_g_input, |
| 1371 | .vidioc_s_input = soc_camera_s_input, | 1385 | .vidioc_s_input = soc_camera_s_input, |
| 1372 | .vidioc_s_std = soc_camera_s_std, | 1386 | .vidioc_s_std = soc_camera_s_std, |
| 1387 | .vidioc_g_std = soc_camera_g_std, | ||
| 1373 | .vidioc_enum_framesizes = soc_camera_enum_fsizes, | 1388 | .vidioc_enum_framesizes = soc_camera_enum_fsizes, |
| 1374 | .vidioc_reqbufs = soc_camera_reqbufs, | 1389 | .vidioc_reqbufs = soc_camera_reqbufs, |
| 1375 | .vidioc_try_fmt_vid_cap = soc_camera_try_fmt_vid_cap, | ||
| 1376 | .vidioc_querybuf = soc_camera_querybuf, | 1390 | .vidioc_querybuf = soc_camera_querybuf, |
| 1377 | .vidioc_qbuf = soc_camera_qbuf, | 1391 | .vidioc_qbuf = soc_camera_qbuf, |
| 1378 | .vidioc_dqbuf = soc_camera_dqbuf, | 1392 | .vidioc_dqbuf = soc_camera_dqbuf, |
| 1393 | .vidioc_create_bufs = soc_camera_create_bufs, | ||
| 1394 | .vidioc_prepare_buf = soc_camera_prepare_buf, | ||
| 1379 | .vidioc_streamon = soc_camera_streamon, | 1395 | .vidioc_streamon = soc_camera_streamon, |
| 1380 | .vidioc_streamoff = soc_camera_streamoff, | 1396 | .vidioc_streamoff = soc_camera_streamoff, |
| 1381 | .vidioc_queryctrl = soc_camera_queryctrl, | ||
| 1382 | .vidioc_g_ctrl = soc_camera_g_ctrl, | ||
| 1383 | .vidioc_s_ctrl = soc_camera_s_ctrl, | ||
| 1384 | .vidioc_cropcap = soc_camera_cropcap, | 1397 | .vidioc_cropcap = soc_camera_cropcap, |
| 1385 | .vidioc_g_crop = soc_camera_g_crop, | 1398 | .vidioc_g_crop = soc_camera_g_crop, |
| 1386 | .vidioc_s_crop = soc_camera_s_crop, | 1399 | .vidioc_s_crop = soc_camera_s_crop, |
| @@ -1409,6 +1422,7 @@ static int video_dev_create(struct soc_camera_device *icd) | |||
| 1409 | vdev->ioctl_ops = &soc_camera_ioctl_ops; | 1422 | vdev->ioctl_ops = &soc_camera_ioctl_ops; |
| 1410 | vdev->release = video_device_release; | 1423 | vdev->release = video_device_release; |
| 1411 | vdev->tvnorms = V4L2_STD_UNKNOWN; | 1424 | vdev->tvnorms = V4L2_STD_UNKNOWN; |
| 1425 | vdev->ctrl_handler = &icd->ctrl_handler; | ||
| 1412 | vdev->lock = &icd->video_lock; | 1426 | vdev->lock = &icd->video_lock; |
| 1413 | 1427 | ||
| 1414 | icd->vdev = vdev; | 1428 | icd->vdev = vdev; |
| @@ -1427,11 +1441,6 @@ static int soc_camera_video_start(struct soc_camera_device *icd) | |||
| 1427 | if (!icd->parent) | 1441 | if (!icd->parent) |
| 1428 | return -ENODEV; | 1442 | return -ENODEV; |
| 1429 | 1443 | ||
| 1430 | if (!icd->ops || | ||
| 1431 | !icd->ops->query_bus_param || | ||
| 1432 | !icd->ops->set_bus_param) | ||
| 1433 | return -EINVAL; | ||
| 1434 | |||
| 1435 | ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER, -1); | 1444 | ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER, -1); |
| 1436 | if (ret < 0) { | 1445 | if (ret < 0) { |
| 1437 | dev_err(icd->pdev, "video_register_device failed: %d\n", ret); | 1446 | dev_err(icd->pdev, "video_register_device failed: %d\n", ret); |
diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c index 8069cd6bc5e8..4402a8a74f7a 100644 --- a/drivers/media/video/soc_camera_platform.c +++ b/drivers/media/video/soc_camera_platform.c | |||
| @@ -30,32 +30,12 @@ static struct soc_camera_platform_priv *get_priv(struct platform_device *pdev) | |||
| 30 | return container_of(subdev, struct soc_camera_platform_priv, subdev); | 30 | return container_of(subdev, struct soc_camera_platform_priv, subdev); |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | static struct soc_camera_platform_info *get_info(struct soc_camera_device *icd) | ||
| 34 | { | ||
| 35 | struct platform_device *pdev = | ||
| 36 | to_platform_device(to_soc_camera_control(icd)); | ||
| 37 | return pdev->dev.platform_data; | ||
| 38 | } | ||
| 39 | |||
| 40 | static int soc_camera_platform_s_stream(struct v4l2_subdev *sd, int enable) | 33 | static int soc_camera_platform_s_stream(struct v4l2_subdev *sd, int enable) |
| 41 | { | 34 | { |
| 42 | struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); | 35 | struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); |
| 43 | return p->set_capture(p, enable); | 36 | return p->set_capture(p, enable); |
| 44 | } | 37 | } |
| 45 | 38 | ||
| 46 | static int soc_camera_platform_set_bus_param(struct soc_camera_device *icd, | ||
| 47 | unsigned long flags) | ||
| 48 | { | ||
| 49 | return 0; | ||
| 50 | } | ||
| 51 | |||
| 52 | static unsigned long | ||
| 53 | soc_camera_platform_query_bus_param(struct soc_camera_device *icd) | ||
| 54 | { | ||
| 55 | struct soc_camera_platform_info *p = get_info(icd); | ||
| 56 | return p->bus_param; | ||
| 57 | } | ||
| 58 | |||
| 59 | static int soc_camera_platform_fill_fmt(struct v4l2_subdev *sd, | 39 | static int soc_camera_platform_fill_fmt(struct v4l2_subdev *sd, |
| 60 | struct v4l2_mbus_framefmt *mf) | 40 | struct v4l2_mbus_framefmt *mf) |
| 61 | { | 41 | { |
| @@ -115,6 +95,17 @@ static int soc_camera_platform_cropcap(struct v4l2_subdev *sd, | |||
| 115 | return 0; | 95 | return 0; |
| 116 | } | 96 | } |
| 117 | 97 | ||
| 98 | static int soc_camera_platform_g_mbus_config(struct v4l2_subdev *sd, | ||
| 99 | struct v4l2_mbus_config *cfg) | ||
| 100 | { | ||
| 101 | struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); | ||
| 102 | |||
| 103 | cfg->flags = p->mbus_param; | ||
| 104 | cfg->type = p->mbus_type; | ||
| 105 | |||
| 106 | return 0; | ||
| 107 | } | ||
| 108 | |||
| 118 | static struct v4l2_subdev_video_ops platform_subdev_video_ops = { | 109 | static struct v4l2_subdev_video_ops platform_subdev_video_ops = { |
| 119 | .s_stream = soc_camera_platform_s_stream, | 110 | .s_stream = soc_camera_platform_s_stream, |
| 120 | .enum_mbus_fmt = soc_camera_platform_enum_fmt, | 111 | .enum_mbus_fmt = soc_camera_platform_enum_fmt, |
| @@ -123,6 +114,7 @@ static struct v4l2_subdev_video_ops platform_subdev_video_ops = { | |||
| 123 | .try_mbus_fmt = soc_camera_platform_fill_fmt, | 114 | .try_mbus_fmt = soc_camera_platform_fill_fmt, |
| 124 | .g_mbus_fmt = soc_camera_platform_fill_fmt, | 115 | .g_mbus_fmt = soc_camera_platform_fill_fmt, |
| 125 | .s_mbus_fmt = soc_camera_platform_fill_fmt, | 116 | .s_mbus_fmt = soc_camera_platform_fill_fmt, |
| 117 | .g_mbus_config = soc_camera_platform_g_mbus_config, | ||
| 126 | }; | 118 | }; |
| 127 | 119 | ||
| 128 | static struct v4l2_subdev_ops platform_subdev_ops = { | 120 | static struct v4l2_subdev_ops platform_subdev_ops = { |
| @@ -130,11 +122,6 @@ static struct v4l2_subdev_ops platform_subdev_ops = { | |||
| 130 | .video = &platform_subdev_video_ops, | 122 | .video = &platform_subdev_video_ops, |
| 131 | }; | 123 | }; |
| 132 | 124 | ||
| 133 | static struct soc_camera_ops soc_camera_platform_ops = { | ||
| 134 | .set_bus_param = soc_camera_platform_set_bus_param, | ||
| 135 | .query_bus_param = soc_camera_platform_query_bus_param, | ||
| 136 | }; | ||
| 137 | |||
| 138 | static int soc_camera_platform_probe(struct platform_device *pdev) | 125 | static int soc_camera_platform_probe(struct platform_device *pdev) |
| 139 | { | 126 | { |
| 140 | struct soc_camera_host *ici; | 127 | struct soc_camera_host *ici; |
| @@ -163,8 +150,6 @@ static int soc_camera_platform_probe(struct platform_device *pdev) | |||
| 163 | /* Set the control device reference */ | 150 | /* Set the control device reference */ |
| 164 | icd->control = &pdev->dev; | 151 | icd->control = &pdev->dev; |
| 165 | 152 | ||
| 166 | icd->ops = &soc_camera_platform_ops; | ||
| 167 | |||
| 168 | ici = to_soc_camera_host(icd->parent); | 153 | ici = to_soc_camera_host(icd->parent); |
| 169 | 154 | ||
| 170 | v4l2_subdev_init(&priv->subdev, &platform_subdev_ops); | 155 | v4l2_subdev_init(&priv->subdev, &platform_subdev_ops); |
| @@ -178,7 +163,6 @@ static int soc_camera_platform_probe(struct platform_device *pdev) | |||
| 178 | return ret; | 163 | return ret; |
| 179 | 164 | ||
| 180 | evdrs: | 165 | evdrs: |
| 181 | icd->ops = NULL; | ||
| 182 | platform_set_drvdata(pdev, NULL); | 166 | platform_set_drvdata(pdev, NULL); |
| 183 | kfree(priv); | 167 | kfree(priv); |
| 184 | return ret; | 168 | return ret; |
| @@ -187,11 +171,10 @@ evdrs: | |||
| 187 | static int soc_camera_platform_remove(struct platform_device *pdev) | 171 | static int soc_camera_platform_remove(struct platform_device *pdev) |
| 188 | { | 172 | { |
| 189 | struct soc_camera_platform_priv *priv = get_priv(pdev); | 173 | struct soc_camera_platform_priv *priv = get_priv(pdev); |
| 190 | struct soc_camera_platform_info *p = pdev->dev.platform_data; | 174 | struct soc_camera_platform_info *p = v4l2_get_subdevdata(&priv->subdev); |
| 191 | struct soc_camera_device *icd = p->icd; | ||
| 192 | 175 | ||
| 176 | p->icd->control = NULL; | ||
| 193 | v4l2_device_unregister_subdev(&priv->subdev); | 177 | v4l2_device_unregister_subdev(&priv->subdev); |
| 194 | icd->ops = NULL; | ||
| 195 | platform_set_drvdata(pdev, NULL); | 178 | platform_set_drvdata(pdev, NULL); |
| 196 | kfree(priv); | 179 | kfree(priv); |
| 197 | return 0; | 180 | return 0; |
diff --git a/drivers/media/video/soc_mediabus.c b/drivers/media/video/soc_mediabus.c index bea7c9cf4f88..cf7f2194ded4 100644 --- a/drivers/media/video/soc_mediabus.c +++ b/drivers/media/video/soc_mediabus.c | |||
| @@ -383,6 +383,39 @@ const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc( | |||
| 383 | } | 383 | } |
| 384 | EXPORT_SYMBOL(soc_mbus_get_fmtdesc); | 384 | EXPORT_SYMBOL(soc_mbus_get_fmtdesc); |
| 385 | 385 | ||
| 386 | unsigned int soc_mbus_config_compatible(const struct v4l2_mbus_config *cfg, | ||
| 387 | unsigned int flags) | ||
| 388 | { | ||
| 389 | unsigned long common_flags; | ||
| 390 | bool hsync = true, vsync = true, pclk, data, mode; | ||
| 391 | bool mipi_lanes, mipi_clock; | ||
| 392 | |||
| 393 | common_flags = cfg->flags & flags; | ||
| 394 | |||
| 395 | switch (cfg->type) { | ||
| 396 | case V4L2_MBUS_PARALLEL: | ||
| 397 | hsync = common_flags & (V4L2_MBUS_HSYNC_ACTIVE_HIGH | | ||
| 398 | V4L2_MBUS_HSYNC_ACTIVE_LOW); | ||
| 399 | vsync = common_flags & (V4L2_MBUS_VSYNC_ACTIVE_HIGH | | ||
| 400 | V4L2_MBUS_VSYNC_ACTIVE_LOW); | ||
| 401 | case V4L2_MBUS_BT656: | ||
| 402 | pclk = common_flags & (V4L2_MBUS_PCLK_SAMPLE_RISING | | ||
| 403 | V4L2_MBUS_PCLK_SAMPLE_FALLING); | ||
| 404 | data = common_flags & (V4L2_MBUS_DATA_ACTIVE_HIGH | | ||
| 405 | V4L2_MBUS_DATA_ACTIVE_LOW); | ||
| 406 | mode = common_flags & (V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE); | ||
| 407 | return (!hsync || !vsync || !pclk || !data || !mode) ? | ||
| 408 | 0 : common_flags; | ||
| 409 | case V4L2_MBUS_CSI2: | ||
| 410 | mipi_lanes = common_flags & V4L2_MBUS_CSI2_LANES; | ||
| 411 | mipi_clock = common_flags & (V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK | | ||
| 412 | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK); | ||
| 413 | return (!mipi_lanes || !mipi_clock) ? 0 : common_flags; | ||
| 414 | } | ||
| 415 | return 0; | ||
| 416 | } | ||
| 417 | EXPORT_SYMBOL(soc_mbus_config_compatible); | ||
| 418 | |||
| 386 | static int __init soc_mbus_init(void) | 419 | static int __init soc_mbus_init(void) |
| 387 | { | 420 | { |
| 388 | return 0; | 421 | return 0; |
diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c index 742482e30011..a514fa61116c 100644 --- a/drivers/media/video/tw9910.c +++ b/drivers/media/video/tw9910.c | |||
| @@ -22,11 +22,13 @@ | |||
| 22 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
| 23 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
| 24 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
| 25 | #include <linux/v4l2-mediabus.h> | ||
| 25 | #include <linux/videodev2.h> | 26 | #include <linux/videodev2.h> |
| 26 | #include <media/v4l2-chip-ident.h> | 27 | |
| 27 | #include <media/v4l2-subdev.h> | ||
| 28 | #include <media/soc_camera.h> | 28 | #include <media/soc_camera.h> |
| 29 | #include <media/tw9910.h> | 29 | #include <media/tw9910.h> |
| 30 | #include <media/v4l2-chip-ident.h> | ||
| 31 | #include <media/v4l2-subdev.h> | ||
| 30 | 32 | ||
| 31 | #define GET_ID(val) ((val & 0xF8) >> 3) | 33 | #define GET_ID(val) ((val & 0xF8) >> 3) |
| 32 | #define GET_REV(val) (val & 0x07) | 34 | #define GET_REV(val) (val & 0x07) |
| @@ -203,6 +205,10 @@ | |||
| 203 | #define RTSEL_FIELD 0x06 /* 0110 = FIELD */ | 205 | #define RTSEL_FIELD 0x06 /* 0110 = FIELD */ |
| 204 | #define RTSEL_RTCO 0x07 /* 0111 = RTCO ( Real Time Control ) */ | 206 | #define RTSEL_RTCO 0x07 /* 0111 = RTCO ( Real Time Control ) */ |
| 205 | 207 | ||
| 208 | /* HSYNC start and end are constant for now */ | ||
| 209 | #define HSYNC_START 0x0260 | ||
| 210 | #define HSYNC_END 0x0300 | ||
| 211 | |||
| 206 | /* | 212 | /* |
| 207 | * structure | 213 | * structure |
| 208 | */ | 214 | */ |
| @@ -220,22 +226,11 @@ struct tw9910_scale_ctrl { | |||
| 220 | u16 vscale; | 226 | u16 vscale; |
| 221 | }; | 227 | }; |
| 222 | 228 | ||
| 223 | struct tw9910_cropping_ctrl { | ||
| 224 | u16 vdelay; | ||
| 225 | u16 vactive; | ||
| 226 | u16 hdelay; | ||
| 227 | u16 hactive; | ||
| 228 | }; | ||
| 229 | |||
| 230 | struct tw9910_hsync_ctrl { | ||
| 231 | u16 start; | ||
| 232 | u16 end; | ||
| 233 | }; | ||
| 234 | |||
| 235 | struct tw9910_priv { | 229 | struct tw9910_priv { |
| 236 | struct v4l2_subdev subdev; | 230 | struct v4l2_subdev subdev; |
| 237 | struct tw9910_video_info *info; | 231 | struct tw9910_video_info *info; |
| 238 | const struct tw9910_scale_ctrl *scale; | 232 | const struct tw9910_scale_ctrl *scale; |
| 233 | v4l2_std_id norm; | ||
| 239 | u32 revision; | 234 | u32 revision; |
| 240 | }; | 235 | }; |
| 241 | 236 | ||
| @@ -329,11 +324,6 @@ static const struct tw9910_scale_ctrl tw9910_pal_scales[] = { | |||
| 329 | }, | 324 | }, |
| 330 | }; | 325 | }; |
| 331 | 326 | ||
| 332 | static const struct tw9910_hsync_ctrl tw9910_hsync_ctrl = { | ||
| 333 | .start = 0x0260, | ||
| 334 | .end = 0x0300, | ||
| 335 | }; | ||
| 336 | |||
| 337 | /* | 327 | /* |
| 338 | * general function | 328 | * general function |
| 339 | */ | 329 | */ |
| @@ -378,21 +368,20 @@ static int tw9910_set_scale(struct i2c_client *client, | |||
| 378 | return ret; | 368 | return ret; |
| 379 | } | 369 | } |
| 380 | 370 | ||
| 381 | static int tw9910_set_hsync(struct i2c_client *client, | 371 | static int tw9910_set_hsync(struct i2c_client *client) |
| 382 | const struct tw9910_hsync_ctrl *hsync) | ||
| 383 | { | 372 | { |
| 384 | struct tw9910_priv *priv = to_tw9910(client); | 373 | struct tw9910_priv *priv = to_tw9910(client); |
| 385 | int ret; | 374 | int ret; |
| 386 | 375 | ||
| 387 | /* bit 10 - 3 */ | 376 | /* bit 10 - 3 */ |
| 388 | ret = i2c_smbus_write_byte_data(client, HSBEGIN, | 377 | ret = i2c_smbus_write_byte_data(client, HSBEGIN, |
| 389 | (hsync->start & 0x07F8) >> 3); | 378 | (HSYNC_START & 0x07F8) >> 3); |
| 390 | if (ret < 0) | 379 | if (ret < 0) |
| 391 | return ret; | 380 | return ret; |
| 392 | 381 | ||
| 393 | /* bit 10 - 3 */ | 382 | /* bit 10 - 3 */ |
| 394 | ret = i2c_smbus_write_byte_data(client, HSEND, | 383 | ret = i2c_smbus_write_byte_data(client, HSEND, |
| 395 | (hsync->end & 0x07F8) >> 3); | 384 | (HSYNC_END & 0x07F8) >> 3); |
| 396 | if (ret < 0) | 385 | if (ret < 0) |
| 397 | return ret; | 386 | return ret; |
| 398 | 387 | ||
| @@ -400,8 +389,8 @@ static int tw9910_set_hsync(struct i2c_client *client, | |||
| 400 | /* bit 2 - 0 */ | 389 | /* bit 2 - 0 */ |
| 401 | if (1 == priv->revision) | 390 | if (1 == priv->revision) |
| 402 | ret = tw9910_mask_set(client, HSLOWCTL, 0x77, | 391 | ret = tw9910_mask_set(client, HSLOWCTL, 0x77, |
| 403 | (hsync->start & 0x0007) << 4 | | 392 | (HSYNC_START & 0x0007) << 4 | |
| 404 | (hsync->end & 0x0007)); | 393 | (HSYNC_END & 0x0007)); |
| 405 | 394 | ||
| 406 | return ret; | 395 | return ret; |
| 407 | } | 396 | } |
| @@ -433,12 +422,11 @@ static int tw9910_power(struct i2c_client *client, int enable) | |||
| 433 | return tw9910_mask_set(client, ACNTL2, ACNTL2_PDN_MASK, acntl2); | 422 | return tw9910_mask_set(client, ACNTL2, ACNTL2_PDN_MASK, acntl2); |
| 434 | } | 423 | } |
| 435 | 424 | ||
| 436 | static const struct tw9910_scale_ctrl* | 425 | static const struct tw9910_scale_ctrl *tw9910_select_norm(v4l2_std_id norm, |
| 437 | tw9910_select_norm(struct soc_camera_device *icd, u32 width, u32 height) | 426 | u32 width, u32 height) |
| 438 | { | 427 | { |
| 439 | const struct tw9910_scale_ctrl *scale; | 428 | const struct tw9910_scale_ctrl *scale; |
| 440 | const struct tw9910_scale_ctrl *ret = NULL; | 429 | const struct tw9910_scale_ctrl *ret = NULL; |
| 441 | v4l2_std_id norm = icd->vdev->current_norm; | ||
| 442 | __u32 diff = 0xffffffff, tmp; | 430 | __u32 diff = 0xffffffff, tmp; |
| 443 | int size, i; | 431 | int size, i; |
| 444 | 432 | ||
| @@ -465,7 +453,7 @@ tw9910_select_norm(struct soc_camera_device *icd, u32 width, u32 height) | |||
| 465 | } | 453 | } |
| 466 | 454 | ||
| 467 | /* | 455 | /* |
| 468 | * soc_camera_ops function | 456 | * subdevice operations |
| 469 | */ | 457 | */ |
| 470 | static int tw9910_s_stream(struct v4l2_subdev *sd, int enable) | 458 | static int tw9910_s_stream(struct v4l2_subdev *sd, int enable) |
| 471 | { | 459 | { |
| @@ -507,49 +495,27 @@ static int tw9910_s_stream(struct v4l2_subdev *sd, int enable) | |||
| 507 | return tw9910_power(client, enable); | 495 | return tw9910_power(client, enable); |
| 508 | } | 496 | } |
| 509 | 497 | ||
| 510 | static int tw9910_set_bus_param(struct soc_camera_device *icd, | 498 | static int tw9910_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm) |
| 511 | unsigned long flags) | ||
| 512 | { | 499 | { |
| 513 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
| 514 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 500 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 515 | u8 val = VSSL_VVALID | HSSL_DVALID; | 501 | struct tw9910_priv *priv = to_tw9910(client); |
| 516 | 502 | ||
| 517 | /* | 503 | *norm = priv->norm; |
| 518 | * set OUTCTR1 | ||
| 519 | * | ||
| 520 | * We use VVALID and DVALID signals to control VSYNC and HSYNC | ||
| 521 | * outputs, in this mode their polarity is inverted. | ||
| 522 | */ | ||
| 523 | if (flags & SOCAM_HSYNC_ACTIVE_LOW) | ||
| 524 | val |= HSP_HI; | ||
| 525 | 504 | ||
| 526 | if (flags & SOCAM_VSYNC_ACTIVE_LOW) | 505 | return 0; |
| 527 | val |= VSP_HI; | ||
| 528 | |||
| 529 | return i2c_smbus_write_byte_data(client, OUTCTR1, val); | ||
| 530 | } | 506 | } |
| 531 | 507 | ||
| 532 | static unsigned long tw9910_query_bus_param(struct soc_camera_device *icd) | 508 | static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) |
| 533 | { | 509 | { |
| 534 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); | 510 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 535 | struct tw9910_priv *priv = to_tw9910(client); | 511 | struct tw9910_priv *priv = to_tw9910(client); |
| 536 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
| 537 | unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | | ||
| 538 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | | ||
| 539 | SOCAM_VSYNC_ACTIVE_LOW | SOCAM_HSYNC_ACTIVE_LOW | | ||
| 540 | SOCAM_DATA_ACTIVE_HIGH | priv->info->buswidth; | ||
| 541 | 512 | ||
| 542 | return soc_camera_apply_sensor_flags(icl, flags); | 513 | if (!(norm & (V4L2_STD_NTSC | V4L2_STD_PAL))) |
| 543 | } | 514 | return -EINVAL; |
| 544 | |||
| 545 | static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) | ||
| 546 | { | ||
| 547 | int ret = -EINVAL; | ||
| 548 | 515 | ||
| 549 | if (norm & (V4L2_STD_NTSC | V4L2_STD_PAL)) | 516 | priv->norm = norm; |
| 550 | ret = 0; | ||
| 551 | 517 | ||
| 552 | return ret; | 518 | return 0; |
| 553 | } | 519 | } |
| 554 | 520 | ||
| 555 | static int tw9910_g_chip_ident(struct v4l2_subdev *sd, | 521 | static int tw9910_g_chip_ident(struct v4l2_subdev *sd, |
| @@ -600,19 +566,17 @@ static int tw9910_s_register(struct v4l2_subdev *sd, | |||
| 600 | } | 566 | } |
| 601 | #endif | 567 | #endif |
| 602 | 568 | ||
| 603 | static int tw9910_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 569 | static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height) |
| 604 | { | 570 | { |
| 605 | struct v4l2_rect *rect = &a->c; | ||
| 606 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 571 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 607 | struct tw9910_priv *priv = to_tw9910(client); | 572 | struct tw9910_priv *priv = to_tw9910(client); |
| 608 | struct soc_camera_device *icd = client->dev.platform_data; | 573 | int ret = -EINVAL; |
| 609 | int ret = -EINVAL; | 574 | u8 val; |
| 610 | u8 val; | ||
| 611 | 575 | ||
| 612 | /* | 576 | /* |
| 613 | * select suitable norm | 577 | * select suitable norm |
| 614 | */ | 578 | */ |
| 615 | priv->scale = tw9910_select_norm(icd, rect->width, rect->height); | 579 | priv->scale = tw9910_select_norm(priv->norm, *width, *height); |
| 616 | if (!priv->scale) | 580 | if (!priv->scale) |
| 617 | goto tw9910_set_fmt_error; | 581 | goto tw9910_set_fmt_error; |
| 618 | 582 | ||
| @@ -670,14 +634,12 @@ static int tw9910_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
| 670 | /* | 634 | /* |
| 671 | * set hsync | 635 | * set hsync |
| 672 | */ | 636 | */ |
| 673 | ret = tw9910_set_hsync(client, &tw9910_hsync_ctrl); | 637 | ret = tw9910_set_hsync(client); |
| 674 | if (ret < 0) | 638 | if (ret < 0) |
| 675 | goto tw9910_set_fmt_error; | 639 | goto tw9910_set_fmt_error; |
| 676 | 640 | ||
| 677 | rect->width = priv->scale->width; | 641 | *width = priv->scale->width; |
| 678 | rect->height = priv->scale->height; | 642 | *height = priv->scale->height; |
| 679 | rect->left = 0; | ||
| 680 | rect->top = 0; | ||
| 681 | 643 | ||
| 682 | return ret; | 644 | return ret; |
| 683 | 645 | ||
| @@ -694,25 +656,15 @@ static int tw9910_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
| 694 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 656 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 695 | struct tw9910_priv *priv = to_tw9910(client); | 657 | struct tw9910_priv *priv = to_tw9910(client); |
| 696 | 658 | ||
| 697 | if (!priv->scale) { | ||
| 698 | int ret; | ||
| 699 | struct v4l2_crop crop = { | ||
| 700 | .c = { | ||
| 701 | .left = 0, | ||
| 702 | .top = 0, | ||
| 703 | .width = 640, | ||
| 704 | .height = 480, | ||
| 705 | }, | ||
| 706 | }; | ||
| 707 | ret = tw9910_s_crop(sd, &crop); | ||
| 708 | if (ret < 0) | ||
| 709 | return ret; | ||
| 710 | } | ||
| 711 | |||
| 712 | a->c.left = 0; | 659 | a->c.left = 0; |
| 713 | a->c.top = 0; | 660 | a->c.top = 0; |
| 714 | a->c.width = priv->scale->width; | 661 | if (priv->norm & V4L2_STD_NTSC) { |
| 715 | a->c.height = priv->scale->height; | 662 | a->c.width = 640; |
| 663 | a->c.height = 480; | ||
| 664 | } else { | ||
| 665 | a->c.width = 768; | ||
| 666 | a->c.height = 576; | ||
| 667 | } | ||
| 716 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 668 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 717 | 669 | ||
| 718 | return 0; | 670 | return 0; |
| @@ -720,14 +672,19 @@ static int tw9910_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
| 720 | 672 | ||
| 721 | static int tw9910_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | 673 | static int tw9910_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) |
| 722 | { | 674 | { |
| 675 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 676 | struct tw9910_priv *priv = to_tw9910(client); | ||
| 677 | |||
| 723 | a->bounds.left = 0; | 678 | a->bounds.left = 0; |
| 724 | a->bounds.top = 0; | 679 | a->bounds.top = 0; |
| 725 | a->bounds.width = 768; | 680 | if (priv->norm & V4L2_STD_NTSC) { |
| 726 | a->bounds.height = 576; | 681 | a->bounds.width = 640; |
| 727 | a->defrect.left = 0; | 682 | a->bounds.height = 480; |
| 728 | a->defrect.top = 0; | 683 | } else { |
| 729 | a->defrect.width = 640; | 684 | a->bounds.width = 768; |
| 730 | a->defrect.height = 480; | 685 | a->bounds.height = 576; |
| 686 | } | ||
| 687 | a->defrect = a->bounds; | ||
| 731 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 688 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 732 | a->pixelaspect.numerator = 1; | 689 | a->pixelaspect.numerator = 1; |
| 733 | a->pixelaspect.denominator = 1; | 690 | a->pixelaspect.denominator = 1; |
| @@ -743,15 +700,8 @@ static int tw9910_g_fmt(struct v4l2_subdev *sd, | |||
| 743 | 700 | ||
| 744 | if (!priv->scale) { | 701 | if (!priv->scale) { |
| 745 | int ret; | 702 | int ret; |
| 746 | struct v4l2_crop crop = { | 703 | u32 width = 640, height = 480; |
| 747 | .c = { | 704 | ret = tw9910_set_frame(sd, &width, &height); |
| 748 | .left = 0, | ||
| 749 | .top = 0, | ||
| 750 | .width = 640, | ||
| 751 | .height = 480, | ||
| 752 | }, | ||
| 753 | }; | ||
| 754 | ret = tw9910_s_crop(sd, &crop); | ||
| 755 | if (ret < 0) | 705 | if (ret < 0) |
| 756 | return ret; | 706 | return ret; |
| 757 | } | 707 | } |
| @@ -768,17 +718,7 @@ static int tw9910_g_fmt(struct v4l2_subdev *sd, | |||
| 768 | static int tw9910_s_fmt(struct v4l2_subdev *sd, | 718 | static int tw9910_s_fmt(struct v4l2_subdev *sd, |
| 769 | struct v4l2_mbus_framefmt *mf) | 719 | struct v4l2_mbus_framefmt *mf) |
| 770 | { | 720 | { |
| 771 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 721 | u32 width = mf->width, height = mf->height; |
| 772 | struct tw9910_priv *priv = to_tw9910(client); | ||
| 773 | /* See tw9910_s_crop() - no proper cropping support */ | ||
| 774 | struct v4l2_crop a = { | ||
| 775 | .c = { | ||
| 776 | .left = 0, | ||
| 777 | .top = 0, | ||
| 778 | .width = mf->width, | ||
| 779 | .height = mf->height, | ||
| 780 | }, | ||
| 781 | }; | ||
| 782 | int ret; | 722 | int ret; |
| 783 | 723 | ||
| 784 | WARN_ON(mf->field != V4L2_FIELD_ANY && | 724 | WARN_ON(mf->field != V4L2_FIELD_ANY && |
| @@ -792,10 +732,10 @@ static int tw9910_s_fmt(struct v4l2_subdev *sd, | |||
| 792 | 732 | ||
| 793 | mf->colorspace = V4L2_COLORSPACE_JPEG; | 733 | mf->colorspace = V4L2_COLORSPACE_JPEG; |
| 794 | 734 | ||
| 795 | ret = tw9910_s_crop(sd, &a); | 735 | ret = tw9910_set_frame(sd, &width, &height); |
| 796 | if (!ret) { | 736 | if (!ret) { |
| 797 | mf->width = priv->scale->width; | 737 | mf->width = width; |
| 798 | mf->height = priv->scale->height; | 738 | mf->height = height; |
| 799 | } | 739 | } |
| 800 | return ret; | 740 | return ret; |
| 801 | } | 741 | } |
| @@ -804,7 +744,7 @@ static int tw9910_try_fmt(struct v4l2_subdev *sd, | |||
| 804 | struct v4l2_mbus_framefmt *mf) | 744 | struct v4l2_mbus_framefmt *mf) |
| 805 | { | 745 | { |
| 806 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 746 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 807 | struct soc_camera_device *icd = client->dev.platform_data; | 747 | struct tw9910_priv *priv = to_tw9910(client); |
| 808 | const struct tw9910_scale_ctrl *scale; | 748 | const struct tw9910_scale_ctrl *scale; |
| 809 | 749 | ||
| 810 | if (V4L2_FIELD_ANY == mf->field) { | 750 | if (V4L2_FIELD_ANY == mf->field) { |
| @@ -820,7 +760,7 @@ static int tw9910_try_fmt(struct v4l2_subdev *sd, | |||
| 820 | /* | 760 | /* |
| 821 | * select suitable norm | 761 | * select suitable norm |
| 822 | */ | 762 | */ |
| 823 | scale = tw9910_select_norm(icd, mf->width, mf->height); | 763 | scale = tw9910_select_norm(priv->norm, mf->width, mf->height); |
| 824 | if (!scale) | 764 | if (!scale) |
| 825 | return -EINVAL; | 765 | return -EINVAL; |
| 826 | 766 | ||
| @@ -830,16 +770,11 @@ static int tw9910_try_fmt(struct v4l2_subdev *sd, | |||
| 830 | return 0; | 770 | return 0; |
| 831 | } | 771 | } |
| 832 | 772 | ||
| 833 | static int tw9910_video_probe(struct soc_camera_device *icd, | 773 | static int tw9910_video_probe(struct i2c_client *client) |
| 834 | struct i2c_client *client) | ||
| 835 | { | 774 | { |
| 836 | struct tw9910_priv *priv = to_tw9910(client); | 775 | struct tw9910_priv *priv = to_tw9910(client); |
| 837 | s32 id; | 776 | s32 id; |
| 838 | 777 | ||
| 839 | /* We must have a parent by now. And it cannot be a wrong one. */ | ||
| 840 | BUG_ON(!icd->parent || | ||
| 841 | to_soc_camera_host(icd->parent)->nr != icd->iface); | ||
| 842 | |||
| 843 | /* | 778 | /* |
| 844 | * tw9910 only use 8 or 16 bit bus width | 779 | * tw9910 only use 8 or 16 bit bus width |
| 845 | */ | 780 | */ |
| @@ -868,20 +803,15 @@ static int tw9910_video_probe(struct soc_camera_device *icd, | |||
| 868 | dev_info(&client->dev, | 803 | dev_info(&client->dev, |
| 869 | "tw9910 Product ID %0x:%0x\n", id, priv->revision); | 804 | "tw9910 Product ID %0x:%0x\n", id, priv->revision); |
| 870 | 805 | ||
| 871 | icd->vdev->tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL; | 806 | priv->norm = V4L2_STD_NTSC; |
| 872 | icd->vdev->current_norm = V4L2_STD_NTSC; | ||
| 873 | 807 | ||
| 874 | return 0; | 808 | return 0; |
| 875 | } | 809 | } |
| 876 | 810 | ||
| 877 | static struct soc_camera_ops tw9910_ops = { | ||
| 878 | .set_bus_param = tw9910_set_bus_param, | ||
| 879 | .query_bus_param = tw9910_query_bus_param, | ||
| 880 | }; | ||
| 881 | |||
| 882 | static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = { | 811 | static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = { |
| 883 | .g_chip_ident = tw9910_g_chip_ident, | 812 | .g_chip_ident = tw9910_g_chip_ident, |
| 884 | .s_std = tw9910_s_std, | 813 | .s_std = tw9910_s_std, |
| 814 | .g_std = tw9910_g_std, | ||
| 885 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 815 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
| 886 | .g_register = tw9910_g_register, | 816 | .g_register = tw9910_g_register, |
| 887 | .s_register = tw9910_s_register, | 817 | .s_register = tw9910_s_register, |
| @@ -898,6 +828,45 @@ static int tw9910_enum_fmt(struct v4l2_subdev *sd, unsigned int index, | |||
| 898 | return 0; | 828 | return 0; |
| 899 | } | 829 | } |
| 900 | 830 | ||
| 831 | static int tw9910_g_mbus_config(struct v4l2_subdev *sd, | ||
| 832 | struct v4l2_mbus_config *cfg) | ||
| 833 | { | ||
| 834 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 835 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
| 836 | |||
| 837 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | | ||
| 838 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | | ||
| 839 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW | | ||
| 840 | V4L2_MBUS_DATA_ACTIVE_HIGH; | ||
| 841 | cfg->type = V4L2_MBUS_PARALLEL; | ||
| 842 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | ||
| 843 | |||
| 844 | return 0; | ||
| 845 | } | ||
| 846 | |||
| 847 | static int tw9910_s_mbus_config(struct v4l2_subdev *sd, | ||
| 848 | const struct v4l2_mbus_config *cfg) | ||
| 849 | { | ||
| 850 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 851 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); | ||
| 852 | u8 val = VSSL_VVALID | HSSL_DVALID; | ||
| 853 | unsigned long flags = soc_camera_apply_board_flags(icl, cfg); | ||
| 854 | |||
| 855 | /* | ||
| 856 | * set OUTCTR1 | ||
| 857 | * | ||
| 858 | * We use VVALID and DVALID signals to control VSYNC and HSYNC | ||
| 859 | * outputs, in this mode their polarity is inverted. | ||
| 860 | */ | ||
| 861 | if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) | ||
| 862 | val |= HSP_HI; | ||
| 863 | |||
| 864 | if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) | ||
| 865 | val |= VSP_HI; | ||
| 866 | |||
| 867 | return i2c_smbus_write_byte_data(client, OUTCTR1, val); | ||
| 868 | } | ||
| 869 | |||
| 901 | static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = { | 870 | static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = { |
| 902 | .s_stream = tw9910_s_stream, | 871 | .s_stream = tw9910_s_stream, |
| 903 | .g_mbus_fmt = tw9910_g_fmt, | 872 | .g_mbus_fmt = tw9910_g_fmt, |
| @@ -905,8 +874,9 @@ static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = { | |||
| 905 | .try_mbus_fmt = tw9910_try_fmt, | 874 | .try_mbus_fmt = tw9910_try_fmt, |
| 906 | .cropcap = tw9910_cropcap, | 875 | .cropcap = tw9910_cropcap, |
| 907 | .g_crop = tw9910_g_crop, | 876 | .g_crop = tw9910_g_crop, |
| 908 | .s_crop = tw9910_s_crop, | ||
| 909 | .enum_mbus_fmt = tw9910_enum_fmt, | 877 | .enum_mbus_fmt = tw9910_enum_fmt, |
| 878 | .g_mbus_config = tw9910_g_mbus_config, | ||
| 879 | .s_mbus_config = tw9910_s_mbus_config, | ||
| 910 | }; | 880 | }; |
| 911 | 881 | ||
| 912 | static struct v4l2_subdev_ops tw9910_subdev_ops = { | 882 | static struct v4l2_subdev_ops tw9910_subdev_ops = { |
| @@ -922,23 +892,18 @@ static int tw9910_probe(struct i2c_client *client, | |||
| 922 | const struct i2c_device_id *did) | 892 | const struct i2c_device_id *did) |
| 923 | 893 | ||
| 924 | { | 894 | { |
| 925 | struct tw9910_priv *priv; | 895 | struct tw9910_priv *priv; |
| 926 | struct tw9910_video_info *info; | 896 | struct tw9910_video_info *info; |
| 927 | struct soc_camera_device *icd = client->dev.platform_data; | 897 | struct i2c_adapter *adapter = |
| 928 | struct i2c_adapter *adapter = | ||
| 929 | to_i2c_adapter(client->dev.parent); | 898 | to_i2c_adapter(client->dev.parent); |
| 930 | struct soc_camera_link *icl; | 899 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
| 931 | int ret; | 900 | int ret; |
| 932 | 901 | ||
| 933 | if (!icd) { | 902 | if (!icl || !icl->priv) { |
| 934 | dev_err(&client->dev, "TW9910: missing soc-camera data!\n"); | 903 | dev_err(&client->dev, "TW9910: missing platform data!\n"); |
| 935 | return -EINVAL; | 904 | return -EINVAL; |
| 936 | } | 905 | } |
| 937 | 906 | ||
| 938 | icl = to_soc_camera_link(icd); | ||
| 939 | if (!icl || !icl->priv) | ||
| 940 | return -EINVAL; | ||
| 941 | |||
| 942 | info = icl->priv; | 907 | info = icl->priv; |
| 943 | 908 | ||
| 944 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { | 909 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { |
| @@ -956,14 +921,9 @@ static int tw9910_probe(struct i2c_client *client, | |||
| 956 | 921 | ||
| 957 | v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops); | 922 | v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops); |
| 958 | 923 | ||
| 959 | icd->ops = &tw9910_ops; | 924 | ret = tw9910_video_probe(client); |
| 960 | icd->iface = icl->bus_id; | 925 | if (ret) |
| 961 | |||
| 962 | ret = tw9910_video_probe(icd, client); | ||
| 963 | if (ret) { | ||
| 964 | icd->ops = NULL; | ||
| 965 | kfree(priv); | 926 | kfree(priv); |
| 966 | } | ||
| 967 | 927 | ||
| 968 | return ret; | 928 | return ret; |
| 969 | } | 929 | } |
| @@ -971,9 +931,7 @@ static int tw9910_probe(struct i2c_client *client, | |||
| 971 | static int tw9910_remove(struct i2c_client *client) | 931 | static int tw9910_remove(struct i2c_client *client) |
| 972 | { | 932 | { |
| 973 | struct tw9910_priv *priv = to_tw9910(client); | 933 | struct tw9910_priv *priv = to_tw9910(client); |
| 974 | struct soc_camera_device *icd = client->dev.platform_data; | ||
| 975 | 934 | ||
| 976 | icd->ops = NULL; | ||
| 977 | kfree(priv); | 935 | kfree(priv); |
| 978 | return 0; | 936 | return 0; |
| 979 | } | 937 | } |
diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c index 61979b70f388..c68531b88279 100644 --- a/drivers/media/video/v4l2-compat-ioctl32.c +++ b/drivers/media/video/v4l2-compat-ioctl32.c | |||
| @@ -159,11 +159,25 @@ struct v4l2_format32 { | |||
| 159 | } fmt; | 159 | } fmt; |
| 160 | }; | 160 | }; |
| 161 | 161 | ||
| 162 | static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) | 162 | /** |
| 163 | * struct v4l2_create_buffers32 - VIDIOC_CREATE_BUFS32 argument | ||
| 164 | * @index: on return, index of the first created buffer | ||
| 165 | * @count: entry: number of requested buffers, | ||
| 166 | * return: number of created buffers | ||
| 167 | * @memory: buffer memory type | ||
| 168 | * @format: frame format, for which buffers are requested | ||
| 169 | * @reserved: future extensions | ||
| 170 | */ | ||
| 171 | struct v4l2_create_buffers32 { | ||
| 172 | __u32 index; | ||
| 173 | __u32 count; | ||
| 174 | enum v4l2_memory memory; | ||
| 175 | struct v4l2_format32 format; | ||
| 176 | __u32 reserved[8]; | ||
| 177 | }; | ||
| 178 | |||
| 179 | static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) | ||
| 163 | { | 180 | { |
| 164 | if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)) || | ||
| 165 | get_user(kp->type, &up->type)) | ||
| 166 | return -EFAULT; | ||
| 167 | switch (kp->type) { | 181 | switch (kp->type) { |
| 168 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 182 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
| 169 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | 183 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: |
| @@ -192,11 +206,24 @@ static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user | |||
| 192 | } | 206 | } |
| 193 | } | 207 | } |
| 194 | 208 | ||
| 195 | static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) | 209 | static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) |
| 210 | { | ||
| 211 | if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)) || | ||
| 212 | get_user(kp->type, &up->type)) | ||
| 213 | return -EFAULT; | ||
| 214 | return __get_v4l2_format32(kp, up); | ||
| 215 | } | ||
| 216 | |||
| 217 | static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) | ||
| 218 | { | ||
| 219 | if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_create_buffers32)) || | ||
| 220 | copy_from_user(kp, up, offsetof(struct v4l2_create_buffers32, format.fmt))) | ||
| 221 | return -EFAULT; | ||
| 222 | return __get_v4l2_format32(&kp->format, &up->format); | ||
| 223 | } | ||
| 224 | |||
| 225 | static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) | ||
| 196 | { | 226 | { |
| 197 | if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) || | ||
| 198 | put_user(kp->type, &up->type)) | ||
| 199 | return -EFAULT; | ||
| 200 | switch (kp->type) { | 227 | switch (kp->type) { |
| 201 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 228 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
| 202 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | 229 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: |
| @@ -225,6 +252,22 @@ static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user | |||
| 225 | } | 252 | } |
| 226 | } | 253 | } |
| 227 | 254 | ||
| 255 | static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up) | ||
| 256 | { | ||
| 257 | if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) || | ||
| 258 | put_user(kp->type, &up->type)) | ||
| 259 | return -EFAULT; | ||
| 260 | return __put_v4l2_format32(kp, up); | ||
| 261 | } | ||
| 262 | |||
| 263 | static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up) | ||
| 264 | { | ||
| 265 | if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) || | ||
| 266 | copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format.fmt))) | ||
| 267 | return -EFAULT; | ||
| 268 | return __put_v4l2_format32(&kp->format, &up->format); | ||
| 269 | } | ||
| 270 | |||
| 228 | struct v4l2_standard32 { | 271 | struct v4l2_standard32 { |
| 229 | __u32 index; | 272 | __u32 index; |
| 230 | __u32 id[2]; /* __u64 would get the alignment wrong */ | 273 | __u32 id[2]; /* __u64 would get the alignment wrong */ |
| @@ -702,6 +745,8 @@ static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *u | |||
| 702 | #define VIDIOC_S_EXT_CTRLS32 _IOWR('V', 72, struct v4l2_ext_controls32) | 745 | #define VIDIOC_S_EXT_CTRLS32 _IOWR('V', 72, struct v4l2_ext_controls32) |
| 703 | #define VIDIOC_TRY_EXT_CTRLS32 _IOWR('V', 73, struct v4l2_ext_controls32) | 746 | #define VIDIOC_TRY_EXT_CTRLS32 _IOWR('V', 73, struct v4l2_ext_controls32) |
| 704 | #define VIDIOC_DQEVENT32 _IOR ('V', 89, struct v4l2_event32) | 747 | #define VIDIOC_DQEVENT32 _IOR ('V', 89, struct v4l2_event32) |
| 748 | #define VIDIOC_CREATE_BUFS32 _IOWR('V', 92, struct v4l2_create_buffers32) | ||
| 749 | #define VIDIOC_PREPARE_BUF32 _IOWR('V', 93, struct v4l2_buffer32) | ||
| 705 | 750 | ||
| 706 | #define VIDIOC_OVERLAY32 _IOW ('V', 14, s32) | 751 | #define VIDIOC_OVERLAY32 _IOW ('V', 14, s32) |
| 707 | #define VIDIOC_STREAMON32 _IOW ('V', 18, s32) | 752 | #define VIDIOC_STREAMON32 _IOW ('V', 18, s32) |
| @@ -721,6 +766,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar | |||
| 721 | struct v4l2_standard v2s; | 766 | struct v4l2_standard v2s; |
| 722 | struct v4l2_ext_controls v2ecs; | 767 | struct v4l2_ext_controls v2ecs; |
| 723 | struct v4l2_event v2ev; | 768 | struct v4l2_event v2ev; |
| 769 | struct v4l2_create_buffers v2crt; | ||
| 724 | unsigned long vx; | 770 | unsigned long vx; |
| 725 | int vi; | 771 | int vi; |
| 726 | } karg; | 772 | } karg; |
| @@ -751,6 +797,8 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar | |||
| 751 | case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break; | 797 | case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break; |
| 752 | case VIDIOC_G_OUTPUT32: cmd = VIDIOC_G_OUTPUT; break; | 798 | case VIDIOC_G_OUTPUT32: cmd = VIDIOC_G_OUTPUT; break; |
| 753 | case VIDIOC_S_OUTPUT32: cmd = VIDIOC_S_OUTPUT; break; | 799 | case VIDIOC_S_OUTPUT32: cmd = VIDIOC_S_OUTPUT; break; |
| 800 | case VIDIOC_CREATE_BUFS32: cmd = VIDIOC_CREATE_BUFS; break; | ||
| 801 | case VIDIOC_PREPARE_BUF32: cmd = VIDIOC_PREPARE_BUF; break; | ||
| 754 | } | 802 | } |
| 755 | 803 | ||
| 756 | switch (cmd) { | 804 | switch (cmd) { |
| @@ -775,6 +823,12 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar | |||
| 775 | compatible_arg = 0; | 823 | compatible_arg = 0; |
| 776 | break; | 824 | break; |
| 777 | 825 | ||
| 826 | case VIDIOC_CREATE_BUFS: | ||
| 827 | err = get_v4l2_create32(&karg.v2crt, up); | ||
| 828 | compatible_arg = 0; | ||
| 829 | break; | ||
| 830 | |||
| 831 | case VIDIOC_PREPARE_BUF: | ||
| 778 | case VIDIOC_QUERYBUF: | 832 | case VIDIOC_QUERYBUF: |
| 779 | case VIDIOC_QBUF: | 833 | case VIDIOC_QBUF: |
| 780 | case VIDIOC_DQBUF: | 834 | case VIDIOC_DQBUF: |
| @@ -860,6 +914,10 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar | |||
| 860 | err = put_v4l2_format32(&karg.v2f, up); | 914 | err = put_v4l2_format32(&karg.v2f, up); |
| 861 | break; | 915 | break; |
| 862 | 916 | ||
| 917 | case VIDIOC_CREATE_BUFS: | ||
| 918 | err = put_v4l2_create32(&karg.v2crt, up); | ||
| 919 | break; | ||
| 920 | |||
| 863 | case VIDIOC_QUERYBUF: | 921 | case VIDIOC_QUERYBUF: |
| 864 | case VIDIOC_QBUF: | 922 | case VIDIOC_QBUF: |
| 865 | case VIDIOC_DQBUF: | 923 | case VIDIOC_DQBUF: |
| @@ -959,6 +1017,8 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) | |||
| 959 | case VIDIOC_DQEVENT32: | 1017 | case VIDIOC_DQEVENT32: |
| 960 | case VIDIOC_SUBSCRIBE_EVENT: | 1018 | case VIDIOC_SUBSCRIBE_EVENT: |
| 961 | case VIDIOC_UNSUBSCRIBE_EVENT: | 1019 | case VIDIOC_UNSUBSCRIBE_EVENT: |
| 1020 | case VIDIOC_CREATE_BUFS32: | ||
| 1021 | case VIDIOC_PREPARE_BUF32: | ||
| 962 | ret = do_video_ioctl(file, cmd, arg); | 1022 | ret = do_video_ioctl(file, cmd, arg); |
| 963 | break; | 1023 | break; |
| 964 | 1024 | ||
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c index fc8666ae408f..5552f8137571 100644 --- a/drivers/media/video/v4l2-ctrls.c +++ b/drivers/media/video/v4l2-ctrls.c | |||
| @@ -210,6 +210,7 @@ const char * const *v4l2_ctrl_get_menu(u32 id) | |||
| 210 | "Disabled", | 210 | "Disabled", |
| 211 | "50 Hz", | 211 | "50 Hz", |
| 212 | "60 Hz", | 212 | "60 Hz", |
| 213 | "Auto", | ||
| 213 | NULL | 214 | NULL |
| 214 | }; | 215 | }; |
| 215 | static const char * const camera_exposure_auto[] = { | 216 | static const char * const camera_exposure_auto[] = { |
diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c index e6a2c3b302d4..9fc0ae8a526a 100644 --- a/drivers/media/video/v4l2-device.c +++ b/drivers/media/video/v4l2-device.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <linux/types.h> | 21 | #include <linux/types.h> |
| 22 | #include <linux/ioctl.h> | 22 | #include <linux/ioctl.h> |
| 23 | #include <linux/i2c.h> | 23 | #include <linux/i2c.h> |
| 24 | #include <linux/slab.h> | ||
| 24 | #if defined(CONFIG_SPI) | 25 | #if defined(CONFIG_SPI) |
| 25 | #include <linux/spi/spi.h> | 26 | #include <linux/spi/spi.h> |
| 26 | #endif | 27 | #endif |
| @@ -193,6 +194,13 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, | |||
| 193 | } | 194 | } |
| 194 | EXPORT_SYMBOL_GPL(v4l2_device_register_subdev); | 195 | EXPORT_SYMBOL_GPL(v4l2_device_register_subdev); |
| 195 | 196 | ||
| 197 | static void v4l2_device_release_subdev_node(struct video_device *vdev) | ||
| 198 | { | ||
| 199 | struct v4l2_subdev *sd = video_get_drvdata(vdev); | ||
| 200 | sd->devnode = NULL; | ||
| 201 | kfree(vdev); | ||
| 202 | } | ||
| 203 | |||
| 196 | int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev) | 204 | int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev) |
| 197 | { | 205 | { |
| 198 | struct video_device *vdev; | 206 | struct video_device *vdev; |
| @@ -206,22 +214,40 @@ int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev) | |||
| 206 | if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)) | 214 | if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)) |
| 207 | continue; | 215 | continue; |
| 208 | 216 | ||
| 209 | vdev = &sd->devnode; | 217 | vdev = kzalloc(sizeof(*vdev), GFP_KERNEL); |
| 218 | if (!vdev) { | ||
| 219 | err = -ENOMEM; | ||
| 220 | goto clean_up; | ||
| 221 | } | ||
| 222 | |||
| 223 | video_set_drvdata(vdev, sd); | ||
| 210 | strlcpy(vdev->name, sd->name, sizeof(vdev->name)); | 224 | strlcpy(vdev->name, sd->name, sizeof(vdev->name)); |
| 211 | vdev->v4l2_dev = v4l2_dev; | 225 | vdev->v4l2_dev = v4l2_dev; |
| 212 | vdev->fops = &v4l2_subdev_fops; | 226 | vdev->fops = &v4l2_subdev_fops; |
| 213 | vdev->release = video_device_release_empty; | 227 | vdev->release = v4l2_device_release_subdev_node; |
| 214 | vdev->ctrl_handler = sd->ctrl_handler; | 228 | vdev->ctrl_handler = sd->ctrl_handler; |
| 215 | err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1, | 229 | err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1, |
| 216 | sd->owner); | 230 | sd->owner); |
| 217 | if (err < 0) | 231 | if (err < 0) { |
| 218 | return err; | 232 | kfree(vdev); |
| 233 | goto clean_up; | ||
| 234 | } | ||
| 219 | #if defined(CONFIG_MEDIA_CONTROLLER) | 235 | #if defined(CONFIG_MEDIA_CONTROLLER) |
| 220 | sd->entity.v4l.major = VIDEO_MAJOR; | 236 | sd->entity.v4l.major = VIDEO_MAJOR; |
| 221 | sd->entity.v4l.minor = vdev->minor; | 237 | sd->entity.v4l.minor = vdev->minor; |
| 222 | #endif | 238 | #endif |
| 239 | sd->devnode = vdev; | ||
| 223 | } | 240 | } |
| 224 | return 0; | 241 | return 0; |
| 242 | |||
| 243 | clean_up: | ||
| 244 | list_for_each_entry(sd, &v4l2_dev->subdevs, list) { | ||
| 245 | if (!sd->devnode) | ||
| 246 | break; | ||
| 247 | video_unregister_device(sd->devnode); | ||
| 248 | } | ||
| 249 | |||
| 250 | return err; | ||
| 225 | } | 251 | } |
| 226 | EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes); | 252 | EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes); |
| 227 | 253 | ||
| @@ -247,7 +273,7 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd) | |||
| 247 | if (v4l2_dev->mdev) | 273 | if (v4l2_dev->mdev) |
| 248 | media_device_unregister_entity(&sd->entity); | 274 | media_device_unregister_entity(&sd->entity); |
| 249 | #endif | 275 | #endif |
| 250 | video_unregister_device(&sd->devnode); | 276 | video_unregister_device(sd->devnode); |
| 251 | module_put(sd->owner); | 277 | module_put(sd->owner); |
| 252 | } | 278 | } |
| 253 | EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev); | 279 | EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev); |
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index 24fd43322150..e1da8fc9dd2f 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c | |||
| @@ -273,6 +273,8 @@ static const char *v4l2_ioctls[] = { | |||
| 273 | [_IOC_NR(VIDIOC_DQEVENT)] = "VIDIOC_DQEVENT", | 273 | [_IOC_NR(VIDIOC_DQEVENT)] = "VIDIOC_DQEVENT", |
| 274 | [_IOC_NR(VIDIOC_SUBSCRIBE_EVENT)] = "VIDIOC_SUBSCRIBE_EVENT", | 274 | [_IOC_NR(VIDIOC_SUBSCRIBE_EVENT)] = "VIDIOC_SUBSCRIBE_EVENT", |
| 275 | [_IOC_NR(VIDIOC_UNSUBSCRIBE_EVENT)] = "VIDIOC_UNSUBSCRIBE_EVENT", | 275 | [_IOC_NR(VIDIOC_UNSUBSCRIBE_EVENT)] = "VIDIOC_UNSUBSCRIBE_EVENT", |
| 276 | [_IOC_NR(VIDIOC_CREATE_BUFS)] = "VIDIOC_CREATE_BUFS", | ||
| 277 | [_IOC_NR(VIDIOC_PREPARE_BUF)] = "VIDIOC_PREPARE_BUF", | ||
| 276 | }; | 278 | }; |
| 277 | #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) | 279 | #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) |
| 278 | 280 | ||
| @@ -2104,6 +2106,40 @@ static long __video_do_ioctl(struct file *file, | |||
| 2104 | dbgarg(cmd, "type=0x%8.8x", sub->type); | 2106 | dbgarg(cmd, "type=0x%8.8x", sub->type); |
| 2105 | break; | 2107 | break; |
| 2106 | } | 2108 | } |
| 2109 | case VIDIOC_CREATE_BUFS: | ||
| 2110 | { | ||
| 2111 | struct v4l2_create_buffers *create = arg; | ||
| 2112 | |||
| 2113 | if (!ops->vidioc_create_bufs) | ||
| 2114 | break; | ||
| 2115 | if (ret_prio) { | ||
| 2116 | ret = ret_prio; | ||
| 2117 | break; | ||
| 2118 | } | ||
| 2119 | ret = check_fmt(ops, create->format.type); | ||
| 2120 | if (ret) | ||
| 2121 | break; | ||
| 2122 | |||
| 2123 | ret = ops->vidioc_create_bufs(file, fh, create); | ||
| 2124 | |||
| 2125 | dbgarg(cmd, "count=%d @ %d\n", create->count, create->index); | ||
| 2126 | break; | ||
| 2127 | } | ||
| 2128 | case VIDIOC_PREPARE_BUF: | ||
| 2129 | { | ||
| 2130 | struct v4l2_buffer *b = arg; | ||
| 2131 | |||
| 2132 | if (!ops->vidioc_prepare_buf) | ||
| 2133 | break; | ||
| 2134 | ret = check_fmt(ops, b->type); | ||
| 2135 | if (ret) | ||
| 2136 | break; | ||
| 2137 | |||
| 2138 | ret = ops->vidioc_prepare_buf(file, fh, b); | ||
| 2139 | |||
| 2140 | dbgarg(cmd, "index=%d", b->index); | ||
| 2141 | break; | ||
| 2142 | } | ||
| 2107 | default: | 2143 | default: |
| 2108 | if (!ops->vidioc_default) | 2144 | if (!ops->vidioc_default) |
| 2109 | break; | 2145 | break; |
diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index 3f5c7a38e6e8..979e544388cb 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c | |||
| @@ -38,7 +38,8 @@ module_param(debug, int, 0644); | |||
| 38 | (((q)->ops->op) ? ((q)->ops->op(args)) : 0) | 38 | (((q)->ops->op) ? ((q)->ops->op(args)) : 0) |
| 39 | 39 | ||
| 40 | #define V4L2_BUFFER_STATE_FLAGS (V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | \ | 40 | #define V4L2_BUFFER_STATE_FLAGS (V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | \ |
| 41 | V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_ERROR) | 41 | V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_ERROR | \ |
| 42 | V4L2_BUF_FLAG_PREPARED) | ||
| 42 | 43 | ||
| 43 | /** | 44 | /** |
| 44 | * __vb2_buf_mem_alloc() - allocate video memory for the given buffer | 45 | * __vb2_buf_mem_alloc() - allocate video memory for the given buffer |
| @@ -109,13 +110,22 @@ static void __vb2_buf_userptr_put(struct vb2_buffer *vb) | |||
| 109 | * __setup_offsets() - setup unique offsets ("cookies") for every plane in | 110 | * __setup_offsets() - setup unique offsets ("cookies") for every plane in |
| 110 | * every buffer on the queue | 111 | * every buffer on the queue |
| 111 | */ | 112 | */ |
| 112 | static void __setup_offsets(struct vb2_queue *q) | 113 | static void __setup_offsets(struct vb2_queue *q, unsigned int n) |
| 113 | { | 114 | { |
| 114 | unsigned int buffer, plane; | 115 | unsigned int buffer, plane; |
| 115 | struct vb2_buffer *vb; | 116 | struct vb2_buffer *vb; |
| 116 | unsigned long off = 0; | 117 | unsigned long off; |
| 117 | 118 | ||
| 118 | for (buffer = 0; buffer < q->num_buffers; ++buffer) { | 119 | if (q->num_buffers) { |
| 120 | struct v4l2_plane *p; | ||
| 121 | vb = q->bufs[q->num_buffers - 1]; | ||
| 122 | p = &vb->v4l2_planes[vb->num_planes - 1]; | ||
| 123 | off = PAGE_ALIGN(p->m.mem_offset + p->length); | ||
| 124 | } else { | ||
| 125 | off = 0; | ||
| 126 | } | ||
| 127 | |||
| 128 | for (buffer = q->num_buffers; buffer < q->num_buffers + n; ++buffer) { | ||
| 119 | vb = q->bufs[buffer]; | 129 | vb = q->bufs[buffer]; |
| 120 | if (!vb) | 130 | if (!vb) |
| 121 | continue; | 131 | continue; |
| @@ -161,7 +171,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory, | |||
| 161 | vb->state = VB2_BUF_STATE_DEQUEUED; | 171 | vb->state = VB2_BUF_STATE_DEQUEUED; |
| 162 | vb->vb2_queue = q; | 172 | vb->vb2_queue = q; |
| 163 | vb->num_planes = num_planes; | 173 | vb->num_planes = num_planes; |
| 164 | vb->v4l2_buf.index = buffer; | 174 | vb->v4l2_buf.index = q->num_buffers + buffer; |
| 165 | vb->v4l2_buf.type = q->type; | 175 | vb->v4l2_buf.type = q->type; |
| 166 | vb->v4l2_buf.memory = memory; | 176 | vb->v4l2_buf.memory = memory; |
| 167 | 177 | ||
| @@ -189,15 +199,13 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory, | |||
| 189 | } | 199 | } |
| 190 | } | 200 | } |
| 191 | 201 | ||
| 192 | q->bufs[buffer] = vb; | 202 | q->bufs[q->num_buffers + buffer] = vb; |
| 193 | } | 203 | } |
| 194 | 204 | ||
| 195 | q->num_buffers = buffer; | 205 | __setup_offsets(q, buffer); |
| 196 | |||
| 197 | __setup_offsets(q); | ||
| 198 | 206 | ||
| 199 | dprintk(1, "Allocated %d buffers, %d plane(s) each\n", | 207 | dprintk(1, "Allocated %d buffers, %d plane(s) each\n", |
| 200 | q->num_buffers, num_planes); | 208 | buffer, num_planes); |
| 201 | 209 | ||
| 202 | return buffer; | 210 | return buffer; |
| 203 | } | 211 | } |
| @@ -205,12 +213,13 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory, | |||
| 205 | /** | 213 | /** |
| 206 | * __vb2_free_mem() - release all video buffer memory for a given queue | 214 | * __vb2_free_mem() - release all video buffer memory for a given queue |
| 207 | */ | 215 | */ |
| 208 | static void __vb2_free_mem(struct vb2_queue *q) | 216 | static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers) |
| 209 | { | 217 | { |
| 210 | unsigned int buffer; | 218 | unsigned int buffer; |
| 211 | struct vb2_buffer *vb; | 219 | struct vb2_buffer *vb; |
| 212 | 220 | ||
| 213 | for (buffer = 0; buffer < q->num_buffers; ++buffer) { | 221 | for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; |
| 222 | ++buffer) { | ||
| 214 | vb = q->bufs[buffer]; | 223 | vb = q->bufs[buffer]; |
| 215 | if (!vb) | 224 | if (!vb) |
| 216 | continue; | 225 | continue; |
| @@ -224,17 +233,18 @@ static void __vb2_free_mem(struct vb2_queue *q) | |||
| 224 | } | 233 | } |
| 225 | 234 | ||
| 226 | /** | 235 | /** |
| 227 | * __vb2_queue_free() - free the queue - video memory and related information | 236 | * __vb2_queue_free() - free buffers at the end of the queue - video memory and |
| 228 | * and return the queue to an uninitialized state. Might be called even if the | 237 | * related information, if no buffers are left return the queue to an |
| 229 | * queue has already been freed. | 238 | * uninitialized state. Might be called even if the queue has already been freed. |
| 230 | */ | 239 | */ |
| 231 | static void __vb2_queue_free(struct vb2_queue *q) | 240 | static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) |
| 232 | { | 241 | { |
| 233 | unsigned int buffer; | 242 | unsigned int buffer; |
| 234 | 243 | ||
| 235 | /* Call driver-provided cleanup function for each buffer, if provided */ | 244 | /* Call driver-provided cleanup function for each buffer, if provided */ |
| 236 | if (q->ops->buf_cleanup) { | 245 | if (q->ops->buf_cleanup) { |
| 237 | for (buffer = 0; buffer < q->num_buffers; ++buffer) { | 246 | for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; |
| 247 | ++buffer) { | ||
| 238 | if (NULL == q->bufs[buffer]) | 248 | if (NULL == q->bufs[buffer]) |
| 239 | continue; | 249 | continue; |
| 240 | q->ops->buf_cleanup(q->bufs[buffer]); | 250 | q->ops->buf_cleanup(q->bufs[buffer]); |
| @@ -242,23 +252,25 @@ static void __vb2_queue_free(struct vb2_queue *q) | |||
| 242 | } | 252 | } |
| 243 | 253 | ||
| 244 | /* Release video buffer memory */ | 254 | /* Release video buffer memory */ |
| 245 | __vb2_free_mem(q); | 255 | __vb2_free_mem(q, buffers); |
| 246 | 256 | ||
| 247 | /* Free videobuf buffers */ | 257 | /* Free videobuf buffers */ |
| 248 | for (buffer = 0; buffer < q->num_buffers; ++buffer) { | 258 | for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; |
| 259 | ++buffer) { | ||
| 249 | kfree(q->bufs[buffer]); | 260 | kfree(q->bufs[buffer]); |
| 250 | q->bufs[buffer] = NULL; | 261 | q->bufs[buffer] = NULL; |
| 251 | } | 262 | } |
| 252 | 263 | ||
| 253 | q->num_buffers = 0; | 264 | q->num_buffers -= buffers; |
| 254 | q->memory = 0; | 265 | if (!q->num_buffers) |
| 266 | q->memory = 0; | ||
| 255 | } | 267 | } |
| 256 | 268 | ||
| 257 | /** | 269 | /** |
| 258 | * __verify_planes_array() - verify that the planes array passed in struct | 270 | * __verify_planes_array() - verify that the planes array passed in struct |
| 259 | * v4l2_buffer from userspace can be safely used | 271 | * v4l2_buffer from userspace can be safely used |
| 260 | */ | 272 | */ |
| 261 | static int __verify_planes_array(struct vb2_buffer *vb, struct v4l2_buffer *b) | 273 | static int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_buffer *b) |
| 262 | { | 274 | { |
| 263 | /* Is memory for copying plane information present? */ | 275 | /* Is memory for copying plane information present? */ |
| 264 | if (NULL == b->m.planes) { | 276 | if (NULL == b->m.planes) { |
| @@ -318,7 +330,7 @@ static bool __buffers_in_use(struct vb2_queue *q) | |||
| 318 | static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) | 330 | static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) |
| 319 | { | 331 | { |
| 320 | struct vb2_queue *q = vb->vb2_queue; | 332 | struct vb2_queue *q = vb->vb2_queue; |
| 321 | int ret = 0; | 333 | int ret; |
| 322 | 334 | ||
| 323 | /* Copy back data such as timestamp, flags, input, etc. */ | 335 | /* Copy back data such as timestamp, flags, input, etc. */ |
| 324 | memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m)); | 336 | memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m)); |
| @@ -365,6 +377,9 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) | |||
| 365 | case VB2_BUF_STATE_DONE: | 377 | case VB2_BUF_STATE_DONE: |
| 366 | b->flags |= V4L2_BUF_FLAG_DONE; | 378 | b->flags |= V4L2_BUF_FLAG_DONE; |
| 367 | break; | 379 | break; |
| 380 | case VB2_BUF_STATE_PREPARED: | ||
| 381 | b->flags |= V4L2_BUF_FLAG_PREPARED; | ||
| 382 | break; | ||
| 368 | case VB2_BUF_STATE_DEQUEUED: | 383 | case VB2_BUF_STATE_DEQUEUED: |
| 369 | /* nothing */ | 384 | /* nothing */ |
| 370 | break; | 385 | break; |
| @@ -373,7 +388,7 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) | |||
| 373 | if (__buffer_in_use(q, vb)) | 388 | if (__buffer_in_use(q, vb)) |
| 374 | b->flags |= V4L2_BUF_FLAG_MAPPED; | 389 | b->flags |= V4L2_BUF_FLAG_MAPPED; |
| 375 | 390 | ||
| 376 | return ret; | 391 | return 0; |
| 377 | } | 392 | } |
| 378 | 393 | ||
| 379 | /** | 394 | /** |
| @@ -459,7 +474,7 @@ static int __verify_mmap_ops(struct vb2_queue *q) | |||
| 459 | */ | 474 | */ |
| 460 | int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) | 475 | int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) |
| 461 | { | 476 | { |
| 462 | unsigned int num_buffers, num_planes; | 477 | unsigned int num_buffers, allocated_buffers, num_planes = 0; |
| 463 | int ret = 0; | 478 | int ret = 0; |
| 464 | 479 | ||
| 465 | if (q->fileio) { | 480 | if (q->fileio) { |
| @@ -507,7 +522,7 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) | |||
| 507 | return -EBUSY; | 522 | return -EBUSY; |
| 508 | } | 523 | } |
| 509 | 524 | ||
| 510 | __vb2_queue_free(q); | 525 | __vb2_queue_free(q, q->num_buffers); |
| 511 | 526 | ||
| 512 | /* | 527 | /* |
| 513 | * In case of REQBUFS(0) return immediately without calling | 528 | * In case of REQBUFS(0) return immediately without calling |
| @@ -529,7 +544,7 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) | |||
| 529 | * Ask the driver how many buffers and planes per buffer it requires. | 544 | * Ask the driver how many buffers and planes per buffer it requires. |
| 530 | * Driver also sets the size and allocator context for each plane. | 545 | * Driver also sets the size and allocator context for each plane. |
| 531 | */ | 546 | */ |
| 532 | ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes, | 547 | ret = call_qop(q, queue_setup, q, NULL, &num_buffers, &num_planes, |
| 533 | q->plane_sizes, q->alloc_ctx); | 548 | q->plane_sizes, q->alloc_ctx); |
| 534 | if (ret) | 549 | if (ret) |
| 535 | return ret; | 550 | return ret; |
| @@ -541,44 +556,168 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) | |||
| 541 | return -ENOMEM; | 556 | return -ENOMEM; |
| 542 | } | 557 | } |
| 543 | 558 | ||
| 559 | allocated_buffers = ret; | ||
| 560 | |||
| 544 | /* | 561 | /* |
| 545 | * Check if driver can handle the allocated number of buffers. | 562 | * Check if driver can handle the allocated number of buffers. |
| 546 | */ | 563 | */ |
| 547 | if (ret < num_buffers) { | 564 | if (allocated_buffers < num_buffers) { |
| 548 | unsigned int orig_num_buffers; | 565 | num_buffers = allocated_buffers; |
| 549 | 566 | ||
| 550 | orig_num_buffers = num_buffers = ret; | 567 | ret = call_qop(q, queue_setup, q, NULL, &num_buffers, |
| 551 | ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes, | 568 | &num_planes, q->plane_sizes, q->alloc_ctx); |
| 552 | q->plane_sizes, q->alloc_ctx); | ||
| 553 | if (ret) | ||
| 554 | goto free_mem; | ||
| 555 | 569 | ||
| 556 | if (orig_num_buffers < num_buffers) { | 570 | if (!ret && allocated_buffers < num_buffers) |
| 557 | ret = -ENOMEM; | 571 | ret = -ENOMEM; |
| 558 | goto free_mem; | ||
| 559 | } | ||
| 560 | 572 | ||
| 561 | /* | 573 | /* |
| 562 | * Ok, driver accepted smaller number of buffers. | 574 | * Either the driver has accepted a smaller number of buffers, |
| 575 | * or .queue_setup() returned an error | ||
| 563 | */ | 576 | */ |
| 564 | ret = num_buffers; | 577 | } |
| 578 | |||
| 579 | q->num_buffers = allocated_buffers; | ||
| 580 | |||
| 581 | if (ret < 0) { | ||
| 582 | __vb2_queue_free(q, allocated_buffers); | ||
| 583 | return ret; | ||
| 565 | } | 584 | } |
| 566 | 585 | ||
| 567 | /* | 586 | /* |
| 568 | * Return the number of successfully allocated buffers | 587 | * Return the number of successfully allocated buffers |
| 569 | * to the userspace. | 588 | * to the userspace. |
| 570 | */ | 589 | */ |
| 571 | req->count = ret; | 590 | req->count = allocated_buffers; |
| 572 | 591 | ||
| 573 | return 0; | 592 | return 0; |
| 574 | |||
| 575 | free_mem: | ||
| 576 | __vb2_queue_free(q); | ||
| 577 | return ret; | ||
| 578 | } | 593 | } |
| 579 | EXPORT_SYMBOL_GPL(vb2_reqbufs); | 594 | EXPORT_SYMBOL_GPL(vb2_reqbufs); |
| 580 | 595 | ||
| 581 | /** | 596 | /** |
| 597 | * vb2_create_bufs() - Allocate buffers and any required auxiliary structs | ||
| 598 | * @q: videobuf2 queue | ||
| 599 | * @create: creation parameters, passed from userspace to vidioc_create_bufs | ||
| 600 | * handler in driver | ||
| 601 | * | ||
| 602 | * Should be called from vidioc_create_bufs ioctl handler of a driver. | ||
| 603 | * This function: | ||
| 604 | * 1) verifies parameter sanity | ||
| 605 | * 2) calls the .queue_setup() queue operation | ||
| 606 | * 3) performs any necessary memory allocations | ||
| 607 | * | ||
| 608 | * The return values from this function are intended to be directly returned | ||
| 609 | * from vidioc_create_bufs handler in driver. | ||
| 610 | */ | ||
| 611 | int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) | ||
| 612 | { | ||
| 613 | unsigned int num_planes = 0, num_buffers, allocated_buffers; | ||
| 614 | int ret = 0; | ||
| 615 | |||
| 616 | if (q->fileio) { | ||
| 617 | dprintk(1, "%s(): file io in progress\n", __func__); | ||
| 618 | return -EBUSY; | ||
| 619 | } | ||
| 620 | |||
| 621 | if (create->memory != V4L2_MEMORY_MMAP | ||
| 622 | && create->memory != V4L2_MEMORY_USERPTR) { | ||
| 623 | dprintk(1, "%s(): unsupported memory type\n", __func__); | ||
| 624 | return -EINVAL; | ||
| 625 | } | ||
| 626 | |||
| 627 | if (create->format.type != q->type) { | ||
| 628 | dprintk(1, "%s(): requested type is incorrect\n", __func__); | ||
| 629 | return -EINVAL; | ||
| 630 | } | ||
| 631 | |||
| 632 | /* | ||
| 633 | * Make sure all the required memory ops for given memory type | ||
| 634 | * are available. | ||
| 635 | */ | ||
| 636 | if (create->memory == V4L2_MEMORY_MMAP && __verify_mmap_ops(q)) { | ||
| 637 | dprintk(1, "%s(): MMAP for current setup unsupported\n", __func__); | ||
| 638 | return -EINVAL; | ||
| 639 | } | ||
| 640 | |||
| 641 | if (create->memory == V4L2_MEMORY_USERPTR && __verify_userptr_ops(q)) { | ||
| 642 | dprintk(1, "%s(): USERPTR for current setup unsupported\n", __func__); | ||
| 643 | return -EINVAL; | ||
| 644 | } | ||
| 645 | |||
| 646 | if (q->num_buffers == VIDEO_MAX_FRAME) { | ||
| 647 | dprintk(1, "%s(): maximum number of buffers already allocated\n", | ||
| 648 | __func__); | ||
| 649 | return -ENOBUFS; | ||
| 650 | } | ||
| 651 | |||
| 652 | create->index = q->num_buffers; | ||
| 653 | |||
| 654 | if (!q->num_buffers) { | ||
| 655 | memset(q->plane_sizes, 0, sizeof(q->plane_sizes)); | ||
| 656 | memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx)); | ||
| 657 | q->memory = create->memory; | ||
| 658 | } | ||
| 659 | |||
| 660 | num_buffers = min(create->count, VIDEO_MAX_FRAME - q->num_buffers); | ||
| 661 | |||
| 662 | /* | ||
| 663 | * Ask the driver, whether the requested number of buffers, planes per | ||
| 664 | * buffer and their sizes are acceptable | ||
| 665 | */ | ||
| 666 | ret = call_qop(q, queue_setup, q, &create->format, &num_buffers, | ||
| 667 | &num_planes, q->plane_sizes, q->alloc_ctx); | ||
| 668 | if (ret) | ||
| 669 | return ret; | ||
| 670 | |||
| 671 | /* Finally, allocate buffers and video memory */ | ||
| 672 | ret = __vb2_queue_alloc(q, create->memory, num_buffers, | ||
| 673 | num_planes); | ||
| 674 | if (ret < 0) { | ||
| 675 | dprintk(1, "Memory allocation failed with error: %d\n", ret); | ||
| 676 | return ret; | ||
| 677 | } | ||
| 678 | |||
| 679 | allocated_buffers = ret; | ||
| 680 | |||
| 681 | /* | ||
| 682 | * Check if driver can handle the so far allocated number of buffers. | ||
| 683 | */ | ||
| 684 | if (ret < num_buffers) { | ||
| 685 | num_buffers = ret; | ||
| 686 | |||
| 687 | /* | ||
| 688 | * q->num_buffers contains the total number of buffers, that the | ||
| 689 | * queue driver has set up | ||
| 690 | */ | ||
| 691 | ret = call_qop(q, queue_setup, q, &create->format, &num_buffers, | ||
| 692 | &num_planes, q->plane_sizes, q->alloc_ctx); | ||
| 693 | |||
| 694 | if (!ret && allocated_buffers < num_buffers) | ||
| 695 | ret = -ENOMEM; | ||
| 696 | |||
| 697 | /* | ||
| 698 | * Either the driver has accepted a smaller number of buffers, | ||
| 699 | * or .queue_setup() returned an error | ||
| 700 | */ | ||
| 701 | } | ||
| 702 | |||
| 703 | q->num_buffers += allocated_buffers; | ||
| 704 | |||
| 705 | if (ret < 0) { | ||
| 706 | __vb2_queue_free(q, allocated_buffers); | ||
| 707 | return ret; | ||
| 708 | } | ||
| 709 | |||
| 710 | /* | ||
| 711 | * Return the number of successfully allocated buffers | ||
| 712 | * to the userspace. | ||
| 713 | */ | ||
| 714 | create->count = allocated_buffers; | ||
| 715 | |||
| 716 | return 0; | ||
| 717 | } | ||
| 718 | EXPORT_SYMBOL_GPL(vb2_create_bufs); | ||
| 719 | |||
| 720 | /** | ||
| 582 | * vb2_plane_vaddr() - Return a kernel virtual address of a given plane | 721 | * vb2_plane_vaddr() - Return a kernel virtual address of a given plane |
| 583 | * @vb: vb2_buffer to which the plane in question belongs to | 722 | * @vb: vb2_buffer to which the plane in question belongs to |
| 584 | * @plane_no: plane number for which the address is to be returned | 723 | * @plane_no: plane number for which the address is to be returned |
| @@ -662,7 +801,7 @@ EXPORT_SYMBOL_GPL(vb2_buffer_done); | |||
| 662 | * __fill_vb2_buffer() - fill a vb2_buffer with information provided in | 801 | * __fill_vb2_buffer() - fill a vb2_buffer with information provided in |
| 663 | * a v4l2_buffer by the userspace | 802 | * a v4l2_buffer by the userspace |
| 664 | */ | 803 | */ |
| 665 | static int __fill_vb2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b, | 804 | static int __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b, |
| 666 | struct v4l2_plane *v4l2_planes) | 805 | struct v4l2_plane *v4l2_planes) |
| 667 | { | 806 | { |
| 668 | unsigned int plane; | 807 | unsigned int plane; |
| @@ -726,7 +865,7 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b, | |||
| 726 | /** | 865 | /** |
| 727 | * __qbuf_userptr() - handle qbuf of a USERPTR buffer | 866 | * __qbuf_userptr() - handle qbuf of a USERPTR buffer |
| 728 | */ | 867 | */ |
| 729 | static int __qbuf_userptr(struct vb2_buffer *vb, struct v4l2_buffer *b) | 868 | static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b) |
| 730 | { | 869 | { |
| 731 | struct v4l2_plane planes[VIDEO_MAX_PLANES]; | 870 | struct v4l2_plane planes[VIDEO_MAX_PLANES]; |
| 732 | struct vb2_queue *q = vb->vb2_queue; | 871 | struct vb2_queue *q = vb->vb2_queue; |
| @@ -815,7 +954,7 @@ err: | |||
| 815 | /** | 954 | /** |
| 816 | * __qbuf_mmap() - handle qbuf of an MMAP buffer | 955 | * __qbuf_mmap() - handle qbuf of an MMAP buffer |
| 817 | */ | 956 | */ |
| 818 | static int __qbuf_mmap(struct vb2_buffer *vb, struct v4l2_buffer *b) | 957 | static int __qbuf_mmap(struct vb2_buffer *vb, const struct v4l2_buffer *b) |
| 819 | { | 958 | { |
| 820 | return __fill_vb2_buffer(vb, b, vb->v4l2_planes); | 959 | return __fill_vb2_buffer(vb, b, vb->v4l2_planes); |
| 821 | } | 960 | } |
| @@ -832,6 +971,95 @@ static void __enqueue_in_driver(struct vb2_buffer *vb) | |||
| 832 | q->ops->buf_queue(vb); | 971 | q->ops->buf_queue(vb); |
| 833 | } | 972 | } |
| 834 | 973 | ||
| 974 | static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b) | ||
| 975 | { | ||
| 976 | struct vb2_queue *q = vb->vb2_queue; | ||
| 977 | int ret; | ||
| 978 | |||
| 979 | switch (q->memory) { | ||
| 980 | case V4L2_MEMORY_MMAP: | ||
| 981 | ret = __qbuf_mmap(vb, b); | ||
| 982 | break; | ||
| 983 | case V4L2_MEMORY_USERPTR: | ||
| 984 | ret = __qbuf_userptr(vb, b); | ||
| 985 | break; | ||
| 986 | default: | ||
| 987 | WARN(1, "Invalid queue type\n"); | ||
| 988 | ret = -EINVAL; | ||
| 989 | } | ||
| 990 | |||
| 991 | if (!ret) | ||
| 992 | ret = call_qop(q, buf_prepare, vb); | ||
| 993 | if (ret) | ||
| 994 | dprintk(1, "qbuf: buffer preparation failed: %d\n", ret); | ||
| 995 | else | ||
| 996 | vb->state = VB2_BUF_STATE_PREPARED; | ||
| 997 | |||
| 998 | return ret; | ||
| 999 | } | ||
| 1000 | |||
| 1001 | /** | ||
| 1002 | * vb2_prepare_buf() - Pass ownership of a buffer from userspace to the kernel | ||
| 1003 | * @q: videobuf2 queue | ||
| 1004 | * @b: buffer structure passed from userspace to vidioc_prepare_buf | ||
| 1005 | * handler in driver | ||
| 1006 | * | ||
| 1007 | * Should be called from vidioc_prepare_buf ioctl handler of a driver. | ||
| 1008 | * This function: | ||
| 1009 | * 1) verifies the passed buffer, | ||
| 1010 | * 2) calls buf_prepare callback in the driver (if provided), in which | ||
| 1011 | * driver-specific buffer initialization can be performed, | ||
| 1012 | * | ||
| 1013 | * The return values from this function are intended to be directly returned | ||
| 1014 | * from vidioc_prepare_buf handler in driver. | ||
| 1015 | */ | ||
| 1016 | int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b) | ||
| 1017 | { | ||
| 1018 | struct vb2_buffer *vb; | ||
| 1019 | int ret; | ||
| 1020 | |||
| 1021 | if (q->fileio) { | ||
| 1022 | dprintk(1, "%s(): file io in progress\n", __func__); | ||
| 1023 | return -EBUSY; | ||
| 1024 | } | ||
| 1025 | |||
| 1026 | if (b->type != q->type) { | ||
| 1027 | dprintk(1, "%s(): invalid buffer type\n", __func__); | ||
| 1028 | return -EINVAL; | ||
| 1029 | } | ||
| 1030 | |||
| 1031 | if (b->index >= q->num_buffers) { | ||
| 1032 | dprintk(1, "%s(): buffer index out of range\n", __func__); | ||
| 1033 | return -EINVAL; | ||
| 1034 | } | ||
| 1035 | |||
| 1036 | vb = q->bufs[b->index]; | ||
| 1037 | if (NULL == vb) { | ||
| 1038 | /* Should never happen */ | ||
| 1039 | dprintk(1, "%s(): buffer is NULL\n", __func__); | ||
| 1040 | return -EINVAL; | ||
| 1041 | } | ||
| 1042 | |||
| 1043 | if (b->memory != q->memory) { | ||
| 1044 | dprintk(1, "%s(): invalid memory type\n", __func__); | ||
| 1045 | return -EINVAL; | ||
| 1046 | } | ||
| 1047 | |||
| 1048 | if (vb->state != VB2_BUF_STATE_DEQUEUED) { | ||
| 1049 | dprintk(1, "%s(): invalid buffer state %d\n", __func__, vb->state); | ||
| 1050 | return -EINVAL; | ||
| 1051 | } | ||
| 1052 | |||
| 1053 | ret = __buf_prepare(vb, b); | ||
| 1054 | if (ret < 0) | ||
| 1055 | return ret; | ||
| 1056 | |||
| 1057 | __fill_v4l2_buffer(vb, b); | ||
| 1058 | |||
| 1059 | return 0; | ||
| 1060 | } | ||
| 1061 | EXPORT_SYMBOL_GPL(vb2_prepare_buf); | ||
| 1062 | |||
| 835 | /** | 1063 | /** |
| 836 | * vb2_qbuf() - Queue a buffer from userspace | 1064 | * vb2_qbuf() - Queue a buffer from userspace |
| 837 | * @q: videobuf2 queue | 1065 | * @q: videobuf2 queue |
| @@ -841,8 +1069,8 @@ static void __enqueue_in_driver(struct vb2_buffer *vb) | |||
| 841 | * Should be called from vidioc_qbuf ioctl handler of a driver. | 1069 | * Should be called from vidioc_qbuf ioctl handler of a driver. |
| 842 | * This function: | 1070 | * This function: |
| 843 | * 1) verifies the passed buffer, | 1071 | * 1) verifies the passed buffer, |
| 844 | * 2) calls buf_prepare callback in the driver (if provided), in which | 1072 | * 2) if necessary, calls buf_prepare callback in the driver (if provided), in |
| 845 | * driver-specific buffer initialization can be performed, | 1073 | * which driver-specific buffer initialization can be performed, |
| 846 | * 3) if streaming is on, queues the buffer in driver by the means of buf_queue | 1074 | * 3) if streaming is on, queues the buffer in driver by the means of buf_queue |
| 847 | * callback for processing. | 1075 | * callback for processing. |
| 848 | * | 1076 | * |
| @@ -852,7 +1080,7 @@ static void __enqueue_in_driver(struct vb2_buffer *vb) | |||
| 852 | int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) | 1080 | int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) |
| 853 | { | 1081 | { |
| 854 | struct vb2_buffer *vb; | 1082 | struct vb2_buffer *vb; |
| 855 | int ret = 0; | 1083 | int ret; |
| 856 | 1084 | ||
| 857 | if (q->fileio) { | 1085 | if (q->fileio) { |
| 858 | dprintk(1, "qbuf: file io in progress\n"); | 1086 | dprintk(1, "qbuf: file io in progress\n"); |
| @@ -881,29 +1109,18 @@ int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) | |||
| 881 | return -EINVAL; | 1109 | return -EINVAL; |
| 882 | } | 1110 | } |
| 883 | 1111 | ||
| 884 | if (vb->state != VB2_BUF_STATE_DEQUEUED) { | 1112 | switch (vb->state) { |
| 1113 | case VB2_BUF_STATE_DEQUEUED: | ||
| 1114 | ret = __buf_prepare(vb, b); | ||
| 1115 | if (ret) | ||
| 1116 | return ret; | ||
| 1117 | case VB2_BUF_STATE_PREPARED: | ||
| 1118 | break; | ||
| 1119 | default: | ||
| 885 | dprintk(1, "qbuf: buffer already in use\n"); | 1120 | dprintk(1, "qbuf: buffer already in use\n"); |
| 886 | return -EINVAL; | 1121 | return -EINVAL; |
| 887 | } | 1122 | } |
| 888 | 1123 | ||
| 889 | if (q->memory == V4L2_MEMORY_MMAP) | ||
| 890 | ret = __qbuf_mmap(vb, b); | ||
| 891 | else if (q->memory == V4L2_MEMORY_USERPTR) | ||
| 892 | ret = __qbuf_userptr(vb, b); | ||
| 893 | else { | ||
| 894 | WARN(1, "Invalid queue type\n"); | ||
| 895 | return -EINVAL; | ||
| 896 | } | ||
| 897 | |||
| 898 | if (ret) | ||
| 899 | return ret; | ||
| 900 | |||
| 901 | ret = call_qop(q, buf_prepare, vb); | ||
| 902 | if (ret) { | ||
| 903 | dprintk(1, "qbuf: buffer preparation failed\n"); | ||
| 904 | return ret; | ||
| 905 | } | ||
| 906 | |||
| 907 | /* | 1124 | /* |
| 908 | * Add to the queued buffers list, a buffer will stay on it until | 1125 | * Add to the queued buffers list, a buffer will stay on it until |
| 909 | * dequeued in dqbuf. | 1126 | * dequeued in dqbuf. |
| @@ -918,6 +1135,9 @@ int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) | |||
| 918 | if (q->streaming) | 1135 | if (q->streaming) |
| 919 | __enqueue_in_driver(vb); | 1136 | __enqueue_in_driver(vb); |
| 920 | 1137 | ||
| 1138 | /* Fill buffer information for the userspace */ | ||
| 1139 | __fill_v4l2_buffer(vb, b); | ||
| 1140 | |||
| 921 | dprintk(1, "qbuf of buffer %d succeeded\n", vb->v4l2_buf.index); | 1141 | dprintk(1, "qbuf of buffer %d succeeded\n", vb->v4l2_buf.index); |
| 922 | return 0; | 1142 | return 0; |
| 923 | } | 1143 | } |
| @@ -1347,6 +1567,37 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) | |||
| 1347 | } | 1567 | } |
| 1348 | EXPORT_SYMBOL_GPL(vb2_mmap); | 1568 | EXPORT_SYMBOL_GPL(vb2_mmap); |
| 1349 | 1569 | ||
| 1570 | #ifndef CONFIG_MMU | ||
| 1571 | unsigned long vb2_get_unmapped_area(struct vb2_queue *q, | ||
| 1572 | unsigned long addr, | ||
| 1573 | unsigned long len, | ||
| 1574 | unsigned long pgoff, | ||
| 1575 | unsigned long flags) | ||
| 1576 | { | ||
| 1577 | unsigned long off = pgoff << PAGE_SHIFT; | ||
| 1578 | struct vb2_buffer *vb; | ||
| 1579 | unsigned int buffer, plane; | ||
| 1580 | int ret; | ||
| 1581 | |||
| 1582 | if (q->memory != V4L2_MEMORY_MMAP) { | ||
| 1583 | dprintk(1, "Queue is not currently set up for mmap\n"); | ||
| 1584 | return -EINVAL; | ||
| 1585 | } | ||
| 1586 | |||
| 1587 | /* | ||
| 1588 | * Find the plane corresponding to the offset passed by userspace. | ||
| 1589 | */ | ||
| 1590 | ret = __find_plane_by_offset(q, off, &buffer, &plane); | ||
| 1591 | if (ret) | ||
| 1592 | return ret; | ||
| 1593 | |||
| 1594 | vb = q->bufs[buffer]; | ||
| 1595 | |||
| 1596 | return (unsigned long)vb2_plane_vaddr(vb, plane); | ||
| 1597 | } | ||
| 1598 | EXPORT_SYMBOL_GPL(vb2_get_unmapped_area); | ||
| 1599 | #endif | ||
| 1600 | |||
| 1350 | static int __vb2_init_fileio(struct vb2_queue *q, int read); | 1601 | static int __vb2_init_fileio(struct vb2_queue *q, int read); |
| 1351 | static int __vb2_cleanup_fileio(struct vb2_queue *q); | 1602 | static int __vb2_cleanup_fileio(struct vb2_queue *q); |
| 1352 | 1603 | ||
| @@ -1464,7 +1715,7 @@ void vb2_queue_release(struct vb2_queue *q) | |||
| 1464 | { | 1715 | { |
| 1465 | __vb2_cleanup_fileio(q); | 1716 | __vb2_cleanup_fileio(q); |
| 1466 | __vb2_queue_cancel(q); | 1717 | __vb2_queue_cancel(q); |
| 1467 | __vb2_queue_free(q); | 1718 | __vb2_queue_free(q, q->num_buffers); |
| 1468 | } | 1719 | } |
| 1469 | EXPORT_SYMBOL_GPL(vb2_queue_release); | 1720 | EXPORT_SYMBOL_GPL(vb2_queue_release); |
| 1470 | 1721 | ||
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 7cf94c09d99a..7d754fbcccbf 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c | |||
| @@ -650,9 +650,9 @@ static void vivi_stop_generating(struct vivi_dev *dev) | |||
| 650 | /* ------------------------------------------------------------------ | 650 | /* ------------------------------------------------------------------ |
| 651 | Videobuf operations | 651 | Videobuf operations |
| 652 | ------------------------------------------------------------------*/ | 652 | ------------------------------------------------------------------*/ |
| 653 | static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, | 653 | static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, |
| 654 | unsigned int *nplanes, unsigned int sizes[], | 654 | unsigned int *nbuffers, unsigned int *nplanes, |
| 655 | void *alloc_ctxs[]) | 655 | unsigned int sizes[], void *alloc_ctxs[]) |
| 656 | { | 656 | { |
| 657 | struct vivi_dev *dev = vb2_get_drv_priv(vq); | 657 | struct vivi_dev *dev = vb2_get_drv_priv(vq); |
| 658 | unsigned long size; | 658 | unsigned long size; |
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index d132c27dfb3f..25cdff36a78a 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig | |||
| @@ -30,12 +30,6 @@ source "drivers/staging/et131x/Kconfig" | |||
| 30 | 30 | ||
| 31 | source "drivers/staging/slicoss/Kconfig" | 31 | source "drivers/staging/slicoss/Kconfig" |
| 32 | 32 | ||
| 33 | source "drivers/staging/go7007/Kconfig" | ||
| 34 | |||
| 35 | source "drivers/staging/cx25821/Kconfig" | ||
| 36 | |||
| 37 | source "drivers/staging/cxd2099/Kconfig" | ||
| 38 | |||
| 39 | source "drivers/staging/usbip/Kconfig" | 33 | source "drivers/staging/usbip/Kconfig" |
| 40 | 34 | ||
| 41 | source "drivers/staging/winbond/Kconfig" | 35 | source "drivers/staging/winbond/Kconfig" |
| @@ -104,20 +98,12 @@ source "drivers/staging/wlags49_h25/Kconfig" | |||
| 104 | 98 | ||
| 105 | source "drivers/staging/sm7xx/Kconfig" | 99 | source "drivers/staging/sm7xx/Kconfig" |
| 106 | 100 | ||
| 107 | source "drivers/staging/dt3155v4l/Kconfig" | ||
| 108 | |||
| 109 | source "drivers/staging/crystalhd/Kconfig" | 101 | source "drivers/staging/crystalhd/Kconfig" |
| 110 | 102 | ||
| 111 | source "drivers/staging/cxt1e1/Kconfig" | 103 | source "drivers/staging/cxt1e1/Kconfig" |
| 112 | 104 | ||
| 113 | source "drivers/staging/xgifb/Kconfig" | 105 | source "drivers/staging/xgifb/Kconfig" |
| 114 | 106 | ||
| 115 | source "drivers/staging/lirc/Kconfig" | ||
| 116 | |||
| 117 | source "drivers/staging/easycap/Kconfig" | ||
| 118 | |||
| 119 | source "drivers/staging/solo6x10/Kconfig" | ||
| 120 | |||
| 121 | source "drivers/staging/tidspbridge/Kconfig" | 107 | source "drivers/staging/tidspbridge/Kconfig" |
| 122 | 108 | ||
| 123 | source "drivers/staging/quickstart/Kconfig" | 109 | source "drivers/staging/quickstart/Kconfig" |
| @@ -144,4 +130,6 @@ source "drivers/staging/mei/Kconfig" | |||
| 144 | 130 | ||
| 145 | source "drivers/staging/nvec/Kconfig" | 131 | source "drivers/staging/nvec/Kconfig" |
| 146 | 132 | ||
| 133 | source "drivers/staging/media/Kconfig" | ||
| 134 | |||
| 147 | endif # STAGING | 135 | endif # STAGING |
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 936b7c22e18e..a25f3f26c7ff 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile | |||
| @@ -4,12 +4,9 @@ | |||
| 4 | obj-$(CONFIG_STAGING) += staging.o | 4 | obj-$(CONFIG_STAGING) += staging.o |
| 5 | 5 | ||
| 6 | obj-y += serial/ | 6 | obj-y += serial/ |
| 7 | obj-y += media/ | ||
| 7 | obj-$(CONFIG_ET131X) += et131x/ | 8 | obj-$(CONFIG_ET131X) += et131x/ |
| 8 | obj-$(CONFIG_SLICOSS) += slicoss/ | 9 | obj-$(CONFIG_SLICOSS) += slicoss/ |
| 9 | obj-$(CONFIG_VIDEO_GO7007) += go7007/ | ||
| 10 | obj-$(CONFIG_VIDEO_CX25821) += cx25821/ | ||
| 11 | obj-$(CONFIG_DVB_CXD2099) += cxd2099/ | ||
| 12 | obj-$(CONFIG_LIRC_STAGING) += lirc/ | ||
| 13 | obj-$(CONFIG_USBIP_CORE) += usbip/ | 10 | obj-$(CONFIG_USBIP_CORE) += usbip/ |
| 14 | obj-$(CONFIG_W35UND) += winbond/ | 11 | obj-$(CONFIG_W35UND) += winbond/ |
| 15 | obj-$(CONFIG_PRISM2_USB) += wlan-ng/ | 12 | obj-$(CONFIG_PRISM2_USB) += wlan-ng/ |
| @@ -44,12 +41,9 @@ obj-$(CONFIG_ZCACHE) += zcache/ | |||
| 44 | obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/ | 41 | obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/ |
| 45 | obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/ | 42 | obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/ |
| 46 | obj-$(CONFIG_FB_SM7XX) += sm7xx/ | 43 | obj-$(CONFIG_FB_SM7XX) += sm7xx/ |
| 47 | obj-$(CONFIG_VIDEO_DT3155) += dt3155v4l/ | ||
| 48 | obj-$(CONFIG_CRYSTALHD) += crystalhd/ | 44 | obj-$(CONFIG_CRYSTALHD) += crystalhd/ |
| 49 | obj-$(CONFIG_CXT1E1) += cxt1e1/ | 45 | obj-$(CONFIG_CXT1E1) += cxt1e1/ |
| 50 | obj-$(CONFIG_FB_XGI) += xgifb/ | 46 | obj-$(CONFIG_FB_XGI) += xgifb/ |
| 51 | obj-$(CONFIG_EASYCAP) += easycap/ | ||
| 52 | obj-$(CONFIG_SOLO6X10) += solo6x10/ | ||
| 53 | obj-$(CONFIG_TIDSPBRIDGE) += tidspbridge/ | 47 | obj-$(CONFIG_TIDSPBRIDGE) += tidspbridge/ |
| 54 | obj-$(CONFIG_ACPI_QUICKSTART) += quickstart/ | 48 | obj-$(CONFIG_ACPI_QUICKSTART) += quickstart/ |
| 55 | obj-$(CONFIG_SBE_2T3E3) += sbe-2t3e3/ | 49 | obj-$(CONFIG_SBE_2T3E3) += sbe-2t3e3/ |
diff --git a/drivers/staging/cx25821/README b/drivers/staging/cx25821/README deleted file mode 100644 index a9ba50b9888b..000000000000 --- a/drivers/staging/cx25821/README +++ /dev/null | |||
| @@ -1,6 +0,0 @@ | |||
| 1 | Todo: | ||
| 2 | - checkpatch.pl cleanups | ||
| 3 | - sparse cleanups | ||
| 4 | |||
| 5 | Please send patches to linux-media@vger.kernel.org | ||
| 6 | |||
diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig new file mode 100644 index 000000000000..7e5caa39ed3f --- /dev/null +++ b/drivers/staging/media/Kconfig | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | menuconfig STAGING_MEDIA | ||
| 2 | bool "Media staging drivers" | ||
| 3 | default n | ||
| 4 | ---help--- | ||
| 5 | This option allows you to select a number of media drivers that | ||
| 6 | don't have the "normal" Linux kernel quality level. | ||
| 7 | Most of them don't follow properly the V4L, DVB and/or RC API's, | ||
| 8 | so, they won't likely work fine with the existing applications. | ||
| 9 | That also means that, one fixed, their API's will change to match | ||
| 10 | the existing ones. | ||
| 11 | |||
| 12 | If you wish to work on these drivers, to help improve them, or | ||
| 13 | to report problems you have with them, please use the | ||
| 14 | linux-media@vger.kernel.org mailing list. | ||
| 15 | |||
| 16 | If in doubt, say N here. | ||
| 17 | |||
| 18 | |||
| 19 | if STAGING_MEDIA | ||
| 20 | |||
| 21 | # Please keep them in alphabetic order | ||
| 22 | source "drivers/staging/media/as102/Kconfig" | ||
| 23 | |||
| 24 | source "drivers/staging/media/cxd2099/Kconfig" | ||
| 25 | |||
| 26 | source "drivers/staging/media/dt3155v4l/Kconfig" | ||
| 27 | |||
| 28 | source "drivers/staging/media/easycap/Kconfig" | ||
| 29 | |||
| 30 | source "drivers/staging/media/go7007/Kconfig" | ||
| 31 | |||
| 32 | source "drivers/staging/media/solo6x10/Kconfig" | ||
| 33 | |||
| 34 | # Keep LIRC at the end, as it has sub-menus | ||
| 35 | source "drivers/staging/media/lirc/Kconfig" | ||
| 36 | |||
| 37 | endif | ||
diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile new file mode 100644 index 000000000000..c69124cdb0d3 --- /dev/null +++ b/drivers/staging/media/Makefile | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | obj-$(CONFIG_DVB_AS102) += as102/ | ||
| 2 | obj-$(CONFIG_DVB_CXD2099) += cxd2099/ | ||
| 3 | obj-$(CONFIG_EASYCAP) += easycap/ | ||
| 4 | obj-$(CONFIG_LIRC_STAGING) += lirc/ | ||
| 5 | obj-$(CONFIG_SOLO6X10) += solo6x10/ | ||
| 6 | obj-$(CONFIG_VIDEO_DT3155) += dt3155v4l/ | ||
| 7 | obj-$(CONFIG_VIDEO_GO7007) += go7007/ | ||
diff --git a/drivers/staging/media/as102/Kconfig b/drivers/staging/media/as102/Kconfig new file mode 100644 index 000000000000..5865029db0f6 --- /dev/null +++ b/drivers/staging/media/as102/Kconfig | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | config DVB_AS102 | ||
| 2 | tristate "Abilis AS102 DVB receiver" | ||
| 3 | depends on DVB_CORE && USB && I2C && INPUT | ||
| 4 | help | ||
| 5 | Choose Y or M here if you have a device containing an AS102 | ||
| 6 | |||
| 7 | To compile this driver as a module, choose M here | ||
diff --git a/drivers/staging/media/as102/Makefile b/drivers/staging/media/as102/Makefile new file mode 100644 index 000000000000..e7dbb6f814d5 --- /dev/null +++ b/drivers/staging/media/as102/Makefile | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | dvb-as102-objs := as102_drv.o as102_fw.o as10x_cmd.o as10x_cmd_stream.o \ | ||
| 2 | as102_fe.o as102_usb_drv.o as10x_cmd_cfg.o | ||
| 3 | |||
| 4 | obj-$(CONFIG_DVB_AS102) += dvb-as102.o | ||
| 5 | |||
| 6 | EXTRA_CFLAGS += -DCONFIG_AS102_USB -Idrivers/media/dvb/dvb-core | ||
diff --git a/drivers/staging/media/as102/as102_drv.c b/drivers/staging/media/as102/as102_drv.c new file mode 100644 index 000000000000..d335c7d6fa0f --- /dev/null +++ b/drivers/staging/media/as102/as102_drv.c | |||
| @@ -0,0 +1,351 @@ | |||
| 1 | /* | ||
| 2 | * Abilis Systems Single DVB-T Receiver | ||
| 3 | * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com> | ||
| 4 | * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 9 | * any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 19 | */ | ||
| 20 | #include <linux/kernel.h> | ||
| 21 | #include <linux/errno.h> | ||
| 22 | #include <linux/init.h> | ||
| 23 | #include <linux/slab.h> | ||
| 24 | #include <linux/module.h> | ||
| 25 | #include <linux/mm.h> | ||
| 26 | #include <linux/kref.h> | ||
| 27 | #include <asm/uaccess.h> | ||
| 28 | #include <linux/usb.h> | ||
| 29 | |||
| 30 | /* header file for Usb device driver*/ | ||
| 31 | #include "as102_drv.h" | ||
| 32 | #include "as102_fw.h" | ||
| 33 | #include "dvbdev.h" | ||
| 34 | |||
| 35 | int debug; | ||
| 36 | module_param_named(debug, debug, int, 0644); | ||
| 37 | MODULE_PARM_DESC(debug, "Turn on/off debugging (default: off)"); | ||
| 38 | |||
| 39 | int dual_tuner; | ||
| 40 | module_param_named(dual_tuner, dual_tuner, int, 0644); | ||
| 41 | MODULE_PARM_DESC(dual_tuner, "Activate Dual-Tuner config (default: off)"); | ||
| 42 | |||
| 43 | static int fw_upload = 1; | ||
| 44 | module_param_named(fw_upload, fw_upload, int, 0644); | ||
| 45 | MODULE_PARM_DESC(fw_upload, "Turn on/off default FW upload (default: on)"); | ||
| 46 | |||
| 47 | static int pid_filtering; | ||
| 48 | module_param_named(pid_filtering, pid_filtering, int, 0644); | ||
| 49 | MODULE_PARM_DESC(pid_filtering, "Activate HW PID filtering (default: off)"); | ||
| 50 | |||
| 51 | static int ts_auto_disable; | ||
| 52 | module_param_named(ts_auto_disable, ts_auto_disable, int, 0644); | ||
| 53 | MODULE_PARM_DESC(ts_auto_disable, "Stream Auto Enable on FW (default: off)"); | ||
| 54 | |||
| 55 | int elna_enable = 1; | ||
| 56 | module_param_named(elna_enable, elna_enable, int, 0644); | ||
| 57 | MODULE_PARM_DESC(elna_enable, "Activate eLNA (default: on)"); | ||
| 58 | |||
| 59 | #ifdef DVB_DEFINE_MOD_OPT_ADAPTER_NR | ||
| 60 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | ||
| 61 | #endif | ||
| 62 | |||
| 63 | static void as102_stop_stream(struct as102_dev_t *dev) | ||
| 64 | { | ||
| 65 | struct as102_bus_adapter_t *bus_adap; | ||
| 66 | |||
| 67 | if (dev != NULL) | ||
| 68 | bus_adap = &dev->bus_adap; | ||
| 69 | else | ||
| 70 | return; | ||
| 71 | |||
| 72 | if (bus_adap->ops->stop_stream != NULL) | ||
| 73 | bus_adap->ops->stop_stream(dev); | ||
| 74 | |||
| 75 | if (ts_auto_disable) { | ||
| 76 | if (mutex_lock_interruptible(&dev->bus_adap.lock)) | ||
| 77 | return; | ||
| 78 | |||
| 79 | if (as10x_cmd_stop_streaming(bus_adap) < 0) | ||
| 80 | dprintk(debug, "as10x_cmd_stop_streaming failed\n"); | ||
| 81 | |||
| 82 | mutex_unlock(&dev->bus_adap.lock); | ||
| 83 | } | ||
| 84 | } | ||
| 85 | |||
| 86 | static int as102_start_stream(struct as102_dev_t *dev) | ||
| 87 | { | ||
| 88 | struct as102_bus_adapter_t *bus_adap; | ||
| 89 | int ret = -EFAULT; | ||
| 90 | |||
| 91 | if (dev != NULL) | ||
| 92 | bus_adap = &dev->bus_adap; | ||
| 93 | else | ||
| 94 | return ret; | ||
| 95 | |||
| 96 | if (bus_adap->ops->start_stream != NULL) | ||
| 97 | ret = bus_adap->ops->start_stream(dev); | ||
| 98 | |||
| 99 | if (ts_auto_disable) { | ||
| 100 | if (mutex_lock_interruptible(&dev->bus_adap.lock)) | ||
| 101 | return -EFAULT; | ||
| 102 | |||
| 103 | ret = as10x_cmd_start_streaming(bus_adap); | ||
| 104 | |||
| 105 | mutex_unlock(&dev->bus_adap.lock); | ||
| 106 | } | ||
| 107 | |||
| 108 | return ret; | ||
| 109 | } | ||
| 110 | |||
| 111 | static int as10x_pid_filter(struct as102_dev_t *dev, | ||
| 112 | int index, u16 pid, int onoff) { | ||
| 113 | |||
| 114 | struct as102_bus_adapter_t *bus_adap = &dev->bus_adap; | ||
| 115 | int ret = -EFAULT; | ||
| 116 | |||
| 117 | ENTER(); | ||
| 118 | |||
| 119 | if (mutex_lock_interruptible(&dev->bus_adap.lock)) { | ||
| 120 | dprintk(debug, "mutex_lock_interruptible(lock) failed !\n"); | ||
| 121 | return -EBUSY; | ||
| 122 | } | ||
| 123 | |||
| 124 | switch (onoff) { | ||
| 125 | case 0: | ||
| 126 | ret = as10x_cmd_del_PID_filter(bus_adap, (uint16_t) pid); | ||
| 127 | dprintk(debug, "DEL_PID_FILTER([%02d] 0x%04x) ret = %d\n", | ||
| 128 | index, pid, ret); | ||
| 129 | break; | ||
| 130 | case 1: | ||
| 131 | { | ||
| 132 | struct as10x_ts_filter filter; | ||
| 133 | |||
| 134 | filter.type = TS_PID_TYPE_TS; | ||
| 135 | filter.idx = 0xFF; | ||
| 136 | filter.pid = pid; | ||
| 137 | |||
| 138 | ret = as10x_cmd_add_PID_filter(bus_adap, &filter); | ||
| 139 | dprintk(debug, "ADD_PID_FILTER([%02d -> %02d], 0x%04x) ret = %d\n", | ||
| 140 | index, filter.idx, filter.pid, ret); | ||
| 141 | break; | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | mutex_unlock(&dev->bus_adap.lock); | ||
| 146 | |||
| 147 | LEAVE(); | ||
| 148 | return ret; | ||
| 149 | } | ||
| 150 | |||
| 151 | static int as102_dvb_dmx_start_feed(struct dvb_demux_feed *dvbdmxfeed) | ||
| 152 | { | ||
| 153 | int ret = 0; | ||
| 154 | struct dvb_demux *demux = dvbdmxfeed->demux; | ||
| 155 | struct as102_dev_t *as102_dev = demux->priv; | ||
| 156 | |||
| 157 | ENTER(); | ||
| 158 | |||
| 159 | if (mutex_lock_interruptible(&as102_dev->sem)) | ||
| 160 | return -ERESTARTSYS; | ||
| 161 | |||
| 162 | if (pid_filtering) { | ||
| 163 | as10x_pid_filter(as102_dev, | ||
| 164 | dvbdmxfeed->index, dvbdmxfeed->pid, 1); | ||
| 165 | } | ||
| 166 | |||
| 167 | if (as102_dev->streaming++ == 0) | ||
| 168 | ret = as102_start_stream(as102_dev); | ||
| 169 | |||
| 170 | mutex_unlock(&as102_dev->sem); | ||
| 171 | LEAVE(); | ||
| 172 | return ret; | ||
| 173 | } | ||
| 174 | |||
| 175 | static int as102_dvb_dmx_stop_feed(struct dvb_demux_feed *dvbdmxfeed) | ||
| 176 | { | ||
| 177 | struct dvb_demux *demux = dvbdmxfeed->demux; | ||
| 178 | struct as102_dev_t *as102_dev = demux->priv; | ||
| 179 | |||
| 180 | ENTER(); | ||
| 181 | |||
| 182 | if (mutex_lock_interruptible(&as102_dev->sem)) | ||
| 183 | return -ERESTARTSYS; | ||
| 184 | |||
| 185 | if (--as102_dev->streaming == 0) | ||
| 186 | as102_stop_stream(as102_dev); | ||
| 187 | |||
| 188 | if (pid_filtering) { | ||
| 189 | as10x_pid_filter(as102_dev, | ||
| 190 | dvbdmxfeed->index, dvbdmxfeed->pid, 0); | ||
| 191 | } | ||
| 192 | |||
| 193 | mutex_unlock(&as102_dev->sem); | ||
| 194 | LEAVE(); | ||
| 195 | return 0; | ||
| 196 | } | ||
| 197 | |||
| 198 | int as102_dvb_register(struct as102_dev_t *as102_dev) | ||
| 199 | { | ||
| 200 | int ret = 0; | ||
| 201 | ENTER(); | ||
| 202 | |||
| 203 | ret = dvb_register_adapter(&as102_dev->dvb_adap, | ||
| 204 | as102_dev->name, | ||
| 205 | THIS_MODULE, | ||
| 206 | #if defined(CONFIG_AS102_USB) | ||
| 207 | &as102_dev->bus_adap.usb_dev->dev | ||
| 208 | #elif defined(CONFIG_AS102_SPI) | ||
| 209 | &as102_dev->bus_adap.spi_dev->dev | ||
| 210 | #else | ||
| 211 | #error >>> dvb_register_adapter <<< | ||
| 212 | #endif | ||
| 213 | #ifdef DVB_DEFINE_MOD_OPT_ADAPTER_NR | ||
| 214 | , adapter_nr | ||
| 215 | #endif | ||
| 216 | ); | ||
| 217 | if (ret < 0) { | ||
| 218 | err("%s: dvb_register_adapter() failed (errno = %d)", | ||
| 219 | __func__, ret); | ||
| 220 | goto failed; | ||
| 221 | } | ||
| 222 | |||
| 223 | as102_dev->dvb_dmx.priv = as102_dev; | ||
| 224 | as102_dev->dvb_dmx.filternum = pid_filtering ? 16 : 256; | ||
| 225 | as102_dev->dvb_dmx.feednum = 256; | ||
| 226 | as102_dev->dvb_dmx.start_feed = as102_dvb_dmx_start_feed; | ||
| 227 | as102_dev->dvb_dmx.stop_feed = as102_dvb_dmx_stop_feed; | ||
| 228 | |||
| 229 | as102_dev->dvb_dmx.dmx.capabilities = DMX_TS_FILTERING | | ||
| 230 | DMX_SECTION_FILTERING; | ||
| 231 | |||
| 232 | as102_dev->dvb_dmxdev.filternum = as102_dev->dvb_dmx.filternum; | ||
| 233 | as102_dev->dvb_dmxdev.demux = &as102_dev->dvb_dmx.dmx; | ||
| 234 | as102_dev->dvb_dmxdev.capabilities = 0; | ||
| 235 | |||
| 236 | ret = dvb_dmx_init(&as102_dev->dvb_dmx); | ||
| 237 | if (ret < 0) { | ||
| 238 | err("%s: dvb_dmx_init() failed (errno = %d)", __func__, ret); | ||
| 239 | goto failed; | ||
| 240 | } | ||
| 241 | |||
| 242 | ret = dvb_dmxdev_init(&as102_dev->dvb_dmxdev, &as102_dev->dvb_adap); | ||
| 243 | if (ret < 0) { | ||
| 244 | err("%s: dvb_dmxdev_init() failed (errno = %d)", __func__, | ||
| 245 | ret); | ||
| 246 | goto failed; | ||
| 247 | } | ||
| 248 | |||
| 249 | ret = as102_dvb_register_fe(as102_dev, &as102_dev->dvb_fe); | ||
| 250 | if (ret < 0) { | ||
| 251 | err("%s: as102_dvb_register_frontend() failed (errno = %d)", | ||
| 252 | __func__, ret); | ||
| 253 | goto failed; | ||
| 254 | } | ||
| 255 | |||
| 256 | /* init bus mutex for token locking */ | ||
| 257 | mutex_init(&as102_dev->bus_adap.lock); | ||
| 258 | |||
| 259 | /* init start / stop stream mutex */ | ||
| 260 | mutex_init(&as102_dev->sem); | ||
| 261 | |||
| 262 | #if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) | ||
| 263 | /* | ||
| 264 | * try to load as102 firmware. If firmware upload failed, we'll be | ||
| 265 | * able to upload it later. | ||
| 266 | */ | ||
| 267 | if (fw_upload) | ||
| 268 | try_then_request_module(as102_fw_upload(&as102_dev->bus_adap), | ||
| 269 | "firmware_class"); | ||
| 270 | #endif | ||
| 271 | |||
| 272 | failed: | ||
| 273 | LEAVE(); | ||
| 274 | /* FIXME: free dvb_XXX */ | ||
| 275 | return ret; | ||
| 276 | } | ||
| 277 | |||
| 278 | void as102_dvb_unregister(struct as102_dev_t *as102_dev) | ||
| 279 | { | ||
| 280 | ENTER(); | ||
| 281 | |||
| 282 | /* unregister as102 frontend */ | ||
| 283 | as102_dvb_unregister_fe(&as102_dev->dvb_fe); | ||
| 284 | |||
| 285 | /* unregister demux device */ | ||
| 286 | dvb_dmxdev_release(&as102_dev->dvb_dmxdev); | ||
| 287 | dvb_dmx_release(&as102_dev->dvb_dmx); | ||
| 288 | |||
| 289 | /* unregister dvb adapter */ | ||
| 290 | dvb_unregister_adapter(&as102_dev->dvb_adap); | ||
| 291 | |||
| 292 | LEAVE(); | ||
| 293 | } | ||
| 294 | |||
| 295 | static int __init as102_driver_init(void) | ||
| 296 | { | ||
| 297 | int ret = 0; | ||
| 298 | |||
| 299 | ENTER(); | ||
| 300 | |||
| 301 | /* register this driver with the low level subsystem */ | ||
| 302 | #if defined(CONFIG_AS102_USB) | ||
| 303 | ret = usb_register(&as102_usb_driver); | ||
| 304 | if (ret) | ||
| 305 | err("usb_register failed (ret = %d)", ret); | ||
| 306 | #endif | ||
| 307 | #if defined(CONFIG_AS102_SPI) | ||
| 308 | ret = spi_register_driver(&as102_spi_driver); | ||
| 309 | if (ret) | ||
| 310 | printk(KERN_ERR "spi_register failed (ret = %d)", ret); | ||
| 311 | #endif | ||
| 312 | |||
| 313 | LEAVE(); | ||
| 314 | return ret; | ||
| 315 | } | ||
| 316 | |||
| 317 | /* | ||
| 318 | * Mandatory function : Adds a special section to the module indicating | ||
| 319 | * where initialisation function is defined | ||
| 320 | */ | ||
| 321 | module_init(as102_driver_init); | ||
| 322 | |||
| 323 | /** | ||
| 324 | * as102_driver_exit - as102 driver exit point | ||
| 325 | * | ||
| 326 | * This function is called when device has to be removed. | ||
| 327 | */ | ||
| 328 | static void __exit as102_driver_exit(void) | ||
| 329 | { | ||
| 330 | ENTER(); | ||
| 331 | /* deregister this driver with the low level bus subsystem */ | ||
| 332 | #if defined(CONFIG_AS102_USB) | ||
| 333 | usb_deregister(&as102_usb_driver); | ||
| 334 | #endif | ||
| 335 | #if defined(CONFIG_AS102_SPI) | ||
| 336 | spi_unregister_driver(&as102_spi_driver); | ||
| 337 | #endif | ||
| 338 | LEAVE(); | ||
| 339 | } | ||
| 340 | |||
| 341 | /* | ||
| 342 | * required function for unload: Adds a special section to the module | ||
| 343 | * indicating where unload function is defined | ||
| 344 | */ | ||
| 345 | module_exit(as102_driver_exit); | ||
| 346 | /* modinfo details */ | ||
| 347 | MODULE_DESCRIPTION(DRIVER_FULL_NAME); | ||
| 348 | MODULE_LICENSE("GPL"); | ||
| 349 | MODULE_AUTHOR("Pierrick Hascoet <pierrick.hascoet@abilis.com>"); | ||
| 350 | |||
| 351 | /* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */ | ||
diff --git a/drivers/staging/media/as102/as102_drv.h b/drivers/staging/media/as102/as102_drv.h new file mode 100644 index 000000000000..bcda635b5a99 --- /dev/null +++ b/drivers/staging/media/as102/as102_drv.h | |||
| @@ -0,0 +1,141 @@ | |||
| 1 | /* | ||
| 2 | * Abilis Systems Single DVB-T Receiver | ||
| 3 | * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com> | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 8 | * any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #if defined(CONFIG_AS102_USB) | ||
| 21 | #include <linux/usb.h> | ||
| 22 | extern struct usb_driver as102_usb_driver; | ||
| 23 | #endif | ||
| 24 | |||
| 25 | #if defined(CONFIG_AS102_SPI) | ||
| 26 | #include <linux/platform_device.h> | ||
| 27 | #include <linux/spi/spi.h> | ||
| 28 | #include <linux/cdev.h> | ||
| 29 | |||
| 30 | extern struct spi_driver as102_spi_driver; | ||
| 31 | #endif | ||
| 32 | |||
| 33 | #include "dvb_demux.h" | ||
| 34 | #include "dvb_frontend.h" | ||
| 35 | #include "dmxdev.h" | ||
| 36 | |||
| 37 | #define DRIVER_FULL_NAME "Abilis Systems as10x usb driver" | ||
| 38 | #define DRIVER_NAME "as10x_usb" | ||
| 39 | |||
| 40 | extern int debug; | ||
| 41 | |||
| 42 | #define dprintk(debug, args...) \ | ||
| 43 | do { if (debug) { \ | ||
| 44 | printk(KERN_DEBUG "%s: ",__FUNCTION__); \ | ||
| 45 | printk(args); \ | ||
| 46 | } } while (0) | ||
| 47 | |||
| 48 | #ifdef TRACE | ||
| 49 | #define ENTER() printk(">> enter %s\n", __FUNCTION__) | ||
| 50 | #define LEAVE() printk("<< leave %s\n", __FUNCTION__) | ||
| 51 | #else | ||
| 52 | #define ENTER() | ||
| 53 | #define LEAVE() | ||
| 54 | #endif | ||
| 55 | |||
| 56 | #define AS102_DEVICE_MAJOR 192 | ||
| 57 | |||
| 58 | #define AS102_USB_BUF_SIZE 512 | ||
| 59 | #define MAX_STREAM_URB 32 | ||
| 60 | |||
| 61 | #include "as10x_cmd.h" | ||
| 62 | |||
| 63 | #if defined(CONFIG_AS102_USB) | ||
| 64 | #include "as102_usb_drv.h" | ||
| 65 | #endif | ||
| 66 | |||
| 67 | #if defined(CONFIG_AS102_SPI) | ||
| 68 | #include "as10x_spi_drv.h" | ||
| 69 | #endif | ||
| 70 | |||
| 71 | |||
| 72 | struct as102_bus_adapter_t { | ||
| 73 | #if defined(CONFIG_AS102_USB) | ||
| 74 | struct usb_device *usb_dev; | ||
| 75 | #elif defined(CONFIG_AS102_SPI) | ||
| 76 | struct spi_device *spi_dev; | ||
| 77 | struct cdev cdev; /* spidev raw device */ | ||
| 78 | |||
| 79 | struct timer_list timer; | ||
| 80 | struct completion xfer_done; | ||
| 81 | #endif | ||
| 82 | /* bus token lock */ | ||
| 83 | struct mutex lock; | ||
| 84 | /* low level interface for bus adapter */ | ||
| 85 | union as10x_bus_token_t { | ||
| 86 | #if defined(CONFIG_AS102_USB) | ||
| 87 | /* usb token */ | ||
| 88 | struct as10x_usb_token_cmd_t usb; | ||
| 89 | #endif | ||
| 90 | #if defined(CONFIG_AS102_SPI) | ||
| 91 | /* spi token */ | ||
| 92 | struct as10x_spi_token_cmd_t spi; | ||
| 93 | #endif | ||
| 94 | } token; | ||
| 95 | |||
| 96 | /* token cmd xfer id */ | ||
| 97 | uint16_t cmd_xid; | ||
| 98 | |||
| 99 | /* as10x command and response for dvb interface*/ | ||
| 100 | struct as10x_cmd_t *cmd, *rsp; | ||
| 101 | |||
| 102 | /* bus adapter private ops callback */ | ||
| 103 | struct as102_priv_ops_t *ops; | ||
| 104 | }; | ||
| 105 | |||
| 106 | struct as102_dev_t { | ||
| 107 | const char *name; | ||
| 108 | struct as102_bus_adapter_t bus_adap; | ||
| 109 | struct list_head device_entry; | ||
| 110 | struct kref kref; | ||
| 111 | unsigned long minor; | ||
| 112 | |||
| 113 | struct dvb_adapter dvb_adap; | ||
| 114 | struct dvb_frontend dvb_fe; | ||
| 115 | struct dvb_demux dvb_dmx; | ||
| 116 | struct dmxdev dvb_dmxdev; | ||
| 117 | |||
| 118 | /* demodulator stats */ | ||
| 119 | struct as10x_demod_stats demod_stats; | ||
| 120 | /* signal strength */ | ||
| 121 | uint16_t signal_strength; | ||
| 122 | /* bit error rate */ | ||
| 123 | uint32_t ber; | ||
| 124 | |||
| 125 | /* timer handle to trig ts stream download */ | ||
| 126 | struct timer_list timer_handle; | ||
| 127 | |||
| 128 | struct mutex sem; | ||
| 129 | dma_addr_t dma_addr; | ||
| 130 | void *stream; | ||
| 131 | int streaming; | ||
| 132 | struct urb *stream_urb[MAX_STREAM_URB]; | ||
| 133 | }; | ||
| 134 | |||
| 135 | int as102_dvb_register(struct as102_dev_t *dev); | ||
| 136 | void as102_dvb_unregister(struct as102_dev_t *dev); | ||
| 137 | |||
| 138 | int as102_dvb_register_fe(struct as102_dev_t *dev, struct dvb_frontend *fe); | ||
| 139 | int as102_dvb_unregister_fe(struct dvb_frontend *dev); | ||
| 140 | |||
| 141 | /* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */ | ||
diff --git a/drivers/staging/media/as102/as102_fe.c b/drivers/staging/media/as102/as102_fe.c new file mode 100644 index 000000000000..3550f905367e --- /dev/null +++ b/drivers/staging/media/as102/as102_fe.c | |||
| @@ -0,0 +1,603 @@ | |||
| 1 | /* | ||
| 2 | * Abilis Systems Single DVB-T Receiver | ||
| 3 | * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com> | ||
| 4 | * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 9 | * any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 19 | */ | ||
| 20 | #include <linux/version.h> | ||
| 21 | |||
| 22 | #include "as102_drv.h" | ||
| 23 | #include "as10x_types.h" | ||
| 24 | #include "as10x_cmd.h" | ||
| 25 | |||
| 26 | extern int elna_enable; | ||
| 27 | |||
| 28 | static void as10x_fe_copy_tps_parameters(struct dvb_frontend_parameters *dst, | ||
| 29 | struct as10x_tps *src); | ||
| 30 | |||
| 31 | static void as102_fe_copy_tune_parameters(struct as10x_tune_args *dst, | ||
| 32 | struct dvb_frontend_parameters *src); | ||
| 33 | |||
| 34 | static int as102_fe_set_frontend(struct dvb_frontend *fe, | ||
| 35 | struct dvb_frontend_parameters *params) | ||
| 36 | { | ||
| 37 | int ret = 0; | ||
| 38 | struct as102_dev_t *dev; | ||
| 39 | struct as10x_tune_args tune_args = { 0 }; | ||
| 40 | |||
| 41 | ENTER(); | ||
| 42 | |||
| 43 | dev = (struct as102_dev_t *) fe->tuner_priv; | ||
| 44 | if (dev == NULL) | ||
| 45 | return -ENODEV; | ||
| 46 | |||
| 47 | if (mutex_lock_interruptible(&dev->bus_adap.lock)) | ||
| 48 | return -EBUSY; | ||
| 49 | |||
| 50 | as102_fe_copy_tune_parameters(&tune_args, params); | ||
| 51 | |||
| 52 | /* send abilis command: SET_TUNE */ | ||
| 53 | ret = as10x_cmd_set_tune(&dev->bus_adap, &tune_args); | ||
| 54 | if (ret != 0) | ||
| 55 | dprintk(debug, "as10x_cmd_set_tune failed. (err = %d)\n", ret); | ||
| 56 | |||
| 57 | mutex_unlock(&dev->bus_adap.lock); | ||
| 58 | |||
| 59 | LEAVE(); | ||
| 60 | return (ret < 0) ? -EINVAL : 0; | ||
| 61 | } | ||
| 62 | |||
| 63 | static int as102_fe_get_frontend(struct dvb_frontend *fe, | ||
| 64 | struct dvb_frontend_parameters *p) { | ||
| 65 | int ret = 0; | ||
| 66 | struct as102_dev_t *dev; | ||
| 67 | struct as10x_tps tps = { 0 }; | ||
| 68 | |||
| 69 | ENTER(); | ||
| 70 | |||
| 71 | dev = (struct as102_dev_t *) fe->tuner_priv; | ||
| 72 | if (dev == NULL) | ||
| 73 | return -EINVAL; | ||
| 74 | |||
| 75 | if (mutex_lock_interruptible(&dev->bus_adap.lock)) | ||
| 76 | return -EBUSY; | ||
| 77 | |||
| 78 | /* send abilis command: GET_TPS */ | ||
| 79 | ret = as10x_cmd_get_tps(&dev->bus_adap, &tps); | ||
| 80 | |||
| 81 | if (ret == 0) | ||
| 82 | as10x_fe_copy_tps_parameters(p, &tps); | ||
| 83 | |||
| 84 | mutex_unlock(&dev->bus_adap.lock); | ||
| 85 | |||
| 86 | LEAVE(); | ||
| 87 | return (ret < 0) ? -EINVAL : 0; | ||
| 88 | } | ||
| 89 | |||
| 90 | static int as102_fe_get_tune_settings(struct dvb_frontend *fe, | ||
| 91 | struct dvb_frontend_tune_settings *settings) { | ||
| 92 | ENTER(); | ||
| 93 | |||
| 94 | #if 0 | ||
| 95 | dprintk(debug, "step_size = %d\n", settings->step_size); | ||
| 96 | dprintk(debug, "max_drift = %d\n", settings->max_drift); | ||
| 97 | dprintk(debug, "min_delay_ms = %d -> %d\n", settings->min_delay_ms, | ||
| 98 | 1000); | ||
| 99 | #endif | ||
| 100 | |||
| 101 | settings->min_delay_ms = 1000; | ||
| 102 | |||
| 103 | LEAVE(); | ||
| 104 | return 0; | ||
| 105 | } | ||
| 106 | |||
| 107 | |||
| 108 | static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status) | ||
| 109 | { | ||
| 110 | int ret = 0; | ||
| 111 | struct as102_dev_t *dev; | ||
| 112 | struct as10x_tune_status tstate = { 0 }; | ||
| 113 | |||
| 114 | ENTER(); | ||
| 115 | |||
| 116 | dev = (struct as102_dev_t *) fe->tuner_priv; | ||
| 117 | if (dev == NULL) | ||
| 118 | return -ENODEV; | ||
| 119 | |||
| 120 | if (mutex_lock_interruptible(&dev->bus_adap.lock)) | ||
| 121 | return -EBUSY; | ||
| 122 | |||
| 123 | /* send abilis command: GET_TUNE_STATUS */ | ||
| 124 | ret = as10x_cmd_get_tune_status(&dev->bus_adap, &tstate); | ||
| 125 | if (ret < 0) { | ||
| 126 | dprintk(debug, "as10x_cmd_get_tune_status failed (err = %d)\n", | ||
| 127 | ret); | ||
| 128 | goto out; | ||
| 129 | } | ||
| 130 | |||
| 131 | dev->signal_strength = tstate.signal_strength; | ||
| 132 | dev->ber = tstate.BER; | ||
| 133 | |||
| 134 | switch (tstate.tune_state) { | ||
| 135 | case TUNE_STATUS_SIGNAL_DVB_OK: | ||
| 136 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; | ||
| 137 | break; | ||
| 138 | case TUNE_STATUS_STREAM_DETECTED: | ||
| 139 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC; | ||
| 140 | break; | ||
| 141 | case TUNE_STATUS_STREAM_TUNED: | ||
| 142 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | | ||
| 143 | FE_HAS_LOCK; | ||
| 144 | break; | ||
| 145 | default: | ||
| 146 | *status = TUNE_STATUS_NOT_TUNED; | ||
| 147 | } | ||
| 148 | |||
| 149 | dprintk(debug, "tuner status: 0x%02x, strength %d, per: %d, ber: %d\n", | ||
| 150 | tstate.tune_state, tstate.signal_strength, | ||
| 151 | tstate.PER, tstate.BER); | ||
| 152 | |||
| 153 | if (*status & FE_HAS_LOCK) { | ||
| 154 | if (as10x_cmd_get_demod_stats(&dev->bus_adap, | ||
| 155 | (struct as10x_demod_stats *) &dev->demod_stats) < 0) { | ||
| 156 | memset(&dev->demod_stats, 0, sizeof(dev->demod_stats)); | ||
| 157 | dprintk(debug, "as10x_cmd_get_demod_stats failed " | ||
| 158 | "(probably not tuned)\n"); | ||
| 159 | } else { | ||
| 160 | dprintk(debug, | ||
| 161 | "demod status: fc: 0x%08x, bad fc: 0x%08x, " | ||
| 162 | "bytes corrected: 0x%08x , MER: 0x%04x\n", | ||
| 163 | dev->demod_stats.frame_count, | ||
| 164 | dev->demod_stats.bad_frame_count, | ||
| 165 | dev->demod_stats.bytes_fixed_by_rs, | ||
| 166 | dev->demod_stats.mer); | ||
| 167 | } | ||
| 168 | } else { | ||
| 169 | memset(&dev->demod_stats, 0, sizeof(dev->demod_stats)); | ||
| 170 | } | ||
| 171 | |||
| 172 | out: | ||
| 173 | mutex_unlock(&dev->bus_adap.lock); | ||
| 174 | LEAVE(); | ||
| 175 | return ret; | ||
| 176 | } | ||
| 177 | |||
| 178 | /* | ||
| 179 | * Note: | ||
| 180 | * - in AS102 SNR=MER | ||
| 181 | * - the SNR will be returned in linear terms, i.e. not in dB | ||
| 182 | * - the accuracy equals ±2dB for a SNR range from 4dB to 30dB | ||
| 183 | * - the accuracy is >2dB for SNR values outside this range | ||
| 184 | */ | ||
| 185 | static int as102_fe_read_snr(struct dvb_frontend *fe, u16 *snr) | ||
| 186 | { | ||
| 187 | struct as102_dev_t *dev; | ||
| 188 | |||
| 189 | ENTER(); | ||
| 190 | |||
| 191 | dev = (struct as102_dev_t *) fe->tuner_priv; | ||
| 192 | if (dev == NULL) | ||
| 193 | return -ENODEV; | ||
| 194 | |||
| 195 | *snr = dev->demod_stats.mer; | ||
| 196 | |||
| 197 | LEAVE(); | ||
| 198 | return 0; | ||
| 199 | } | ||
| 200 | |||
| 201 | static int as102_fe_read_ber(struct dvb_frontend *fe, u32 *ber) | ||
| 202 | { | ||
| 203 | struct as102_dev_t *dev; | ||
| 204 | |||
| 205 | ENTER(); | ||
| 206 | |||
| 207 | dev = (struct as102_dev_t *) fe->tuner_priv; | ||
| 208 | if (dev == NULL) | ||
| 209 | return -ENODEV; | ||
| 210 | |||
| 211 | *ber = dev->ber; | ||
| 212 | |||
| 213 | LEAVE(); | ||
| 214 | return 0; | ||
| 215 | } | ||
| 216 | |||
| 217 | static int as102_fe_read_signal_strength(struct dvb_frontend *fe, | ||
| 218 | u16 *strength) | ||
| 219 | { | ||
| 220 | struct as102_dev_t *dev; | ||
| 221 | |||
| 222 | ENTER(); | ||
| 223 | |||
| 224 | dev = (struct as102_dev_t *) fe->tuner_priv; | ||
| 225 | if (dev == NULL) | ||
| 226 | return -ENODEV; | ||
| 227 | |||
| 228 | *strength = (((0xffff * 400) * dev->signal_strength + 41000) * 2); | ||
| 229 | |||
| 230 | LEAVE(); | ||
| 231 | return 0; | ||
| 232 | } | ||
| 233 | |||
| 234 | static int as102_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) | ||
| 235 | { | ||
| 236 | struct as102_dev_t *dev; | ||
| 237 | |||
| 238 | ENTER(); | ||
| 239 | |||
| 240 | dev = (struct as102_dev_t *) fe->tuner_priv; | ||
| 241 | if (dev == NULL) | ||
| 242 | return -ENODEV; | ||
| 243 | |||
| 244 | if (dev->demod_stats.has_started) | ||
| 245 | *ucblocks = dev->demod_stats.bad_frame_count; | ||
| 246 | else | ||
| 247 | *ucblocks = 0; | ||
| 248 | |||
| 249 | LEAVE(); | ||
| 250 | return 0; | ||
| 251 | } | ||
| 252 | |||
| 253 | static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) | ||
| 254 | { | ||
| 255 | struct as102_dev_t *dev; | ||
| 256 | int ret; | ||
| 257 | |||
| 258 | ENTER(); | ||
| 259 | |||
| 260 | dev = (struct as102_dev_t *) fe->tuner_priv; | ||
| 261 | if (dev == NULL) | ||
| 262 | return -ENODEV; | ||
| 263 | |||
| 264 | if (mutex_lock_interruptible(&dev->bus_adap.lock)) | ||
| 265 | return -EBUSY; | ||
| 266 | |||
| 267 | if (acquire) { | ||
| 268 | if (elna_enable) | ||
| 269 | as10x_cmd_set_context(&dev->bus_adap, 1010, 0xC0); | ||
| 270 | |||
| 271 | ret = as10x_cmd_turn_on(&dev->bus_adap); | ||
| 272 | } else { | ||
| 273 | ret = as10x_cmd_turn_off(&dev->bus_adap); | ||
| 274 | } | ||
| 275 | |||
| 276 | mutex_unlock(&dev->bus_adap.lock); | ||
| 277 | |||
| 278 | LEAVE(); | ||
| 279 | return ret; | ||
| 280 | } | ||
| 281 | |||
| 282 | static struct dvb_frontend_ops as102_fe_ops = { | ||
| 283 | .info = { | ||
| 284 | .name = "Unknown AS102 device", | ||
| 285 | .type = FE_OFDM, | ||
| 286 | .frequency_min = 174000000, | ||
| 287 | .frequency_max = 862000000, | ||
| 288 | .frequency_stepsize = 166667, | ||
| 289 | .caps = FE_CAN_INVERSION_AUTO | ||
| 290 | | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | ||
| 291 | | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | ||
| 292 | | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QPSK | ||
| 293 | | FE_CAN_QAM_AUTO | ||
| 294 | | FE_CAN_TRANSMISSION_MODE_AUTO | ||
| 295 | | FE_CAN_GUARD_INTERVAL_AUTO | ||
| 296 | | FE_CAN_HIERARCHY_AUTO | ||
| 297 | | FE_CAN_RECOVER | ||
| 298 | | FE_CAN_MUTE_TS | ||
| 299 | }, | ||
| 300 | |||
| 301 | .set_frontend = as102_fe_set_frontend, | ||
| 302 | .get_frontend = as102_fe_get_frontend, | ||
| 303 | .get_tune_settings = as102_fe_get_tune_settings, | ||
| 304 | |||
| 305 | .read_status = as102_fe_read_status, | ||
| 306 | .read_snr = as102_fe_read_snr, | ||
| 307 | .read_ber = as102_fe_read_ber, | ||
| 308 | .read_signal_strength = as102_fe_read_signal_strength, | ||
| 309 | .read_ucblocks = as102_fe_read_ucblocks, | ||
| 310 | .ts_bus_ctrl = as102_fe_ts_bus_ctrl, | ||
| 311 | }; | ||
| 312 | |||
| 313 | int as102_dvb_unregister_fe(struct dvb_frontend *fe) | ||
| 314 | { | ||
| 315 | /* unregister frontend */ | ||
| 316 | dvb_unregister_frontend(fe); | ||
| 317 | |||
| 318 | /* detach frontend */ | ||
| 319 | dvb_frontend_detach(fe); | ||
| 320 | |||
| 321 | return 0; | ||
| 322 | } | ||
| 323 | |||
| 324 | int as102_dvb_register_fe(struct as102_dev_t *as102_dev, | ||
| 325 | struct dvb_frontend *dvb_fe) | ||
| 326 | { | ||
| 327 | int errno; | ||
| 328 | struct dvb_adapter *dvb_adap; | ||
| 329 | |||
| 330 | if (as102_dev == NULL) | ||
| 331 | return -EINVAL; | ||
| 332 | |||
| 333 | /* extract dvb_adapter */ | ||
| 334 | dvb_adap = &as102_dev->dvb_adap; | ||
| 335 | |||
| 336 | /* init frontend callback ops */ | ||
| 337 | memcpy(&dvb_fe->ops, &as102_fe_ops, sizeof(struct dvb_frontend_ops)); | ||
| 338 | strncpy(dvb_fe->ops.info.name, as102_dev->name, | ||
| 339 | sizeof(dvb_fe->ops.info.name)); | ||
| 340 | |||
| 341 | /* register dbvb frontend */ | ||
| 342 | errno = dvb_register_frontend(dvb_adap, dvb_fe); | ||
| 343 | if (errno == 0) | ||
| 344 | dvb_fe->tuner_priv = as102_dev; | ||
| 345 | |||
| 346 | return errno; | ||
| 347 | } | ||
| 348 | |||
| 349 | static void as10x_fe_copy_tps_parameters(struct dvb_frontend_parameters *dst, | ||
| 350 | struct as10x_tps *as10x_tps) | ||
| 351 | { | ||
| 352 | |||
| 353 | struct dvb_ofdm_parameters *fe_tps = &dst->u.ofdm; | ||
| 354 | |||
| 355 | /* extract consteallation */ | ||
| 356 | switch (as10x_tps->constellation) { | ||
| 357 | case CONST_QPSK: | ||
| 358 | fe_tps->constellation = QPSK; | ||
| 359 | break; | ||
| 360 | case CONST_QAM16: | ||
| 361 | fe_tps->constellation = QAM_16; | ||
| 362 | break; | ||
| 363 | case CONST_QAM64: | ||
| 364 | fe_tps->constellation = QAM_64; | ||
| 365 | break; | ||
| 366 | } | ||
| 367 | |||
| 368 | /* extract hierarchy */ | ||
| 369 | switch (as10x_tps->hierarchy) { | ||
| 370 | case HIER_NONE: | ||
| 371 | fe_tps->hierarchy_information = HIERARCHY_NONE; | ||
| 372 | break; | ||
| 373 | case HIER_ALPHA_1: | ||
| 374 | fe_tps->hierarchy_information = HIERARCHY_1; | ||
| 375 | break; | ||
| 376 | case HIER_ALPHA_2: | ||
| 377 | fe_tps->hierarchy_information = HIERARCHY_2; | ||
| 378 | break; | ||
| 379 | case HIER_ALPHA_4: | ||
| 380 | fe_tps->hierarchy_information = HIERARCHY_4; | ||
| 381 | break; | ||
| 382 | } | ||
| 383 | |||
| 384 | /* extract code rate HP */ | ||
| 385 | switch (as10x_tps->code_rate_HP) { | ||
| 386 | case CODE_RATE_1_2: | ||
| 387 | fe_tps->code_rate_HP = FEC_1_2; | ||
| 388 | break; | ||
| 389 | case CODE_RATE_2_3: | ||
| 390 | fe_tps->code_rate_HP = FEC_2_3; | ||
| 391 | break; | ||
| 392 | case CODE_RATE_3_4: | ||
| 393 | fe_tps->code_rate_HP = FEC_3_4; | ||
| 394 | break; | ||
| 395 | case CODE_RATE_5_6: | ||
| 396 | fe_tps->code_rate_HP = FEC_5_6; | ||
| 397 | break; | ||
| 398 | case CODE_RATE_7_8: | ||
| 399 | fe_tps->code_rate_HP = FEC_7_8; | ||
| 400 | break; | ||
| 401 | } | ||
| 402 | |||
| 403 | /* extract code rate LP */ | ||
| 404 | switch (as10x_tps->code_rate_LP) { | ||
| 405 | case CODE_RATE_1_2: | ||
| 406 | fe_tps->code_rate_LP = FEC_1_2; | ||
| 407 | break; | ||
| 408 | case CODE_RATE_2_3: | ||
| 409 | fe_tps->code_rate_LP = FEC_2_3; | ||
| 410 | break; | ||
| 411 | case CODE_RATE_3_4: | ||
| 412 | fe_tps->code_rate_LP = FEC_3_4; | ||
| 413 | break; | ||
| 414 | case CODE_RATE_5_6: | ||
| 415 | fe_tps->code_rate_LP = FEC_5_6; | ||
| 416 | break; | ||
| 417 | case CODE_RATE_7_8: | ||
| 418 | fe_tps->code_rate_LP = FEC_7_8; | ||
| 419 | break; | ||
| 420 | } | ||
| 421 | |||
| 422 | /* extract guard interval */ | ||
| 423 | switch (as10x_tps->guard_interval) { | ||
| 424 | case GUARD_INT_1_32: | ||
| 425 | fe_tps->guard_interval = GUARD_INTERVAL_1_32; | ||
| 426 | break; | ||
| 427 | case GUARD_INT_1_16: | ||
| 428 | fe_tps->guard_interval = GUARD_INTERVAL_1_16; | ||
| 429 | break; | ||
| 430 | case GUARD_INT_1_8: | ||
| 431 | fe_tps->guard_interval = GUARD_INTERVAL_1_8; | ||
| 432 | break; | ||
| 433 | case GUARD_INT_1_4: | ||
| 434 | fe_tps->guard_interval = GUARD_INTERVAL_1_4; | ||
| 435 | break; | ||
| 436 | } | ||
| 437 | |||
| 438 | /* extract transmission mode */ | ||
| 439 | switch (as10x_tps->transmission_mode) { | ||
| 440 | case TRANS_MODE_2K: | ||
| 441 | fe_tps->transmission_mode = TRANSMISSION_MODE_2K; | ||
| 442 | break; | ||
| 443 | case TRANS_MODE_8K: | ||
| 444 | fe_tps->transmission_mode = TRANSMISSION_MODE_8K; | ||
| 445 | break; | ||
| 446 | } | ||
| 447 | } | ||
| 448 | |||
| 449 | static uint8_t as102_fe_get_code_rate(fe_code_rate_t arg) | ||
| 450 | { | ||
| 451 | uint8_t c; | ||
| 452 | |||
| 453 | switch (arg) { | ||
| 454 | case FEC_1_2: | ||
| 455 | c = CODE_RATE_1_2; | ||
| 456 | break; | ||
| 457 | case FEC_2_3: | ||
| 458 | c = CODE_RATE_2_3; | ||
| 459 | break; | ||
| 460 | case FEC_3_4: | ||
| 461 | c = CODE_RATE_3_4; | ||
| 462 | break; | ||
| 463 | case FEC_5_6: | ||
| 464 | c = CODE_RATE_5_6; | ||
| 465 | break; | ||
| 466 | case FEC_7_8: | ||
| 467 | c = CODE_RATE_7_8; | ||
| 468 | break; | ||
| 469 | default: | ||
| 470 | c = CODE_RATE_UNKNOWN; | ||
| 471 | break; | ||
| 472 | } | ||
| 473 | |||
| 474 | return c; | ||
| 475 | } | ||
| 476 | |||
| 477 | static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args, | ||
| 478 | struct dvb_frontend_parameters *params) | ||
| 479 | { | ||
| 480 | |||
| 481 | /* set frequency */ | ||
| 482 | tune_args->freq = params->frequency / 1000; | ||
| 483 | |||
| 484 | /* fix interleaving_mode */ | ||
| 485 | tune_args->interleaving_mode = INTLV_NATIVE; | ||
| 486 | |||
| 487 | switch (params->u.ofdm.bandwidth) { | ||
| 488 | case BANDWIDTH_8_MHZ: | ||
| 489 | tune_args->bandwidth = BW_8_MHZ; | ||
| 490 | break; | ||
| 491 | case BANDWIDTH_7_MHZ: | ||
| 492 | tune_args->bandwidth = BW_7_MHZ; | ||
| 493 | break; | ||
| 494 | case BANDWIDTH_6_MHZ: | ||
| 495 | tune_args->bandwidth = BW_6_MHZ; | ||
| 496 | break; | ||
| 497 | default: | ||
| 498 | tune_args->bandwidth = BW_8_MHZ; | ||
| 499 | } | ||
| 500 | |||
| 501 | switch (params->u.ofdm.guard_interval) { | ||
| 502 | case GUARD_INTERVAL_1_32: | ||
| 503 | tune_args->guard_interval = GUARD_INT_1_32; | ||
| 504 | break; | ||
| 505 | case GUARD_INTERVAL_1_16: | ||
| 506 | tune_args->guard_interval = GUARD_INT_1_16; | ||
| 507 | break; | ||
| 508 | case GUARD_INTERVAL_1_8: | ||
| 509 | tune_args->guard_interval = GUARD_INT_1_8; | ||
| 510 | break; | ||
| 511 | case GUARD_INTERVAL_1_4: | ||
| 512 | tune_args->guard_interval = GUARD_INT_1_4; | ||
| 513 | break; | ||
| 514 | case GUARD_INTERVAL_AUTO: | ||
| 515 | default: | ||
| 516 | tune_args->guard_interval = GUARD_UNKNOWN; | ||
| 517 | break; | ||
| 518 | } | ||
| 519 | |||
| 520 | switch (params->u.ofdm.constellation) { | ||
| 521 | case QPSK: | ||
| 522 | tune_args->constellation = CONST_QPSK; | ||
| 523 | break; | ||
| 524 | case QAM_16: | ||
| 525 | tune_args->constellation = CONST_QAM16; | ||
| 526 | break; | ||
| 527 | case QAM_64: | ||
| 528 | tune_args->constellation = CONST_QAM64; | ||
| 529 | break; | ||
| 530 | default: | ||
| 531 | tune_args->constellation = CONST_UNKNOWN; | ||
| 532 | break; | ||
| 533 | } | ||
| 534 | |||
| 535 | switch (params->u.ofdm.transmission_mode) { | ||
| 536 | case TRANSMISSION_MODE_2K: | ||
| 537 | tune_args->transmission_mode = TRANS_MODE_2K; | ||
| 538 | break; | ||
| 539 | case TRANSMISSION_MODE_8K: | ||
| 540 | tune_args->transmission_mode = TRANS_MODE_8K; | ||
| 541 | break; | ||
| 542 | default: | ||
| 543 | tune_args->transmission_mode = TRANS_MODE_UNKNOWN; | ||
| 544 | } | ||
| 545 | |||
| 546 | switch (params->u.ofdm.hierarchy_information) { | ||
| 547 | case HIERARCHY_NONE: | ||
| 548 | tune_args->hierarchy = HIER_NONE; | ||
| 549 | break; | ||
| 550 | case HIERARCHY_1: | ||
| 551 | tune_args->hierarchy = HIER_ALPHA_1; | ||
| 552 | break; | ||
| 553 | case HIERARCHY_2: | ||
| 554 | tune_args->hierarchy = HIER_ALPHA_2; | ||
| 555 | break; | ||
| 556 | case HIERARCHY_4: | ||
| 557 | tune_args->hierarchy = HIER_ALPHA_4; | ||
| 558 | break; | ||
| 559 | case HIERARCHY_AUTO: | ||
| 560 | tune_args->hierarchy = HIER_UNKNOWN; | ||
| 561 | break; | ||
| 562 | } | ||
| 563 | |||
| 564 | dprintk(debug, "tuner parameters: freq: %d bw: 0x%02x gi: 0x%02x\n", | ||
| 565 | params->frequency, | ||
| 566 | tune_args->bandwidth, | ||
| 567 | tune_args->guard_interval); | ||
| 568 | |||
| 569 | /* | ||
| 570 | * Detect a hierarchy selection | ||
| 571 | * if HP/LP are both set to FEC_NONE, HP will be selected. | ||
| 572 | */ | ||
| 573 | if ((tune_args->hierarchy != HIER_NONE) && | ||
| 574 | ((params->u.ofdm.code_rate_LP == FEC_NONE) || | ||
| 575 | (params->u.ofdm.code_rate_HP == FEC_NONE))) { | ||
| 576 | |||
| 577 | if (params->u.ofdm.code_rate_LP == FEC_NONE) { | ||
| 578 | tune_args->hier_select = HIER_HIGH_PRIORITY; | ||
| 579 | tune_args->code_rate = | ||
| 580 | as102_fe_get_code_rate(params->u.ofdm.code_rate_HP); | ||
| 581 | } | ||
| 582 | |||
| 583 | if (params->u.ofdm.code_rate_HP == FEC_NONE) { | ||
| 584 | tune_args->hier_select = HIER_LOW_PRIORITY; | ||
| 585 | tune_args->code_rate = | ||
| 586 | as102_fe_get_code_rate(params->u.ofdm.code_rate_LP); | ||
| 587 | } | ||
| 588 | |||
| 589 | dprintk(debug, "\thierarchy: 0x%02x " | ||
| 590 | "selected: %s code_rate_%s: 0x%02x\n", | ||
| 591 | tune_args->hierarchy, | ||
| 592 | tune_args->hier_select == HIER_HIGH_PRIORITY ? | ||
| 593 | "HP" : "LP", | ||
| 594 | tune_args->hier_select == HIER_HIGH_PRIORITY ? | ||
| 595 | "HP" : "LP", | ||
| 596 | tune_args->code_rate); | ||
| 597 | } else { | ||
| 598 | tune_args->code_rate = | ||
| 599 | as102_fe_get_code_rate(params->u.ofdm.code_rate_HP); | ||
| 600 | } | ||
| 601 | } | ||
| 602 | |||
| 603 | /* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */ | ||
diff --git a/drivers/staging/media/as102/as102_fw.c b/drivers/staging/media/as102/as102_fw.c new file mode 100644 index 000000000000..c019df933cc9 --- /dev/null +++ b/drivers/staging/media/as102/as102_fw.c | |||
| @@ -0,0 +1,251 @@ | |||
| 1 | /* | ||
| 2 | * Abilis Systems Single DVB-T Receiver | ||
| 3 | * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com> | ||
| 4 | * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 9 | * any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 19 | */ | ||
| 20 | #include <linux/kernel.h> | ||
| 21 | #include <linux/errno.h> | ||
| 22 | #include <linux/ctype.h> | ||
| 23 | #include <linux/delay.h> | ||
| 24 | #include <linux/firmware.h> | ||
| 25 | |||
| 26 | #include "as102_drv.h" | ||
| 27 | #include "as102_fw.h" | ||
| 28 | |||
| 29 | #if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) | ||
| 30 | char as102_st_fw1[] = "as102_data1_st.hex"; | ||
| 31 | char as102_st_fw2[] = "as102_data2_st.hex"; | ||
| 32 | char as102_dt_fw1[] = "as102_data1_dt.hex"; | ||
| 33 | char as102_dt_fw2[] = "as102_data2_dt.hex"; | ||
| 34 | |||
| 35 | static unsigned char atohx(unsigned char *dst, char *src) | ||
| 36 | { | ||
| 37 | unsigned char value = 0; | ||
| 38 | |||
| 39 | char msb = tolower(*src) - '0'; | ||
| 40 | char lsb = tolower(*(src + 1)) - '0'; | ||
| 41 | |||
| 42 | if (msb > 9) | ||
| 43 | msb -= 7; | ||
| 44 | if (lsb > 9) | ||
| 45 | lsb -= 7; | ||
| 46 | |||
| 47 | *dst = value = ((msb & 0xF) << 4) | (lsb & 0xF); | ||
| 48 | return value; | ||
| 49 | } | ||
| 50 | |||
| 51 | /* | ||
| 52 | * Parse INTEL HEX firmware file to extract address and data. | ||
| 53 | */ | ||
| 54 | static int parse_hex_line(unsigned char *fw_data, unsigned char *addr, | ||
| 55 | unsigned char *data, int *dataLength, | ||
| 56 | unsigned char *addr_has_changed) { | ||
| 57 | |||
| 58 | int count = 0; | ||
| 59 | unsigned char *src, dst; | ||
| 60 | |||
| 61 | if (*fw_data++ != ':') { | ||
| 62 | printk(KERN_ERR "invalid firmware file\n"); | ||
| 63 | return -EFAULT; | ||
| 64 | } | ||
| 65 | |||
| 66 | /* locate end of line */ | ||
| 67 | for (src = fw_data; *src != '\n'; src += 2) { | ||
| 68 | atohx(&dst, src); | ||
| 69 | /* parse line to split addr / data */ | ||
| 70 | switch (count) { | ||
| 71 | case 0: | ||
| 72 | *dataLength = dst; | ||
| 73 | break; | ||
| 74 | case 1: | ||
| 75 | addr[2] = dst; | ||
| 76 | break; | ||
| 77 | case 2: | ||
| 78 | addr[3] = dst; | ||
| 79 | break; | ||
| 80 | case 3: | ||
| 81 | /* check if data is an address */ | ||
| 82 | if (dst == 0x04) | ||
| 83 | *addr_has_changed = 1; | ||
| 84 | else | ||
| 85 | *addr_has_changed = 0; | ||
| 86 | break; | ||
| 87 | case 4: | ||
| 88 | case 5: | ||
| 89 | if (*addr_has_changed) | ||
| 90 | addr[(count - 4)] = dst; | ||
| 91 | else | ||
| 92 | data[(count - 4)] = dst; | ||
| 93 | break; | ||
| 94 | default: | ||
| 95 | data[(count - 4)] = dst; | ||
| 96 | break; | ||
| 97 | } | ||
| 98 | count++; | ||
| 99 | } | ||
| 100 | |||
| 101 | /* return read value + ':' + '\n' */ | ||
| 102 | return (count * 2) + 2; | ||
| 103 | } | ||
| 104 | |||
| 105 | static int as102_firmware_upload(struct as102_bus_adapter_t *bus_adap, | ||
| 106 | unsigned char *cmd, | ||
| 107 | const struct firmware *firmware) { | ||
| 108 | |||
| 109 | struct as10x_fw_pkt_t fw_pkt; | ||
| 110 | int total_read_bytes = 0, errno = 0; | ||
| 111 | unsigned char addr_has_changed = 0; | ||
| 112 | |||
| 113 | ENTER(); | ||
| 114 | |||
| 115 | for (total_read_bytes = 0; total_read_bytes < firmware->size; ) { | ||
| 116 | int read_bytes = 0, data_len = 0; | ||
| 117 | |||
| 118 | /* parse intel hex line */ | ||
| 119 | read_bytes = parse_hex_line( | ||
| 120 | (u8 *) (firmware->data + total_read_bytes), | ||
| 121 | fw_pkt.raw.address, | ||
| 122 | fw_pkt.raw.data, | ||
| 123 | &data_len, | ||
| 124 | &addr_has_changed); | ||
| 125 | |||
| 126 | if (read_bytes <= 0) | ||
| 127 | goto error; | ||
| 128 | |||
| 129 | /* detect the end of file */ | ||
| 130 | total_read_bytes += read_bytes; | ||
| 131 | if (total_read_bytes == firmware->size) { | ||
| 132 | fw_pkt.u.request[0] = 0x00; | ||
| 133 | fw_pkt.u.request[1] = 0x03; | ||
| 134 | |||
| 135 | /* send EOF command */ | ||
| 136 | errno = bus_adap->ops->upload_fw_pkt(bus_adap, | ||
| 137 | (uint8_t *) | ||
| 138 | &fw_pkt, 2, 0); | ||
| 139 | if (errno < 0) | ||
| 140 | goto error; | ||
| 141 | } else { | ||
| 142 | if (!addr_has_changed) { | ||
| 143 | /* prepare command to send */ | ||
| 144 | fw_pkt.u.request[0] = 0x00; | ||
| 145 | fw_pkt.u.request[1] = 0x01; | ||
| 146 | |||
| 147 | data_len += sizeof(fw_pkt.u.request); | ||
| 148 | data_len += sizeof(fw_pkt.raw.address); | ||
| 149 | |||
| 150 | /* send cmd to device */ | ||
| 151 | errno = bus_adap->ops->upload_fw_pkt(bus_adap, | ||
| 152 | (uint8_t *) | ||
| 153 | &fw_pkt, | ||
| 154 | data_len, | ||
| 155 | 0); | ||
| 156 | if (errno < 0) | ||
| 157 | goto error; | ||
| 158 | } | ||
| 159 | } | ||
| 160 | } | ||
| 161 | error: | ||
| 162 | LEAVE(); | ||
| 163 | return (errno == 0) ? total_read_bytes : errno; | ||
| 164 | } | ||
| 165 | |||
| 166 | int as102_fw_upload(struct as102_bus_adapter_t *bus_adap) | ||
| 167 | { | ||
| 168 | int errno = -EFAULT; | ||
| 169 | const struct firmware *firmware; | ||
| 170 | unsigned char *cmd_buf = NULL; | ||
| 171 | char *fw1, *fw2; | ||
| 172 | |||
| 173 | #if defined(CONFIG_AS102_USB) | ||
| 174 | struct usb_device *dev = bus_adap->usb_dev; | ||
| 175 | #endif | ||
| 176 | #if defined(CONFIG_AS102_SPI) | ||
| 177 | struct spi_device *dev = bus_adap->spi_dev; | ||
| 178 | #endif | ||
| 179 | ENTER(); | ||
| 180 | |||
| 181 | /* select fw file to upload */ | ||
| 182 | if (dual_tuner) { | ||
| 183 | fw1 = as102_dt_fw1; | ||
| 184 | fw2 = as102_dt_fw2; | ||
| 185 | } else { | ||
| 186 | fw1 = as102_st_fw1; | ||
| 187 | fw2 = as102_st_fw2; | ||
| 188 | } | ||
| 189 | |||
| 190 | #if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) | ||
| 191 | /* allocate buffer to store firmware upload command and data */ | ||
| 192 | cmd_buf = kzalloc(MAX_FW_PKT_SIZE, GFP_KERNEL); | ||
| 193 | if (cmd_buf == NULL) { | ||
| 194 | errno = -ENOMEM; | ||
| 195 | goto error; | ||
| 196 | } | ||
| 197 | |||
| 198 | /* request kernel to locate firmware file: part1 */ | ||
| 199 | errno = request_firmware(&firmware, fw1, &dev->dev); | ||
| 200 | if (errno < 0) { | ||
| 201 | printk(KERN_ERR "%s: unable to locate firmware file: %s\n", | ||
| 202 | DRIVER_NAME, fw1); | ||
| 203 | goto error; | ||
| 204 | } | ||
| 205 | |||
| 206 | /* initiate firmware upload */ | ||
| 207 | errno = as102_firmware_upload(bus_adap, cmd_buf, firmware); | ||
| 208 | if (errno < 0) { | ||
| 209 | printk(KERN_ERR "%s: error during firmware upload part1\n", | ||
| 210 | DRIVER_NAME); | ||
| 211 | goto error; | ||
| 212 | } | ||
| 213 | |||
| 214 | printk(KERN_INFO "%s: fimrware: %s loaded with success\n", | ||
| 215 | DRIVER_NAME, fw1); | ||
| 216 | release_firmware(firmware); | ||
| 217 | |||
| 218 | /* wait for boot to complete */ | ||
| 219 | mdelay(100); | ||
| 220 | |||
| 221 | /* request kernel to locate firmware file: part2 */ | ||
| 222 | errno = request_firmware(&firmware, fw2, &dev->dev); | ||
| 223 | if (errno < 0) { | ||
| 224 | printk(KERN_ERR "%s: unable to locate firmware file: %s\n", | ||
| 225 | DRIVER_NAME, fw2); | ||
| 226 | goto error; | ||
| 227 | } | ||
| 228 | |||
| 229 | /* initiate firmware upload */ | ||
| 230 | errno = as102_firmware_upload(bus_adap, cmd_buf, firmware); | ||
| 231 | if (errno < 0) { | ||
| 232 | printk(KERN_ERR "%s: error during firmware upload part2\n", | ||
| 233 | DRIVER_NAME); | ||
| 234 | goto error; | ||
| 235 | } | ||
| 236 | |||
| 237 | printk(KERN_INFO "%s: fimrware: %s loaded with success\n", | ||
| 238 | DRIVER_NAME, fw2); | ||
| 239 | error: | ||
| 240 | /* free data buffer */ | ||
| 241 | kfree(cmd_buf); | ||
| 242 | /* release firmware if needed */ | ||
| 243 | if (firmware != NULL) | ||
| 244 | release_firmware(firmware); | ||
| 245 | #endif | ||
| 246 | LEAVE(); | ||
| 247 | return errno; | ||
| 248 | } | ||
| 249 | #endif | ||
| 250 | |||
| 251 | /* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */ | ||
diff --git a/drivers/staging/media/as102/as102_fw.h b/drivers/staging/media/as102/as102_fw.h new file mode 100644 index 000000000000..27e5347e2e19 --- /dev/null +++ b/drivers/staging/media/as102/as102_fw.h | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | /* | ||
| 2 | * Abilis Systems Single DVB-T Receiver | ||
| 3 | * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com> | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 8 | * any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 18 | */ | ||
| 19 | #define MAX_FW_PKT_SIZE 64 | ||
| 20 | |||
| 21 | extern int dual_tuner; | ||
| 22 | |||
| 23 | #pragma pack(1) | ||
| 24 | struct as10x_raw_fw_pkt { | ||
| 25 | unsigned char address[4]; | ||
| 26 | unsigned char data[MAX_FW_PKT_SIZE - 6]; | ||
| 27 | }; | ||
| 28 | |||
| 29 | struct as10x_fw_pkt_t { | ||
| 30 | union { | ||
| 31 | unsigned char request[2]; | ||
| 32 | unsigned char length[2]; | ||
| 33 | } u; | ||
| 34 | struct as10x_raw_fw_pkt raw; | ||
| 35 | }; | ||
| 36 | #pragma pack() | ||
| 37 | |||
| 38 | #ifdef __KERNEL__ | ||
| 39 | int as102_fw_upload(struct as102_bus_adapter_t *bus_adap); | ||
| 40 | #endif | ||
| 41 | |||
| 42 | /* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */ | ||
diff --git a/drivers/staging/media/as102/as102_usb_drv.c b/drivers/staging/media/as102/as102_usb_drv.c new file mode 100644 index 000000000000..264be2dbd2a4 --- /dev/null +++ b/drivers/staging/media/as102/as102_usb_drv.c | |||
| @@ -0,0 +1,478 @@ | |||
| 1 | /* | ||
| 2 | * Abilis Systems Single DVB-T Receiver | ||
| 3 | * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com> | ||
| 4 | * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 9 | * any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 19 | */ | ||
| 20 | #include <linux/kernel.h> | ||
| 21 | #include <linux/errno.h> | ||
| 22 | #include <linux/slab.h> | ||
| 23 | #include <linux/mm.h> | ||
| 24 | #include <linux/usb.h> | ||
| 25 | |||
| 26 | #include "as102_drv.h" | ||
| 27 | #include "as102_usb_drv.h" | ||
| 28 | #include "as102_fw.h" | ||
| 29 | |||
| 30 | static void as102_usb_disconnect(struct usb_interface *interface); | ||
| 31 | static int as102_usb_probe(struct usb_interface *interface, | ||
| 32 | const struct usb_device_id *id); | ||
| 33 | |||
| 34 | static int as102_usb_start_stream(struct as102_dev_t *dev); | ||
| 35 | static void as102_usb_stop_stream(struct as102_dev_t *dev); | ||
| 36 | |||
| 37 | static int as102_open(struct inode *inode, struct file *file); | ||
| 38 | static int as102_release(struct inode *inode, struct file *file); | ||
| 39 | |||
| 40 | static struct usb_device_id as102_usb_id_table[] = { | ||
| 41 | { USB_DEVICE(AS102_USB_DEVICE_VENDOR_ID, AS102_USB_DEVICE_PID_0001) }, | ||
| 42 | { USB_DEVICE(PCTV_74E_USB_VID, PCTV_74E_USB_PID) }, | ||
| 43 | { USB_DEVICE(ELGATO_EYETV_DTT_USB_VID, ELGATO_EYETV_DTT_USB_PID) }, | ||
| 44 | { USB_DEVICE(NBOX_DVBT_DONGLE_USB_VID, NBOX_DVBT_DONGLE_USB_PID) }, | ||
| 45 | { } /* Terminating entry */ | ||
| 46 | }; | ||
| 47 | |||
| 48 | /* Note that this table must always have the same number of entries as the | ||
| 49 | as102_usb_id_table struct */ | ||
| 50 | static const char *as102_device_names[] = { | ||
| 51 | AS102_REFERENCE_DESIGN, | ||
| 52 | AS102_PCTV_74E, | ||
| 53 | AS102_ELGATO_EYETV_DTT_NAME, | ||
| 54 | AS102_NBOX_DVBT_DONGLE_NAME, | ||
| 55 | NULL /* Terminating entry */ | ||
| 56 | }; | ||
| 57 | |||
| 58 | struct usb_driver as102_usb_driver = { | ||
| 59 | .name = DRIVER_FULL_NAME, | ||
| 60 | .probe = as102_usb_probe, | ||
| 61 | .disconnect = as102_usb_disconnect, | ||
| 62 | .id_table = as102_usb_id_table | ||
| 63 | }; | ||
| 64 | |||
| 65 | static const struct file_operations as102_dev_fops = { | ||
| 66 | .owner = THIS_MODULE, | ||
| 67 | .open = as102_open, | ||
| 68 | .release = as102_release, | ||
| 69 | }; | ||
| 70 | |||
| 71 | static struct usb_class_driver as102_usb_class_driver = { | ||
| 72 | .name = "aton2-%d", | ||
| 73 | .fops = &as102_dev_fops, | ||
| 74 | .minor_base = AS102_DEVICE_MAJOR, | ||
| 75 | }; | ||
| 76 | |||
| 77 | static int as102_usb_xfer_cmd(struct as102_bus_adapter_t *bus_adap, | ||
| 78 | unsigned char *send_buf, int send_buf_len, | ||
| 79 | unsigned char *recv_buf, int recv_buf_len) | ||
| 80 | { | ||
| 81 | int ret = 0; | ||
| 82 | ENTER(); | ||
| 83 | |||
| 84 | if (send_buf != NULL) { | ||
| 85 | ret = usb_control_msg(bus_adap->usb_dev, | ||
| 86 | usb_sndctrlpipe(bus_adap->usb_dev, 0), | ||
| 87 | AS102_USB_DEVICE_TX_CTRL_CMD, | ||
| 88 | USB_DIR_OUT | USB_TYPE_VENDOR | | ||
| 89 | USB_RECIP_DEVICE, | ||
| 90 | bus_adap->cmd_xid, /* value */ | ||
| 91 | 0, /* index */ | ||
| 92 | send_buf, send_buf_len, | ||
| 93 | USB_CTRL_SET_TIMEOUT /* 200 */); | ||
| 94 | if (ret < 0) { | ||
| 95 | dprintk(debug, "usb_control_msg(send) failed, err %i\n", | ||
| 96 | ret); | ||
| 97 | return ret; | ||
| 98 | } | ||
| 99 | |||
| 100 | if (ret != send_buf_len) { | ||
| 101 | dprintk(debug, "only wrote %d of %d bytes\n", | ||
| 102 | ret, send_buf_len); | ||
| 103 | return -1; | ||
| 104 | } | ||
| 105 | } | ||
| 106 | |||
| 107 | if (recv_buf != NULL) { | ||
| 108 | #ifdef TRACE | ||
| 109 | dprintk(debug, "want to read: %d bytes\n", recv_buf_len); | ||
| 110 | #endif | ||
| 111 | ret = usb_control_msg(bus_adap->usb_dev, | ||
| 112 | usb_rcvctrlpipe(bus_adap->usb_dev, 0), | ||
| 113 | AS102_USB_DEVICE_RX_CTRL_CMD, | ||
| 114 | USB_DIR_IN | USB_TYPE_VENDOR | | ||
| 115 | USB_RECIP_DEVICE, | ||
| 116 | bus_adap->cmd_xid, /* value */ | ||
| 117 | 0, /* index */ | ||
| 118 | recv_buf, recv_buf_len, | ||
| 119 | USB_CTRL_GET_TIMEOUT /* 200 */); | ||
| 120 | if (ret < 0) { | ||
| 121 | dprintk(debug, "usb_control_msg(recv) failed, err %i\n", | ||
| 122 | ret); | ||
| 123 | return ret; | ||
| 124 | } | ||
| 125 | #ifdef TRACE | ||
| 126 | dprintk(debug, "read %d bytes\n", recv_buf_len); | ||
| 127 | #endif | ||
| 128 | } | ||
| 129 | |||
| 130 | LEAVE(); | ||
| 131 | return ret; | ||
| 132 | } | ||
| 133 | |||
| 134 | static int as102_send_ep1(struct as102_bus_adapter_t *bus_adap, | ||
| 135 | unsigned char *send_buf, | ||
| 136 | int send_buf_len, | ||
| 137 | int swap32) | ||
| 138 | { | ||
| 139 | int ret = 0, actual_len; | ||
| 140 | |||
| 141 | ret = usb_bulk_msg(bus_adap->usb_dev, | ||
| 142 | usb_sndbulkpipe(bus_adap->usb_dev, 1), | ||
| 143 | send_buf, send_buf_len, &actual_len, 200); | ||
| 144 | if (ret) { | ||
| 145 | dprintk(debug, "usb_bulk_msg(send) failed, err %i\n", ret); | ||
| 146 | return ret; | ||
| 147 | } | ||
| 148 | |||
| 149 | if (actual_len != send_buf_len) { | ||
| 150 | dprintk(debug, "only wrote %d of %d bytes\n", | ||
| 151 | actual_len, send_buf_len); | ||
| 152 | return -1; | ||
| 153 | } | ||
| 154 | return ret ? ret : actual_len; | ||
| 155 | } | ||
| 156 | |||
| 157 | static int as102_read_ep2(struct as102_bus_adapter_t *bus_adap, | ||
| 158 | unsigned char *recv_buf, int recv_buf_len) | ||
| 159 | { | ||
| 160 | int ret = 0, actual_len; | ||
| 161 | |||
| 162 | if (recv_buf == NULL) | ||
| 163 | return -EINVAL; | ||
| 164 | |||
| 165 | ret = usb_bulk_msg(bus_adap->usb_dev, | ||
| 166 | usb_rcvbulkpipe(bus_adap->usb_dev, 2), | ||
| 167 | recv_buf, recv_buf_len, &actual_len, 200); | ||
| 168 | if (ret) { | ||
| 169 | dprintk(debug, "usb_bulk_msg(recv) failed, err %i\n", ret); | ||
| 170 | return ret; | ||
| 171 | } | ||
| 172 | |||
| 173 | if (actual_len != recv_buf_len) { | ||
| 174 | dprintk(debug, "only read %d of %d bytes\n", | ||
| 175 | actual_len, recv_buf_len); | ||
| 176 | return -1; | ||
| 177 | } | ||
| 178 | return ret ? ret : actual_len; | ||
| 179 | } | ||
| 180 | |||
| 181 | struct as102_priv_ops_t as102_priv_ops = { | ||
| 182 | .upload_fw_pkt = as102_send_ep1, | ||
| 183 | .xfer_cmd = as102_usb_xfer_cmd, | ||
| 184 | .as102_read_ep2 = as102_read_ep2, | ||
| 185 | .start_stream = as102_usb_start_stream, | ||
| 186 | .stop_stream = as102_usb_stop_stream, | ||
| 187 | }; | ||
| 188 | |||
| 189 | static int as102_submit_urb_stream(struct as102_dev_t *dev, struct urb *urb) | ||
| 190 | { | ||
| 191 | int err; | ||
| 192 | |||
| 193 | usb_fill_bulk_urb(urb, | ||
| 194 | dev->bus_adap.usb_dev, | ||
| 195 | usb_rcvbulkpipe(dev->bus_adap.usb_dev, 0x2), | ||
| 196 | urb->transfer_buffer, | ||
| 197 | AS102_USB_BUF_SIZE, | ||
| 198 | as102_urb_stream_irq, | ||
| 199 | dev); | ||
| 200 | |||
| 201 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 202 | if (err) | ||
| 203 | dprintk(debug, "%s: usb_submit_urb failed\n", __func__); | ||
| 204 | |||
| 205 | return err; | ||
| 206 | } | ||
| 207 | |||
| 208 | void as102_urb_stream_irq(struct urb *urb) | ||
| 209 | { | ||
| 210 | struct as102_dev_t *as102_dev = urb->context; | ||
| 211 | |||
| 212 | if (urb->actual_length > 0) { | ||
| 213 | dvb_dmx_swfilter(&as102_dev->dvb_dmx, | ||
| 214 | urb->transfer_buffer, | ||
| 215 | urb->actual_length); | ||
| 216 | } else { | ||
| 217 | if (urb->actual_length == 0) | ||
| 218 | memset(urb->transfer_buffer, 0, AS102_USB_BUF_SIZE); | ||
| 219 | } | ||
| 220 | |||
| 221 | /* is not stopped, re-submit urb */ | ||
| 222 | if (as102_dev->streaming) | ||
| 223 | as102_submit_urb_stream(as102_dev, urb); | ||
| 224 | } | ||
| 225 | |||
| 226 | static void as102_free_usb_stream_buffer(struct as102_dev_t *dev) | ||
| 227 | { | ||
| 228 | int i; | ||
| 229 | |||
| 230 | ENTER(); | ||
| 231 | |||
| 232 | for (i = 0; i < MAX_STREAM_URB; i++) | ||
| 233 | usb_free_urb(dev->stream_urb[i]); | ||
| 234 | |||
| 235 | usb_free_coherent(dev->bus_adap.usb_dev, | ||
| 236 | MAX_STREAM_URB * AS102_USB_BUF_SIZE, | ||
| 237 | dev->stream, | ||
| 238 | dev->dma_addr); | ||
| 239 | LEAVE(); | ||
| 240 | } | ||
| 241 | |||
| 242 | static int as102_alloc_usb_stream_buffer(struct as102_dev_t *dev) | ||
| 243 | { | ||
| 244 | int i, ret = 0; | ||
| 245 | |||
| 246 | ENTER(); | ||
| 247 | |||
| 248 | dev->stream = usb_alloc_coherent(dev->bus_adap.usb_dev, | ||
| 249 | MAX_STREAM_URB * AS102_USB_BUF_SIZE, | ||
| 250 | GFP_KERNEL, | ||
| 251 | &dev->dma_addr); | ||
| 252 | if (!dev->stream) { | ||
| 253 | dprintk(debug, "%s: usb_buffer_alloc failed\n", __func__); | ||
| 254 | return -ENOMEM; | ||
| 255 | } | ||
| 256 | |||
| 257 | memset(dev->stream, 0, MAX_STREAM_URB * AS102_USB_BUF_SIZE); | ||
| 258 | |||
| 259 | /* init urb buffers */ | ||
| 260 | for (i = 0; i < MAX_STREAM_URB; i++) { | ||
| 261 | struct urb *urb; | ||
| 262 | |||
| 263 | urb = usb_alloc_urb(0, GFP_ATOMIC); | ||
| 264 | if (urb == NULL) { | ||
| 265 | dprintk(debug, "%s: usb_alloc_urb failed\n", __func__); | ||
| 266 | as102_free_usb_stream_buffer(dev); | ||
| 267 | return -ENOMEM; | ||
| 268 | } | ||
| 269 | |||
| 270 | urb->transfer_buffer = dev->stream + (i * AS102_USB_BUF_SIZE); | ||
| 271 | urb->transfer_buffer_length = AS102_USB_BUF_SIZE; | ||
| 272 | |||
| 273 | dev->stream_urb[i] = urb; | ||
| 274 | } | ||
| 275 | LEAVE(); | ||
| 276 | return ret; | ||
| 277 | } | ||
| 278 | |||
| 279 | static void as102_usb_stop_stream(struct as102_dev_t *dev) | ||
| 280 | { | ||
| 281 | int i; | ||
| 282 | |||
| 283 | for (i = 0; i < MAX_STREAM_URB; i++) | ||
| 284 | usb_kill_urb(dev->stream_urb[i]); | ||
| 285 | } | ||
| 286 | |||
| 287 | static int as102_usb_start_stream(struct as102_dev_t *dev) | ||
| 288 | { | ||
| 289 | int i, ret = 0; | ||
| 290 | |||
| 291 | for (i = 0; i < MAX_STREAM_URB; i++) { | ||
| 292 | ret = as102_submit_urb_stream(dev, dev->stream_urb[i]); | ||
| 293 | if (ret) { | ||
| 294 | as102_usb_stop_stream(dev); | ||
| 295 | return ret; | ||
| 296 | } | ||
| 297 | } | ||
| 298 | |||
| 299 | return 0; | ||
| 300 | } | ||
| 301 | |||
| 302 | static void as102_usb_release(struct kref *kref) | ||
| 303 | { | ||
| 304 | struct as102_dev_t *as102_dev; | ||
| 305 | |||
| 306 | ENTER(); | ||
| 307 | |||
| 308 | as102_dev = container_of(kref, struct as102_dev_t, kref); | ||
| 309 | if (as102_dev != NULL) { | ||
| 310 | usb_put_dev(as102_dev->bus_adap.usb_dev); | ||
| 311 | kfree(as102_dev); | ||
| 312 | } | ||
| 313 | |||
| 314 | LEAVE(); | ||
| 315 | } | ||
| 316 | |||
| 317 | static void as102_usb_disconnect(struct usb_interface *intf) | ||
| 318 | { | ||
| 319 | struct as102_dev_t *as102_dev; | ||
| 320 | |||
| 321 | ENTER(); | ||
| 322 | |||
| 323 | /* extract as102_dev_t from usb_device private data */ | ||
| 324 | as102_dev = usb_get_intfdata(intf); | ||
| 325 | |||
| 326 | /* unregister dvb layer */ | ||
| 327 | as102_dvb_unregister(as102_dev); | ||
| 328 | |||
| 329 | /* free usb buffers */ | ||
| 330 | as102_free_usb_stream_buffer(as102_dev); | ||
| 331 | |||
| 332 | usb_set_intfdata(intf, NULL); | ||
| 333 | |||
| 334 | /* usb unregister device */ | ||
| 335 | usb_deregister_dev(intf, &as102_usb_class_driver); | ||
| 336 | |||
| 337 | /* decrement usage counter */ | ||
| 338 | kref_put(&as102_dev->kref, as102_usb_release); | ||
| 339 | |||
| 340 | printk(KERN_INFO "%s: device has been disconnected\n", DRIVER_NAME); | ||
| 341 | |||
| 342 | LEAVE(); | ||
| 343 | } | ||
| 344 | |||
| 345 | static int as102_usb_probe(struct usb_interface *intf, | ||
| 346 | const struct usb_device_id *id) | ||
| 347 | { | ||
| 348 | int ret; | ||
| 349 | struct as102_dev_t *as102_dev; | ||
| 350 | int i; | ||
| 351 | |||
| 352 | ENTER(); | ||
| 353 | |||
| 354 | as102_dev = kzalloc(sizeof(struct as102_dev_t), GFP_KERNEL); | ||
| 355 | if (as102_dev == NULL) { | ||
| 356 | err("%s: kzalloc failed", __func__); | ||
| 357 | return -ENOMEM; | ||
| 358 | } | ||
| 359 | |||
| 360 | /* This should never actually happen */ | ||
| 361 | if ((sizeof(as102_usb_id_table) / sizeof(struct usb_device_id)) != | ||
| 362 | (sizeof(as102_device_names) / sizeof(const char *))) { | ||
| 363 | printk(KERN_ERR "Device names table invalid size"); | ||
| 364 | return -EINVAL; | ||
| 365 | } | ||
| 366 | |||
| 367 | /* Assign the user-friendly device name */ | ||
| 368 | for (i = 0; i < (sizeof(as102_usb_id_table) / | ||
| 369 | sizeof(struct usb_device_id)); i++) { | ||
| 370 | if (id == &as102_usb_id_table[i]) | ||
| 371 | as102_dev->name = as102_device_names[i]; | ||
| 372 | } | ||
| 373 | |||
| 374 | if (as102_dev->name == NULL) | ||
| 375 | as102_dev->name = "Unknown AS102 device"; | ||
| 376 | |||
| 377 | /* set private callback functions */ | ||
| 378 | as102_dev->bus_adap.ops = &as102_priv_ops; | ||
| 379 | |||
| 380 | /* init cmd token for usb bus */ | ||
| 381 | as102_dev->bus_adap.cmd = &as102_dev->bus_adap.token.usb.c; | ||
| 382 | as102_dev->bus_adap.rsp = &as102_dev->bus_adap.token.usb.r; | ||
| 383 | |||
| 384 | /* init kernel device reference */ | ||
| 385 | kref_init(&as102_dev->kref); | ||
| 386 | |||
| 387 | /* store as102 device to usb_device private data */ | ||
| 388 | usb_set_intfdata(intf, (void *) as102_dev); | ||
| 389 | |||
| 390 | /* store in as102 device the usb_device pointer */ | ||
| 391 | as102_dev->bus_adap.usb_dev = usb_get_dev(interface_to_usbdev(intf)); | ||
| 392 | |||
| 393 | /* we can register the device now, as it is ready */ | ||
| 394 | ret = usb_register_dev(intf, &as102_usb_class_driver); | ||
| 395 | if (ret < 0) { | ||
| 396 | /* something prevented us from registering this driver */ | ||
| 397 | err("%s: usb_register_dev() failed (errno = %d)", | ||
| 398 | __func__, ret); | ||
| 399 | goto failed; | ||
| 400 | } | ||
| 401 | |||
| 402 | printk(KERN_INFO "%s: device has been detected\n", DRIVER_NAME); | ||
| 403 | |||
| 404 | /* request buffer allocation for streaming */ | ||
| 405 | ret = as102_alloc_usb_stream_buffer(as102_dev); | ||
| 406 | if (ret != 0) | ||
| 407 | goto failed; | ||
| 408 | |||
| 409 | /* register dvb layer */ | ||
| 410 | ret = as102_dvb_register(as102_dev); | ||
| 411 | |||
| 412 | LEAVE(); | ||
| 413 | return ret; | ||
| 414 | |||
| 415 | failed: | ||
| 416 | usb_set_intfdata(intf, NULL); | ||
| 417 | kfree(as102_dev); | ||
| 418 | return ret; | ||
| 419 | } | ||
| 420 | |||
| 421 | static int as102_open(struct inode *inode, struct file *file) | ||
| 422 | { | ||
| 423 | int ret = 0, minor = 0; | ||
| 424 | struct usb_interface *intf = NULL; | ||
| 425 | struct as102_dev_t *dev = NULL; | ||
| 426 | |||
| 427 | ENTER(); | ||
| 428 | |||
| 429 | /* read minor from inode */ | ||
| 430 | minor = iminor(inode); | ||
| 431 | |||
| 432 | /* fetch device from usb interface */ | ||
| 433 | intf = usb_find_interface(&as102_usb_driver, minor); | ||
| 434 | if (intf == NULL) { | ||
| 435 | printk(KERN_ERR "%s: can't find device for minor %d\n", | ||
| 436 | __func__, minor); | ||
| 437 | ret = -ENODEV; | ||
| 438 | goto exit; | ||
| 439 | } | ||
| 440 | |||
| 441 | /* get our device */ | ||
| 442 | dev = usb_get_intfdata(intf); | ||
| 443 | if (dev == NULL) { | ||
| 444 | ret = -EFAULT; | ||
| 445 | goto exit; | ||
| 446 | } | ||
| 447 | |||
| 448 | /* save our device object in the file's private structure */ | ||
| 449 | file->private_data = dev; | ||
| 450 | |||
| 451 | /* increment our usage count for the device */ | ||
| 452 | kref_get(&dev->kref); | ||
| 453 | |||
| 454 | exit: | ||
| 455 | LEAVE(); | ||
| 456 | return ret; | ||
| 457 | } | ||
| 458 | |||
| 459 | static int as102_release(struct inode *inode, struct file *file) | ||
| 460 | { | ||
| 461 | int ret = 0; | ||
| 462 | struct as102_dev_t *dev = NULL; | ||
| 463 | |||
| 464 | ENTER(); | ||
| 465 | |||
| 466 | dev = file->private_data; | ||
| 467 | if (dev != NULL) { | ||
| 468 | /* decrement the count on our device */ | ||
| 469 | kref_put(&dev->kref, as102_usb_release); | ||
| 470 | } | ||
| 471 | |||
| 472 | LEAVE(); | ||
| 473 | return ret; | ||
| 474 | } | ||
| 475 | |||
| 476 | MODULE_DEVICE_TABLE(usb, as102_usb_id_table); | ||
| 477 | |||
| 478 | /* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */ | ||
diff --git a/drivers/staging/media/as102/as102_usb_drv.h b/drivers/staging/media/as102/as102_usb_drv.h new file mode 100644 index 000000000000..fb1fc41dcd79 --- /dev/null +++ b/drivers/staging/media/as102/as102_usb_drv.h | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | /* | ||
| 2 | * Abilis Systems Single DVB-T Receiver | ||
| 3 | * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com> | ||
| 4 | * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 9 | * any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 19 | */ | ||
| 20 | #include <linux/version.h> | ||
| 21 | |||
| 22 | #ifndef _AS102_USB_DRV_H_ | ||
| 23 | #define _AS102_USB_DRV_H_ | ||
| 24 | |||
| 25 | #define AS102_USB_DEVICE_TX_CTRL_CMD 0xF1 | ||
| 26 | #define AS102_USB_DEVICE_RX_CTRL_CMD 0xF2 | ||
| 27 | |||
| 28 | /* define these values to match the supported devices */ | ||
| 29 | |||
| 30 | /* Abilis system: "TITAN" */ | ||
| 31 | #define AS102_REFERENCE_DESIGN "Abilis Systems DVB-Titan" | ||
| 32 | #define AS102_USB_DEVICE_VENDOR_ID 0x1BA6 | ||
| 33 | #define AS102_USB_DEVICE_PID_0001 0x0001 | ||
| 34 | |||
| 35 | /* PCTV Systems: PCTV picoStick (74e) */ | ||
| 36 | #define AS102_PCTV_74E "PCTV Systems picoStick (74e)" | ||
| 37 | #define PCTV_74E_USB_VID 0x2013 | ||
| 38 | #define PCTV_74E_USB_PID 0x0246 | ||
| 39 | |||
| 40 | /* Elgato: EyeTV DTT Deluxe */ | ||
| 41 | #define AS102_ELGATO_EYETV_DTT_NAME "Elgato EyeTV DTT Deluxe" | ||
| 42 | #define ELGATO_EYETV_DTT_USB_VID 0x0fd9 | ||
| 43 | #define ELGATO_EYETV_DTT_USB_PID 0x002c | ||
| 44 | |||
| 45 | /* nBox: nBox DVB-T Dongle */ | ||
| 46 | #define AS102_NBOX_DVBT_DONGLE_NAME "nBox DVB-T Dongle" | ||
| 47 | #define NBOX_DVBT_DONGLE_USB_VID 0x0b89 | ||
| 48 | #define NBOX_DVBT_DONGLE_USB_PID 0x0007 | ||
| 49 | |||
| 50 | void as102_urb_stream_irq(struct urb *urb); | ||
| 51 | |||
| 52 | struct as10x_usb_token_cmd_t { | ||
| 53 | /* token cmd */ | ||
| 54 | struct as10x_cmd_t c; | ||
| 55 | /* token response */ | ||
| 56 | struct as10x_cmd_t r; | ||
| 57 | }; | ||
| 58 | #endif | ||
| 59 | /* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */ | ||
diff --git a/drivers/staging/media/as102/as10x_cmd.c b/drivers/staging/media/as102/as10x_cmd.c new file mode 100644 index 000000000000..0dcba8065780 --- /dev/null +++ b/drivers/staging/media/as102/as10x_cmd.c | |||
| @@ -0,0 +1,452 @@ | |||
| 1 | /* | ||
| 2 | * Abilis Systems Single DVB-T Receiver | ||
| 3 | * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com> | ||
| 4 | * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 9 | * any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/kernel.h> | ||
| 22 | #include "as102_drv.h" | ||
| 23 | #include "as10x_types.h" | ||
| 24 | #include "as10x_cmd.h" | ||
| 25 | |||
| 26 | /** | ||
| 27 | * as10x_cmd_turn_on - send turn on command to AS10x | ||
| 28 | * @phandle: pointer to AS10x handle | ||
| 29 | * | ||
| 30 | * Return 0 when no error, < 0 in case of error. | ||
| 31 | */ | ||
| 32 | int as10x_cmd_turn_on(as10x_handle_t *phandle) | ||
| 33 | { | ||
| 34 | int error; | ||
| 35 | struct as10x_cmd_t *pcmd, *prsp; | ||
| 36 | |||
| 37 | ENTER(); | ||
| 38 | |||
| 39 | pcmd = phandle->cmd; | ||
| 40 | prsp = phandle->rsp; | ||
| 41 | |||
| 42 | /* prepare command */ | ||
| 43 | as10x_cmd_build(pcmd, (++phandle->cmd_xid), | ||
| 44 | sizeof(pcmd->body.turn_on.req)); | ||
| 45 | |||
| 46 | /* fill command */ | ||
| 47 | pcmd->body.turn_on.req.proc_id = cpu_to_le16(CONTROL_PROC_TURNON); | ||
| 48 | |||
| 49 | /* send command */ | ||
| 50 | if (phandle->ops->xfer_cmd) { | ||
| 51 | error = phandle->ops->xfer_cmd(phandle, (uint8_t *) pcmd, | ||
| 52 | sizeof(pcmd->body.turn_on.req) + | ||
| 53 | HEADER_SIZE, | ||
| 54 | (uint8_t *) prsp, | ||
| 55 | sizeof(prsp->body.turn_on.rsp) + | ||
| 56 | HEADER_SIZE); | ||
| 57 | } else { | ||
| 58 | error = AS10X_CMD_ERROR; | ||
| 59 | } | ||
| 60 | |||
| 61 | if (error < 0) | ||
| 62 | goto out; | ||
| 63 | |||
| 64 | /* parse response */ | ||
| 65 | error = as10x_rsp_parse(prsp, CONTROL_PROC_TURNON_RSP); | ||
| 66 | |||
| 67 | out: | ||
| 68 | LEAVE(); | ||
| 69 | return error; | ||
| 70 | } | ||
| 71 | |||
| 72 | /** | ||
| 73 | * as10x_cmd_turn_off - send turn off command to AS10x | ||
| 74 | * @phandle: pointer to AS10x handle | ||
| 75 | * | ||
| 76 | * Return 0 on success or negative value in case of error. | ||
| 77 | */ | ||
| 78 | int as10x_cmd_turn_off(as10x_handle_t *phandle) | ||
| 79 | { | ||
| 80 | int error; | ||
| 81 | struct as10x_cmd_t *pcmd, *prsp; | ||
| 82 | |||
| 83 | ENTER(); | ||
| 84 | |||
| 85 | pcmd = phandle->cmd; | ||
| 86 | prsp = phandle->rsp; | ||
| 87 | |||
| 88 | /* prepare command */ | ||
| 89 | as10x_cmd_build(pcmd, (++phandle->cmd_xid), | ||
| 90 | sizeof(pcmd->body.turn_off.req)); | ||
| 91 | |||
| 92 | /* fill command */ | ||
| 93 | pcmd->body.turn_off.req.proc_id = cpu_to_le16(CONTROL_PROC_TURNOFF); | ||
| 94 | |||
| 95 | /* send command */ | ||
| 96 | if (phandle->ops->xfer_cmd) { | ||
| 97 | error = phandle->ops->xfer_cmd( | ||
| 98 | phandle, (uint8_t *) pcmd, | ||
| 99 | sizeof(pcmd->body.turn_off.req) + HEADER_SIZE, | ||
| 100 | (uint8_t *) prsp, | ||
| 101 | sizeof(prsp->body.turn_off.rsp) + HEADER_SIZE); | ||
| 102 | } else { | ||
| 103 | error = AS10X_CMD_ERROR; | ||
| 104 | } | ||
| 105 | |||
| 106 | if (error < 0) | ||
| 107 | goto out; | ||
| 108 | |||
| 109 | /* parse response */ | ||
| 110 | error = as10x_rsp_parse(prsp, CONTROL_PROC_TURNOFF_RSP); | ||
| 111 | |||
| 112 | out: | ||
| 113 | LEAVE(); | ||
| 114 | return error; | ||
| 115 | } | ||
| 116 | |||
| 117 | /** | ||
| 118 | * as10x_cmd_set_tune - send set tune command to AS10x | ||
| 119 | * @phandle: pointer to AS10x handle | ||
| 120 | * @ptune: tune parameters | ||
| 121 | * | ||
| 122 | * Return 0 on success or negative value in case of error. | ||
| 123 | */ | ||
| 124 | int as10x_cmd_set_tune(as10x_handle_t *phandle, struct as10x_tune_args *ptune) | ||
| 125 | { | ||
| 126 | int error; | ||
| 127 | struct as10x_cmd_t *preq, *prsp; | ||
| 128 | |||
| 129 | ENTER(); | ||
| 130 | |||
| 131 | preq = phandle->cmd; | ||
| 132 | prsp = phandle->rsp; | ||
| 133 | |||
| 134 | /* prepare command */ | ||
| 135 | as10x_cmd_build(preq, (++phandle->cmd_xid), | ||
| 136 | sizeof(preq->body.set_tune.req)); | ||
| 137 | |||
| 138 | /* fill command */ | ||
| 139 | preq->body.set_tune.req.proc_id = cpu_to_le16(CONTROL_PROC_SETTUNE); | ||
| 140 | preq->body.set_tune.req.args.freq = cpu_to_le32(ptune->freq); | ||
| 141 | preq->body.set_tune.req.args.bandwidth = ptune->bandwidth; | ||
| 142 | preq->body.set_tune.req.args.hier_select = ptune->hier_select; | ||
| 143 | preq->body.set_tune.req.args.constellation = ptune->constellation; | ||
| 144 | preq->body.set_tune.req.args.hierarchy = ptune->hierarchy; | ||
| 145 | preq->body.set_tune.req.args.interleaving_mode = | ||
| 146 | ptune->interleaving_mode; | ||
| 147 | preq->body.set_tune.req.args.code_rate = ptune->code_rate; | ||
| 148 | preq->body.set_tune.req.args.guard_interval = ptune->guard_interval; | ||
| 149 | preq->body.set_tune.req.args.transmission_mode = | ||
| 150 | ptune->transmission_mode; | ||
| 151 | |||
| 152 | /* send command */ | ||
| 153 | if (phandle->ops->xfer_cmd) { | ||
| 154 | error = phandle->ops->xfer_cmd(phandle, | ||
| 155 | (uint8_t *) preq, | ||
| 156 | sizeof(preq->body.set_tune.req) | ||
| 157 | + HEADER_SIZE, | ||
| 158 | (uint8_t *) prsp, | ||
| 159 | sizeof(prsp->body.set_tune.rsp) | ||
| 160 | + HEADER_SIZE); | ||
| 161 | } else { | ||
| 162 | error = AS10X_CMD_ERROR; | ||
| 163 | } | ||
| 164 | |||
| 165 | if (error < 0) | ||
| 166 | goto out; | ||
| 167 | |||
| 168 | /* parse response */ | ||
| 169 | error = as10x_rsp_parse(prsp, CONTROL_PROC_SETTUNE_RSP); | ||
| 170 | |||
| 171 | out: | ||
| 172 | LEAVE(); | ||
| 173 | return error; | ||
| 174 | } | ||
| 175 | |||
| 176 | /** | ||
| 177 | * as10x_cmd_get_tune_status - send get tune status command to AS10x | ||
| 178 | * @phandle: pointer to AS10x handle | ||
| 179 | * @pstatus: pointer to updated status structure of the current tune | ||
| 180 | * | ||
| 181 | * Return 0 on success or negative value in case of error. | ||
| 182 | */ | ||
| 183 | int as10x_cmd_get_tune_status(as10x_handle_t *phandle, | ||
| 184 | struct as10x_tune_status *pstatus) | ||
| 185 | { | ||
| 186 | int error; | ||
| 187 | struct as10x_cmd_t *preq, *prsp; | ||
| 188 | |||
| 189 | ENTER(); | ||
| 190 | |||
| 191 | preq = phandle->cmd; | ||
| 192 | prsp = phandle->rsp; | ||
| 193 | |||
| 194 | /* prepare command */ | ||
| 195 | as10x_cmd_build(preq, (++phandle->cmd_xid), | ||
| 196 | sizeof(preq->body.get_tune_status.req)); | ||
| 197 | |||
| 198 | /* fill command */ | ||
| 199 | preq->body.get_tune_status.req.proc_id = | ||
| 200 | cpu_to_le16(CONTROL_PROC_GETTUNESTAT); | ||
| 201 | |||
| 202 | /* send command */ | ||
| 203 | if (phandle->ops->xfer_cmd) { | ||
| 204 | error = phandle->ops->xfer_cmd( | ||
| 205 | phandle, | ||
| 206 | (uint8_t *) preq, | ||
| 207 | sizeof(preq->body.get_tune_status.req) + HEADER_SIZE, | ||
| 208 | (uint8_t *) prsp, | ||
| 209 | sizeof(prsp->body.get_tune_status.rsp) + HEADER_SIZE); | ||
| 210 | } else { | ||
| 211 | error = AS10X_CMD_ERROR; | ||
| 212 | } | ||
| 213 | |||
| 214 | if (error < 0) | ||
| 215 | goto out; | ||
| 216 | |||
| 217 | /* parse response */ | ||
| 218 | error = as10x_rsp_parse(prsp, CONTROL_PROC_GETTUNESTAT_RSP); | ||
| 219 | if (error < 0) | ||
| 220 | goto out; | ||
| 221 | |||
| 222 | /* Response OK -> get response data */ | ||
| 223 | pstatus->tune_state = prsp->body.get_tune_status.rsp.sts.tune_state; | ||
| 224 | pstatus->signal_strength = | ||
| 225 | le16_to_cpu(prsp->body.get_tune_status.rsp.sts.signal_strength); | ||
| 226 | pstatus->PER = le16_to_cpu(prsp->body.get_tune_status.rsp.sts.PER); | ||
| 227 | pstatus->BER = le16_to_cpu(prsp->body.get_tune_status.rsp.sts.BER); | ||
| 228 | |||
| 229 | out: | ||
| 230 | LEAVE(); | ||
| 231 | return error; | ||
| 232 | } | ||
| 233 | |||
| 234 | /** | ||
| 235 | * send get TPS command to AS10x | ||
| 236 | * @phandle: pointer to AS10x handle | ||
| 237 | * @ptps: pointer to TPS parameters structure | ||
| 238 | * | ||
| 239 | * Return 0 on success or negative value in case of error. | ||
| 240 | */ | ||
| 241 | int as10x_cmd_get_tps(as10x_handle_t *phandle, struct as10x_tps *ptps) | ||
| 242 | { | ||
| 243 | int error; | ||
| 244 | struct as10x_cmd_t *pcmd, *prsp; | ||
| 245 | |||
| 246 | ENTER(); | ||
| 247 | |||
| 248 | pcmd = phandle->cmd; | ||
| 249 | prsp = phandle->rsp; | ||
| 250 | |||
| 251 | /* prepare command */ | ||
| 252 | as10x_cmd_build(pcmd, (++phandle->cmd_xid), | ||
| 253 | sizeof(pcmd->body.get_tps.req)); | ||
| 254 | |||
| 255 | /* fill command */ | ||
| 256 | pcmd->body.get_tune_status.req.proc_id = | ||
| 257 | cpu_to_le16(CONTROL_PROC_GETTPS); | ||
| 258 | |||
| 259 | /* send command */ | ||
| 260 | if (phandle->ops->xfer_cmd) { | ||
| 261 | error = phandle->ops->xfer_cmd(phandle, | ||
| 262 | (uint8_t *) pcmd, | ||
| 263 | sizeof(pcmd->body.get_tps.req) + | ||
| 264 | HEADER_SIZE, | ||
| 265 | (uint8_t *) prsp, | ||
| 266 | sizeof(prsp->body.get_tps.rsp) + | ||
| 267 | HEADER_SIZE); | ||
| 268 | } else { | ||
| 269 | error = AS10X_CMD_ERROR; | ||
| 270 | } | ||
| 271 | |||
| 272 | if (error < 0) | ||
| 273 | goto out; | ||
| 274 | |||
| 275 | /* parse response */ | ||
| 276 | error = as10x_rsp_parse(prsp, CONTROL_PROC_GETTPS_RSP); | ||
| 277 | if (error < 0) | ||
| 278 | goto out; | ||
| 279 | |||
| 280 | /* Response OK -> get response data */ | ||
| 281 | ptps->constellation = prsp->body.get_tps.rsp.tps.constellation; | ||
| 282 | ptps->hierarchy = prsp->body.get_tps.rsp.tps.hierarchy; | ||
| 283 | ptps->interleaving_mode = prsp->body.get_tps.rsp.tps.interleaving_mode; | ||
| 284 | ptps->code_rate_HP = prsp->body.get_tps.rsp.tps.code_rate_HP; | ||
| 285 | ptps->code_rate_LP = prsp->body.get_tps.rsp.tps.code_rate_LP; | ||
| 286 | ptps->guard_interval = prsp->body.get_tps.rsp.tps.guard_interval; | ||
| 287 | ptps->transmission_mode = prsp->body.get_tps.rsp.tps.transmission_mode; | ||
| 288 | ptps->DVBH_mask_HP = prsp->body.get_tps.rsp.tps.DVBH_mask_HP; | ||
| 289 | ptps->DVBH_mask_LP = prsp->body.get_tps.rsp.tps.DVBH_mask_LP; | ||
| 290 | ptps->cell_ID = le16_to_cpu(prsp->body.get_tps.rsp.tps.cell_ID); | ||
| 291 | |||
| 292 | out: | ||
| 293 | LEAVE(); | ||
| 294 | return error; | ||
| 295 | } | ||
| 296 | |||
| 297 | /** | ||
| 298 | * as10x_cmd_get_demod_stats - send get demod stats command to AS10x | ||
| 299 | * @phandle: pointer to AS10x handle | ||
| 300 | * @pdemod_stats: pointer to demod stats parameters structure | ||
| 301 | * | ||
| 302 | * Return 0 on success or negative value in case of error. | ||
| 303 | */ | ||
| 304 | int as10x_cmd_get_demod_stats(as10x_handle_t *phandle, | ||
| 305 | struct as10x_demod_stats *pdemod_stats) | ||
| 306 | { | ||
| 307 | int error; | ||
| 308 | struct as10x_cmd_t *pcmd, *prsp; | ||
| 309 | |||
| 310 | ENTER(); | ||
| 311 | |||
| 312 | pcmd = phandle->cmd; | ||
| 313 | prsp = phandle->rsp; | ||
| 314 | |||
| 315 | /* prepare command */ | ||
| 316 | as10x_cmd_build(pcmd, (++phandle->cmd_xid), | ||
| 317 | sizeof(pcmd->body.get_demod_stats.req)); | ||
| 318 | |||
| 319 | /* fill command */ | ||
| 320 | pcmd->body.get_demod_stats.req.proc_id = | ||
| 321 | cpu_to_le16(CONTROL_PROC_GET_DEMOD_STATS); | ||
| 322 | |||
| 323 | /* send command */ | ||
| 324 | if (phandle->ops->xfer_cmd) { | ||
| 325 | error = phandle->ops->xfer_cmd(phandle, | ||
| 326 | (uint8_t *) pcmd, | ||
| 327 | sizeof(pcmd->body.get_demod_stats.req) | ||
| 328 | + HEADER_SIZE, | ||
| 329 | (uint8_t *) prsp, | ||
| 330 | sizeof(prsp->body.get_demod_stats.rsp) | ||
| 331 | + HEADER_SIZE); | ||
| 332 | } else { | ||
| 333 | error = AS10X_CMD_ERROR; | ||
| 334 | } | ||
| 335 | |||
| 336 | if (error < 0) | ||
| 337 | goto out; | ||
| 338 | |||
| 339 | /* parse response */ | ||
| 340 | error = as10x_rsp_parse(prsp, CONTROL_PROC_GET_DEMOD_STATS_RSP); | ||
| 341 | if (error < 0) | ||
| 342 | goto out; | ||
| 343 | |||
| 344 | /* Response OK -> get response data */ | ||
| 345 | pdemod_stats->frame_count = | ||
| 346 | le32_to_cpu(prsp->body.get_demod_stats.rsp.stats.frame_count); | ||
| 347 | pdemod_stats->bad_frame_count = | ||
| 348 | le32_to_cpu(prsp->body.get_demod_stats.rsp.stats.bad_frame_count); | ||
| 349 | pdemod_stats->bytes_fixed_by_rs = | ||
| 350 | le32_to_cpu(prsp->body.get_demod_stats.rsp.stats.bytes_fixed_by_rs); | ||
| 351 | pdemod_stats->mer = | ||
| 352 | le16_to_cpu(prsp->body.get_demod_stats.rsp.stats.mer); | ||
| 353 | pdemod_stats->has_started = | ||
| 354 | prsp->body.get_demod_stats.rsp.stats.has_started; | ||
| 355 | |||
| 356 | out: | ||
| 357 | LEAVE(); | ||
| 358 | return error; | ||
| 359 | } | ||
| 360 | |||
| 361 | /** | ||
| 362 | * as10x_cmd_get_impulse_resp - send get impulse response command to AS10x | ||
| 363 | * @phandle: pointer to AS10x handle | ||
| 364 | * @is_ready: pointer to value indicating when impulse | ||
| 365 | * response data is ready | ||
| 366 | * | ||
| 367 | * Return 0 on success or negative value in case of error. | ||
| 368 | */ | ||
| 369 | int as10x_cmd_get_impulse_resp(as10x_handle_t *phandle, | ||
| 370 | uint8_t *is_ready) | ||
| 371 | { | ||
| 372 | int error; | ||
| 373 | struct as10x_cmd_t *pcmd, *prsp; | ||
| 374 | |||
| 375 | ENTER(); | ||
| 376 | |||
| 377 | pcmd = phandle->cmd; | ||
| 378 | prsp = phandle->rsp; | ||
| 379 | |||
| 380 | /* prepare command */ | ||
| 381 | as10x_cmd_build(pcmd, (++phandle->cmd_xid), | ||
| 382 | sizeof(pcmd->body.get_impulse_rsp.req)); | ||
| 383 | |||
| 384 | /* fill command */ | ||
| 385 | pcmd->body.get_impulse_rsp.req.proc_id = | ||
| 386 | cpu_to_le16(CONTROL_PROC_GET_IMPULSE_RESP); | ||
| 387 | |||
| 388 | /* send command */ | ||
| 389 | if (phandle->ops->xfer_cmd) { | ||
| 390 | error = phandle->ops->xfer_cmd(phandle, | ||
| 391 | (uint8_t *) pcmd, | ||
| 392 | sizeof(pcmd->body.get_impulse_rsp.req) | ||
| 393 | + HEADER_SIZE, | ||
| 394 | (uint8_t *) prsp, | ||
| 395 | sizeof(prsp->body.get_impulse_rsp.rsp) | ||
| 396 | + HEADER_SIZE); | ||
| 397 | } else { | ||
| 398 | error = AS10X_CMD_ERROR; | ||
| 399 | } | ||
| 400 | |||
| 401 | if (error < 0) | ||
| 402 | goto out; | ||
| 403 | |||
| 404 | /* parse response */ | ||
| 405 | error = as10x_rsp_parse(prsp, CONTROL_PROC_GET_IMPULSE_RESP_RSP); | ||
| 406 | if (error < 0) | ||
| 407 | goto out; | ||
| 408 | |||
| 409 | /* Response OK -> get response data */ | ||
| 410 | *is_ready = prsp->body.get_impulse_rsp.rsp.is_ready; | ||
| 411 | |||
| 412 | out: | ||
| 413 | LEAVE(); | ||
| 414 | return error; | ||
| 415 | } | ||
| 416 | |||
| 417 | /** | ||
| 418 | * as10x_cmd_build - build AS10x command header | ||
| 419 | * @pcmd: pointer to AS10x command buffer | ||
| 420 | * @xid: sequence id of the command | ||
| 421 | * @cmd_len: length of the command | ||
| 422 | */ | ||
| 423 | void as10x_cmd_build(struct as10x_cmd_t *pcmd, | ||
| 424 | uint16_t xid, uint16_t cmd_len) | ||
| 425 | { | ||
| 426 | pcmd->header.req_id = cpu_to_le16(xid); | ||
| 427 | pcmd->header.prog = cpu_to_le16(SERVICE_PROG_ID); | ||
| 428 | pcmd->header.version = cpu_to_le16(SERVICE_PROG_VERSION); | ||
| 429 | pcmd->header.data_len = cpu_to_le16(cmd_len); | ||
| 430 | } | ||
| 431 | |||
| 432 | /** | ||
| 433 | * as10x_rsp_parse - Parse command response | ||
| 434 | * @prsp: pointer to AS10x command buffer | ||
| 435 | * @proc_id: id of the command | ||
| 436 | * | ||
| 437 | * Return 0 on success or negative value in case of error. | ||
| 438 | */ | ||
| 439 | int as10x_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id) | ||
| 440 | { | ||
| 441 | int error; | ||
| 442 | |||
| 443 | /* extract command error code */ | ||
| 444 | error = prsp->body.common.rsp.error; | ||
| 445 | |||
| 446 | if ((error == 0) && | ||
| 447 | (le16_to_cpu(prsp->body.common.rsp.proc_id) == proc_id)) { | ||
| 448 | return 0; | ||
| 449 | } | ||
| 450 | |||
| 451 | return AS10X_CMD_ERROR; | ||
| 452 | } | ||
diff --git a/drivers/staging/media/as102/as10x_cmd.h b/drivers/staging/media/as102/as10x_cmd.h new file mode 100644 index 000000000000..01a716380e0a --- /dev/null +++ b/drivers/staging/media/as102/as10x_cmd.h | |||
| @@ -0,0 +1,540 @@ | |||
| 1 | /* | ||
| 2 | * Abilis Systems Single DVB-T Receiver | ||
| 3 | * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com> | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 8 | * any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 18 | */ | ||
| 19 | #ifndef _AS10X_CMD_H_ | ||
| 20 | #define _AS10X_CMD_H_ | ||
| 21 | |||
| 22 | #ifdef __KERNEL__ | ||
| 23 | #include <linux/kernel.h> | ||
| 24 | #endif | ||
| 25 | |||
| 26 | #include "as10x_types.h" | ||
| 27 | |||
| 28 | /*********************************/ | ||
| 29 | /* MACRO DEFINITIONS */ | ||
| 30 | /*********************************/ | ||
| 31 | #define AS10X_CMD_ERROR -1 | ||
| 32 | |||
| 33 | #define SERVICE_PROG_ID 0x0002 | ||
| 34 | #define SERVICE_PROG_VERSION 0x0001 | ||
| 35 | |||
| 36 | #define HIER_NONE 0x00 | ||
| 37 | #define HIER_LOW_PRIORITY 0x01 | ||
| 38 | |||
| 39 | #define HEADER_SIZE (sizeof(struct as10x_cmd_header_t)) | ||
| 40 | |||
| 41 | /* context request types */ | ||
| 42 | #define GET_CONTEXT_DATA 1 | ||
| 43 | #define SET_CONTEXT_DATA 2 | ||
| 44 | |||
| 45 | /* ODSP suspend modes */ | ||
| 46 | #define CFG_MODE_ODSP_RESUME 0 | ||
| 47 | #define CFG_MODE_ODSP_SUSPEND 1 | ||
| 48 | |||
| 49 | /* Dump memory size */ | ||
| 50 | #define DUMP_BLOCK_SIZE_MAX 0x20 | ||
| 51 | |||
| 52 | /*********************************/ | ||
| 53 | /* TYPE DEFINITION */ | ||
| 54 | /*********************************/ | ||
| 55 | typedef enum { | ||
| 56 | CONTROL_PROC_TURNON = 0x0001, | ||
| 57 | CONTROL_PROC_TURNON_RSP = 0x0100, | ||
| 58 | CONTROL_PROC_SET_REGISTER = 0x0002, | ||
| 59 | CONTROL_PROC_SET_REGISTER_RSP = 0x0200, | ||
| 60 | CONTROL_PROC_GET_REGISTER = 0x0003, | ||
| 61 | CONTROL_PROC_GET_REGISTER_RSP = 0x0300, | ||
| 62 | CONTROL_PROC_SETTUNE = 0x000A, | ||
| 63 | CONTROL_PROC_SETTUNE_RSP = 0x0A00, | ||
| 64 | CONTROL_PROC_GETTUNESTAT = 0x000B, | ||
| 65 | CONTROL_PROC_GETTUNESTAT_RSP = 0x0B00, | ||
| 66 | CONTROL_PROC_GETTPS = 0x000D, | ||
| 67 | CONTROL_PROC_GETTPS_RSP = 0x0D00, | ||
| 68 | CONTROL_PROC_SETFILTER = 0x000E, | ||
| 69 | CONTROL_PROC_SETFILTER_RSP = 0x0E00, | ||
| 70 | CONTROL_PROC_REMOVEFILTER = 0x000F, | ||
| 71 | CONTROL_PROC_REMOVEFILTER_RSP = 0x0F00, | ||
| 72 | CONTROL_PROC_GET_IMPULSE_RESP = 0x0012, | ||
| 73 | CONTROL_PROC_GET_IMPULSE_RESP_RSP = 0x1200, | ||
| 74 | CONTROL_PROC_START_STREAMING = 0x0013, | ||
| 75 | CONTROL_PROC_START_STREAMING_RSP = 0x1300, | ||
| 76 | CONTROL_PROC_STOP_STREAMING = 0x0014, | ||
| 77 | CONTROL_PROC_STOP_STREAMING_RSP = 0x1400, | ||
| 78 | CONTROL_PROC_GET_DEMOD_STATS = 0x0015, | ||
| 79 | CONTROL_PROC_GET_DEMOD_STATS_RSP = 0x1500, | ||
| 80 | CONTROL_PROC_ELNA_CHANGE_MODE = 0x0016, | ||
| 81 | CONTROL_PROC_ELNA_CHANGE_MODE_RSP = 0x1600, | ||
| 82 | CONTROL_PROC_ODSP_CHANGE_MODE = 0x0017, | ||
| 83 | CONTROL_PROC_ODSP_CHANGE_MODE_RSP = 0x1700, | ||
| 84 | CONTROL_PROC_AGC_CHANGE_MODE = 0x0018, | ||
| 85 | CONTROL_PROC_AGC_CHANGE_MODE_RSP = 0x1800, | ||
| 86 | |||
| 87 | CONTROL_PROC_CONTEXT = 0x00FC, | ||
| 88 | CONTROL_PROC_CONTEXT_RSP = 0xFC00, | ||
| 89 | CONTROL_PROC_DUMP_MEMORY = 0x00FD, | ||
| 90 | CONTROL_PROC_DUMP_MEMORY_RSP = 0xFD00, | ||
| 91 | CONTROL_PROC_DUMPLOG_MEMORY = 0x00FE, | ||
| 92 | CONTROL_PROC_DUMPLOG_MEMORY_RSP = 0xFE00, | ||
| 93 | CONTROL_PROC_TURNOFF = 0x00FF, | ||
| 94 | CONTROL_PROC_TURNOFF_RSP = 0xFF00 | ||
| 95 | } control_proc; | ||
| 96 | |||
| 97 | |||
| 98 | #pragma pack(1) | ||
| 99 | typedef union { | ||
| 100 | /* request */ | ||
| 101 | struct { | ||
| 102 | /* request identifier */ | ||
| 103 | uint16_t proc_id; | ||
| 104 | } req; | ||
| 105 | /* response */ | ||
| 106 | struct { | ||
| 107 | /* response identifier */ | ||
| 108 | uint16_t proc_id; | ||
| 109 | /* error */ | ||
| 110 | uint8_t error; | ||
| 111 | } rsp; | ||
| 112 | } TURN_ON; | ||
| 113 | |||
| 114 | typedef union { | ||
| 115 | /* request */ | ||
| 116 | struct { | ||
| 117 | /* request identifier */ | ||
| 118 | uint16_t proc_id; | ||
| 119 | } req; | ||
| 120 | /* response */ | ||
| 121 | struct { | ||
| 122 | /* response identifier */ | ||
| 123 | uint16_t proc_id; | ||
| 124 | /* error */ | ||
| 125 | uint8_t err; | ||
| 126 | } rsp; | ||
| 127 | } TURN_OFF; | ||
| 128 | |||
| 129 | typedef union { | ||
| 130 | /* request */ | ||
| 131 | struct { | ||
| 132 | /* request identifier */ | ||
| 133 | uint16_t proc_id; | ||
| 134 | /* tune params */ | ||
| 135 | struct as10x_tune_args args; | ||
| 136 | } req; | ||
| 137 | /* response */ | ||
| 138 | struct { | ||
| 139 | /* response identifier */ | ||
| 140 | uint16_t proc_id; | ||
| 141 | /* response error */ | ||
| 142 | uint8_t error; | ||
| 143 | } rsp; | ||
| 144 | } SET_TUNE; | ||
| 145 | |||
| 146 | typedef union { | ||
| 147 | /* request */ | ||
| 148 | struct { | ||
| 149 | /* request identifier */ | ||
| 150 | uint16_t proc_id; | ||
| 151 | } req; | ||
| 152 | /* response */ | ||
| 153 | struct { | ||
| 154 | /* response identifier */ | ||
| 155 | uint16_t proc_id; | ||
| 156 | /* response error */ | ||
| 157 | uint8_t error; | ||
| 158 | /* tune status */ | ||
| 159 | struct as10x_tune_status sts; | ||
| 160 | } rsp; | ||
| 161 | } GET_TUNE_STATUS; | ||
| 162 | |||
| 163 | typedef union { | ||
| 164 | /* request */ | ||
| 165 | struct { | ||
| 166 | /* request identifier */ | ||
| 167 | uint16_t proc_id; | ||
| 168 | } req; | ||
| 169 | /* response */ | ||
| 170 | struct { | ||
| 171 | /* response identifier */ | ||
| 172 | uint16_t proc_id; | ||
| 173 | /* response error */ | ||
| 174 | uint8_t error; | ||
| 175 | /* tps details */ | ||
| 176 | struct as10x_tps tps; | ||
| 177 | } rsp; | ||
| 178 | } GET_TPS; | ||
| 179 | |||
| 180 | typedef union { | ||
| 181 | /* request */ | ||
| 182 | struct { | ||
| 183 | /* request identifier */ | ||
| 184 | uint16_t proc_id; | ||
| 185 | } req; | ||
| 186 | /* response */ | ||
| 187 | struct { | ||
| 188 | /* response identifier */ | ||
| 189 | uint16_t proc_id; | ||
| 190 | /* response error */ | ||
| 191 | uint8_t error; | ||
| 192 | } rsp; | ||
| 193 | } COMMON; | ||
| 194 | |||
| 195 | typedef union { | ||
| 196 | /* request */ | ||
| 197 | struct { | ||
| 198 | /* request identifier */ | ||
| 199 | uint16_t proc_id; | ||
| 200 | /* PID to filter */ | ||
| 201 | uint16_t pid; | ||
| 202 | /* stream type (MPE, PSI/SI or PES )*/ | ||
| 203 | uint8_t stream_type; | ||
| 204 | /* PID index in filter table */ | ||
| 205 | uint8_t idx; | ||
| 206 | } req; | ||
| 207 | /* response */ | ||
| 208 | struct { | ||
| 209 | /* response identifier */ | ||
| 210 | uint16_t proc_id; | ||
| 211 | /* response error */ | ||
| 212 | uint8_t error; | ||
| 213 | /* Filter id */ | ||
| 214 | uint8_t filter_id; | ||
| 215 | } rsp; | ||
| 216 | } ADD_PID_FILTER; | ||
| 217 | |||
| 218 | typedef union { | ||
| 219 | /* request */ | ||
| 220 | struct { | ||
| 221 | /* request identifier */ | ||
| 222 | uint16_t proc_id; | ||
| 223 | /* PID to remove */ | ||
| 224 | uint16_t pid; | ||
| 225 | } req; | ||
| 226 | /* response */ | ||
| 227 | struct { | ||
| 228 | /* response identifier */ | ||
| 229 | uint16_t proc_id; | ||
| 230 | /* response error */ | ||
| 231 | uint8_t error; | ||
| 232 | } rsp; | ||
| 233 | } DEL_PID_FILTER; | ||
| 234 | |||
| 235 | typedef union { | ||
| 236 | /* request */ | ||
| 237 | struct { | ||
| 238 | /* request identifier */ | ||
| 239 | uint16_t proc_id; | ||
| 240 | } req; | ||
| 241 | /* response */ | ||
| 242 | struct { | ||
| 243 | /* response identifier */ | ||
| 244 | uint16_t proc_id; | ||
| 245 | /* error */ | ||
| 246 | uint8_t error; | ||
| 247 | } rsp; | ||
| 248 | } START_STREAMING; | ||
| 249 | |||
| 250 | typedef union { | ||
| 251 | /* request */ | ||
| 252 | struct { | ||
| 253 | /* request identifier */ | ||
| 254 | uint16_t proc_id; | ||
| 255 | } req; | ||
| 256 | /* response */ | ||
| 257 | struct { | ||
| 258 | /* response identifier */ | ||
| 259 | uint16_t proc_id; | ||
| 260 | /* error */ | ||
| 261 | uint8_t error; | ||
| 262 | } rsp; | ||
| 263 | } STOP_STREAMING; | ||
| 264 | |||
| 265 | typedef union { | ||
| 266 | /* request */ | ||
| 267 | struct { | ||
| 268 | /* request identifier */ | ||
| 269 | uint16_t proc_id; | ||
| 270 | } req; | ||
| 271 | /* response */ | ||
| 272 | struct { | ||
| 273 | /* response identifier */ | ||
| 274 | uint16_t proc_id; | ||
| 275 | /* error */ | ||
| 276 | uint8_t error; | ||
| 277 | /* demod stats */ | ||
| 278 | struct as10x_demod_stats stats; | ||
| 279 | } rsp; | ||
| 280 | } GET_DEMOD_STATS; | ||
| 281 | |||
| 282 | typedef union { | ||
| 283 | /* request */ | ||
| 284 | struct { | ||
| 285 | /* request identifier */ | ||
| 286 | uint16_t proc_id; | ||
| 287 | } req; | ||
| 288 | /* response */ | ||
| 289 | struct { | ||
| 290 | /* response identifier */ | ||
| 291 | uint16_t proc_id; | ||
| 292 | /* error */ | ||
| 293 | uint8_t error; | ||
| 294 | /* impulse response ready */ | ||
| 295 | uint8_t is_ready; | ||
| 296 | } rsp; | ||
| 297 | } GET_IMPULSE_RESP; | ||
| 298 | |||
| 299 | typedef union { | ||
| 300 | /* request */ | ||
| 301 | struct { | ||
| 302 | /* request identifier */ | ||
| 303 | uint16_t proc_id; | ||
| 304 | /* value to write (for set context)*/ | ||
| 305 | struct as10x_register_value reg_val; | ||
| 306 | /* context tag */ | ||
| 307 | uint16_t tag; | ||
| 308 | /* context request type */ | ||
| 309 | uint16_t type; | ||
| 310 | } req; | ||
| 311 | /* response */ | ||
| 312 | struct { | ||
| 313 | /* response identifier */ | ||
| 314 | uint16_t proc_id; | ||
| 315 | /* value read (for get context) */ | ||
| 316 | struct as10x_register_value reg_val; | ||
| 317 | /* context request type */ | ||
| 318 | uint16_t type; | ||
| 319 | /* error */ | ||
| 320 | uint8_t error; | ||
| 321 | } rsp; | ||
| 322 | } FW_CONTEXT; | ||
| 323 | |||
| 324 | typedef union { | ||
| 325 | /* request */ | ||
| 326 | struct { | ||
| 327 | /* response identifier */ | ||
| 328 | uint16_t proc_id; | ||
| 329 | /* register description */ | ||
| 330 | struct as10x_register_addr reg_addr; | ||
| 331 | /* register content */ | ||
| 332 | struct as10x_register_value reg_val; | ||
| 333 | } req; | ||
| 334 | /* response */ | ||
| 335 | struct { | ||
| 336 | /* response identifier */ | ||
| 337 | uint16_t proc_id; | ||
| 338 | /* error */ | ||
| 339 | uint8_t error; | ||
| 340 | } rsp; | ||
| 341 | } SET_REGISTER; | ||
| 342 | |||
| 343 | typedef union { | ||
| 344 | /* request */ | ||
| 345 | struct { | ||
| 346 | /* response identifier */ | ||
| 347 | uint16_t proc_id; | ||
| 348 | /* register description */ | ||
| 349 | struct as10x_register_addr reg_addr; | ||
| 350 | } req; | ||
| 351 | /* response */ | ||
| 352 | struct { | ||
| 353 | /* response identifier */ | ||
| 354 | uint16_t proc_id; | ||
| 355 | /* error */ | ||
| 356 | uint8_t error; | ||
| 357 | /* register content */ | ||
| 358 | struct as10x_register_value reg_val; | ||
| 359 | } rsp; | ||
| 360 | } GET_REGISTER; | ||
| 361 | |||
| 362 | typedef union { | ||
| 363 | /* request */ | ||
| 364 | struct { | ||
| 365 | /* request identifier */ | ||
| 366 | uint16_t proc_id; | ||
| 367 | /* mode */ | ||
| 368 | uint8_t mode; | ||
| 369 | } req; | ||
| 370 | /* response */ | ||
| 371 | struct { | ||
| 372 | /* response identifier */ | ||
| 373 | uint16_t proc_id; | ||
| 374 | /* error */ | ||
| 375 | uint8_t error; | ||
| 376 | } rsp; | ||
| 377 | } CFG_CHANGE_MODE; | ||
| 378 | |||
| 379 | struct as10x_cmd_header_t { | ||
| 380 | uint16_t req_id; | ||
| 381 | uint16_t prog; | ||
| 382 | uint16_t version; | ||
| 383 | uint16_t data_len; | ||
| 384 | }; | ||
| 385 | |||
| 386 | #define DUMP_BLOCK_SIZE 16 | ||
| 387 | typedef union { | ||
| 388 | /* request */ | ||
| 389 | struct { | ||
| 390 | /* request identifier */ | ||
| 391 | uint16_t proc_id; | ||
| 392 | /* dump memory type request */ | ||
| 393 | uint8_t dump_req; | ||
| 394 | /* register description */ | ||
| 395 | struct as10x_register_addr reg_addr; | ||
| 396 | /* nb blocks to read */ | ||
| 397 | uint16_t num_blocks; | ||
| 398 | } req; | ||
| 399 | /* response */ | ||
| 400 | struct { | ||
| 401 | /* response identifier */ | ||
| 402 | uint16_t proc_id; | ||
| 403 | /* error */ | ||
| 404 | uint8_t error; | ||
| 405 | /* dump response */ | ||
| 406 | uint8_t dump_rsp; | ||
| 407 | /* data */ | ||
| 408 | union { | ||
| 409 | uint8_t data8[DUMP_BLOCK_SIZE]; | ||
| 410 | uint16_t data16[DUMP_BLOCK_SIZE / sizeof(uint16_t)]; | ||
| 411 | uint32_t data32[DUMP_BLOCK_SIZE / sizeof(uint32_t)]; | ||
| 412 | } u; | ||
| 413 | } rsp; | ||
| 414 | } DUMP_MEMORY; | ||
| 415 | |||
| 416 | typedef union { | ||
| 417 | struct { | ||
| 418 | /* request identifier */ | ||
| 419 | uint16_t proc_id; | ||
| 420 | /* dump memory type request */ | ||
| 421 | uint8_t dump_req; | ||
| 422 | } req; | ||
| 423 | struct { | ||
| 424 | /* request identifier */ | ||
| 425 | uint16_t proc_id; | ||
| 426 | /* error */ | ||
| 427 | uint8_t error; | ||
| 428 | /* dump response */ | ||
| 429 | uint8_t dump_rsp; | ||
| 430 | /* dump data */ | ||
| 431 | uint8_t data[DUMP_BLOCK_SIZE]; | ||
| 432 | } rsp; | ||
| 433 | } DUMPLOG_MEMORY; | ||
| 434 | |||
| 435 | typedef union { | ||
| 436 | /* request */ | ||
| 437 | struct { | ||
| 438 | uint16_t proc_id; | ||
| 439 | uint8_t data[64 - sizeof(struct as10x_cmd_header_t) -2 /* proc_id */]; | ||
| 440 | } req; | ||
| 441 | /* response */ | ||
| 442 | struct { | ||
| 443 | uint16_t proc_id; | ||
| 444 | uint8_t error; | ||
| 445 | uint8_t data[64 - sizeof(struct as10x_cmd_header_t) /* header */ | ||
| 446 | - 2 /* proc_id */ - 1 /* rc */]; | ||
| 447 | } rsp; | ||
| 448 | } RAW_DATA; | ||
| 449 | |||
| 450 | struct as10x_cmd_t { | ||
| 451 | /* header */ | ||
| 452 | struct as10x_cmd_header_t header; | ||
| 453 | /* body */ | ||
| 454 | union { | ||
| 455 | TURN_ON turn_on; | ||
| 456 | TURN_OFF turn_off; | ||
| 457 | SET_TUNE set_tune; | ||
| 458 | GET_TUNE_STATUS get_tune_status; | ||
| 459 | GET_TPS get_tps; | ||
| 460 | COMMON common; | ||
| 461 | ADD_PID_FILTER add_pid_filter; | ||
| 462 | DEL_PID_FILTER del_pid_filter; | ||
| 463 | START_STREAMING start_streaming; | ||
| 464 | STOP_STREAMING stop_streaming; | ||
| 465 | GET_DEMOD_STATS get_demod_stats; | ||
| 466 | GET_IMPULSE_RESP get_impulse_rsp; | ||
| 467 | FW_CONTEXT context; | ||
| 468 | SET_REGISTER set_register; | ||
| 469 | GET_REGISTER get_register; | ||
| 470 | CFG_CHANGE_MODE cfg_change_mode; | ||
| 471 | DUMP_MEMORY dump_memory; | ||
| 472 | DUMPLOG_MEMORY dumplog_memory; | ||
| 473 | RAW_DATA raw_data; | ||
| 474 | } body; | ||
| 475 | }; | ||
| 476 | |||
| 477 | struct as10x_token_cmd_t { | ||
| 478 | /* token cmd */ | ||
| 479 | struct as10x_cmd_t c; | ||
| 480 | /* token response */ | ||
| 481 | struct as10x_cmd_t r; | ||
| 482 | }; | ||
| 483 | #pragma pack() | ||
| 484 | |||
| 485 | |||
| 486 | /**************************/ | ||
| 487 | /* FUNCTION DECLARATION */ | ||
| 488 | /**************************/ | ||
| 489 | |||
| 490 | void as10x_cmd_build(struct as10x_cmd_t *pcmd, uint16_t proc_id, | ||
| 491 | uint16_t cmd_len); | ||
| 492 | int as10x_rsp_parse(struct as10x_cmd_t *r, uint16_t proc_id); | ||
| 493 | |||
| 494 | #ifdef __cplusplus | ||
| 495 | extern "C" { | ||
| 496 | #endif | ||
| 497 | |||
| 498 | /* as10x cmd */ | ||
| 499 | int as10x_cmd_turn_on(as10x_handle_t *phandle); | ||
| 500 | int as10x_cmd_turn_off(as10x_handle_t *phandle); | ||
| 501 | |||
| 502 | int as10x_cmd_set_tune(as10x_handle_t *phandle, | ||
| 503 | struct as10x_tune_args *ptune); | ||
| 504 | |||
| 505 | int as10x_cmd_get_tune_status(as10x_handle_t *phandle, | ||
| 506 | struct as10x_tune_status *pstatus); | ||
| 507 | |||
| 508 | int as10x_cmd_get_tps(as10x_handle_t *phandle, | ||
| 509 | struct as10x_tps *ptps); | ||
| 510 | |||
| 511 | int as10x_cmd_get_demod_stats(as10x_handle_t *phandle, | ||
| 512 | struct as10x_demod_stats *pdemod_stats); | ||
| 513 | |||
| 514 | int as10x_cmd_get_impulse_resp(as10x_handle_t *phandle, | ||
| 515 | uint8_t *is_ready); | ||
| 516 | |||
| 517 | /* as10x cmd stream */ | ||
| 518 | int as10x_cmd_add_PID_filter(as10x_handle_t *phandle, | ||
| 519 | struct as10x_ts_filter *filter); | ||
| 520 | int as10x_cmd_del_PID_filter(as10x_handle_t *phandle, | ||
| 521 | uint16_t pid_value); | ||
| 522 | |||
| 523 | int as10x_cmd_start_streaming(as10x_handle_t *phandle); | ||
| 524 | int as10x_cmd_stop_streaming(as10x_handle_t *phandle); | ||
| 525 | |||
| 526 | /* as10x cmd cfg */ | ||
| 527 | int as10x_cmd_set_context(as10x_handle_t *phandle, | ||
| 528 | uint16_t tag, | ||
| 529 | uint32_t value); | ||
| 530 | int as10x_cmd_get_context(as10x_handle_t *phandle, | ||
| 531 | uint16_t tag, | ||
| 532 | uint32_t *pvalue); | ||
| 533 | |||
| 534 | int as10x_cmd_eLNA_change_mode(as10x_handle_t *phandle, uint8_t mode); | ||
| 535 | int as10x_context_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id); | ||
| 536 | #ifdef __cplusplus | ||
| 537 | } | ||
| 538 | #endif | ||
| 539 | #endif | ||
| 540 | /* EOF - vim: set textwidth=80 ts=3 sw=3 sts=3 et: */ | ||
diff --git a/drivers/staging/media/as102/as10x_cmd_cfg.c b/drivers/staging/media/as102/as10x_cmd_cfg.c new file mode 100644 index 000000000000..ec6f69fcf399 --- /dev/null +++ b/drivers/staging/media/as102/as10x_cmd_cfg.c | |||
| @@ -0,0 +1,215 @@ | |||
| 1 | /* | ||
| 2 | * Abilis Systems Single DVB-T Receiver | ||
| 3 | * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com> | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 8 | * any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/kernel.h> | ||
| 21 | #include "as102_drv.h" | ||
| 22 | #include "as10x_types.h" | ||
| 23 | #include "as10x_cmd.h" | ||
| 24 | |||
| 25 | /***************************/ | ||
| 26 | /* FUNCTION DEFINITION */ | ||
| 27 | /***************************/ | ||
| 28 | |||
| 29 | /** | ||
| 30 | * as10x_cmd_get_context - Send get context command to AS10x | ||
| 31 | * @phandle: pointer to AS10x handle | ||
| 32 | * @tag: context tag | ||
| 33 | * @pvalue: pointer where to store context value read | ||
| 34 | * | ||
| 35 | * Return 0 on success or negative value in case of error. | ||
| 36 | */ | ||
| 37 | int as10x_cmd_get_context(as10x_handle_t *phandle, uint16_t tag, | ||
| 38 | uint32_t *pvalue) | ||
| 39 | { | ||
| 40 | int error; | ||
| 41 | struct as10x_cmd_t *pcmd, *prsp; | ||
| 42 | |||
| 43 | ENTER(); | ||
| 44 | |||
| 45 | pcmd = phandle->cmd; | ||
| 46 | prsp = phandle->rsp; | ||
| 47 | |||
| 48 | /* prepare command */ | ||
| 49 | as10x_cmd_build(pcmd, (++phandle->cmd_xid), | ||
| 50 | sizeof(pcmd->body.context.req)); | ||
| 51 | |||
| 52 | /* fill command */ | ||
| 53 | pcmd->body.context.req.proc_id = cpu_to_le16(CONTROL_PROC_CONTEXT); | ||
| 54 | pcmd->body.context.req.tag = cpu_to_le16(tag); | ||
| 55 | pcmd->body.context.req.type = cpu_to_le16(GET_CONTEXT_DATA); | ||
| 56 | |||
| 57 | /* send command */ | ||
| 58 | if (phandle->ops->xfer_cmd) { | ||
| 59 | error = phandle->ops->xfer_cmd(phandle, | ||
| 60 | (uint8_t *) pcmd, | ||
| 61 | sizeof(pcmd->body.context.req) | ||
| 62 | + HEADER_SIZE, | ||
| 63 | (uint8_t *) prsp, | ||
| 64 | sizeof(prsp->body.context.rsp) | ||
| 65 | + HEADER_SIZE); | ||
| 66 | } else { | ||
| 67 | error = AS10X_CMD_ERROR; | ||
| 68 | } | ||
| 69 | |||
| 70 | if (error < 0) | ||
| 71 | goto out; | ||
| 72 | |||
| 73 | /* parse response: context command do not follow the common response */ | ||
| 74 | /* structure -> specific handling response parse required */ | ||
| 75 | error = as10x_context_rsp_parse(prsp, CONTROL_PROC_CONTEXT_RSP); | ||
| 76 | |||
| 77 | if (error == 0) { | ||
| 78 | /* Response OK -> get response data */ | ||
| 79 | *pvalue = le32_to_cpu(prsp->body.context.rsp.reg_val.u.value32); | ||
| 80 | /* value returned is always a 32-bit value */ | ||
| 81 | } | ||
| 82 | |||
| 83 | out: | ||
| 84 | LEAVE(); | ||
| 85 | return error; | ||
| 86 | } | ||
| 87 | |||
| 88 | /** | ||
| 89 | * as10x_cmd_set_context - send set context command to AS10x | ||
| 90 | * @phandle: pointer to AS10x handle | ||
| 91 | * @tag: context tag | ||
| 92 | * @value: value to set in context | ||
| 93 | * | ||
| 94 | * Return 0 on success or negative value in case of error. | ||
| 95 | */ | ||
| 96 | int as10x_cmd_set_context(as10x_handle_t *phandle, uint16_t tag, | ||
| 97 | uint32_t value) | ||
| 98 | { | ||
| 99 | int error; | ||
| 100 | struct as10x_cmd_t *pcmd, *prsp; | ||
| 101 | |||
| 102 | ENTER(); | ||
| 103 | |||
| 104 | pcmd = phandle->cmd; | ||
| 105 | prsp = phandle->rsp; | ||
| 106 | |||
| 107 | /* prepare command */ | ||
| 108 | as10x_cmd_build(pcmd, (++phandle->cmd_xid), | ||
| 109 | sizeof(pcmd->body.context.req)); | ||
| 110 | |||
| 111 | /* fill command */ | ||
| 112 | pcmd->body.context.req.proc_id = cpu_to_le16(CONTROL_PROC_CONTEXT); | ||
| 113 | /* pcmd->body.context.req.reg_val.mode initialization is not required */ | ||
| 114 | pcmd->body.context.req.reg_val.u.value32 = cpu_to_le32(value); | ||
| 115 | pcmd->body.context.req.tag = cpu_to_le16(tag); | ||
| 116 | pcmd->body.context.req.type = cpu_to_le16(SET_CONTEXT_DATA); | ||
| 117 | |||
| 118 | /* send command */ | ||
| 119 | if (phandle->ops->xfer_cmd) { | ||
| 120 | error = phandle->ops->xfer_cmd(phandle, | ||
| 121 | (uint8_t *) pcmd, | ||
| 122 | sizeof(pcmd->body.context.req) | ||
| 123 | + HEADER_SIZE, | ||
| 124 | (uint8_t *) prsp, | ||
| 125 | sizeof(prsp->body.context.rsp) | ||
| 126 | + HEADER_SIZE); | ||
| 127 | } else { | ||
| 128 | error = AS10X_CMD_ERROR; | ||
| 129 | } | ||
| 130 | |||
| 131 | if (error < 0) | ||
| 132 | goto out; | ||
| 133 | |||
| 134 | /* parse response: context command do not follow the common response */ | ||
| 135 | /* structure -> specific handling response parse required */ | ||
| 136 | error = as10x_context_rsp_parse(prsp, CONTROL_PROC_CONTEXT_RSP); | ||
| 137 | |||
| 138 | out: | ||
| 139 | LEAVE(); | ||
| 140 | return error; | ||
| 141 | } | ||
| 142 | |||
| 143 | /** | ||
| 144 | * as10x_cmd_eLNA_change_mode - send eLNA change mode command to AS10x | ||
| 145 | * @phandle: pointer to AS10x handle | ||
| 146 | * @mode: mode selected: | ||
| 147 | * - ON : 0x0 => eLNA always ON | ||
| 148 | * - OFF : 0x1 => eLNA always OFF | ||
| 149 | * - AUTO : 0x2 => eLNA follow hysteresis parameters | ||
| 150 | * to be ON or OFF | ||
| 151 | * | ||
| 152 | * Return 0 on success or negative value in case of error. | ||
| 153 | */ | ||
| 154 | int as10x_cmd_eLNA_change_mode(as10x_handle_t *phandle, uint8_t mode) | ||
| 155 | { | ||
| 156 | int error; | ||
| 157 | struct as10x_cmd_t *pcmd, *prsp; | ||
| 158 | |||
| 159 | ENTER(); | ||
| 160 | |||
| 161 | pcmd = phandle->cmd; | ||
| 162 | prsp = phandle->rsp; | ||
| 163 | |||
| 164 | /* prepare command */ | ||
| 165 | as10x_cmd_build(pcmd, (++phandle->cmd_xid), | ||
| 166 | sizeof(pcmd->body.cfg_change_mode.req)); | ||
| 167 | |||
| 168 | /* fill command */ | ||
| 169 | pcmd->body.cfg_change_mode.req.proc_id = | ||
| 170 | cpu_to_le16(CONTROL_PROC_ELNA_CHANGE_MODE); | ||
| 171 | pcmd->body.cfg_change_mode.req.mode = mode; | ||
| 172 | |||
| 173 | /* send command */ | ||
| 174 | if (phandle->ops->xfer_cmd) { | ||
| 175 | error = phandle->ops->xfer_cmd(phandle, (uint8_t *) pcmd, | ||
| 176 | sizeof(pcmd->body.cfg_change_mode.req) | ||
| 177 | + HEADER_SIZE, (uint8_t *) prsp, | ||
| 178 | sizeof(prsp->body.cfg_change_mode.rsp) | ||
| 179 | + HEADER_SIZE); | ||
| 180 | } else { | ||
| 181 | error = AS10X_CMD_ERROR; | ||
| 182 | } | ||
| 183 | |||
| 184 | if (error < 0) | ||
| 185 | goto out; | ||
| 186 | |||
| 187 | /* parse response */ | ||
| 188 | error = as10x_rsp_parse(prsp, CONTROL_PROC_ELNA_CHANGE_MODE_RSP); | ||
| 189 | |||
| 190 | out: | ||
| 191 | LEAVE(); | ||
| 192 | return error; | ||
| 193 | } | ||
| 194 | |||
| 195 | /** | ||
| 196 | * as10x_context_rsp_parse - Parse context command response | ||
| 197 | * @prsp: pointer to AS10x command response buffer | ||
| 198 | * @proc_id: id of the command | ||
| 199 | * | ||
| 200 | * Since the contex command reponse does not follow the common | ||
| 201 | * response, a specific parse function is required. | ||
| 202 | * Return 0 on success or negative value in case of error. | ||
| 203 | */ | ||
| 204 | int as10x_context_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id) | ||
| 205 | { | ||
| 206 | int err; | ||
| 207 | |||
| 208 | err = prsp->body.context.rsp.error; | ||
| 209 | |||
| 210 | if ((err == 0) && | ||
| 211 | (le16_to_cpu(prsp->body.context.rsp.proc_id) == proc_id)) { | ||
| 212 | return 0; | ||
| 213 | } | ||
| 214 | return AS10X_CMD_ERROR; | ||
| 215 | } | ||
diff --git a/drivers/staging/media/as102/as10x_cmd_stream.c b/drivers/staging/media/as102/as10x_cmd_stream.c new file mode 100644 index 000000000000..045c70683193 --- /dev/null +++ b/drivers/staging/media/as102/as10x_cmd_stream.c | |||
| @@ -0,0 +1,223 @@ | |||
| 1 | /* | ||
| 2 | * Abilis Systems Single DVB-T Receiver | ||
| 3 | * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com> | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 8 | * any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/kernel.h> | ||
| 21 | #include "as102_drv.h" | ||
| 22 | #include "as10x_cmd.h" | ||
| 23 | |||
| 24 | /** | ||
| 25 | * as10x_cmd_add_PID_filter - send add filter command to AS10x | ||
| 26 | * @phandle: pointer to AS10x handle | ||
| 27 | * @filter: TSFilter filter for DVB-T | ||
| 28 | * | ||
| 29 | * Return 0 on success or negative value in case of error. | ||
| 30 | */ | ||
| 31 | int as10x_cmd_add_PID_filter(as10x_handle_t *phandle, | ||
| 32 | struct as10x_ts_filter *filter) | ||
| 33 | { | ||
| 34 | int error; | ||
| 35 | struct as10x_cmd_t *pcmd, *prsp; | ||
| 36 | |||
| 37 | ENTER(); | ||
| 38 | |||
| 39 | pcmd = phandle->cmd; | ||
| 40 | prsp = phandle->rsp; | ||
| 41 | |||
| 42 | /* prepare command */ | ||
| 43 | as10x_cmd_build(pcmd, (++phandle->cmd_xid), | ||
| 44 | sizeof(pcmd->body.add_pid_filter.req)); | ||
| 45 | |||
| 46 | /* fill command */ | ||
| 47 | pcmd->body.add_pid_filter.req.proc_id = | ||
| 48 | cpu_to_le16(CONTROL_PROC_SETFILTER); | ||
| 49 | pcmd->body.add_pid_filter.req.pid = cpu_to_le16(filter->pid); | ||
| 50 | pcmd->body.add_pid_filter.req.stream_type = filter->type; | ||
| 51 | |||
| 52 | if (filter->idx < 16) | ||
| 53 | pcmd->body.add_pid_filter.req.idx = filter->idx; | ||
| 54 | else | ||
| 55 | pcmd->body.add_pid_filter.req.idx = 0xFF; | ||
| 56 | |||
| 57 | /* send command */ | ||
| 58 | if (phandle->ops->xfer_cmd) { | ||
| 59 | error = phandle->ops->xfer_cmd(phandle, (uint8_t *) pcmd, | ||
| 60 | sizeof(pcmd->body.add_pid_filter.req) | ||
| 61 | + HEADER_SIZE, (uint8_t *) prsp, | ||
| 62 | sizeof(prsp->body.add_pid_filter.rsp) | ||
| 63 | + HEADER_SIZE); | ||
| 64 | } else { | ||
| 65 | error = AS10X_CMD_ERROR; | ||
| 66 | } | ||
| 67 | |||
| 68 | if (error < 0) | ||
| 69 | goto out; | ||
| 70 | |||
| 71 | /* parse response */ | ||
| 72 | error = as10x_rsp_parse(prsp, CONTROL_PROC_SETFILTER_RSP); | ||
| 73 | |||
| 74 | if (error == 0) { | ||
| 75 | /* Response OK -> get response data */ | ||
| 76 | filter->idx = prsp->body.add_pid_filter.rsp.filter_id; | ||
| 77 | } | ||
| 78 | |||
| 79 | out: | ||
| 80 | LEAVE(); | ||
| 81 | return error; | ||
| 82 | } | ||
| 83 | |||
| 84 | /** | ||
| 85 | * as10x_cmd_del_PID_filter - Send delete filter command to AS10x | ||
| 86 | * @phandle: pointer to AS10x handle | ||
| 87 | * @pid_value: PID to delete | ||
| 88 | * | ||
| 89 | * Return 0 on success or negative value in case of error. | ||
| 90 | */ | ||
| 91 | int as10x_cmd_del_PID_filter(as10x_handle_t *phandle, | ||
| 92 | uint16_t pid_value) | ||
| 93 | { | ||
| 94 | int error; | ||
| 95 | struct as10x_cmd_t *pcmd, *prsp; | ||
| 96 | |||
| 97 | ENTER(); | ||
| 98 | |||
| 99 | pcmd = phandle->cmd; | ||
| 100 | prsp = phandle->rsp; | ||
| 101 | |||
| 102 | /* prepare command */ | ||
| 103 | as10x_cmd_build(pcmd, (++phandle->cmd_xid), | ||
| 104 | sizeof(pcmd->body.del_pid_filter.req)); | ||
| 105 | |||
| 106 | /* fill command */ | ||
| 107 | pcmd->body.del_pid_filter.req.proc_id = | ||
| 108 | cpu_to_le16(CONTROL_PROC_REMOVEFILTER); | ||
| 109 | pcmd->body.del_pid_filter.req.pid = cpu_to_le16(pid_value); | ||
| 110 | |||
| 111 | /* send command */ | ||
| 112 | if (phandle->ops->xfer_cmd) { | ||
| 113 | error = phandle->ops->xfer_cmd(phandle, (uint8_t *) pcmd, | ||
| 114 | sizeof(pcmd->body.del_pid_filter.req) | ||
| 115 | + HEADER_SIZE, (uint8_t *) prsp, | ||
| 116 | sizeof(prsp->body.del_pid_filter.rsp) | ||
| 117 | + HEADER_SIZE); | ||
| 118 | } else { | ||
| 119 | error = AS10X_CMD_ERROR; | ||
| 120 | } | ||
| 121 | |||
| 122 | if (error < 0) | ||
| 123 | goto out; | ||
| 124 | |||
| 125 | /* parse response */ | ||
| 126 | error = as10x_rsp_parse(prsp, CONTROL_PROC_REMOVEFILTER_RSP); | ||
| 127 | |||
| 128 | out: | ||
| 129 | LEAVE(); | ||
| 130 | return error; | ||
| 131 | } | ||
| 132 | |||
| 133 | /** | ||
| 134 | * as10x_cmd_start_streaming - Send start streaming command to AS10x | ||
| 135 | * @phandle: pointer to AS10x handle | ||
| 136 | * | ||
| 137 | * Return 0 on success or negative value in case of error. | ||
| 138 | */ | ||
| 139 | int as10x_cmd_start_streaming(as10x_handle_t *phandle) | ||
| 140 | { | ||
| 141 | int error; | ||
| 142 | struct as10x_cmd_t *pcmd, *prsp; | ||
| 143 | |||
| 144 | ENTER(); | ||
| 145 | |||
| 146 | pcmd = phandle->cmd; | ||
| 147 | prsp = phandle->rsp; | ||
| 148 | |||
| 149 | /* prepare command */ | ||
| 150 | as10x_cmd_build(pcmd, (++phandle->cmd_xid), | ||
| 151 | sizeof(pcmd->body.start_streaming.req)); | ||
| 152 | |||
| 153 | /* fill command */ | ||
| 154 | pcmd->body.start_streaming.req.proc_id = | ||
| 155 | cpu_to_le16(CONTROL_PROC_START_STREAMING); | ||
| 156 | |||
| 157 | /* send command */ | ||
| 158 | if (phandle->ops->xfer_cmd) { | ||
| 159 | error = phandle->ops->xfer_cmd(phandle, (uint8_t *) pcmd, | ||
| 160 | sizeof(pcmd->body.start_streaming.req) | ||
| 161 | + HEADER_SIZE, (uint8_t *) prsp, | ||
| 162 | sizeof(prsp->body.start_streaming.rsp) | ||
| 163 | + HEADER_SIZE); | ||
| 164 | } else { | ||
| 165 | error = AS10X_CMD_ERROR; | ||
| 166 | } | ||
| 167 | |||
| 168 | if (error < 0) | ||
| 169 | goto out; | ||
| 170 | |||
| 171 | /* parse response */ | ||
| 172 | error = as10x_rsp_parse(prsp, CONTROL_PROC_START_STREAMING_RSP); | ||
| 173 | |||
| 174 | out: | ||
| 175 | LEAVE(); | ||
| 176 | return error; | ||
| 177 | } | ||
| 178 | |||
| 179 | /** | ||
| 180 | * as10x_cmd_stop_streaming - Send stop streaming command to AS10x | ||
| 181 | * @phandle: pointer to AS10x handle | ||
| 182 | * | ||
| 183 | * Return 0 on success or negative value in case of error. | ||
| 184 | */ | ||
| 185 | int as10x_cmd_stop_streaming(as10x_handle_t *phandle) | ||
| 186 | { | ||
| 187 | int8_t error; | ||
| 188 | struct as10x_cmd_t *pcmd, *prsp; | ||
| 189 | |||
| 190 | ENTER(); | ||
| 191 | |||
| 192 | pcmd = phandle->cmd; | ||
| 193 | prsp = phandle->rsp; | ||
| 194 | |||
| 195 | /* prepare command */ | ||
| 196 | as10x_cmd_build(pcmd, (++phandle->cmd_xid), | ||
| 197 | sizeof(pcmd->body.stop_streaming.req)); | ||
| 198 | |||
| 199 | /* fill command */ | ||
| 200 | pcmd->body.stop_streaming.req.proc_id = | ||
| 201 | cpu_to_le16(CONTROL_PROC_STOP_STREAMING); | ||
| 202 | |||
| 203 | /* send command */ | ||
| 204 | if (phandle->ops->xfer_cmd) { | ||
| 205 | error = phandle->ops->xfer_cmd(phandle, (uint8_t *) pcmd, | ||
| 206 | sizeof(pcmd->body.stop_streaming.req) | ||
| 207 | + HEADER_SIZE, (uint8_t *) prsp, | ||
| 208 | sizeof(prsp->body.stop_streaming.rsp) | ||
| 209 | + HEADER_SIZE); | ||
| 210 | } else { | ||
| 211 | error = AS10X_CMD_ERROR; | ||
| 212 | } | ||
| 213 | |||
| 214 | if (error < 0) | ||
| 215 | goto out; | ||
| 216 | |||
| 217 | /* parse response */ | ||
| 218 | error = as10x_rsp_parse(prsp, CONTROL_PROC_STOP_STREAMING_RSP); | ||
| 219 | |||
| 220 | out: | ||
| 221 | LEAVE(); | ||
| 222 | return error; | ||
| 223 | } | ||
diff --git a/drivers/staging/media/as102/as10x_handle.h b/drivers/staging/media/as102/as10x_handle.h new file mode 100644 index 000000000000..4f01a76e9829 --- /dev/null +++ b/drivers/staging/media/as102/as10x_handle.h | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | /* | ||
| 2 | * Abilis Systems Single DVB-T Receiver | ||
| 3 | * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com> | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 8 | * any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 18 | */ | ||
| 19 | #ifdef __KERNEL__ | ||
| 20 | struct as102_bus_adapter_t; | ||
| 21 | struct as102_dev_t; | ||
| 22 | |||
| 23 | #define as10x_handle_t struct as102_bus_adapter_t | ||
| 24 | #include "as10x_cmd.h" | ||
| 25 | |||
| 26 | /* values for "mode" field */ | ||
| 27 | #define REGMODE8 8 | ||
| 28 | #define REGMODE16 16 | ||
| 29 | #define REGMODE32 32 | ||
| 30 | |||
| 31 | struct as102_priv_ops_t { | ||
| 32 | int (*upload_fw_pkt) (struct as102_bus_adapter_t *bus_adap, | ||
| 33 | unsigned char *buf, int buflen, int swap32); | ||
| 34 | |||
| 35 | int (*send_cmd) (struct as102_bus_adapter_t *bus_adap, | ||
| 36 | unsigned char *buf, int buflen); | ||
| 37 | |||
| 38 | int (*xfer_cmd) (struct as102_bus_adapter_t *bus_adap, | ||
| 39 | unsigned char *send_buf, int send_buf_len, | ||
| 40 | unsigned char *recv_buf, int recv_buf_len); | ||
| 41 | /* | ||
| 42 | int (*pid_filter) (struct as102_bus_adapter_t *bus_adap, | ||
| 43 | int index, u16 pid, int onoff); | ||
| 44 | */ | ||
| 45 | int (*start_stream) (struct as102_dev_t *dev); | ||
| 46 | void (*stop_stream) (struct as102_dev_t *dev); | ||
| 47 | |||
| 48 | int (*reset_target) (struct as102_bus_adapter_t *bus_adap); | ||
| 49 | |||
| 50 | int (*read_write)(struct as102_bus_adapter_t *bus_adap, uint8_t mode, | ||
| 51 | uint32_t rd_addr, uint16_t rd_len, | ||
| 52 | uint32_t wr_addr, uint16_t wr_len); | ||
| 53 | |||
| 54 | int (*as102_read_ep2) (struct as102_bus_adapter_t *bus_adap, | ||
| 55 | unsigned char *recv_buf, | ||
| 56 | int recv_buf_len); | ||
| 57 | }; | ||
| 58 | #endif | ||
diff --git a/drivers/staging/media/as102/as10x_types.h b/drivers/staging/media/as102/as10x_types.h new file mode 100644 index 000000000000..3dedb3c1420a --- /dev/null +++ b/drivers/staging/media/as102/as10x_types.h | |||
| @@ -0,0 +1,198 @@ | |||
| 1 | /* | ||
| 2 | * Abilis Systems Single DVB-T Receiver | ||
| 3 | * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com> | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 8 | * any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 18 | */ | ||
| 19 | #ifndef _AS10X_TYPES_H_ | ||
| 20 | #define _AS10X_TYPES_H_ | ||
| 21 | |||
| 22 | #include "as10x_handle.h" | ||
| 23 | |||
| 24 | /*********************************/ | ||
| 25 | /* MACRO DEFINITIONS */ | ||
| 26 | /*********************************/ | ||
| 27 | |||
| 28 | /* bandwidth constant values */ | ||
| 29 | #define BW_5_MHZ 0x00 | ||
| 30 | #define BW_6_MHZ 0x01 | ||
| 31 | #define BW_7_MHZ 0x02 | ||
| 32 | #define BW_8_MHZ 0x03 | ||
| 33 | |||
| 34 | /* hierarchy priority selection values */ | ||
| 35 | #define HIER_NO_PRIORITY 0x00 | ||
| 36 | #define HIER_LOW_PRIORITY 0x01 | ||
| 37 | #define HIER_HIGH_PRIORITY 0x02 | ||
| 38 | |||
| 39 | /* constellation available values */ | ||
| 40 | #define CONST_QPSK 0x00 | ||
| 41 | #define CONST_QAM16 0x01 | ||
| 42 | #define CONST_QAM64 0x02 | ||
| 43 | #define CONST_UNKNOWN 0xFF | ||
| 44 | |||
| 45 | /* hierarchy available values */ | ||
| 46 | #define HIER_NONE 0x00 | ||
| 47 | #define HIER_ALPHA_1 0x01 | ||
| 48 | #define HIER_ALPHA_2 0x02 | ||
| 49 | #define HIER_ALPHA_4 0x03 | ||
| 50 | #define HIER_UNKNOWN 0xFF | ||
| 51 | |||
| 52 | /* interleaving available values */ | ||
| 53 | #define INTLV_NATIVE 0x00 | ||
| 54 | #define INTLV_IN_DEPTH 0x01 | ||
| 55 | #define INTLV_UNKNOWN 0xFF | ||
| 56 | |||
| 57 | /* code rate available values */ | ||
| 58 | #define CODE_RATE_1_2 0x00 | ||
| 59 | #define CODE_RATE_2_3 0x01 | ||
| 60 | #define CODE_RATE_3_4 0x02 | ||
| 61 | #define CODE_RATE_5_6 0x03 | ||
| 62 | #define CODE_RATE_7_8 0x04 | ||
| 63 | #define CODE_RATE_UNKNOWN 0xFF | ||
| 64 | |||
| 65 | /* guard interval available values */ | ||
| 66 | #define GUARD_INT_1_32 0x00 | ||
| 67 | #define GUARD_INT_1_16 0x01 | ||
| 68 | #define GUARD_INT_1_8 0x02 | ||
| 69 | #define GUARD_INT_1_4 0x03 | ||
| 70 | #define GUARD_UNKNOWN 0xFF | ||
| 71 | |||
| 72 | /* transmission mode available values */ | ||
| 73 | #define TRANS_MODE_2K 0x00 | ||
| 74 | #define TRANS_MODE_8K 0x01 | ||
| 75 | #define TRANS_MODE_4K 0x02 | ||
| 76 | #define TRANS_MODE_UNKNOWN 0xFF | ||
| 77 | |||
| 78 | /* DVBH signalling available values */ | ||
| 79 | #define TIMESLICING_PRESENT 0x01 | ||
| 80 | #define MPE_FEC_PRESENT 0x02 | ||
| 81 | |||
| 82 | /* tune state available */ | ||
| 83 | #define TUNE_STATUS_NOT_TUNED 0x00 | ||
| 84 | #define TUNE_STATUS_IDLE 0x01 | ||
| 85 | #define TUNE_STATUS_LOCKING 0x02 | ||
| 86 | #define TUNE_STATUS_SIGNAL_DVB_OK 0x03 | ||
| 87 | #define TUNE_STATUS_STREAM_DETECTED 0x04 | ||
| 88 | #define TUNE_STATUS_STREAM_TUNED 0x05 | ||
| 89 | #define TUNE_STATUS_ERROR 0xFF | ||
| 90 | |||
| 91 | /* available TS FID filter types */ | ||
| 92 | #define TS_PID_TYPE_TS 0 | ||
| 93 | #define TS_PID_TYPE_PSI_SI 1 | ||
| 94 | #define TS_PID_TYPE_MPE 2 | ||
| 95 | |||
| 96 | /* number of echos available */ | ||
| 97 | #define MAX_ECHOS 15 | ||
| 98 | |||
| 99 | /* Context types */ | ||
| 100 | #define CONTEXT_LNA 1010 | ||
| 101 | #define CONTEXT_ELNA_HYSTERESIS 4003 | ||
| 102 | #define CONTEXT_ELNA_GAIN 4004 | ||
| 103 | #define CONTEXT_MER_THRESHOLD 5005 | ||
| 104 | #define CONTEXT_MER_OFFSET 5006 | ||
| 105 | #define CONTEXT_IR_STATE 7000 | ||
| 106 | #define CONTEXT_TSOUT_MSB_FIRST 7004 | ||
| 107 | #define CONTEXT_TSOUT_FALLING_EDGE 7005 | ||
| 108 | |||
| 109 | /* Configuration modes */ | ||
| 110 | #define CFG_MODE_ON 0 | ||
| 111 | #define CFG_MODE_OFF 1 | ||
| 112 | #define CFG_MODE_AUTO 2 | ||
| 113 | |||
| 114 | #pragma pack(1) | ||
| 115 | struct as10x_tps { | ||
| 116 | uint8_t constellation; | ||
| 117 | uint8_t hierarchy; | ||
| 118 | uint8_t interleaving_mode; | ||
| 119 | uint8_t code_rate_HP; | ||
| 120 | uint8_t code_rate_LP; | ||
| 121 | uint8_t guard_interval; | ||
| 122 | uint8_t transmission_mode; | ||
| 123 | uint8_t DVBH_mask_HP; | ||
| 124 | uint8_t DVBH_mask_LP; | ||
| 125 | uint16_t cell_ID; | ||
| 126 | }; | ||
| 127 | |||
| 128 | struct as10x_tune_args { | ||
| 129 | /* frequency */ | ||
| 130 | uint32_t freq; | ||
| 131 | /* bandwidth */ | ||
| 132 | uint8_t bandwidth; | ||
| 133 | /* hierarchy selection */ | ||
| 134 | uint8_t hier_select; | ||
| 135 | /* constellation */ | ||
| 136 | uint8_t constellation; | ||
| 137 | /* hierarchy */ | ||
| 138 | uint8_t hierarchy; | ||
| 139 | /* interleaving mode */ | ||
| 140 | uint8_t interleaving_mode; | ||
| 141 | /* code rate */ | ||
| 142 | uint8_t code_rate; | ||
| 143 | /* guard interval */ | ||
| 144 | uint8_t guard_interval; | ||
| 145 | /* transmission mode */ | ||
| 146 | uint8_t transmission_mode; | ||
| 147 | }; | ||
| 148 | |||
| 149 | struct as10x_tune_status { | ||
| 150 | /* tune status */ | ||
| 151 | uint8_t tune_state; | ||
| 152 | /* signal strength */ | ||
| 153 | int16_t signal_strength; | ||
| 154 | /* packet error rate 10^-4 */ | ||
| 155 | uint16_t PER; | ||
| 156 | /* bit error rate 10^-4 */ | ||
| 157 | uint16_t BER; | ||
| 158 | }; | ||
| 159 | |||
| 160 | struct as10x_demod_stats { | ||
| 161 | /* frame counter */ | ||
| 162 | uint32_t frame_count; | ||
| 163 | /* Bad frame counter */ | ||
| 164 | uint32_t bad_frame_count; | ||
| 165 | /* Number of wrong bytes fixed by Reed-Solomon */ | ||
| 166 | uint32_t bytes_fixed_by_rs; | ||
| 167 | /* Averaged MER */ | ||
| 168 | uint16_t mer; | ||
| 169 | /* statistics calculation state indicator (started or not) */ | ||
| 170 | uint8_t has_started; | ||
| 171 | }; | ||
| 172 | |||
| 173 | struct as10x_ts_filter { | ||
| 174 | uint16_t pid; /** valid PID value 0x00 : 0x2000 */ | ||
| 175 | uint8_t type; /** Red TS_PID_TYPE_<N> values */ | ||
| 176 | uint8_t idx; /** index in filtering table */ | ||
| 177 | }; | ||
| 178 | |||
| 179 | struct as10x_register_value { | ||
| 180 | uint8_t mode; | ||
| 181 | union { | ||
| 182 | uint8_t value8; /* 8 bit value */ | ||
| 183 | uint16_t value16; /* 16 bit value */ | ||
| 184 | uint32_t value32; /* 32 bit value */ | ||
| 185 | }u; | ||
| 186 | }; | ||
| 187 | |||
| 188 | #pragma pack() | ||
| 189 | |||
| 190 | struct as10x_register_addr { | ||
| 191 | /* register addr */ | ||
| 192 | uint32_t addr; | ||
| 193 | /* register mode access */ | ||
| 194 | uint8_t mode; | ||
| 195 | }; | ||
| 196 | |||
| 197 | |||
| 198 | #endif | ||
diff --git a/drivers/staging/cxd2099/Kconfig b/drivers/staging/media/cxd2099/Kconfig index b48aefddc84c..b48aefddc84c 100644 --- a/drivers/staging/cxd2099/Kconfig +++ b/drivers/staging/media/cxd2099/Kconfig | |||
diff --git a/drivers/staging/cxd2099/Makefile b/drivers/staging/media/cxd2099/Makefile index 64cfc77be357..64cfc77be357 100644 --- a/drivers/staging/cxd2099/Makefile +++ b/drivers/staging/media/cxd2099/Makefile | |||
diff --git a/drivers/staging/cxd2099/TODO b/drivers/staging/media/cxd2099/TODO index 375bb6f8ee2c..375bb6f8ee2c 100644 --- a/drivers/staging/cxd2099/TODO +++ b/drivers/staging/media/cxd2099/TODO | |||
diff --git a/drivers/staging/cxd2099/cxd2099.c b/drivers/staging/media/cxd2099/cxd2099.c index 1c04185bcfd7..1c04185bcfd7 100644 --- a/drivers/staging/cxd2099/cxd2099.c +++ b/drivers/staging/media/cxd2099/cxd2099.c | |||
diff --git a/drivers/staging/cxd2099/cxd2099.h b/drivers/staging/media/cxd2099/cxd2099.h index 19c588a59588..19c588a59588 100644 --- a/drivers/staging/cxd2099/cxd2099.h +++ b/drivers/staging/media/cxd2099/cxd2099.h | |||
diff --git a/drivers/staging/dt3155v4l/Kconfig b/drivers/staging/media/dt3155v4l/Kconfig index 226a1ca90b3c..226a1ca90b3c 100644 --- a/drivers/staging/dt3155v4l/Kconfig +++ b/drivers/staging/media/dt3155v4l/Kconfig | |||
diff --git a/drivers/staging/dt3155v4l/Makefile b/drivers/staging/media/dt3155v4l/Makefile index ce7a3ec2faf3..ce7a3ec2faf3 100644 --- a/drivers/staging/dt3155v4l/Makefile +++ b/drivers/staging/media/dt3155v4l/Makefile | |||
diff --git a/drivers/staging/dt3155v4l/dt3155v4l.c b/drivers/staging/media/dt3155v4l/dt3155v4l.c index 04e93c49f03a..04e93c49f03a 100644 --- a/drivers/staging/dt3155v4l/dt3155v4l.c +++ b/drivers/staging/media/dt3155v4l/dt3155v4l.c | |||
diff --git a/drivers/staging/dt3155v4l/dt3155v4l.h b/drivers/staging/media/dt3155v4l/dt3155v4l.h index 2e4f89d402e4..2e4f89d402e4 100644 --- a/drivers/staging/dt3155v4l/dt3155v4l.h +++ b/drivers/staging/media/dt3155v4l/dt3155v4l.h | |||
diff --git a/drivers/staging/easycap/Kconfig b/drivers/staging/media/easycap/Kconfig index a425a6f9cdca..a425a6f9cdca 100644 --- a/drivers/staging/easycap/Kconfig +++ b/drivers/staging/media/easycap/Kconfig | |||
diff --git a/drivers/staging/easycap/Makefile b/drivers/staging/media/easycap/Makefile index a34e75f59c18..a34e75f59c18 100644 --- a/drivers/staging/easycap/Makefile +++ b/drivers/staging/media/easycap/Makefile | |||
diff --git a/drivers/staging/easycap/README b/drivers/staging/media/easycap/README index 796b032384bd..796b032384bd 100644 --- a/drivers/staging/easycap/README +++ b/drivers/staging/media/easycap/README | |||
diff --git a/drivers/staging/easycap/easycap.h b/drivers/staging/media/easycap/easycap.h index 7b256a948c27..7b256a948c27 100644 --- a/drivers/staging/easycap/easycap.h +++ b/drivers/staging/media/easycap/easycap.h | |||
diff --git a/drivers/staging/easycap/easycap_ioctl.c b/drivers/staging/media/easycap/easycap_ioctl.c index c99addfb6242..c99addfb6242 100644 --- a/drivers/staging/easycap/easycap_ioctl.c +++ b/drivers/staging/media/easycap/easycap_ioctl.c | |||
diff --git a/drivers/staging/easycap/easycap_low.c b/drivers/staging/media/easycap/easycap_low.c index 0385735ac6df..0385735ac6df 100644 --- a/drivers/staging/easycap/easycap_low.c +++ b/drivers/staging/media/easycap/easycap_low.c | |||
diff --git a/drivers/staging/easycap/easycap_main.c b/drivers/staging/media/easycap/easycap_main.c index a45c0b507067..a45c0b507067 100644 --- a/drivers/staging/easycap/easycap_main.c +++ b/drivers/staging/media/easycap/easycap_main.c | |||
diff --git a/drivers/staging/easycap/easycap_settings.c b/drivers/staging/media/easycap/easycap_settings.c index 70f59b13c34d..70f59b13c34d 100644 --- a/drivers/staging/easycap/easycap_settings.c +++ b/drivers/staging/media/easycap/easycap_settings.c | |||
diff --git a/drivers/staging/easycap/easycap_sound.c b/drivers/staging/media/easycap/easycap_sound.c index b22bb39b5f69..b22bb39b5f69 100644 --- a/drivers/staging/easycap/easycap_sound.c +++ b/drivers/staging/media/easycap/easycap_sound.c | |||
diff --git a/drivers/staging/easycap/easycap_testcard.c b/drivers/staging/media/easycap/easycap_testcard.c index 0f71470ace39..0f71470ace39 100644 --- a/drivers/staging/easycap/easycap_testcard.c +++ b/drivers/staging/media/easycap/easycap_testcard.c | |||
diff --git a/drivers/staging/go7007/Kconfig b/drivers/staging/media/go7007/Kconfig index 7dfb2815b9ec..7dfb2815b9ec 100644 --- a/drivers/staging/go7007/Kconfig +++ b/drivers/staging/media/go7007/Kconfig | |||
diff --git a/drivers/staging/go7007/Makefile b/drivers/staging/media/go7007/Makefile index 6ee837c56706..6ee837c56706 100644 --- a/drivers/staging/go7007/Makefile +++ b/drivers/staging/media/go7007/Makefile | |||
diff --git a/drivers/staging/go7007/README b/drivers/staging/media/go7007/README index 48f447637817..48f447637817 100644 --- a/drivers/staging/go7007/README +++ b/drivers/staging/media/go7007/README | |||
diff --git a/drivers/staging/go7007/go7007-driver.c b/drivers/staging/media/go7007/go7007-driver.c index 6c9279a6d606..6c9279a6d606 100644 --- a/drivers/staging/go7007/go7007-driver.c +++ b/drivers/staging/media/go7007/go7007-driver.c | |||
diff --git a/drivers/staging/go7007/go7007-fw.c b/drivers/staging/media/go7007/go7007-fw.c index c9a6409edfe3..c9a6409edfe3 100644 --- a/drivers/staging/go7007/go7007-fw.c +++ b/drivers/staging/media/go7007/go7007-fw.c | |||
diff --git a/drivers/staging/go7007/go7007-i2c.c b/drivers/staging/media/go7007/go7007-i2c.c index b8cfa1a6eaeb..b8cfa1a6eaeb 100644 --- a/drivers/staging/go7007/go7007-i2c.c +++ b/drivers/staging/media/go7007/go7007-i2c.c | |||
diff --git a/drivers/staging/go7007/go7007-priv.h b/drivers/staging/media/go7007/go7007-priv.h index b58c394c6555..b58c394c6555 100644 --- a/drivers/staging/go7007/go7007-priv.h +++ b/drivers/staging/media/go7007/go7007-priv.h | |||
diff --git a/drivers/staging/go7007/go7007-usb.c b/drivers/staging/media/go7007/go7007-usb.c index 3db3b0a91cc1..3db3b0a91cc1 100644 --- a/drivers/staging/go7007/go7007-usb.c +++ b/drivers/staging/media/go7007/go7007-usb.c | |||
diff --git a/drivers/staging/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index 2b27d8da70a2..2b27d8da70a2 100644 --- a/drivers/staging/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c | |||
diff --git a/drivers/staging/go7007/go7007.h b/drivers/staging/media/go7007/go7007.h index 7399c915a934..7399c915a934 100644 --- a/drivers/staging/go7007/go7007.h +++ b/drivers/staging/media/go7007/go7007.h | |||
diff --git a/drivers/staging/go7007/go7007.txt b/drivers/staging/media/go7007/go7007.txt index 9db1f3952fd2..9db1f3952fd2 100644 --- a/drivers/staging/go7007/go7007.txt +++ b/drivers/staging/media/go7007/go7007.txt | |||
diff --git a/drivers/staging/go7007/s2250-board.c b/drivers/staging/media/go7007/s2250-board.c index e7736a915530..e7736a915530 100644 --- a/drivers/staging/go7007/s2250-board.c +++ b/drivers/staging/media/go7007/s2250-board.c | |||
diff --git a/drivers/staging/go7007/s2250-loader.c b/drivers/staging/media/go7007/s2250-loader.c index 4e132519e253..4e132519e253 100644 --- a/drivers/staging/go7007/s2250-loader.c +++ b/drivers/staging/media/go7007/s2250-loader.c | |||
diff --git a/drivers/staging/go7007/s2250-loader.h b/drivers/staging/media/go7007/s2250-loader.h index b7c301af16cc..b7c301af16cc 100644 --- a/drivers/staging/go7007/s2250-loader.h +++ b/drivers/staging/media/go7007/s2250-loader.h | |||
diff --git a/drivers/staging/go7007/saa7134-go7007.c b/drivers/staging/media/go7007/saa7134-go7007.c index cf7c34a99459..cf7c34a99459 100644 --- a/drivers/staging/go7007/saa7134-go7007.c +++ b/drivers/staging/media/go7007/saa7134-go7007.c | |||
diff --git a/drivers/staging/go7007/snd-go7007.c b/drivers/staging/media/go7007/snd-go7007.c index deac938d8505..deac938d8505 100644 --- a/drivers/staging/go7007/snd-go7007.c +++ b/drivers/staging/media/go7007/snd-go7007.c | |||
diff --git a/drivers/staging/go7007/wis-i2c.h b/drivers/staging/media/go7007/wis-i2c.h index 3c2b9be455df..3c2b9be455df 100644 --- a/drivers/staging/go7007/wis-i2c.h +++ b/drivers/staging/media/go7007/wis-i2c.h | |||
diff --git a/drivers/staging/go7007/wis-ov7640.c b/drivers/staging/media/go7007/wis-ov7640.c index 6bc9470fecb6..6bc9470fecb6 100644 --- a/drivers/staging/go7007/wis-ov7640.c +++ b/drivers/staging/media/go7007/wis-ov7640.c | |||
diff --git a/drivers/staging/go7007/wis-saa7113.c b/drivers/staging/media/go7007/wis-saa7113.c index 05e0e1083864..05e0e1083864 100644 --- a/drivers/staging/go7007/wis-saa7113.c +++ b/drivers/staging/media/go7007/wis-saa7113.c | |||
diff --git a/drivers/staging/go7007/wis-saa7115.c b/drivers/staging/media/go7007/wis-saa7115.c index 46cff59e28b7..46cff59e28b7 100644 --- a/drivers/staging/go7007/wis-saa7115.c +++ b/drivers/staging/media/go7007/wis-saa7115.c | |||
diff --git a/drivers/staging/go7007/wis-sony-tuner.c b/drivers/staging/media/go7007/wis-sony-tuner.c index 8f1b7d4f6a2e..8f1b7d4f6a2e 100644 --- a/drivers/staging/go7007/wis-sony-tuner.c +++ b/drivers/staging/media/go7007/wis-sony-tuner.c | |||
diff --git a/drivers/staging/go7007/wis-tw2804.c b/drivers/staging/media/go7007/wis-tw2804.c index 9134f03e3cf0..9134f03e3cf0 100644 --- a/drivers/staging/go7007/wis-tw2804.c +++ b/drivers/staging/media/go7007/wis-tw2804.c | |||
diff --git a/drivers/staging/go7007/wis-tw9903.c b/drivers/staging/media/go7007/wis-tw9903.c index 9230f4a80529..9230f4a80529 100644 --- a/drivers/staging/go7007/wis-tw9903.c +++ b/drivers/staging/media/go7007/wis-tw9903.c | |||
diff --git a/drivers/staging/go7007/wis-uda1342.c b/drivers/staging/media/go7007/wis-uda1342.c index 0127be2f3be0..0127be2f3be0 100644 --- a/drivers/staging/go7007/wis-uda1342.c +++ b/drivers/staging/media/go7007/wis-uda1342.c | |||
diff --git a/drivers/staging/lirc/Kconfig b/drivers/staging/media/lirc/Kconfig index 526ec0fc2f04..526ec0fc2f04 100644 --- a/drivers/staging/lirc/Kconfig +++ b/drivers/staging/media/lirc/Kconfig | |||
diff --git a/drivers/staging/lirc/Makefile b/drivers/staging/media/lirc/Makefile index d76b0fa2af53..d76b0fa2af53 100644 --- a/drivers/staging/lirc/Makefile +++ b/drivers/staging/media/lirc/Makefile | |||
diff --git a/drivers/staging/lirc/TODO b/drivers/staging/media/lirc/TODO index b6cb593f55c6..b6cb593f55c6 100644 --- a/drivers/staging/lirc/TODO +++ b/drivers/staging/media/lirc/TODO | |||
diff --git a/drivers/staging/lirc/TODO.lirc_zilog b/drivers/staging/media/lirc/TODO.lirc_zilog index a97800a8e127..a97800a8e127 100644 --- a/drivers/staging/lirc/TODO.lirc_zilog +++ b/drivers/staging/media/lirc/TODO.lirc_zilog | |||
diff --git a/drivers/staging/lirc/lirc_bt829.c b/drivers/staging/media/lirc/lirc_bt829.c index c5a0d27a02dc..c5a0d27a02dc 100644 --- a/drivers/staging/lirc/lirc_bt829.c +++ b/drivers/staging/media/lirc/lirc_bt829.c | |||
diff --git a/drivers/staging/lirc/lirc_ene0100.h b/drivers/staging/media/lirc/lirc_ene0100.h index 06bebd6acc46..06bebd6acc46 100644 --- a/drivers/staging/lirc/lirc_ene0100.h +++ b/drivers/staging/media/lirc/lirc_ene0100.h | |||
diff --git a/drivers/staging/lirc/lirc_igorplugusb.c b/drivers/staging/media/lirc/lirc_igorplugusb.c index 0dc2c2b22c2b..0dc2c2b22c2b 100644 --- a/drivers/staging/lirc/lirc_igorplugusb.c +++ b/drivers/staging/media/lirc/lirc_igorplugusb.c | |||
diff --git a/drivers/staging/lirc/lirc_imon.c b/drivers/staging/media/lirc/lirc_imon.c index f5308d5929c6..f5308d5929c6 100644 --- a/drivers/staging/lirc/lirc_imon.c +++ b/drivers/staging/media/lirc/lirc_imon.c | |||
diff --git a/drivers/staging/lirc/lirc_parallel.c b/drivers/staging/media/lirc/lirc_parallel.c index 792aac0a8e7b..792aac0a8e7b 100644 --- a/drivers/staging/lirc/lirc_parallel.c +++ b/drivers/staging/media/lirc/lirc_parallel.c | |||
diff --git a/drivers/staging/lirc/lirc_parallel.h b/drivers/staging/media/lirc/lirc_parallel.h index 4bed6afe0632..4bed6afe0632 100644 --- a/drivers/staging/lirc/lirc_parallel.h +++ b/drivers/staging/media/lirc/lirc_parallel.h | |||
diff --git a/drivers/staging/lirc/lirc_sasem.c b/drivers/staging/media/lirc/lirc_sasem.c index a2d18b0aa048..a2d18b0aa048 100644 --- a/drivers/staging/lirc/lirc_sasem.c +++ b/drivers/staging/media/lirc/lirc_sasem.c | |||
diff --git a/drivers/staging/lirc/lirc_serial.c b/drivers/staging/media/lirc/lirc_serial.c index 8a060a8a7224..8a060a8a7224 100644 --- a/drivers/staging/lirc/lirc_serial.c +++ b/drivers/staging/media/lirc/lirc_serial.c | |||
diff --git a/drivers/staging/lirc/lirc_sir.c b/drivers/staging/media/lirc/lirc_sir.c index 6903d3992eca..6903d3992eca 100644 --- a/drivers/staging/lirc/lirc_sir.c +++ b/drivers/staging/media/lirc/lirc_sir.c | |||
diff --git a/drivers/staging/lirc/lirc_ttusbir.c b/drivers/staging/media/lirc/lirc_ttusbir.c index e4b329b8cafd..e4b329b8cafd 100644 --- a/drivers/staging/lirc/lirc_ttusbir.c +++ b/drivers/staging/media/lirc/lirc_ttusbir.c | |||
diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/media/lirc/lirc_zilog.c index 0302d82a12f7..0302d82a12f7 100644 --- a/drivers/staging/lirc/lirc_zilog.c +++ b/drivers/staging/media/lirc/lirc_zilog.c | |||
diff --git a/drivers/staging/solo6x10/Kconfig b/drivers/staging/media/solo6x10/Kconfig index 03dcac4ea4d0..03dcac4ea4d0 100644 --- a/drivers/staging/solo6x10/Kconfig +++ b/drivers/staging/media/solo6x10/Kconfig | |||
diff --git a/drivers/staging/solo6x10/Makefile b/drivers/staging/media/solo6x10/Makefile index 72816cf16704..72816cf16704 100644 --- a/drivers/staging/solo6x10/Makefile +++ b/drivers/staging/media/solo6x10/Makefile | |||
diff --git a/drivers/staging/solo6x10/TODO b/drivers/staging/media/solo6x10/TODO index 7e6c4fa130df..7e6c4fa130df 100644 --- a/drivers/staging/solo6x10/TODO +++ b/drivers/staging/media/solo6x10/TODO | |||
diff --git a/drivers/staging/solo6x10/core.c b/drivers/staging/media/solo6x10/core.c index f974f6412ad7..f974f6412ad7 100644 --- a/drivers/staging/solo6x10/core.c +++ b/drivers/staging/media/solo6x10/core.c | |||
diff --git a/drivers/staging/solo6x10/disp.c b/drivers/staging/media/solo6x10/disp.c index 884c0eb757c4..884c0eb757c4 100644 --- a/drivers/staging/solo6x10/disp.c +++ b/drivers/staging/media/solo6x10/disp.c | |||
diff --git a/drivers/staging/solo6x10/enc.c b/drivers/staging/media/solo6x10/enc.c index de502599bb19..de502599bb19 100644 --- a/drivers/staging/solo6x10/enc.c +++ b/drivers/staging/media/solo6x10/enc.c | |||
diff --git a/drivers/staging/solo6x10/g723.c b/drivers/staging/media/solo6x10/g723.c index 59274bfca95b..59274bfca95b 100644 --- a/drivers/staging/solo6x10/g723.c +++ b/drivers/staging/media/solo6x10/g723.c | |||
diff --git a/drivers/staging/solo6x10/gpio.c b/drivers/staging/media/solo6x10/gpio.c index 0925e6f33a99..0925e6f33a99 100644 --- a/drivers/staging/solo6x10/gpio.c +++ b/drivers/staging/media/solo6x10/gpio.c | |||
diff --git a/drivers/staging/solo6x10/i2c.c b/drivers/staging/media/solo6x10/i2c.c index ef95a500b4da..ef95a500b4da 100644 --- a/drivers/staging/solo6x10/i2c.c +++ b/drivers/staging/media/solo6x10/i2c.c | |||
diff --git a/drivers/staging/solo6x10/jpeg.h b/drivers/staging/media/solo6x10/jpeg.h index 50defec318cc..50defec318cc 100644 --- a/drivers/staging/solo6x10/jpeg.h +++ b/drivers/staging/media/solo6x10/jpeg.h | |||
diff --git a/drivers/staging/solo6x10/offsets.h b/drivers/staging/media/solo6x10/offsets.h index 3d7e569f1cf8..3d7e569f1cf8 100644 --- a/drivers/staging/solo6x10/offsets.h +++ b/drivers/staging/media/solo6x10/offsets.h | |||
diff --git a/drivers/staging/solo6x10/osd-font.h b/drivers/staging/media/solo6x10/osd-font.h index 591e0e82e0e8..591e0e82e0e8 100644 --- a/drivers/staging/solo6x10/osd-font.h +++ b/drivers/staging/media/solo6x10/osd-font.h | |||
diff --git a/drivers/staging/solo6x10/p2m.c b/drivers/staging/media/solo6x10/p2m.c index 56210f0fc5ec..56210f0fc5ec 100644 --- a/drivers/staging/solo6x10/p2m.c +++ b/drivers/staging/media/solo6x10/p2m.c | |||
diff --git a/drivers/staging/solo6x10/registers.h b/drivers/staging/media/solo6x10/registers.h index aca544472c93..aca544472c93 100644 --- a/drivers/staging/solo6x10/registers.h +++ b/drivers/staging/media/solo6x10/registers.h | |||
diff --git a/drivers/staging/solo6x10/solo6x10.h b/drivers/staging/media/solo6x10/solo6x10.h index abee7213202f..abee7213202f 100644 --- a/drivers/staging/solo6x10/solo6x10.h +++ b/drivers/staging/media/solo6x10/solo6x10.h | |||
diff --git a/drivers/staging/solo6x10/tw28.c b/drivers/staging/media/solo6x10/tw28.c index db56b42c56c6..db56b42c56c6 100644 --- a/drivers/staging/solo6x10/tw28.c +++ b/drivers/staging/media/solo6x10/tw28.c | |||
diff --git a/drivers/staging/solo6x10/tw28.h b/drivers/staging/media/solo6x10/tw28.h index a44a03afbd30..a44a03afbd30 100644 --- a/drivers/staging/solo6x10/tw28.h +++ b/drivers/staging/media/solo6x10/tw28.h | |||
diff --git a/drivers/staging/solo6x10/v4l2-enc.c b/drivers/staging/media/solo6x10/v4l2-enc.c index bee7280bbed9..bee7280bbed9 100644 --- a/drivers/staging/solo6x10/v4l2-enc.c +++ b/drivers/staging/media/solo6x10/v4l2-enc.c | |||
diff --git a/drivers/staging/solo6x10/v4l2.c b/drivers/staging/media/solo6x10/v4l2.c index 571c3a348d30..571c3a348d30 100644 --- a/drivers/staging/solo6x10/v4l2.c +++ b/drivers/staging/media/solo6x10/v4l2.c | |||
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index 225560c1a10f..4b752d5ee80e 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h | |||
| @@ -653,6 +653,10 @@ struct v4l2_buffer { | |||
| 653 | #define V4L2_BUF_FLAG_ERROR 0x0040 | 653 | #define V4L2_BUF_FLAG_ERROR 0x0040 |
| 654 | #define V4L2_BUF_FLAG_TIMECODE 0x0100 /* timecode field is valid */ | 654 | #define V4L2_BUF_FLAG_TIMECODE 0x0100 /* timecode field is valid */ |
| 655 | #define V4L2_BUF_FLAG_INPUT 0x0200 /* input field is valid */ | 655 | #define V4L2_BUF_FLAG_INPUT 0x0200 /* input field is valid */ |
| 656 | #define V4L2_BUF_FLAG_PREPARED 0x0400 /* Buffer is prepared for queuing */ | ||
| 657 | /* Cache handling flags */ | ||
| 658 | #define V4L2_BUF_FLAG_NO_CACHE_INVALIDATE 0x0800 | ||
| 659 | #define V4L2_BUF_FLAG_NO_CACHE_CLEAN 0x1000 | ||
| 656 | 660 | ||
| 657 | /* | 661 | /* |
| 658 | * O V E R L A Y P R E V I E W | 662 | * O V E R L A Y P R E V I E W |
| @@ -1165,6 +1169,7 @@ enum v4l2_power_line_frequency { | |||
| 1165 | V4L2_CID_POWER_LINE_FREQUENCY_DISABLED = 0, | 1169 | V4L2_CID_POWER_LINE_FREQUENCY_DISABLED = 0, |
| 1166 | V4L2_CID_POWER_LINE_FREQUENCY_50HZ = 1, | 1170 | V4L2_CID_POWER_LINE_FREQUENCY_50HZ = 1, |
| 1167 | V4L2_CID_POWER_LINE_FREQUENCY_60HZ = 2, | 1171 | V4L2_CID_POWER_LINE_FREQUENCY_60HZ = 2, |
| 1172 | V4L2_CID_POWER_LINE_FREQUENCY_AUTO = 3, | ||
| 1168 | }; | 1173 | }; |
| 1169 | #define V4L2_CID_HUE_AUTO (V4L2_CID_BASE+25) | 1174 | #define V4L2_CID_HUE_AUTO (V4L2_CID_BASE+25) |
| 1170 | #define V4L2_CID_WHITE_BALANCE_TEMPERATURE (V4L2_CID_BASE+26) | 1175 | #define V4L2_CID_WHITE_BALANCE_TEMPERATURE (V4L2_CID_BASE+26) |
| @@ -2138,6 +2143,23 @@ struct v4l2_dbg_chip_ident { | |||
| 2138 | __u32 revision; /* chip revision, chip specific */ | 2143 | __u32 revision; /* chip revision, chip specific */ |
| 2139 | } __attribute__ ((packed)); | 2144 | } __attribute__ ((packed)); |
| 2140 | 2145 | ||
| 2146 | /** | ||
| 2147 | * struct v4l2_create_buffers - VIDIOC_CREATE_BUFS argument | ||
| 2148 | * @index: on return, index of the first created buffer | ||
| 2149 | * @count: entry: number of requested buffers, | ||
| 2150 | * return: number of created buffers | ||
| 2151 | * @memory: buffer memory type | ||
| 2152 | * @format: frame format, for which buffers are requested | ||
| 2153 | * @reserved: future extensions | ||
| 2154 | */ | ||
| 2155 | struct v4l2_create_buffers { | ||
| 2156 | __u32 index; | ||
| 2157 | __u32 count; | ||
| 2158 | enum v4l2_memory memory; | ||
| 2159 | struct v4l2_format format; | ||
| 2160 | __u32 reserved[8]; | ||
| 2161 | }; | ||
| 2162 | |||
| 2141 | /* | 2163 | /* |
| 2142 | * I O C T L C O D E S F O R V I D E O D E V I C E S | 2164 | * I O C T L C O D E S F O R V I D E O D E V I C E S |
| 2143 | * | 2165 | * |
| @@ -2228,6 +2250,11 @@ struct v4l2_dbg_chip_ident { | |||
| 2228 | #define VIDIOC_SUBSCRIBE_EVENT _IOW('V', 90, struct v4l2_event_subscription) | 2250 | #define VIDIOC_SUBSCRIBE_EVENT _IOW('V', 90, struct v4l2_event_subscription) |
| 2229 | #define VIDIOC_UNSUBSCRIBE_EVENT _IOW('V', 91, struct v4l2_event_subscription) | 2251 | #define VIDIOC_UNSUBSCRIBE_EVENT _IOW('V', 91, struct v4l2_event_subscription) |
| 2230 | 2252 | ||
| 2253 | /* Experimental, the below two ioctls may change over the next couple of kernel | ||
| 2254 | versions */ | ||
| 2255 | #define VIDIOC_CREATE_BUFS _IOWR('V', 92, struct v4l2_create_buffers) | ||
| 2256 | #define VIDIOC_PREPARE_BUF _IOWR('V', 93, struct v4l2_buffer) | ||
| 2257 | |||
| 2231 | /* Reminder: when adding new ioctls please add support for them to | 2258 | /* Reminder: when adding new ioctls please add support for them to |
| 2232 | drivers/media/video/v4l2-compat-ioctl32.c as well! */ | 2259 | drivers/media/video/v4l2-compat-ioctl32.c as well! */ |
| 2233 | 2260 | ||
diff --git a/include/media/ov772x.h b/include/media/ov772x.h index 548bf1155c83..00dbb7c4feae 100644 --- a/include/media/ov772x.h +++ b/include/media/ov772x.h | |||
| @@ -12,12 +12,9 @@ | |||
| 12 | #ifndef __OV772X_H__ | 12 | #ifndef __OV772X_H__ |
| 13 | #define __OV772X_H__ | 13 | #define __OV772X_H__ |
| 14 | 14 | ||
| 15 | #include <media/soc_camera.h> | ||
| 16 | |||
| 17 | /* for flags */ | 15 | /* for flags */ |
| 18 | #define OV772X_FLAG_VFLIP (1 << 0) /* Vertical flip image */ | 16 | #define OV772X_FLAG_VFLIP (1 << 0) /* Vertical flip image */ |
| 19 | #define OV772X_FLAG_HFLIP (1 << 1) /* Horizontal flip image */ | 17 | #define OV772X_FLAG_HFLIP (1 << 1) /* Horizontal flip image */ |
| 20 | #define OV772X_FLAG_8BIT (1 << 2) /* default 10 bit */ | ||
| 21 | 18 | ||
| 22 | /* | 19 | /* |
| 23 | * for Edge ctrl | 20 | * for Edge ctrl |
| @@ -32,22 +29,23 @@ struct ov772x_edge_ctrl { | |||
| 32 | unsigned char lower; | 29 | unsigned char lower; |
| 33 | }; | 30 | }; |
| 34 | 31 | ||
| 35 | #define OV772X_MANUAL_EDGE_CTRL 0x80 /* un-used bit of strength */ | 32 | #define OV772X_MANUAL_EDGE_CTRL 0x80 /* un-used bit of strength */ |
| 36 | #define EDGE_STRENGTH_MASK 0x1F | 33 | #define OV772X_EDGE_STRENGTH_MASK 0x1F |
| 37 | #define EDGE_THRESHOLD_MASK 0x0F | 34 | #define OV772X_EDGE_THRESHOLD_MASK 0x0F |
| 38 | #define EDGE_UPPER_MASK 0xFF | 35 | #define OV772X_EDGE_UPPER_MASK 0xFF |
| 39 | #define EDGE_LOWER_MASK 0xFF | 36 | #define OV772X_EDGE_LOWER_MASK 0xFF |
| 40 | 37 | ||
| 41 | #define OV772X_AUTO_EDGECTRL(u, l) \ | 38 | #define OV772X_AUTO_EDGECTRL(u, l) \ |
| 42 | { \ | 39 | { \ |
| 43 | .upper = (u & EDGE_UPPER_MASK), \ | 40 | .upper = (u & OV772X_EDGE_UPPER_MASK), \ |
| 44 | .lower = (l & EDGE_LOWER_MASK), \ | 41 | .lower = (l & OV772X_EDGE_LOWER_MASK), \ |
| 45 | } | 42 | } |
| 46 | 43 | ||
| 47 | #define OV772X_MANUAL_EDGECTRL(s, t) \ | 44 | #define OV772X_MANUAL_EDGECTRL(s, t) \ |
| 48 | { \ | 45 | { \ |
| 49 | .strength = (s & EDGE_STRENGTH_MASK) | OV772X_MANUAL_EDGE_CTRL,\ | 46 | .strength = (s & OV772X_EDGE_STRENGTH_MASK) | \ |
| 50 | .threshold = (t & EDGE_THRESHOLD_MASK), \ | 47 | OV772X_MANUAL_EDGE_CTRL, \ |
| 48 | .threshold = (t & OV772X_EDGE_THRESHOLD_MASK), \ | ||
| 51 | } | 49 | } |
| 52 | 50 | ||
| 53 | /* | 51 | /* |
diff --git a/include/media/s5k6aa.h b/include/media/s5k6aa.h new file mode 100644 index 000000000000..ba34f7055e55 --- /dev/null +++ b/include/media/s5k6aa.h | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | /* | ||
| 2 | * S5K6AAFX camera sensor driver header | ||
| 3 | * | ||
| 4 | * Copyright (C) 2011 Samsung Electronics Co., Ltd. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #ifndef S5K6AA_H | ||
| 13 | #define S5K6AA_H | ||
| 14 | |||
| 15 | #include <media/v4l2-mediabus.h> | ||
| 16 | |||
| 17 | /** | ||
| 18 | * struct s5k6aa_gpio - data structure describing a GPIO | ||
| 19 | * @gpio: GPIO number | ||
| 20 | * @level: indicates active state of the @gpio | ||
| 21 | */ | ||
| 22 | struct s5k6aa_gpio { | ||
| 23 | int gpio; | ||
| 24 | int level; | ||
| 25 | }; | ||
| 26 | |||
| 27 | /** | ||
| 28 | * struct s5k6aa_platform_data - s5k6aa driver platform data | ||
| 29 | * @set_power: an additional callback to the board code, called | ||
| 30 | * after enabling the regulators and before switching | ||
| 31 | * the sensor off | ||
| 32 | * @mclk_frequency: sensor's master clock frequency in Hz | ||
| 33 | * @gpio_reset: GPIO driving RESET pin | ||
| 34 | * @gpio_stby: GPIO driving STBY pin | ||
| 35 | * @nlanes: maximum number of MIPI-CSI lanes used | ||
| 36 | * @horiz_flip: default horizontal image flip value, non zero to enable | ||
| 37 | * @vert_flip: default vertical image flip value, non zero to enable | ||
| 38 | */ | ||
| 39 | |||
| 40 | struct s5k6aa_platform_data { | ||
| 41 | int (*set_power)(int enable); | ||
| 42 | unsigned long mclk_frequency; | ||
| 43 | struct s5k6aa_gpio gpio_reset; | ||
| 44 | struct s5k6aa_gpio gpio_stby; | ||
| 45 | enum v4l2_mbus_type bus_type; | ||
| 46 | u8 nlanes; | ||
| 47 | u8 horiz_flip; | ||
| 48 | u8 vert_flip; | ||
| 49 | }; | ||
| 50 | |||
| 51 | #endif /* S5K6AA_H */ | ||
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index 7582952dceae..b1377b931eb7 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h | |||
| @@ -12,12 +12,14 @@ | |||
| 12 | #ifndef SOC_CAMERA_H | 12 | #ifndef SOC_CAMERA_H |
| 13 | #define SOC_CAMERA_H | 13 | #define SOC_CAMERA_H |
| 14 | 14 | ||
| 15 | #include <linux/bitops.h> | ||
| 15 | #include <linux/device.h> | 16 | #include <linux/device.h> |
| 16 | #include <linux/mutex.h> | 17 | #include <linux/mutex.h> |
| 17 | #include <linux/pm.h> | 18 | #include <linux/pm.h> |
| 18 | #include <linux/videodev2.h> | 19 | #include <linux/videodev2.h> |
| 19 | #include <media/videobuf-core.h> | 20 | #include <media/videobuf-core.h> |
| 20 | #include <media/videobuf2-core.h> | 21 | #include <media/videobuf2-core.h> |
| 22 | #include <media/v4l2-ctrls.h> | ||
| 21 | #include <media/v4l2-device.h> | 23 | #include <media/v4l2-device.h> |
| 22 | 24 | ||
| 23 | struct file; | 25 | struct file; |
| @@ -37,8 +39,8 @@ struct soc_camera_device { | |||
| 37 | unsigned char iface; /* Host number */ | 39 | unsigned char iface; /* Host number */ |
| 38 | unsigned char devnum; /* Device number per host */ | 40 | unsigned char devnum; /* Device number per host */ |
| 39 | struct soc_camera_sense *sense; /* See comment in struct definition */ | 41 | struct soc_camera_sense *sense; /* See comment in struct definition */ |
| 40 | struct soc_camera_ops *ops; | ||
| 41 | struct video_device *vdev; | 42 | struct video_device *vdev; |
| 43 | struct v4l2_ctrl_handler ctrl_handler; | ||
| 42 | const struct soc_camera_format_xlate *current_fmt; | 44 | const struct soc_camera_format_xlate *current_fmt; |
| 43 | struct soc_camera_format_xlate *user_formats; | 45 | struct soc_camera_format_xlate *user_formats; |
| 44 | int num_user_formats; | 46 | int num_user_formats; |
| @@ -93,14 +95,10 @@ struct soc_camera_host_ops { | |||
| 93 | int (*reqbufs)(struct soc_camera_device *, struct v4l2_requestbuffers *); | 95 | int (*reqbufs)(struct soc_camera_device *, struct v4l2_requestbuffers *); |
| 94 | int (*querycap)(struct soc_camera_host *, struct v4l2_capability *); | 96 | int (*querycap)(struct soc_camera_host *, struct v4l2_capability *); |
| 95 | int (*set_bus_param)(struct soc_camera_device *, __u32); | 97 | int (*set_bus_param)(struct soc_camera_device *, __u32); |
| 96 | int (*get_ctrl)(struct soc_camera_device *, struct v4l2_control *); | ||
| 97 | int (*set_ctrl)(struct soc_camera_device *, struct v4l2_control *); | ||
| 98 | int (*get_parm)(struct soc_camera_device *, struct v4l2_streamparm *); | 98 | int (*get_parm)(struct soc_camera_device *, struct v4l2_streamparm *); |
| 99 | int (*set_parm)(struct soc_camera_device *, struct v4l2_streamparm *); | 99 | int (*set_parm)(struct soc_camera_device *, struct v4l2_streamparm *); |
| 100 | int (*enum_fsizes)(struct soc_camera_device *, struct v4l2_frmsizeenum *); | 100 | int (*enum_fsizes)(struct soc_camera_device *, struct v4l2_frmsizeenum *); |
| 101 | unsigned int (*poll)(struct file *, poll_table *); | 101 | unsigned int (*poll)(struct file *, poll_table *); |
| 102 | const struct v4l2_queryctrl *controls; | ||
| 103 | int num_controls; | ||
| 104 | }; | 102 | }; |
| 105 | 103 | ||
| 106 | #define SOCAM_SENSOR_INVERT_PCLK (1 << 0) | 104 | #define SOCAM_SENSOR_INVERT_PCLK (1 << 0) |
| @@ -193,13 +191,6 @@ struct soc_camera_format_xlate { | |||
| 193 | const struct soc_mbus_pixelfmt *host_fmt; | 191 | const struct soc_mbus_pixelfmt *host_fmt; |
| 194 | }; | 192 | }; |
| 195 | 193 | ||
| 196 | struct soc_camera_ops { | ||
| 197 | unsigned long (*query_bus_param)(struct soc_camera_device *); | ||
| 198 | int (*set_bus_param)(struct soc_camera_device *, unsigned long); | ||
| 199 | const struct v4l2_queryctrl *controls; | ||
| 200 | int num_controls; | ||
| 201 | }; | ||
| 202 | |||
| 203 | #define SOCAM_SENSE_PCLK_CHANGED (1 << 0) | 194 | #define SOCAM_SENSE_PCLK_CHANGED (1 << 0) |
| 204 | 195 | ||
| 205 | /** | 196 | /** |
| @@ -226,65 +217,18 @@ struct soc_camera_sense { | |||
| 226 | unsigned long pixel_clock; | 217 | unsigned long pixel_clock; |
| 227 | }; | 218 | }; |
| 228 | 219 | ||
| 229 | static inline struct v4l2_queryctrl const *soc_camera_find_qctrl( | 220 | #define SOCAM_DATAWIDTH(x) BIT((x) - 1) |
| 230 | struct soc_camera_ops *ops, int id) | 221 | #define SOCAM_DATAWIDTH_4 SOCAM_DATAWIDTH(4) |
| 231 | { | 222 | #define SOCAM_DATAWIDTH_8 SOCAM_DATAWIDTH(8) |
| 232 | int i; | 223 | #define SOCAM_DATAWIDTH_9 SOCAM_DATAWIDTH(9) |
| 233 | 224 | #define SOCAM_DATAWIDTH_10 SOCAM_DATAWIDTH(10) | |
| 234 | for (i = 0; i < ops->num_controls; i++) | 225 | #define SOCAM_DATAWIDTH_15 SOCAM_DATAWIDTH(15) |
| 235 | if (ops->controls[i].id == id) | 226 | #define SOCAM_DATAWIDTH_16 SOCAM_DATAWIDTH(16) |
| 236 | return &ops->controls[i]; | ||
| 237 | |||
| 238 | return NULL; | ||
| 239 | } | ||
| 240 | |||
| 241 | #define SOCAM_MASTER (1 << 0) | ||
| 242 | #define SOCAM_SLAVE (1 << 1) | ||
| 243 | #define SOCAM_HSYNC_ACTIVE_HIGH (1 << 2) | ||
| 244 | #define SOCAM_HSYNC_ACTIVE_LOW (1 << 3) | ||
| 245 | #define SOCAM_VSYNC_ACTIVE_HIGH (1 << 4) | ||
| 246 | #define SOCAM_VSYNC_ACTIVE_LOW (1 << 5) | ||
| 247 | #define SOCAM_DATAWIDTH_4 (1 << 6) | ||
| 248 | #define SOCAM_DATAWIDTH_8 (1 << 7) | ||
| 249 | #define SOCAM_DATAWIDTH_9 (1 << 8) | ||
| 250 | #define SOCAM_DATAWIDTH_10 (1 << 9) | ||
| 251 | #define SOCAM_DATAWIDTH_15 (1 << 10) | ||
| 252 | #define SOCAM_DATAWIDTH_16 (1 << 11) | ||
| 253 | #define SOCAM_PCLK_SAMPLE_RISING (1 << 12) | ||
| 254 | #define SOCAM_PCLK_SAMPLE_FALLING (1 << 13) | ||
| 255 | #define SOCAM_DATA_ACTIVE_HIGH (1 << 14) | ||
| 256 | #define SOCAM_DATA_ACTIVE_LOW (1 << 15) | ||
| 257 | #define SOCAM_MIPI_1LANE (1 << 16) | ||
| 258 | #define SOCAM_MIPI_2LANE (1 << 17) | ||
| 259 | #define SOCAM_MIPI_3LANE (1 << 18) | ||
| 260 | #define SOCAM_MIPI_4LANE (1 << 19) | ||
| 261 | #define SOCAM_MIPI (SOCAM_MIPI_1LANE | SOCAM_MIPI_2LANE | \ | ||
| 262 | SOCAM_MIPI_3LANE | SOCAM_MIPI_4LANE) | ||
| 263 | 227 | ||
| 264 | #define SOCAM_DATAWIDTH_MASK (SOCAM_DATAWIDTH_4 | SOCAM_DATAWIDTH_8 | \ | 228 | #define SOCAM_DATAWIDTH_MASK (SOCAM_DATAWIDTH_4 | SOCAM_DATAWIDTH_8 | \ |
| 265 | SOCAM_DATAWIDTH_9 | SOCAM_DATAWIDTH_10 | \ | 229 | SOCAM_DATAWIDTH_9 | SOCAM_DATAWIDTH_10 | \ |
| 266 | SOCAM_DATAWIDTH_15 | SOCAM_DATAWIDTH_16) | 230 | SOCAM_DATAWIDTH_15 | SOCAM_DATAWIDTH_16) |
| 267 | 231 | ||
| 268 | static inline unsigned long soc_camera_bus_param_compatible( | ||
| 269 | unsigned long camera_flags, unsigned long bus_flags) | ||
| 270 | { | ||
| 271 | unsigned long common_flags, hsync, vsync, pclk, data, buswidth, mode; | ||
| 272 | unsigned long mipi; | ||
| 273 | |||
| 274 | common_flags = camera_flags & bus_flags; | ||
| 275 | |||
| 276 | hsync = common_flags & (SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW); | ||
| 277 | vsync = common_flags & (SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW); | ||
| 278 | pclk = common_flags & (SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING); | ||
| 279 | data = common_flags & (SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_LOW); | ||
| 280 | mode = common_flags & (SOCAM_MASTER | SOCAM_SLAVE); | ||
| 281 | buswidth = common_flags & SOCAM_DATAWIDTH_MASK; | ||
| 282 | mipi = common_flags & SOCAM_MIPI; | ||
| 283 | |||
| 284 | return ((!hsync || !vsync || !pclk || !data || !mode || !buswidth) && !mipi) ? 0 : | ||
| 285 | common_flags; | ||
| 286 | } | ||
| 287 | |||
| 288 | static inline void soc_camera_limit_side(int *start, int *length, | 232 | static inline void soc_camera_limit_side(int *start, int *length, |
| 289 | unsigned int start_min, | 233 | unsigned int start_min, |
| 290 | unsigned int length_min, unsigned int length_max) | 234 | unsigned int length_min, unsigned int length_max) |
| @@ -300,23 +244,37 @@ static inline void soc_camera_limit_side(int *start, int *length, | |||
| 300 | *start = start_min + length_max - *length; | 244 | *start = start_min + length_max - *length; |
| 301 | } | 245 | } |
| 302 | 246 | ||
| 303 | extern unsigned long soc_camera_apply_sensor_flags(struct soc_camera_link *icl, | 247 | unsigned long soc_camera_apply_sensor_flags(struct soc_camera_link *icl, |
| 304 | unsigned long flags); | 248 | unsigned long flags); |
| 249 | unsigned long soc_camera_apply_board_flags(struct soc_camera_link *icl, | ||
| 250 | const struct v4l2_mbus_config *cfg); | ||
| 305 | 251 | ||
| 306 | /* This is only temporary here - until v4l2-subdev begins to link to video_device */ | 252 | /* This is only temporary here - until v4l2-subdev begins to link to video_device */ |
| 307 | #include <linux/i2c.h> | 253 | #include <linux/i2c.h> |
| 308 | static inline struct video_device *soc_camera_i2c_to_vdev(struct i2c_client *client) | 254 | static inline struct video_device *soc_camera_i2c_to_vdev(const struct i2c_client *client) |
| 255 | { | ||
| 256 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | ||
| 257 | struct soc_camera_device *icd = (struct soc_camera_device *)sd->grp_id; | ||
| 258 | return icd ? icd->vdev : NULL; | ||
| 259 | } | ||
| 260 | |||
| 261 | static inline struct soc_camera_link *soc_camera_i2c_to_link(const struct i2c_client *client) | ||
| 262 | { | ||
| 263 | return client->dev.platform_data; | ||
| 264 | } | ||
| 265 | |||
| 266 | static inline struct v4l2_subdev *soc_camera_vdev_to_subdev(const struct video_device *vdev) | ||
| 309 | { | 267 | { |
| 310 | struct soc_camera_device *icd = client->dev.platform_data; | 268 | struct soc_camera_device *icd = dev_get_drvdata(vdev->parent); |
| 311 | return icd->vdev; | 269 | return soc_camera_to_subdev(icd); |
| 312 | } | 270 | } |
| 313 | 271 | ||
| 314 | static inline struct soc_camera_device *soc_camera_from_vb2q(struct vb2_queue *vq) | 272 | static inline struct soc_camera_device *soc_camera_from_vb2q(const struct vb2_queue *vq) |
| 315 | { | 273 | { |
| 316 | return container_of(vq, struct soc_camera_device, vb2_vidq); | 274 | return container_of(vq, struct soc_camera_device, vb2_vidq); |
| 317 | } | 275 | } |
| 318 | 276 | ||
| 319 | static inline struct soc_camera_device *soc_camera_from_vbq(struct videobuf_queue *vq) | 277 | static inline struct soc_camera_device *soc_camera_from_vbq(const struct videobuf_queue *vq) |
| 320 | { | 278 | { |
| 321 | return container_of(vq, struct soc_camera_device, vb_vidq); | 279 | return container_of(vq, struct soc_camera_device, vb_vidq); |
| 322 | } | 280 | } |
diff --git a/include/media/soc_camera_platform.h b/include/media/soc_camera_platform.h index 74f0fa15ca47..8aa4200a0b1d 100644 --- a/include/media/soc_camera_platform.h +++ b/include/media/soc_camera_platform.h | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | 13 | ||
| 14 | #include <linux/videodev2.h> | 14 | #include <linux/videodev2.h> |
| 15 | #include <media/soc_camera.h> | 15 | #include <media/soc_camera.h> |
| 16 | #include <media/v4l2-mediabus.h> | ||
| 16 | 17 | ||
| 17 | struct device; | 18 | struct device; |
| 18 | 19 | ||
| @@ -20,7 +21,8 @@ struct soc_camera_platform_info { | |||
| 20 | const char *format_name; | 21 | const char *format_name; |
| 21 | unsigned long format_depth; | 22 | unsigned long format_depth; |
| 22 | struct v4l2_mbus_framefmt format; | 23 | struct v4l2_mbus_framefmt format; |
| 23 | unsigned long bus_param; | 24 | unsigned long mbus_param; |
| 25 | enum v4l2_mbus_type mbus_type; | ||
| 24 | struct soc_camera_device *icd; | 26 | struct soc_camera_device *icd; |
| 25 | int (*set_capture)(struct soc_camera_platform_info *info, int enable); | 27 | int (*set_capture)(struct soc_camera_platform_info *info, int enable); |
| 26 | }; | 28 | }; |
diff --git a/include/media/soc_mediabus.h b/include/media/soc_mediabus.h index fae432544b41..73f1e7eb60f3 100644 --- a/include/media/soc_mediabus.h +++ b/include/media/soc_mediabus.h | |||
| @@ -82,5 +82,7 @@ const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc( | |||
| 82 | s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf); | 82 | s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf); |
| 83 | int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf, | 83 | int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf, |
| 84 | unsigned int *numerator, unsigned int *denominator); | 84 | unsigned int *numerator, unsigned int *denominator); |
| 85 | unsigned int soc_mbus_config_compatible(const struct v4l2_mbus_config *cfg, | ||
| 86 | unsigned int flags); | ||
| 85 | 87 | ||
| 86 | #endif | 88 | #endif |
diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index dd9f1e7b8ff7..4d1c74ad4c84 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h | |||
| @@ -122,6 +122,8 @@ struct v4l2_ioctl_ops { | |||
| 122 | int (*vidioc_qbuf) (struct file *file, void *fh, struct v4l2_buffer *b); | 122 | int (*vidioc_qbuf) (struct file *file, void *fh, struct v4l2_buffer *b); |
| 123 | int (*vidioc_dqbuf) (struct file *file, void *fh, struct v4l2_buffer *b); | 123 | int (*vidioc_dqbuf) (struct file *file, void *fh, struct v4l2_buffer *b); |
| 124 | 124 | ||
| 125 | int (*vidioc_create_bufs)(struct file *file, void *fh, struct v4l2_create_buffers *b); | ||
| 126 | int (*vidioc_prepare_buf)(struct file *file, void *fh, struct v4l2_buffer *b); | ||
| 125 | 127 | ||
| 126 | int (*vidioc_overlay) (struct file *file, void *fh, unsigned int i); | 128 | int (*vidioc_overlay) (struct file *file, void *fh, unsigned int i); |
| 127 | int (*vidioc_g_fbuf) (struct file *file, void *fh, | 129 | int (*vidioc_g_fbuf) (struct file *file, void *fh, |
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 257da1a30f66..f0f3358d1b1b 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h | |||
| @@ -158,6 +158,7 @@ struct v4l2_subdev_core_ops { | |||
| 158 | int (*s_ext_ctrls)(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls); | 158 | int (*s_ext_ctrls)(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls); |
| 159 | int (*try_ext_ctrls)(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls); | 159 | int (*try_ext_ctrls)(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls); |
| 160 | int (*querymenu)(struct v4l2_subdev *sd, struct v4l2_querymenu *qm); | 160 | int (*querymenu)(struct v4l2_subdev *sd, struct v4l2_querymenu *qm); |
| 161 | int (*g_std)(struct v4l2_subdev *sd, v4l2_std_id *norm); | ||
| 161 | int (*s_std)(struct v4l2_subdev *sd, v4l2_std_id norm); | 162 | int (*s_std)(struct v4l2_subdev *sd, v4l2_std_id norm); |
| 162 | long (*ioctl)(struct v4l2_subdev *sd, unsigned int cmd, void *arg); | 163 | long (*ioctl)(struct v4l2_subdev *sd, unsigned int cmd, void *arg); |
| 163 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 164 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
| @@ -534,13 +535,13 @@ struct v4l2_subdev { | |||
| 534 | void *dev_priv; | 535 | void *dev_priv; |
| 535 | void *host_priv; | 536 | void *host_priv; |
| 536 | /* subdev device node */ | 537 | /* subdev device node */ |
| 537 | struct video_device devnode; | 538 | struct video_device *devnode; |
| 538 | }; | 539 | }; |
| 539 | 540 | ||
| 540 | #define media_entity_to_v4l2_subdev(ent) \ | 541 | #define media_entity_to_v4l2_subdev(ent) \ |
| 541 | container_of(ent, struct v4l2_subdev, entity) | 542 | container_of(ent, struct v4l2_subdev, entity) |
| 542 | #define vdev_to_v4l2_subdev(vdev) \ | 543 | #define vdev_to_v4l2_subdev(vdev) \ |
| 543 | container_of(vdev, struct v4l2_subdev, devnode) | 544 | video_get_drvdata(vdev) |
| 544 | 545 | ||
| 545 | /* | 546 | /* |
| 546 | * Used for storing subdev information per file handle | 547 | * Used for storing subdev information per file handle |
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index ea55c08eddfb..a15d1f1b319e 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h | |||
| @@ -105,6 +105,7 @@ enum vb2_fileio_flags { | |||
| 105 | /** | 105 | /** |
| 106 | * enum vb2_buffer_state - current video buffer state | 106 | * enum vb2_buffer_state - current video buffer state |
| 107 | * @VB2_BUF_STATE_DEQUEUED: buffer under userspace control | 107 | * @VB2_BUF_STATE_DEQUEUED: buffer under userspace control |
| 108 | * @VB2_BUF_STATE_PREPARED: buffer prepared in videobuf and by the driver | ||
| 108 | * @VB2_BUF_STATE_QUEUED: buffer queued in videobuf, but not in driver | 109 | * @VB2_BUF_STATE_QUEUED: buffer queued in videobuf, but not in driver |
| 109 | * @VB2_BUF_STATE_ACTIVE: buffer queued in driver and possibly used | 110 | * @VB2_BUF_STATE_ACTIVE: buffer queued in driver and possibly used |
| 110 | * in a hardware operation | 111 | * in a hardware operation |
| @@ -116,6 +117,7 @@ enum vb2_fileio_flags { | |||
| 116 | */ | 117 | */ |
| 117 | enum vb2_buffer_state { | 118 | enum vb2_buffer_state { |
| 118 | VB2_BUF_STATE_DEQUEUED, | 119 | VB2_BUF_STATE_DEQUEUED, |
| 120 | VB2_BUF_STATE_PREPARED, | ||
| 119 | VB2_BUF_STATE_QUEUED, | 121 | VB2_BUF_STATE_QUEUED, |
| 120 | VB2_BUF_STATE_ACTIVE, | 122 | VB2_BUF_STATE_ACTIVE, |
| 121 | VB2_BUF_STATE_DONE, | 123 | VB2_BUF_STATE_DONE, |
| @@ -167,13 +169,21 @@ struct vb2_buffer { | |||
| 167 | /** | 169 | /** |
| 168 | * struct vb2_ops - driver-specific callbacks | 170 | * struct vb2_ops - driver-specific callbacks |
| 169 | * | 171 | * |
| 170 | * @queue_setup: called from a VIDIOC_REQBUFS handler, before | 172 | * @queue_setup: called from VIDIOC_REQBUFS and VIDIOC_CREATE_BUFS |
| 171 | * memory allocation; driver should return the required | 173 | * handlers before memory allocation, or, if |
| 172 | * number of buffers in num_buffers, the required number | 174 | * *num_planes != 0, after the allocation to verify a |
| 173 | * of planes per buffer in num_planes; the size of each | 175 | * smaller number of buffers. Driver should return |
| 174 | * plane should be set in the sizes[] array and optional | 176 | * the required number of buffers in *num_buffers, the |
| 175 | * per-plane allocator specific context in alloc_ctxs[] | 177 | * required number of planes per buffer in *num_planes; the |
| 176 | * array | 178 | * size of each plane should be set in the sizes[] array |
| 179 | * and optional per-plane allocator specific context in the | ||
| 180 | * alloc_ctxs[] array. When called from VIDIOC_REQBUFS, | ||
| 181 | * fmt == NULL, the driver has to use the currently | ||
| 182 | * configured format and *num_buffers is the total number | ||
| 183 | * of buffers, that are being allocated. When called from | ||
| 184 | * VIDIOC_CREATE_BUFS, fmt != NULL and it describes the | ||
| 185 | * target frame format. In this case *num_buffers are being | ||
| 186 | * allocated additionally to q->num_buffers. | ||
| 177 | * @wait_prepare: release any locks taken while calling vb2 functions; | 187 | * @wait_prepare: release any locks taken while calling vb2 functions; |
| 178 | * it is called before an ioctl needs to wait for a new | 188 | * it is called before an ioctl needs to wait for a new |
| 179 | * buffer to arrive; required to avoid a deadlock in | 189 | * buffer to arrive; required to avoid a deadlock in |
| @@ -186,11 +196,11 @@ struct vb2_buffer { | |||
| 186 | * perform additional buffer-related initialization; | 196 | * perform additional buffer-related initialization; |
| 187 | * initialization failure (return != 0) will prevent | 197 | * initialization failure (return != 0) will prevent |
| 188 | * queue setup from completing successfully; optional | 198 | * queue setup from completing successfully; optional |
| 189 | * @buf_prepare: called every time the buffer is queued from userspace; | 199 | * @buf_prepare: called every time the buffer is queued from userspace |
| 190 | * drivers may perform any initialization required before | 200 | * and from the VIDIOC_PREPARE_BUF ioctl; drivers may |
| 191 | * each hardware operation in this callback; | 201 | * perform any initialization required before each hardware |
| 192 | * if an error is returned, the buffer will not be queued | 202 | * operation in this callback; if an error is returned, the |
| 193 | * in driver; optional | 203 | * buffer will not be queued in driver; optional |
| 194 | * @buf_finish: called before every dequeue of the buffer back to | 204 | * @buf_finish: called before every dequeue of the buffer back to |
| 195 | * userspace; drivers may perform any operations required | 205 | * userspace; drivers may perform any operations required |
| 196 | * before userspace accesses the buffer; optional | 206 | * before userspace accesses the buffer; optional |
| @@ -216,9 +226,9 @@ struct vb2_buffer { | |||
| 216 | * pre-queued buffers before calling STREAMON | 226 | * pre-queued buffers before calling STREAMON |
| 217 | */ | 227 | */ |
| 218 | struct vb2_ops { | 228 | struct vb2_ops { |
| 219 | int (*queue_setup)(struct vb2_queue *q, unsigned int *num_buffers, | 229 | int (*queue_setup)(struct vb2_queue *q, const struct v4l2_format *fmt, |
| 220 | unsigned int *num_planes, unsigned int sizes[], | 230 | unsigned int *num_buffers, unsigned int *num_planes, |
| 221 | void *alloc_ctxs[]); | 231 | unsigned int sizes[], void *alloc_ctxs[]); |
| 222 | 232 | ||
| 223 | void (*wait_prepare)(struct vb2_queue *q); | 233 | void (*wait_prepare)(struct vb2_queue *q); |
| 224 | void (*wait_finish)(struct vb2_queue *q); | 234 | void (*wait_finish)(struct vb2_queue *q); |
| @@ -298,6 +308,9 @@ int vb2_wait_for_all_buffers(struct vb2_queue *q); | |||
| 298 | int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b); | 308 | int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b); |
| 299 | int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req); | 309 | int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req); |
| 300 | 310 | ||
| 311 | int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create); | ||
| 312 | int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b); | ||
| 313 | |||
| 301 | int vb2_queue_init(struct vb2_queue *q); | 314 | int vb2_queue_init(struct vb2_queue *q); |
| 302 | 315 | ||
| 303 | void vb2_queue_release(struct vb2_queue *q); | 316 | void vb2_queue_release(struct vb2_queue *q); |
| @@ -309,6 +322,13 @@ int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type); | |||
| 309 | int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type); | 322 | int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type); |
| 310 | 323 | ||
| 311 | int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma); | 324 | int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma); |
| 325 | #ifndef CONFIG_MMU | ||
| 326 | unsigned long vb2_get_unmapped_area(struct vb2_queue *q, | ||
| 327 | unsigned long addr, | ||
| 328 | unsigned long len, | ||
| 329 | unsigned long pgoff, | ||
| 330 | unsigned long flags); | ||
| 331 | #endif | ||
| 312 | unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait); | 332 | unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait); |
| 313 | size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count, | 333 | size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count, |
| 314 | loff_t *ppos, int nonblock); | 334 | loff_t *ppos, int nonblock); |
