diff options
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); |