diff options
author | Benjamin Gaignard <benjamin.gaignard@linaro.org> | 2016-07-29 03:38:55 -0400 |
---|---|---|
committer | Benjamin Gaignard <benjamin.gaignard@linaro.org> | 2016-07-29 03:38:55 -0400 |
commit | 62c2cd0f49333a2bb53602ec23039ca99a19cb9d (patch) | |
tree | 82ce682c6902ebe63275a60bdc3d406b26f09c84 | |
parent | a1f5524a66ff6284d1380cdd7723de82698ff9d3 (diff) | |
parent | 894dde5c5d1c6d33c4bd3d4384c6cf0aff3f8015 (diff) |
Merge remote-tracking branch 'media_tree/vsp1' into generic-zpos-v8
122 files changed, 7425 insertions, 7051 deletions
diff --git a/Documentation/DocBook/media/v4l/media-types.xml b/Documentation/DocBook/media/v4l/media-types.xml index 5e3f20fdcf17..95aa1f9c836a 100644 --- a/Documentation/DocBook/media/v4l/media-types.xml +++ b/Documentation/DocBook/media/v4l/media-types.xml | |||
@@ -121,6 +121,70 @@ | |||
121 | <entry><constant>MEDIA_ENT_F_AUDIO_MIXER</constant></entry> | 121 | <entry><constant>MEDIA_ENT_F_AUDIO_MIXER</constant></entry> |
122 | <entry>Audio Mixer Function Entity.</entry> | 122 | <entry>Audio Mixer Function Entity.</entry> |
123 | </row> | 123 | </row> |
124 | <row> | ||
125 | <entry><constant>MEDIA_ENT_F_PROC_VIDEO_COMPOSER</constant></entry> | ||
126 | <entry>Video composer (blender). An entity capable of video | ||
127 | composing must have at least two sink pads and one source | ||
128 | pad, and composes input video frames onto output video | ||
129 | frames. Composition can be performed using alpha blending, | ||
130 | color keying, raster operations (ROP), stitching or any other | ||
131 | means. | ||
132 | </entry> | ||
133 | </row> | ||
134 | <row> | ||
135 | <entry><constant>MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER</constant></entry> | ||
136 | <entry>Video pixel formatter. An entity capable of pixel formatting | ||
137 | must have at least one sink pad and one source pad. Read | ||
138 | pixel formatters read pixels from memory and perform a subset | ||
139 | of unpacking, cropping, color keying, alpha multiplication | ||
140 | and pixel encoding conversion. Write pixel formatters perform | ||
141 | a subset of dithering, pixel encoding conversion and packing | ||
142 | and write pixels to memory. | ||
143 | </entry> | ||
144 | </row> | ||
145 | <row> | ||
146 | <entry><constant>MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV</constant></entry> | ||
147 | <entry>Video pixel encoding converter. An entity capable of pixel | ||
148 | enconding conversion must have at least one sink pad and one | ||
149 | source pad, and convert the encoding of pixels received on | ||
150 | its sink pad(s) to a different encoding output on its source | ||
151 | pad(s). Pixel encoding conversion includes but isn't limited | ||
152 | to RGB to/from HSV, RGB to/from YUV and CFA (Bayer) to RGB | ||
153 | conversions. | ||
154 | </entry> | ||
155 | </row> | ||
156 | <row> | ||
157 | <entry><constant>MEDIA_ENT_F_PROC_VIDEO_LUT</constant></entry> | ||
158 | <entry>Video look-up table. An entity capable of video lookup table | ||
159 | processing must have one sink pad and one source pad. It uses | ||
160 | the values of the pixels received on its sink pad to look up | ||
161 | entries in internal tables and output them on its source pad. | ||
162 | The lookup processing can be performed on all components | ||
163 | separately or combine them for multi-dimensional table | ||
164 | lookups. | ||
165 | </entry> | ||
166 | </row> | ||
167 | <row> | ||
168 | <entry><constant>MEDIA_ENT_F_PROC_VIDEO_SCALER</constant></entry> | ||
169 | <entry>Video scaler. An entity capable of video scaling must have | ||
170 | at least one sink pad and one source pad, and scale the | ||
171 | video frame(s) received on its sink pad(s) to a different | ||
172 | resolution output on its source pad(s). The range of | ||
173 | supported scaling ratios is entity-specific and can differ | ||
174 | between the horizontal and vertical directions (in particular | ||
175 | scaling can be supported in one direction only). Binning and | ||
176 | skipping are considered as scaling. | ||
177 | </entry> | ||
178 | </row> | ||
179 | <row> | ||
180 | <entry><constant>MEDIA_ENT_F_PROC_VIDEO_STATISTICS</constant></entry> | ||
181 | <entry>Video statistics computation (histogram, 3A, ...). An entity | ||
182 | capable of statistics computation must have one sink pad and | ||
183 | one source pad. It computes statistics over the frames | ||
184 | received on its sink pad and outputs the statistics data on | ||
185 | its source pad. | ||
186 | </entry> | ||
187 | </row> | ||
124 | </tbody> | 188 | </tbody> |
125 | </tgroup> | 189 | </tgroup> |
126 | </table> | 190 | </table> |
diff --git a/Documentation/devicetree/bindings/media/mediatek-vpu.txt b/Documentation/devicetree/bindings/media/mediatek-vpu.txt new file mode 100644 index 000000000000..2a5bac37f9a2 --- /dev/null +++ b/Documentation/devicetree/bindings/media/mediatek-vpu.txt | |||
@@ -0,0 +1,31 @@ | |||
1 | * Mediatek Video Processor Unit | ||
2 | |||
3 | Video Processor Unit is a HW video controller. It controls HW Codec including | ||
4 | H.264/VP8/VP9 Decode, H.264/VP8 Encode and Image Processor (scale/rotate/color convert). | ||
5 | |||
6 | Required properties: | ||
7 | - compatible: "mediatek,mt8173-vpu" | ||
8 | - reg: Must contain an entry for each entry in reg-names. | ||
9 | - reg-names: Must include the following entries: | ||
10 | "tcm": tcm base | ||
11 | "cfg_reg": Main configuration registers base | ||
12 | - interrupts: interrupt number to the cpu. | ||
13 | - clocks : clock name from clock manager | ||
14 | - clock-names: must be main. It is the main clock of VPU | ||
15 | |||
16 | Optional properties: | ||
17 | - memory-region: phandle to a node describing memory (see | ||
18 | Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt) | ||
19 | to be used for VPU extended memory; if not present, VPU may be located | ||
20 | anywhere in the memory | ||
21 | |||
22 | Example: | ||
23 | vpu: vpu@10020000 { | ||
24 | compatible = "mediatek,mt8173-vpu"; | ||
25 | reg = <0 0x10020000 0 0x30000>, | ||
26 | <0 0x10050000 0 0x100>; | ||
27 | reg-names = "tcm", "cfg_reg"; | ||
28 | interrupts = <GIC_SPI 166 IRQ_TYPE_LEVEL_HIGH>; | ||
29 | clocks = <&topckgen TOP_SCP_SEL>; | ||
30 | clock-names = "main"; | ||
31 | }; | ||
diff --git a/Documentation/devicetree/bindings/media/renesas,fcp.txt b/Documentation/devicetree/bindings/media/renesas,fcp.txt new file mode 100644 index 000000000000..6a12960609d8 --- /dev/null +++ b/Documentation/devicetree/bindings/media/renesas,fcp.txt | |||
@@ -0,0 +1,32 @@ | |||
1 | Renesas R-Car Frame Compression Processor (FCP) | ||
2 | ----------------------------------------------- | ||
3 | |||
4 | The FCP is a companion module of video processing modules in the Renesas R-Car | ||
5 | Gen3 SoCs. It provides data compression and decompression, data caching, and | ||
6 | conversion of AXI transactions in order to reduce the memory bandwidth. | ||
7 | |||
8 | There are three types of FCP: FCP for Codec (FCPC), FCP for VSP (FCPV) and FCP | ||
9 | for FDP (FCPF). Their configuration and behaviour depend on the module they | ||
10 | are paired with. These DT bindings currently support the FCPV only. | ||
11 | |||
12 | - compatible: Must be one or more of the following | ||
13 | |||
14 | - "renesas,r8a7795-fcpv" for R8A7795 (R-Car H3) compatible 'FCP for VSP' | ||
15 | - "renesas,fcpv" for generic compatible 'FCP for VSP' | ||
16 | |||
17 | When compatible with the generic version, nodes must list the | ||
18 | SoC-specific version corresponding to the platform first, followed by the | ||
19 | family-specific and/or generic versions. | ||
20 | |||
21 | - reg: the register base and size for the device registers | ||
22 | - clocks: Reference to the functional clock | ||
23 | |||
24 | |||
25 | Device node example | ||
26 | ------------------- | ||
27 | |||
28 | fcpvd1: fcp@fea2f000 { | ||
29 | compatible = "renesas,r8a7795-fcpv", "renesas,fcpv"; | ||
30 | reg = <0 0xfea2f000 0 0x200>; | ||
31 | clocks = <&cpg CPG_MOD 602>; | ||
32 | }; | ||
diff --git a/Documentation/devicetree/bindings/media/renesas,vsp1.txt b/Documentation/devicetree/bindings/media/renesas,vsp1.txt index 627405abd144..9b695bcbf219 100644 --- a/Documentation/devicetree/bindings/media/renesas,vsp1.txt +++ b/Documentation/devicetree/bindings/media/renesas,vsp1.txt | |||
@@ -14,6 +14,11 @@ Required properties: | |||
14 | - interrupts: VSP interrupt specifier. | 14 | - interrupts: VSP interrupt specifier. |
15 | - clocks: A phandle + clock-specifier pair for the VSP functional clock. | 15 | - clocks: A phandle + clock-specifier pair for the VSP functional clock. |
16 | 16 | ||
17 | Optional properties: | ||
18 | |||
19 | - renesas,fcp: A phandle referencing the FCP that handles memory accesses | ||
20 | for the VSP. Not needed on Gen2, mandatory on Gen3. | ||
21 | |||
17 | 22 | ||
18 | Example: R8A7790 (R-Car H2) VSP1-S node | 23 | Example: R8A7790 (R-Car H2) VSP1-S node |
19 | 24 | ||
diff --git a/Documentation/devicetree/bindings/media/s5p-mfc.txt b/Documentation/devicetree/bindings/media/s5p-mfc.txt index 2d5787eac91a..92c94f5ecbf1 100644 --- a/Documentation/devicetree/bindings/media/s5p-mfc.txt +++ b/Documentation/devicetree/bindings/media/s5p-mfc.txt | |||
@@ -21,15 +21,18 @@ Required properties: | |||
21 | - clock-names : from common clock binding: must contain "mfc", | 21 | - clock-names : from common clock binding: must contain "mfc", |
22 | corresponding to entry in the clocks property. | 22 | corresponding to entry in the clocks property. |
23 | 23 | ||
24 | - samsung,mfc-r : Base address of the first memory bank used by MFC | ||
25 | for DMA contiguous memory allocation and its size. | ||
26 | |||
27 | - samsung,mfc-l : Base address of the second memory bank used by MFC | ||
28 | for DMA contiguous memory allocation and its size. | ||
29 | |||
30 | Optional properties: | 24 | Optional properties: |
31 | - power-domains : power-domain property defined with a phandle | 25 | - power-domains : power-domain property defined with a phandle |
32 | to respective power domain. | 26 | to respective power domain. |
27 | - memory-region : from reserved memory binding: phandles to two reserved | ||
28 | memory regions, first is for "left" mfc memory bus interfaces, | ||
29 | second if for the "right" mfc memory bus, used when no SYSMMU | ||
30 | support is available | ||
31 | |||
32 | Obsolete properties: | ||
33 | - samsung,mfc-r, samsung,mfc-l : support removed, please use memory-region | ||
34 | property instead | ||
35 | |||
33 | 36 | ||
34 | Example: | 37 | Example: |
35 | SoC specific DT entry: | 38 | SoC specific DT entry: |
@@ -43,9 +46,29 @@ mfc: codec@13400000 { | |||
43 | clock-names = "mfc"; | 46 | clock-names = "mfc"; |
44 | }; | 47 | }; |
45 | 48 | ||
49 | Reserved memory specific DT entry for given board (see reserved memory binding | ||
50 | for more information): | ||
51 | |||
52 | reserved-memory { | ||
53 | #address-cells = <1>; | ||
54 | #size-cells = <1>; | ||
55 | ranges; | ||
56 | |||
57 | mfc_left: region@51000000 { | ||
58 | compatible = "shared-dma-pool"; | ||
59 | no-map; | ||
60 | reg = <0x51000000 0x800000>; | ||
61 | }; | ||
62 | |||
63 | mfc_right: region@43000000 { | ||
64 | compatible = "shared-dma-pool"; | ||
65 | no-map; | ||
66 | reg = <0x43000000 0x800000>; | ||
67 | }; | ||
68 | }; | ||
69 | |||
46 | Board specific DT entry: | 70 | Board specific DT entry: |
47 | 71 | ||
48 | codec@13400000 { | 72 | codec@13400000 { |
49 | samsung,mfc-r = <0x43000000 0x800000>; | 73 | memory-region = <&mfc_left>, <&mfc_right>; |
50 | samsung,mfc-l = <0x51000000 0x800000>; | ||
51 | }; | 74 | }; |
diff --git a/MAINTAINERS b/MAINTAINERS index ea8c7ab56cf5..6fc95411d705 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -7357,6 +7357,16 @@ L: linux-iio@vger.kernel.org | |||
7357 | S: Maintained | 7357 | S: Maintained |
7358 | F: drivers/iio/potentiometer/mcp4531.c | 7358 | F: drivers/iio/potentiometer/mcp4531.c |
7359 | 7359 | ||
7360 | MEDIA DRIVERS FOR RENESAS - FCP | ||
7361 | M: Laurent Pinchart <laurent.pinchart@ideasonboard.com> | ||
7362 | L: linux-media@vger.kernel.org | ||
7363 | L: linux-renesas-soc@vger.kernel.org | ||
7364 | T: git git://linuxtv.org/media_tree.git | ||
7365 | S: Supported | ||
7366 | F: Documentation/devicetree/bindings/media/renesas,fcp.txt | ||
7367 | F: drivers/media/platform/rcar-fcp.c | ||
7368 | F: include/media/rcar-fcp.h | ||
7369 | |||
7360 | MEDIA DRIVERS FOR RENESAS - VSP1 | 7370 | MEDIA DRIVERS FOR RENESAS - VSP1 |
7361 | M: Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 7371 | M: Laurent Pinchart <laurent.pinchart@ideasonboard.com> |
7362 | L: linux-media@vger.kernel.org | 7372 | L: linux-media@vger.kernel.org |
@@ -7366,8 +7376,18 @@ S: Supported | |||
7366 | F: Documentation/devicetree/bindings/media/renesas,vsp1.txt | 7376 | F: Documentation/devicetree/bindings/media/renesas,vsp1.txt |
7367 | F: drivers/media/platform/vsp1/ | 7377 | F: drivers/media/platform/vsp1/ |
7368 | 7378 | ||
7379 | MEDIA DRIVERS FOR HELENE | ||
7380 | M: Abylay Ospan <aospan@netup.ru> | ||
7381 | L: linux-media@vger.kernel.org | ||
7382 | W: https://linuxtv.org | ||
7383 | W: http://netup.tv/ | ||
7384 | T: git git://linuxtv.org/media_tree.git | ||
7385 | S: Supported | ||
7386 | F: drivers/media/dvb-frontends/helene* | ||
7387 | |||
7369 | MEDIA DRIVERS FOR ASCOT2E | 7388 | MEDIA DRIVERS FOR ASCOT2E |
7370 | M: Sergey Kozlov <serjk@netup.ru> | 7389 | M: Sergey Kozlov <serjk@netup.ru> |
7390 | M: Abylay Ospan <aospan@netup.ru> | ||
7371 | L: linux-media@vger.kernel.org | 7391 | L: linux-media@vger.kernel.org |
7372 | W: https://linuxtv.org | 7392 | W: https://linuxtv.org |
7373 | W: http://netup.tv/ | 7393 | W: http://netup.tv/ |
@@ -7377,6 +7397,7 @@ F: drivers/media/dvb-frontends/ascot2e* | |||
7377 | 7397 | ||
7378 | MEDIA DRIVERS FOR CXD2841ER | 7398 | MEDIA DRIVERS FOR CXD2841ER |
7379 | M: Sergey Kozlov <serjk@netup.ru> | 7399 | M: Sergey Kozlov <serjk@netup.ru> |
7400 | M: Abylay Ospan <aospan@netup.ru> | ||
7380 | L: linux-media@vger.kernel.org | 7401 | L: linux-media@vger.kernel.org |
7381 | W: https://linuxtv.org | 7402 | W: https://linuxtv.org |
7382 | W: http://netup.tv/ | 7403 | W: http://netup.tv/ |
@@ -7386,6 +7407,7 @@ F: drivers/media/dvb-frontends/cxd2841er* | |||
7386 | 7407 | ||
7387 | MEDIA DRIVERS FOR HORUS3A | 7408 | MEDIA DRIVERS FOR HORUS3A |
7388 | M: Sergey Kozlov <serjk@netup.ru> | 7409 | M: Sergey Kozlov <serjk@netup.ru> |
7410 | M: Abylay Ospan <aospan@netup.ru> | ||
7389 | L: linux-media@vger.kernel.org | 7411 | L: linux-media@vger.kernel.org |
7390 | W: https://linuxtv.org | 7412 | W: https://linuxtv.org |
7391 | W: http://netup.tv/ | 7413 | W: http://netup.tv/ |
@@ -7395,6 +7417,7 @@ F: drivers/media/dvb-frontends/horus3a* | |||
7395 | 7417 | ||
7396 | MEDIA DRIVERS FOR LNBH25 | 7418 | MEDIA DRIVERS FOR LNBH25 |
7397 | M: Sergey Kozlov <serjk@netup.ru> | 7419 | M: Sergey Kozlov <serjk@netup.ru> |
7420 | M: Abylay Ospan <aospan@netup.ru> | ||
7398 | L: linux-media@vger.kernel.org | 7421 | L: linux-media@vger.kernel.org |
7399 | W: https://linuxtv.org | 7422 | W: https://linuxtv.org |
7400 | W: http://netup.tv/ | 7423 | W: http://netup.tv/ |
@@ -7404,6 +7427,7 @@ F: drivers/media/dvb-frontends/lnbh25* | |||
7404 | 7427 | ||
7405 | MEDIA DRIVERS FOR NETUP PCI UNIVERSAL DVB devices | 7428 | MEDIA DRIVERS FOR NETUP PCI UNIVERSAL DVB devices |
7406 | M: Sergey Kozlov <serjk@netup.ru> | 7429 | M: Sergey Kozlov <serjk@netup.ru> |
7430 | M: Abylay Ospan <aospan@netup.ru> | ||
7407 | L: linux-media@vger.kernel.org | 7431 | L: linux-media@vger.kernel.org |
7408 | W: https://linuxtv.org | 7432 | W: https://linuxtv.org |
7409 | W: http://netup.tv/ | 7433 | W: http://netup.tv/ |
@@ -7653,10 +7677,8 @@ L: linux-media@vger.kernel.org | |||
7653 | W: https://linuxtv.org | 7677 | W: https://linuxtv.org |
7654 | W: http://palosaari.fi/linux/ | 7678 | W: http://palosaari.fi/linux/ |
7655 | Q: http://patchwork.linuxtv.org/project/linux-media/list/ | 7679 | Q: http://patchwork.linuxtv.org/project/linux-media/list/ |
7656 | T: git git://linuxtv.org/anttip/media_tree.git | ||
7657 | S: Maintained | 7680 | S: Maintained |
7658 | F: drivers/staging/media/mn88472/ | 7681 | F: drivers/media/dvb-frontends/mn88472* |
7659 | F: drivers/media/dvb-frontends/mn88472.h | ||
7660 | 7682 | ||
7661 | MN88473 MEDIA DRIVER | 7683 | MN88473 MEDIA DRIVER |
7662 | M: Antti Palosaari <crope@iki.fi> | 7684 | M: Antti Palosaari <crope@iki.fi> |
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c index e671a7cd3463..6ac717f2056f 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c | |||
@@ -148,40 +148,39 @@ static void rcar_du_vsp_plane_setup(struct rcar_du_vsp_plane *plane) | |||
148 | struct rcar_du_vsp_plane_state *state = | 148 | struct rcar_du_vsp_plane_state *state = |
149 | to_rcar_vsp_plane_state(plane->plane.state); | 149 | to_rcar_vsp_plane_state(plane->plane.state); |
150 | struct drm_framebuffer *fb = plane->plane.state->fb; | 150 | struct drm_framebuffer *fb = plane->plane.state->fb; |
151 | struct v4l2_rect src; | 151 | struct vsp1_du_atomic_config cfg = { |
152 | struct v4l2_rect dst; | 152 | .pixelformat = 0, |
153 | dma_addr_t paddr[2] = { 0, }; | 153 | .pitch = fb->pitches[0], |
154 | u32 pixelformat = 0; | 154 | .alpha = state->alpha, |
155 | .zpos = state->zpos, | ||
156 | }; | ||
155 | unsigned int i; | 157 | unsigned int i; |
156 | 158 | ||
157 | src.left = state->state.src_x >> 16; | 159 | cfg.src.left = state->state.src_x >> 16; |
158 | src.top = state->state.src_y >> 16; | 160 | cfg.src.top = state->state.src_y >> 16; |
159 | src.width = state->state.src_w >> 16; | 161 | cfg.src.width = state->state.src_w >> 16; |
160 | src.height = state->state.src_h >> 16; | 162 | cfg.src.height = state->state.src_h >> 16; |
161 | 163 | ||
162 | dst.left = state->state.crtc_x; | 164 | cfg.dst.left = state->state.crtc_x; |
163 | dst.top = state->state.crtc_y; | 165 | cfg.dst.top = state->state.crtc_y; |
164 | dst.width = state->state.crtc_w; | 166 | cfg.dst.width = state->state.crtc_w; |
165 | dst.height = state->state.crtc_h; | 167 | cfg.dst.height = state->state.crtc_h; |
166 | 168 | ||
167 | for (i = 0; i < state->format->planes; ++i) { | 169 | for (i = 0; i < state->format->planes; ++i) { |
168 | struct drm_gem_cma_object *gem; | 170 | struct drm_gem_cma_object *gem; |
169 | 171 | ||
170 | gem = drm_fb_cma_get_gem_obj(fb, i); | 172 | gem = drm_fb_cma_get_gem_obj(fb, i); |
171 | paddr[i] = gem->paddr + fb->offsets[i]; | 173 | cfg.mem[i] = gem->paddr + fb->offsets[i]; |
172 | } | 174 | } |
173 | 175 | ||
174 | for (i = 0; i < ARRAY_SIZE(formats_kms); ++i) { | 176 | for (i = 0; i < ARRAY_SIZE(formats_kms); ++i) { |
175 | if (formats_kms[i] == state->format->fourcc) { | 177 | if (formats_kms[i] == state->format->fourcc) { |
176 | pixelformat = formats_v4l2[i]; | 178 | cfg.pixelformat = formats_v4l2[i]; |
177 | break; | 179 | break; |
178 | } | 180 | } |
179 | } | 181 | } |
180 | 182 | ||
181 | WARN_ON(!pixelformat); | 183 | vsp1_du_atomic_update(plane->vsp->vsp, plane->index, &cfg); |
182 | |||
183 | vsp1_du_atomic_update(plane->vsp->vsp, plane->index, pixelformat, | ||
184 | fb->pitches[0], paddr, &src, &dst); | ||
185 | } | 184 | } |
186 | 185 | ||
187 | static int rcar_du_vsp_plane_atomic_check(struct drm_plane *plane, | 186 | static int rcar_du_vsp_plane_atomic_check(struct drm_plane *plane, |
@@ -220,8 +219,7 @@ static void rcar_du_vsp_plane_atomic_update(struct drm_plane *plane, | |||
220 | if (plane->state->crtc) | 219 | if (plane->state->crtc) |
221 | rcar_du_vsp_plane_setup(rplane); | 220 | rcar_du_vsp_plane_setup(rplane); |
222 | else | 221 | else |
223 | vsp1_du_atomic_update(rplane->vsp->vsp, rplane->index, 0, 0, 0, | 222 | vsp1_du_atomic_update(rplane->vsp->vsp, rplane->index, NULL); |
224 | NULL, NULL); | ||
225 | } | 223 | } |
226 | 224 | ||
227 | static const struct drm_plane_helper_funcs rcar_du_vsp_plane_helper_funcs = { | 225 | static const struct drm_plane_helper_funcs rcar_du_vsp_plane_helper_funcs = { |
@@ -269,6 +267,7 @@ static void rcar_du_vsp_plane_reset(struct drm_plane *plane) | |||
269 | return; | 267 | return; |
270 | 268 | ||
271 | state->alpha = 255; | 269 | state->alpha = 255; |
270 | state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : 1; | ||
272 | 271 | ||
273 | plane->state = &state->state; | 272 | plane->state = &state->state; |
274 | plane->state->plane = plane; | 273 | plane->state->plane = plane; |
@@ -283,6 +282,8 @@ static int rcar_du_vsp_plane_atomic_set_property(struct drm_plane *plane, | |||
283 | 282 | ||
284 | if (property == rcdu->props.alpha) | 283 | if (property == rcdu->props.alpha) |
285 | rstate->alpha = val; | 284 | rstate->alpha = val; |
285 | else if (property == rcdu->props.zpos) | ||
286 | rstate->zpos = val; | ||
286 | else | 287 | else |
287 | return -EINVAL; | 288 | return -EINVAL; |
288 | 289 | ||
@@ -299,6 +300,8 @@ static int rcar_du_vsp_plane_atomic_get_property(struct drm_plane *plane, | |||
299 | 300 | ||
300 | if (property == rcdu->props.alpha) | 301 | if (property == rcdu->props.alpha) |
301 | *val = rstate->alpha; | 302 | *val = rstate->alpha; |
303 | else if (property == rcdu->props.zpos) | ||
304 | *val = rstate->zpos; | ||
302 | else | 305 | else |
303 | return -EINVAL; | 306 | return -EINVAL; |
304 | 307 | ||
@@ -378,6 +381,8 @@ int rcar_du_vsp_init(struct rcar_du_vsp *vsp) | |||
378 | 381 | ||
379 | drm_object_attach_property(&plane->plane.base, | 382 | drm_object_attach_property(&plane->plane.base, |
380 | rcdu->props.alpha, 255); | 383 | rcdu->props.alpha, 255); |
384 | drm_object_attach_property(&plane->plane.base, | ||
385 | rcdu->props.zpos, 1); | ||
381 | } | 386 | } |
382 | 387 | ||
383 | return 0; | 388 | return 0; |
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.h b/drivers/gpu/drm/rcar-du/rcar_du_vsp.h index df3bf3805c69..510dcc9c6816 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.h | |||
@@ -44,6 +44,7 @@ static inline struct rcar_du_vsp_plane *to_rcar_vsp_plane(struct drm_plane *p) | |||
44 | * @state: base DRM plane state | 44 | * @state: base DRM plane state |
45 | * @format: information about the pixel format used by the plane | 45 | * @format: information about the pixel format used by the plane |
46 | * @alpha: value of the plane alpha property | 46 | * @alpha: value of the plane alpha property |
47 | * @zpos: value of the plane zpos property | ||
47 | */ | 48 | */ |
48 | struct rcar_du_vsp_plane_state { | 49 | struct rcar_du_vsp_plane_state { |
49 | struct drm_plane_state state; | 50 | struct drm_plane_state state; |
@@ -51,6 +52,7 @@ struct rcar_du_vsp_plane_state { | |||
51 | const struct rcar_du_format_info *format; | 52 | const struct rcar_du_format_info *format; |
52 | 53 | ||
53 | unsigned int alpha; | 54 | unsigned int alpha; |
55 | unsigned int zpos; | ||
54 | }; | 56 | }; |
55 | 57 | ||
56 | static inline struct rcar_du_vsp_plane_state * | 58 | static inline struct rcar_du_vsp_plane_state * |
diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c index f82cd1ff4f3a..b1e3a26b1431 100644 --- a/drivers/media/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb-core/dvb_ca_en50221.c | |||
@@ -161,6 +161,18 @@ struct dvb_ca_private { | |||
161 | struct mutex ioctl_mutex; | 161 | struct mutex ioctl_mutex; |
162 | }; | 162 | }; |
163 | 163 | ||
164 | static void dvb_ca_private_free(struct dvb_ca_private *ca) | ||
165 | { | ||
166 | unsigned int i; | ||
167 | |||
168 | dvb_unregister_device(ca->dvbdev); | ||
169 | for (i = 0; i < ca->slot_count; i++) | ||
170 | vfree(ca->slot_info[i].rx_buffer.data); | ||
171 | |||
172 | kfree(ca->slot_info); | ||
173 | kfree(ca); | ||
174 | } | ||
175 | |||
164 | static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca); | 176 | static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca); |
165 | static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount); | 177 | static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount); |
166 | static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount); | 178 | static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount); |
@@ -1759,10 +1771,7 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca) | |||
1759 | 1771 | ||
1760 | for (i = 0; i < ca->slot_count; i++) { | 1772 | for (i = 0; i < ca->slot_count; i++) { |
1761 | dvb_ca_en50221_slot_shutdown(ca, i); | 1773 | dvb_ca_en50221_slot_shutdown(ca, i); |
1762 | vfree(ca->slot_info[i].rx_buffer.data); | ||
1763 | } | 1774 | } |
1764 | kfree(ca->slot_info); | 1775 | dvb_ca_private_free(ca); |
1765 | dvb_unregister_device(ca->dvbdev); | ||
1766 | kfree(ca); | ||
1767 | pubca->private = NULL; | 1776 | pubca->private = NULL; |
1768 | } | 1777 | } |
diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index a82f77c49bd5..c645aa81f423 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig | |||
@@ -73,6 +73,14 @@ config DVB_SI2165 | |||
73 | 73 | ||
74 | Say Y when you want to support this frontend. | 74 | Say Y when you want to support this frontend. |
75 | 75 | ||
76 | config DVB_MN88472 | ||
77 | tristate "Panasonic MN88472" | ||
78 | depends on DVB_CORE && I2C | ||
79 | select REGMAP_I2C | ||
80 | default m if !MEDIA_SUBDRV_AUTOSELECT | ||
81 | help | ||
82 | Say Y when you want to support this frontend. | ||
83 | |||
76 | config DVB_MN88473 | 84 | config DVB_MN88473 |
77 | tristate "Panasonic MN88473" | 85 | tristate "Panasonic MN88473" |
78 | depends on DVB_CORE && I2C | 86 | depends on DVB_CORE && I2C |
@@ -853,6 +861,13 @@ config DVB_ASCOT2E | |||
853 | help | 861 | help |
854 | Say Y when you want to support this frontend. | 862 | Say Y when you want to support this frontend. |
855 | 863 | ||
864 | config DVB_HELENE | ||
865 | tristate "Sony HELENE Sat/Ter tuner (CXD2858ER)" | ||
866 | depends on DVB_CORE && I2C | ||
867 | default m if !MEDIA_SUBDRV_AUTOSELECT | ||
868 | help | ||
869 | Say Y when you want to support this frontend. | ||
870 | |||
856 | comment "Tools to develop new frontends" | 871 | comment "Tools to develop new frontends" |
857 | 872 | ||
858 | config DVB_DUMMY_FE | 873 | config DVB_DUMMY_FE |
diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile index eb7191f4219d..e90165ad361b 100644 --- a/drivers/media/dvb-frontends/Makefile +++ b/drivers/media/dvb-frontends/Makefile | |||
@@ -95,6 +95,7 @@ obj-$(CONFIG_DVB_STV0900) += stv0900.o | |||
95 | obj-$(CONFIG_DVB_STV090x) += stv090x.o | 95 | obj-$(CONFIG_DVB_STV090x) += stv090x.o |
96 | obj-$(CONFIG_DVB_STV6110x) += stv6110x.o | 96 | obj-$(CONFIG_DVB_STV6110x) += stv6110x.o |
97 | obj-$(CONFIG_DVB_M88DS3103) += m88ds3103.o | 97 | obj-$(CONFIG_DVB_M88DS3103) += m88ds3103.o |
98 | obj-$(CONFIG_DVB_MN88472) += mn88472.o | ||
98 | obj-$(CONFIG_DVB_MN88473) += mn88473.o | 99 | obj-$(CONFIG_DVB_MN88473) += mn88473.o |
99 | obj-$(CONFIG_DVB_ISL6423) += isl6423.o | 100 | obj-$(CONFIG_DVB_ISL6423) += isl6423.o |
100 | obj-$(CONFIG_DVB_EC100) += ec100.o | 101 | obj-$(CONFIG_DVB_EC100) += ec100.o |
@@ -123,3 +124,4 @@ obj-$(CONFIG_DVB_AS102_FE) += as102_fe.o | |||
123 | obj-$(CONFIG_DVB_TC90522) += tc90522.o | 124 | obj-$(CONFIG_DVB_TC90522) += tc90522.o |
124 | obj-$(CONFIG_DVB_HORUS3A) += horus3a.o | 125 | obj-$(CONFIG_DVB_HORUS3A) += horus3a.o |
125 | obj-$(CONFIG_DVB_ASCOT2E) += ascot2e.o | 126 | obj-$(CONFIG_DVB_ASCOT2E) += ascot2e.o |
127 | obj-$(CONFIG_DVB_HELENE) += helene.o | ||
diff --git a/drivers/media/dvb-frontends/cxd2841er.c b/drivers/media/dvb-frontends/cxd2841er.c index 900186ba8e62..d369a7567d18 100644 --- a/drivers/media/dvb-frontends/cxd2841er.c +++ b/drivers/media/dvb-frontends/cxd2841er.c | |||
@@ -1,7 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * cxd2841er.c | 2 | * cxd2841er.c |
3 | * | 3 | * |
4 | * Sony CXD2441ER digital demodulator driver | 4 | * Sony digital demodulator driver for |
5 | * CXD2841ER - DVB-S/S2/T/T2/C/C2 | ||
6 | * CXD2854ER - DVB-S/S2/T/T2/C/C2, ISDB-T/S | ||
5 | * | 7 | * |
6 | * Copyright 2012 Sony Corporation | 8 | * Copyright 2012 Sony Corporation |
7 | * Copyright (C) 2014 NetUP Inc. | 9 | * Copyright (C) 2014 NetUP Inc. |
@@ -51,6 +53,8 @@ struct cxd2841er_priv { | |||
51 | const struct cxd2841er_config *config; | 53 | const struct cxd2841er_config *config; |
52 | enum cxd2841er_state state; | 54 | enum cxd2841er_state state; |
53 | u8 system; | 55 | u8 system; |
56 | enum cxd2841er_xtal xtal; | ||
57 | enum fe_caps caps; | ||
54 | }; | 58 | }; |
55 | 59 | ||
56 | static const struct cxd2841er_cnr_data s_cn_data[] = { | 60 | static const struct cxd2841er_cnr_data s_cn_data[] = { |
@@ -188,6 +192,9 @@ static const struct cxd2841er_cnr_data s2_cn_data[] = { | |||
188 | }; | 192 | }; |
189 | 193 | ||
190 | #define MAKE_IFFREQ_CONFIG(iffreq) ((u32)(((iffreq)/41.0)*16777216.0 + 0.5)) | 194 | #define MAKE_IFFREQ_CONFIG(iffreq) ((u32)(((iffreq)/41.0)*16777216.0 + 0.5)) |
195 | #define MAKE_IFFREQ_CONFIG_XTAL(xtal, iffreq) ((xtal == SONY_XTAL_24000) ? \ | ||
196 | (u32)(((iffreq)/48.0)*16777216.0 + 0.5) : \ | ||
197 | (u32)(((iffreq)/41.0)*16777216.0 + 0.5)) | ||
191 | 198 | ||
192 | static void cxd2841er_i2c_debug(struct cxd2841er_priv *priv, | 199 | static void cxd2841er_i2c_debug(struct cxd2841er_priv *priv, |
193 | u8 addr, u8 reg, u8 write, | 200 | u8 addr, u8 reg, u8 write, |
@@ -217,7 +224,7 @@ static int cxd2841er_write_regs(struct cxd2841er_priv *priv, | |||
217 | }; | 224 | }; |
218 | 225 | ||
219 | if (len + 1 >= sizeof(buf)) { | 226 | if (len + 1 >= sizeof(buf)) { |
220 | dev_warn(&priv->i2c->dev,"wr reg=%04x: len=%d is too big!\n", | 227 | dev_warn(&priv->i2c->dev, "wr reg=%04x: len=%d is too big!\n", |
221 | reg, len + 1); | 228 | reg, len + 1); |
222 | return -E2BIG; | 229 | return -E2BIG; |
223 | } | 230 | } |
@@ -282,6 +289,7 @@ static int cxd2841er_read_regs(struct cxd2841er_priv *priv, | |||
282 | KBUILD_MODNAME, ret, i2c_addr, reg); | 289 | KBUILD_MODNAME, ret, i2c_addr, reg); |
283 | return ret; | 290 | return ret; |
284 | } | 291 | } |
292 | cxd2841er_i2c_debug(priv, i2c_addr, reg, 0, val, len); | ||
285 | return 0; | 293 | return 0; |
286 | } | 294 | } |
287 | 295 | ||
@@ -427,6 +435,15 @@ static int cxd2841er_sleep_tc_to_active_t2_band(struct cxd2841er_priv *priv, | |||
427 | static int cxd2841er_sleep_tc_to_active_c_band(struct cxd2841er_priv *priv, | 435 | static int cxd2841er_sleep_tc_to_active_c_band(struct cxd2841er_priv *priv, |
428 | u32 bandwidth); | 436 | u32 bandwidth); |
429 | 437 | ||
438 | static int cxd2841er_sleep_tc_to_active_i(struct cxd2841er_priv *priv, | ||
439 | u32 bandwidth); | ||
440 | |||
441 | static int cxd2841er_active_i_to_sleep_tc(struct cxd2841er_priv *priv); | ||
442 | |||
443 | static int cxd2841er_sleep_tc_to_shutdown(struct cxd2841er_priv *priv); | ||
444 | |||
445 | static int cxd2841er_shutdown_to_sleep_tc(struct cxd2841er_priv *priv); | ||
446 | |||
430 | static int cxd2841er_retune_active(struct cxd2841er_priv *priv, | 447 | static int cxd2841er_retune_active(struct cxd2841er_priv *priv, |
431 | struct dtv_frontend_properties *p) | 448 | struct dtv_frontend_properties *p) |
432 | { | 449 | { |
@@ -454,7 +471,13 @@ static int cxd2841er_retune_active(struct cxd2841er_priv *priv, | |||
454 | priv, p->bandwidth_hz); | 471 | priv, p->bandwidth_hz); |
455 | case SYS_DVBC_ANNEX_A: | 472 | case SYS_DVBC_ANNEX_A: |
456 | return cxd2841er_sleep_tc_to_active_c_band( | 473 | return cxd2841er_sleep_tc_to_active_c_band( |
457 | priv, 8000000); | 474 | priv, p->bandwidth_hz); |
475 | case SYS_ISDBT: | ||
476 | cxd2841er_active_i_to_sleep_tc(priv); | ||
477 | cxd2841er_sleep_tc_to_shutdown(priv); | ||
478 | cxd2841er_shutdown_to_sleep_tc(priv); | ||
479 | return cxd2841er_sleep_tc_to_active_i( | ||
480 | priv, p->bandwidth_hz); | ||
458 | } | 481 | } |
459 | } | 482 | } |
460 | dev_dbg(&priv->i2c->dev, "%s(): invalid delivery system %d\n", | 483 | dev_dbg(&priv->i2c->dev, "%s(): invalid delivery system %d\n", |
@@ -669,6 +692,45 @@ static int cxd2841er_active_c_to_sleep_tc(struct cxd2841er_priv *priv) | |||
669 | return 0; | 692 | return 0; |
670 | } | 693 | } |
671 | 694 | ||
695 | static int cxd2841er_active_i_to_sleep_tc(struct cxd2841er_priv *priv) | ||
696 | { | ||
697 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | ||
698 | if (priv->state != STATE_ACTIVE_TC) { | ||
699 | dev_err(&priv->i2c->dev, "%s(): invalid state %d\n", | ||
700 | __func__, priv->state); | ||
701 | return -EINVAL; | ||
702 | } | ||
703 | /* Set SLV-T Bank : 0x00 */ | ||
704 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00); | ||
705 | /* disable TS output */ | ||
706 | cxd2841er_write_reg(priv, I2C_SLVT, 0xc3, 0x01); | ||
707 | /* enable Hi-Z setting 1 */ | ||
708 | cxd2841er_write_reg(priv, I2C_SLVT, 0x80, 0x3f); | ||
709 | /* enable Hi-Z setting 2 */ | ||
710 | cxd2841er_write_reg(priv, I2C_SLVT, 0x81, 0xff); | ||
711 | |||
712 | /* TODO: Cancel demod parameter */ | ||
713 | |||
714 | /* Set SLV-X Bank : 0x00 */ | ||
715 | cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00); | ||
716 | /* disable ADC 1 */ | ||
717 | cxd2841er_write_reg(priv, I2C_SLVX, 0x18, 0x01); | ||
718 | /* Set SLV-T Bank : 0x00 */ | ||
719 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00); | ||
720 | /* Disable ADC 2 */ | ||
721 | cxd2841er_write_reg(priv, I2C_SLVT, 0x43, 0x0a); | ||
722 | /* Disable ADC 3 */ | ||
723 | cxd2841er_write_reg(priv, I2C_SLVT, 0x41, 0x0a); | ||
724 | /* Disable ADC clock */ | ||
725 | cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00); | ||
726 | /* Disable RF level monitor */ | ||
727 | cxd2841er_write_reg(priv, I2C_SLVT, 0x2f, 0x00); | ||
728 | /* Disable demod clock */ | ||
729 | cxd2841er_write_reg(priv, I2C_SLVT, 0x2c, 0x00); | ||
730 | priv->state = STATE_SLEEP_TC; | ||
731 | return 0; | ||
732 | } | ||
733 | |||
672 | static int cxd2841er_shutdown_to_sleep_s(struct cxd2841er_priv *priv) | 734 | static int cxd2841er_shutdown_to_sleep_s(struct cxd2841er_priv *priv) |
673 | { | 735 | { |
674 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | 736 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); |
@@ -686,8 +748,25 @@ static int cxd2841er_shutdown_to_sleep_s(struct cxd2841er_priv *priv) | |||
686 | cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00); | 748 | cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00); |
687 | /* Set demod SW reset */ | 749 | /* Set demod SW reset */ |
688 | cxd2841er_write_reg(priv, I2C_SLVX, 0x10, 0x01); | 750 | cxd2841er_write_reg(priv, I2C_SLVX, 0x10, 0x01); |
689 | /* Set X'tal clock to 20.5Mhz */ | 751 | |
690 | cxd2841er_write_reg(priv, I2C_SLVX, 0x14, 0x00); | 752 | switch (priv->xtal) { |
753 | case SONY_XTAL_20500: | ||
754 | cxd2841er_write_reg(priv, I2C_SLVX, 0x14, 0x00); | ||
755 | break; | ||
756 | case SONY_XTAL_24000: | ||
757 | /* Select demod frequency */ | ||
758 | cxd2841er_write_reg(priv, I2C_SLVX, 0x12, 0x00); | ||
759 | cxd2841er_write_reg(priv, I2C_SLVX, 0x14, 0x03); | ||
760 | break; | ||
761 | case SONY_XTAL_41000: | ||
762 | cxd2841er_write_reg(priv, I2C_SLVX, 0x14, 0x01); | ||
763 | break; | ||
764 | default: | ||
765 | dev_dbg(&priv->i2c->dev, "%s(): invalid demod xtal %d\n", | ||
766 | __func__, priv->xtal); | ||
767 | return -EINVAL; | ||
768 | } | ||
769 | |||
691 | /* Set demod mode */ | 770 | /* Set demod mode */ |
692 | cxd2841er_write_reg(priv, I2C_SLVX, 0x17, 0x0a); | 771 | cxd2841er_write_reg(priv, I2C_SLVX, 0x17, 0x0a); |
693 | /* Clear demod SW reset */ | 772 | /* Clear demod SW reset */ |
@@ -712,6 +791,8 @@ static int cxd2841er_shutdown_to_sleep_s(struct cxd2841er_priv *priv) | |||
712 | 791 | ||
713 | static int cxd2841er_shutdown_to_sleep_tc(struct cxd2841er_priv *priv) | 792 | static int cxd2841er_shutdown_to_sleep_tc(struct cxd2841er_priv *priv) |
714 | { | 793 | { |
794 | u8 data = 0; | ||
795 | |||
715 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | 796 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); |
716 | if (priv->state != STATE_SHUTDOWN) { | 797 | if (priv->state != STATE_SHUTDOWN) { |
717 | dev_dbg(&priv->i2c->dev, "%s(): invalid demod state %d\n", | 798 | dev_dbg(&priv->i2c->dev, "%s(): invalid demod state %d\n", |
@@ -727,9 +808,24 @@ static int cxd2841er_shutdown_to_sleep_tc(struct cxd2841er_priv *priv) | |||
727 | cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00); | 808 | cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00); |
728 | /* Set demod SW reset */ | 809 | /* Set demod SW reset */ |
729 | cxd2841er_write_reg(priv, I2C_SLVX, 0x10, 0x01); | 810 | cxd2841er_write_reg(priv, I2C_SLVX, 0x10, 0x01); |
730 | /* Set X'tal clock to 20.5Mhz */ | 811 | /* Select ADC clock mode */ |
731 | cxd2841er_write_reg(priv, I2C_SLVX, 0x13, 0x00); | 812 | cxd2841er_write_reg(priv, I2C_SLVX, 0x13, 0x00); |
732 | cxd2841er_write_reg(priv, I2C_SLVX, 0x14, 0x00); | 813 | |
814 | switch (priv->xtal) { | ||
815 | case SONY_XTAL_20500: | ||
816 | data = 0x0; | ||
817 | break; | ||
818 | case SONY_XTAL_24000: | ||
819 | /* Select demod frequency */ | ||
820 | cxd2841er_write_reg(priv, I2C_SLVX, 0x12, 0x00); | ||
821 | data = 0x3; | ||
822 | break; | ||
823 | case SONY_XTAL_41000: | ||
824 | cxd2841er_write_reg(priv, I2C_SLVX, 0x12, 0x00); | ||
825 | data = 0x1; | ||
826 | break; | ||
827 | } | ||
828 | cxd2841er_write_reg(priv, I2C_SLVX, 0x14, data); | ||
733 | /* Clear demod SW reset */ | 829 | /* Clear demod SW reset */ |
734 | cxd2841er_write_reg(priv, I2C_SLVX, 0x10, 0x00); | 830 | cxd2841er_write_reg(priv, I2C_SLVX, 0x10, 0x00); |
735 | usleep_range(1000, 2000); | 831 | usleep_range(1000, 2000); |
@@ -809,11 +905,14 @@ static void cxd2841er_set_ts_clock_mode(struct cxd2841er_priv *priv, | |||
809 | 905 | ||
810 | static u8 cxd2841er_chip_id(struct cxd2841er_priv *priv) | 906 | static u8 cxd2841er_chip_id(struct cxd2841er_priv *priv) |
811 | { | 907 | { |
812 | u8 chip_id; | 908 | u8 chip_id = 0; |
813 | 909 | ||
814 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | 910 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); |
815 | cxd2841er_write_reg(priv, I2C_SLVT, 0, 0); | 911 | if (cxd2841er_write_reg(priv, I2C_SLVT, 0, 0) == 0) |
816 | cxd2841er_read_reg(priv, I2C_SLVT, 0xfd, &chip_id); | 912 | cxd2841er_read_reg(priv, I2C_SLVT, 0xfd, &chip_id); |
913 | else if (cxd2841er_write_reg(priv, I2C_SLVX, 0, 0) == 0) | ||
914 | cxd2841er_read_reg(priv, I2C_SLVX, 0xfd, &chip_id); | ||
915 | |||
817 | return chip_id; | 916 | return chip_id; |
818 | } | 917 | } |
819 | 918 | ||
@@ -896,6 +995,25 @@ static int cxd2841er_read_status_c(struct cxd2841er_priv *priv, u8 *tslock) | |||
896 | return 0; | 995 | return 0; |
897 | } | 996 | } |
898 | 997 | ||
998 | static int cxd2841er_read_status_i(struct cxd2841er_priv *priv, | ||
999 | u8 *sync, u8 *tslock, u8 *unlock) | ||
1000 | { | ||
1001 | u8 data = 0; | ||
1002 | |||
1003 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | ||
1004 | if (priv->state != STATE_ACTIVE_TC) | ||
1005 | return -EINVAL; | ||
1006 | /* Set SLV-T Bank : 0x60 */ | ||
1007 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x60); | ||
1008 | cxd2841er_read_reg(priv, I2C_SLVT, 0x10, &data); | ||
1009 | dev_dbg(&priv->i2c->dev, | ||
1010 | "%s(): lock=0x%x\n", __func__, data); | ||
1011 | *sync = ((data & 0x02) ? 1 : 0); | ||
1012 | *tslock = ((data & 0x01) ? 1 : 0); | ||
1013 | *unlock = ((data & 0x10) ? 1 : 0); | ||
1014 | return 0; | ||
1015 | } | ||
1016 | |||
899 | static int cxd2841er_read_status_tc(struct dvb_frontend *fe, | 1017 | static int cxd2841er_read_status_tc(struct dvb_frontend *fe, |
900 | enum fe_status *status) | 1018 | enum fe_status *status) |
901 | { | 1019 | { |
@@ -921,6 +1039,20 @@ static int cxd2841er_read_status_tc(struct dvb_frontend *fe, | |||
921 | FE_HAS_SYNC; | 1039 | FE_HAS_SYNC; |
922 | if (tslock) | 1040 | if (tslock) |
923 | *status |= FE_HAS_LOCK; | 1041 | *status |= FE_HAS_LOCK; |
1042 | } else if (priv->system == SYS_ISDBT) { | ||
1043 | ret = cxd2841er_read_status_i( | ||
1044 | priv, &sync, &tslock, &unlock); | ||
1045 | if (ret) | ||
1046 | goto done; | ||
1047 | if (unlock) | ||
1048 | goto done; | ||
1049 | if (sync) | ||
1050 | *status = FE_HAS_SIGNAL | | ||
1051 | FE_HAS_CARRIER | | ||
1052 | FE_HAS_VITERBI | | ||
1053 | FE_HAS_SYNC; | ||
1054 | if (tslock) | ||
1055 | *status |= FE_HAS_LOCK; | ||
924 | } else if (priv->system == SYS_DVBC_ANNEX_A) { | 1056 | } else if (priv->system == SYS_DVBC_ANNEX_A) { |
925 | ret = cxd2841er_read_status_c(priv, &tslock); | 1057 | ret = cxd2841er_read_status_c(priv, &tslock); |
926 | if (ret) | 1058 | if (ret) |
@@ -997,6 +1129,76 @@ static int cxd2841er_get_carrier_offset_s_s2(struct cxd2841er_priv *priv, | |||
997 | return 0; | 1129 | return 0; |
998 | } | 1130 | } |
999 | 1131 | ||
1132 | static int cxd2841er_get_carrier_offset_i(struct cxd2841er_priv *priv, | ||
1133 | u32 bandwidth, int *offset) | ||
1134 | { | ||
1135 | u8 data[4]; | ||
1136 | |||
1137 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | ||
1138 | if (priv->state != STATE_ACTIVE_TC) { | ||
1139 | dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n", | ||
1140 | __func__, priv->state); | ||
1141 | return -EINVAL; | ||
1142 | } | ||
1143 | if (priv->system != SYS_ISDBT) { | ||
1144 | dev_dbg(&priv->i2c->dev, "%s(): invalid delivery system %d\n", | ||
1145 | __func__, priv->system); | ||
1146 | return -EINVAL; | ||
1147 | } | ||
1148 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x60); | ||
1149 | cxd2841er_read_regs(priv, I2C_SLVT, 0x4c, data, sizeof(data)); | ||
1150 | *offset = -1 * sign_extend32( | ||
1151 | ((u32)(data[0] & 0x1F) << 24) | ((u32)data[1] << 16) | | ||
1152 | ((u32)data[2] << 8) | (u32)data[3], 29); | ||
1153 | |||
1154 | switch (bandwidth) { | ||
1155 | case 6000000: | ||
1156 | *offset = -1 * ((*offset) * 8/264); | ||
1157 | break; | ||
1158 | case 7000000: | ||
1159 | *offset = -1 * ((*offset) * 8/231); | ||
1160 | break; | ||
1161 | case 8000000: | ||
1162 | *offset = -1 * ((*offset) * 8/198); | ||
1163 | break; | ||
1164 | default: | ||
1165 | dev_dbg(&priv->i2c->dev, "%s(): invalid bandwidth %d\n", | ||
1166 | __func__, bandwidth); | ||
1167 | return -EINVAL; | ||
1168 | } | ||
1169 | |||
1170 | dev_dbg(&priv->i2c->dev, "%s(): bandwidth %d offset %d\n", | ||
1171 | __func__, bandwidth, *offset); | ||
1172 | |||
1173 | return 0; | ||
1174 | } | ||
1175 | |||
1176 | static int cxd2841er_get_carrier_offset_t(struct cxd2841er_priv *priv, | ||
1177 | u32 bandwidth, int *offset) | ||
1178 | { | ||
1179 | u8 data[4]; | ||
1180 | |||
1181 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | ||
1182 | if (priv->state != STATE_ACTIVE_TC) { | ||
1183 | dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n", | ||
1184 | __func__, priv->state); | ||
1185 | return -EINVAL; | ||
1186 | } | ||
1187 | if (priv->system != SYS_DVBT) { | ||
1188 | dev_dbg(&priv->i2c->dev, "%s(): invalid delivery system %d\n", | ||
1189 | __func__, priv->system); | ||
1190 | return -EINVAL; | ||
1191 | } | ||
1192 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); | ||
1193 | cxd2841er_read_regs(priv, I2C_SLVT, 0x4c, data, sizeof(data)); | ||
1194 | *offset = -1 * sign_extend32( | ||
1195 | ((u32)(data[0] & 0x1F) << 24) | ((u32)data[1] << 16) | | ||
1196 | ((u32)data[2] << 8) | (u32)data[3], 29); | ||
1197 | *offset *= (bandwidth / 1000000); | ||
1198 | *offset /= 235; | ||
1199 | return 0; | ||
1200 | } | ||
1201 | |||
1000 | static int cxd2841er_get_carrier_offset_t2(struct cxd2841er_priv *priv, | 1202 | static int cxd2841er_get_carrier_offset_t2(struct cxd2841er_priv *priv, |
1001 | u32 bandwidth, int *offset) | 1203 | u32 bandwidth, int *offset) |
1002 | { | 1204 | { |
@@ -1096,6 +1298,38 @@ static int cxd2841er_read_packet_errors_t2( | |||
1096 | return 0; | 1298 | return 0; |
1097 | } | 1299 | } |
1098 | 1300 | ||
1301 | static int cxd2841er_read_packet_errors_i( | ||
1302 | struct cxd2841er_priv *priv, u32 *penum) | ||
1303 | { | ||
1304 | u8 data[2]; | ||
1305 | |||
1306 | *penum = 0; | ||
1307 | if (priv->state != STATE_ACTIVE_TC) { | ||
1308 | dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n", | ||
1309 | __func__, priv->state); | ||
1310 | return -EINVAL; | ||
1311 | } | ||
1312 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x60); | ||
1313 | cxd2841er_read_regs(priv, I2C_SLVT, 0xA1, data, 1); | ||
1314 | |||
1315 | if (!(data[0] & 0x01)) | ||
1316 | return 0; | ||
1317 | |||
1318 | /* Layer A */ | ||
1319 | cxd2841er_read_regs(priv, I2C_SLVT, 0xA2, data, sizeof(data)); | ||
1320 | *penum = ((u32)data[0] << 8) | (u32)data[1]; | ||
1321 | |||
1322 | /* Layer B */ | ||
1323 | cxd2841er_read_regs(priv, I2C_SLVT, 0xA4, data, sizeof(data)); | ||
1324 | *penum += ((u32)data[0] << 8) | (u32)data[1]; | ||
1325 | |||
1326 | /* Layer C */ | ||
1327 | cxd2841er_read_regs(priv, I2C_SLVT, 0xA6, data, sizeof(data)); | ||
1328 | *penum += ((u32)data[0] << 8) | (u32)data[1]; | ||
1329 | |||
1330 | return 0; | ||
1331 | } | ||
1332 | |||
1099 | static u32 cxd2841er_mon_read_ber_s(struct cxd2841er_priv *priv) | 1333 | static u32 cxd2841er_mon_read_ber_s(struct cxd2841er_priv *priv) |
1100 | { | 1334 | { |
1101 | u8 data[11]; | 1335 | u8 data[11]; |
@@ -1391,6 +1625,37 @@ static int cxd2841er_read_snr_t2(struct cxd2841er_priv *priv, u32 *snr) | |||
1391 | return 0; | 1625 | return 0; |
1392 | } | 1626 | } |
1393 | 1627 | ||
1628 | static int cxd2841er_read_snr_i(struct cxd2841er_priv *priv, u32 *snr) | ||
1629 | { | ||
1630 | u32 reg; | ||
1631 | u8 data[2]; | ||
1632 | |||
1633 | *snr = 0; | ||
1634 | if (priv->state != STATE_ACTIVE_TC) { | ||
1635 | dev_dbg(&priv->i2c->dev, | ||
1636 | "%s(): invalid state %d\n", __func__, | ||
1637 | priv->state); | ||
1638 | return -EINVAL; | ||
1639 | } | ||
1640 | |||
1641 | /* Freeze all registers */ | ||
1642 | cxd2841er_write_reg(priv, I2C_SLVT, 0x01, 0x01); | ||
1643 | |||
1644 | |||
1645 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x60); | ||
1646 | cxd2841er_read_regs(priv, I2C_SLVT, 0x28, data, sizeof(data)); | ||
1647 | reg = ((u32)data[0] << 8) | (u32)data[1]; | ||
1648 | if (reg == 0) { | ||
1649 | dev_dbg(&priv->i2c->dev, | ||
1650 | "%s(): reg value out of range\n", __func__); | ||
1651 | return 0; | ||
1652 | } | ||
1653 | if (reg > 4996) | ||
1654 | reg = 4996; | ||
1655 | *snr = 100 * intlog10(reg) - 9031; | ||
1656 | return 0; | ||
1657 | } | ||
1658 | |||
1394 | static u16 cxd2841er_read_agc_gain_t_t2(struct cxd2841er_priv *priv, | 1659 | static u16 cxd2841er_read_agc_gain_t_t2(struct cxd2841er_priv *priv, |
1395 | u8 delsys) | 1660 | u8 delsys) |
1396 | { | 1661 | { |
@@ -1399,6 +1664,26 @@ static u16 cxd2841er_read_agc_gain_t_t2(struct cxd2841er_priv *priv, | |||
1399 | cxd2841er_write_reg( | 1664 | cxd2841er_write_reg( |
1400 | priv, I2C_SLVT, 0x00, (delsys == SYS_DVBT ? 0x10 : 0x20)); | 1665 | priv, I2C_SLVT, 0x00, (delsys == SYS_DVBT ? 0x10 : 0x20)); |
1401 | cxd2841er_read_regs(priv, I2C_SLVT, 0x26, data, 2); | 1666 | cxd2841er_read_regs(priv, I2C_SLVT, 0x26, data, 2); |
1667 | dev_dbg(&priv->i2c->dev, | ||
1668 | "%s(): AGC value=%u\n", | ||
1669 | __func__, (((u16)data[0] & 0x0F) << 8) | | ||
1670 | (u16)(data[1] & 0xFF)); | ||
1671 | return ((((u16)data[0] & 0x0F) << 8) | (u16)(data[1] & 0xFF)) << 4; | ||
1672 | } | ||
1673 | |||
1674 | static u16 cxd2841er_read_agc_gain_i(struct cxd2841er_priv *priv, | ||
1675 | u8 delsys) | ||
1676 | { | ||
1677 | u8 data[2]; | ||
1678 | |||
1679 | cxd2841er_write_reg( | ||
1680 | priv, I2C_SLVT, 0x00, 0x60); | ||
1681 | cxd2841er_read_regs(priv, I2C_SLVT, 0x26, data, 2); | ||
1682 | |||
1683 | dev_dbg(&priv->i2c->dev, | ||
1684 | "%s(): AGC value=%u\n", | ||
1685 | __func__, (((u16)data[0] & 0x0F) << 8) | | ||
1686 | (u16)(data[1] & 0xFF)); | ||
1402 | return ((((u16)data[0] & 0x0F) << 8) | (u16)(data[1] & 0xFF)) << 4; | 1687 | return ((((u16)data[0] & 0x0F) << 8) | (u16)(data[1] & 0xFF)) << 4; |
1403 | } | 1688 | } |
1404 | 1689 | ||
@@ -1455,6 +1740,10 @@ static int cxd2841er_read_signal_strength(struct dvb_frontend *fe, | |||
1455 | *strength = 65535 - cxd2841er_read_agc_gain_t_t2( | 1740 | *strength = 65535 - cxd2841er_read_agc_gain_t_t2( |
1456 | priv, p->delivery_system); | 1741 | priv, p->delivery_system); |
1457 | break; | 1742 | break; |
1743 | case SYS_ISDBT: | ||
1744 | *strength = 65535 - cxd2841er_read_agc_gain_i( | ||
1745 | priv, p->delivery_system); | ||
1746 | break; | ||
1458 | case SYS_DVBS: | 1747 | case SYS_DVBS: |
1459 | case SYS_DVBS2: | 1748 | case SYS_DVBS2: |
1460 | *strength = 65535 - cxd2841er_read_agc_gain_s(priv); | 1749 | *strength = 65535 - cxd2841er_read_agc_gain_s(priv); |
@@ -1480,6 +1769,9 @@ static int cxd2841er_read_snr(struct dvb_frontend *fe, u16 *snr) | |||
1480 | case SYS_DVBT2: | 1769 | case SYS_DVBT2: |
1481 | cxd2841er_read_snr_t2(priv, &tmp); | 1770 | cxd2841er_read_snr_t2(priv, &tmp); |
1482 | break; | 1771 | break; |
1772 | case SYS_ISDBT: | ||
1773 | cxd2841er_read_snr_i(priv, &tmp); | ||
1774 | break; | ||
1483 | case SYS_DVBS: | 1775 | case SYS_DVBS: |
1484 | case SYS_DVBS2: | 1776 | case SYS_DVBS2: |
1485 | tmp = cxd2841er_dvbs_read_snr(priv, p->delivery_system); | 1777 | tmp = cxd2841er_dvbs_read_snr(priv, p->delivery_system); |
@@ -1506,6 +1798,9 @@ static int cxd2841er_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) | |||
1506 | case SYS_DVBT2: | 1798 | case SYS_DVBT2: |
1507 | cxd2841er_read_packet_errors_t2(priv, ucblocks); | 1799 | cxd2841er_read_packet_errors_t2(priv, ucblocks); |
1508 | break; | 1800 | break; |
1801 | case SYS_ISDBT: | ||
1802 | cxd2841er_read_packet_errors_i(priv, ucblocks); | ||
1803 | break; | ||
1509 | default: | 1804 | default: |
1510 | *ucblocks = 0; | 1805 | *ucblocks = 0; |
1511 | break; | 1806 | break; |
@@ -1524,15 +1819,18 @@ static int cxd2841er_dvbt2_set_profile( | |||
1524 | switch (profile) { | 1819 | switch (profile) { |
1525 | case DVBT2_PROFILE_BASE: | 1820 | case DVBT2_PROFILE_BASE: |
1526 | tune_mode = 0x01; | 1821 | tune_mode = 0x01; |
1527 | seq_not2d_time = 12; | 1822 | /* Set early unlock time */ |
1823 | seq_not2d_time = (priv->xtal == SONY_XTAL_24000)?0x0E:0x0C; | ||
1528 | break; | 1824 | break; |
1529 | case DVBT2_PROFILE_LITE: | 1825 | case DVBT2_PROFILE_LITE: |
1530 | tune_mode = 0x05; | 1826 | tune_mode = 0x05; |
1531 | seq_not2d_time = 40; | 1827 | /* Set early unlock time */ |
1828 | seq_not2d_time = (priv->xtal == SONY_XTAL_24000)?0x2E:0x28; | ||
1532 | break; | 1829 | break; |
1533 | case DVBT2_PROFILE_ANY: | 1830 | case DVBT2_PROFILE_ANY: |
1534 | tune_mode = 0x00; | 1831 | tune_mode = 0x00; |
1535 | seq_not2d_time = 40; | 1832 | /* Set early unlock time */ |
1833 | seq_not2d_time = (priv->xtal == SONY_XTAL_24000)?0x2E:0x28; | ||
1536 | break; | 1834 | break; |
1537 | default: | 1835 | default: |
1538 | return -EINVAL; | 1836 | return -EINVAL; |
@@ -1574,254 +1872,617 @@ static int cxd2841er_sleep_tc_to_active_t2_band(struct cxd2841er_priv *priv, | |||
1574 | u32 bandwidth) | 1872 | u32 bandwidth) |
1575 | { | 1873 | { |
1576 | u32 iffreq; | 1874 | u32 iffreq; |
1577 | u8 b20_9f[5]; | 1875 | u8 data[MAX_WRITE_REGSIZE]; |
1578 | u8 b10_a6[14]; | 1876 | |
1579 | u8 b10_b6[3]; | 1877 | const uint8_t nominalRate8bw[3][5] = { |
1580 | u8 b10_d7; | 1878 | /* TRCG Nominal Rate [37:0] */ |
1879 | {0x11, 0xF0, 0x00, 0x00, 0x00}, /* 20.5MHz XTal */ | ||
1880 | {0x15, 0x00, 0x00, 0x00, 0x00}, /* 24MHz XTal */ | ||
1881 | {0x11, 0xF0, 0x00, 0x00, 0x00} /* 41MHz XTal */ | ||
1882 | }; | ||
1883 | |||
1884 | const uint8_t nominalRate7bw[3][5] = { | ||
1885 | /* TRCG Nominal Rate [37:0] */ | ||
1886 | {0x14, 0x80, 0x00, 0x00, 0x00}, /* 20.5MHz XTal */ | ||
1887 | {0x18, 0x00, 0x00, 0x00, 0x00}, /* 24MHz XTal */ | ||
1888 | {0x14, 0x80, 0x00, 0x00, 0x00} /* 41MHz XTal */ | ||
1889 | }; | ||
1890 | |||
1891 | const uint8_t nominalRate6bw[3][5] = { | ||
1892 | /* TRCG Nominal Rate [37:0] */ | ||
1893 | {0x17, 0xEA, 0xAA, 0xAA, 0xAA}, /* 20.5MHz XTal */ | ||
1894 | {0x1C, 0x00, 0x00, 0x00, 0x00}, /* 24MHz XTal */ | ||
1895 | {0x17, 0xEA, 0xAA, 0xAA, 0xAA} /* 41MHz XTal */ | ||
1896 | }; | ||
1897 | |||
1898 | const uint8_t nominalRate5bw[3][5] = { | ||
1899 | /* TRCG Nominal Rate [37:0] */ | ||
1900 | {0x1C, 0xB3, 0x33, 0x33, 0x33}, /* 20.5MHz XTal */ | ||
1901 | {0x21, 0x99, 0x99, 0x99, 0x99}, /* 24MHz XTal */ | ||
1902 | {0x1C, 0xB3, 0x33, 0x33, 0x33} /* 41MHz XTal */ | ||
1903 | }; | ||
1904 | |||
1905 | const uint8_t nominalRate17bw[3][5] = { | ||
1906 | /* TRCG Nominal Rate [37:0] */ | ||
1907 | {0x58, 0xE2, 0xAF, 0xE0, 0xBC}, /* 20.5MHz XTal */ | ||
1908 | {0x68, 0x0F, 0xA2, 0x32, 0xD0}, /* 24MHz XTal */ | ||
1909 | {0x58, 0xE2, 0xAF, 0xE0, 0xBC} /* 41MHz XTal */ | ||
1910 | }; | ||
1911 | |||
1912 | const uint8_t itbCoef8bw[3][14] = { | ||
1913 | {0x26, 0xAF, 0x06, 0xCD, 0x13, 0xBB, 0x28, 0xBA, | ||
1914 | 0x23, 0xA9, 0x1F, 0xA8, 0x2C, 0xC8}, /* 20.5MHz XTal */ | ||
1915 | {0x2F, 0xBA, 0x28, 0x9B, 0x28, 0x9D, 0x28, 0xA1, | ||
1916 | 0x29, 0xA5, 0x2A, 0xAC, 0x29, 0xB5}, /* 24MHz XTal */ | ||
1917 | {0x26, 0xAF, 0x06, 0xCD, 0x13, 0xBB, 0x28, 0xBA, | ||
1918 | 0x23, 0xA9, 0x1F, 0xA8, 0x2C, 0xC8} /* 41MHz XTal */ | ||
1919 | }; | ||
1920 | |||
1921 | const uint8_t itbCoef7bw[3][14] = { | ||
1922 | {0x2C, 0xBD, 0x02, 0xCF, 0x04, 0xF8, 0x23, 0xA6, | ||
1923 | 0x29, 0xB0, 0x26, 0xA9, 0x21, 0xA5}, /* 20.5MHz XTal */ | ||
1924 | {0x30, 0xB1, 0x29, 0x9A, 0x28, 0x9C, 0x28, 0xA0, | ||
1925 | 0x29, 0xA2, 0x2B, 0xA6, 0x2B, 0xAD}, /* 24MHz XTal */ | ||
1926 | {0x2C, 0xBD, 0x02, 0xCF, 0x04, 0xF8, 0x23, 0xA6, | ||
1927 | 0x29, 0xB0, 0x26, 0xA9, 0x21, 0xA5} /* 41MHz XTal */ | ||
1928 | }; | ||
1929 | |||
1930 | const uint8_t itbCoef6bw[3][14] = { | ||
1931 | {0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, | ||
1932 | 0x00, 0xCF, 0x00, 0xE6, 0x23, 0xA4}, /* 20.5MHz XTal */ | ||
1933 | {0x31, 0xA8, 0x29, 0x9B, 0x27, 0x9C, 0x28, 0x9E, | ||
1934 | 0x29, 0xA4, 0x29, 0xA2, 0x29, 0xA8}, /* 24MHz XTal */ | ||
1935 | {0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, | ||
1936 | 0x00, 0xCF, 0x00, 0xE6, 0x23, 0xA4} /* 41MHz XTal */ | ||
1937 | }; | ||
1938 | |||
1939 | const uint8_t itbCoef5bw[3][14] = { | ||
1940 | {0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, | ||
1941 | 0x00, 0xCF, 0x00, 0xE6, 0x23, 0xA4}, /* 20.5MHz XTal */ | ||
1942 | {0x31, 0xA8, 0x29, 0x9B, 0x27, 0x9C, 0x28, 0x9E, | ||
1943 | 0x29, 0xA4, 0x29, 0xA2, 0x29, 0xA8}, /* 24MHz XTal */ | ||
1944 | {0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, | ||
1945 | 0x00, 0xCF, 0x00, 0xE6, 0x23, 0xA4} /* 41MHz XTal */ | ||
1946 | }; | ||
1947 | |||
1948 | const uint8_t itbCoef17bw[3][14] = { | ||
1949 | {0x25, 0xA0, 0x36, 0x8D, 0x2E, 0x94, 0x28, 0x9B, | ||
1950 | 0x32, 0x90, 0x2C, 0x9D, 0x29, 0x99}, /* 20.5MHz XTal */ | ||
1951 | {0x33, 0x8E, 0x2B, 0x97, 0x2D, 0x95, 0x37, 0x8B, | ||
1952 | 0x30, 0x97, 0x2D, 0x9A, 0x21, 0xA4}, /* 24MHz XTal */ | ||
1953 | {0x25, 0xA0, 0x36, 0x8D, 0x2E, 0x94, 0x28, 0x9B, | ||
1954 | 0x32, 0x90, 0x2C, 0x9D, 0x29, 0x99} /* 41MHz XTal */ | ||
1955 | }; | ||
1956 | |||
1957 | /* Set SLV-T Bank : 0x20 */ | ||
1958 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x20); | ||
1581 | 1959 | ||
1582 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | ||
1583 | switch (bandwidth) { | 1960 | switch (bandwidth) { |
1584 | case 8000000: | 1961 | case 8000000: |
1585 | /* bank 0x20, reg 0x9f */ | 1962 | /* <Timing Recovery setting> */ |
1586 | b20_9f[0] = 0x11; | 1963 | cxd2841er_write_regs(priv, I2C_SLVT, |
1587 | b20_9f[1] = 0xf0; | 1964 | 0x9F, nominalRate8bw[priv->xtal], 5); |
1588 | b20_9f[2] = 0x00; | 1965 | |
1589 | b20_9f[3] = 0x00; | 1966 | /* Set SLV-T Bank : 0x27 */ |
1590 | b20_9f[4] = 0x00; | 1967 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x27); |
1591 | /* bank 0x10, reg 0xa6 */ | 1968 | cxd2841er_set_reg_bits(priv, I2C_SLVT, |
1592 | b10_a6[0] = 0x26; | 1969 | 0x7a, 0x00, 0x0f); |
1593 | b10_a6[1] = 0xaf; | 1970 | |
1594 | b10_a6[2] = 0x06; | 1971 | /* Set SLV-T Bank : 0x10 */ |
1595 | b10_a6[3] = 0xcd; | 1972 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); |
1596 | b10_a6[4] = 0x13; | 1973 | |
1597 | b10_a6[5] = 0xbb; | 1974 | /* Group delay equaliser settings for |
1598 | b10_a6[6] = 0x28; | 1975 | * ASCOT2D, ASCOT2E and ASCOT3 tuners |
1599 | b10_a6[7] = 0xba; | 1976 | */ |
1600 | b10_a6[8] = 0x23; | 1977 | cxd2841er_write_regs(priv, I2C_SLVT, |
1601 | b10_a6[9] = 0xa9; | 1978 | 0xA6, itbCoef8bw[priv->xtal], 14); |
1602 | b10_a6[10] = 0x1f; | 1979 | /* <IF freq setting> */ |
1603 | b10_a6[11] = 0xa8; | 1980 | iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 4.80); |
1604 | b10_a6[12] = 0x2c; | 1981 | data[0] = (u8) ((iffreq >> 16) & 0xff); |
1605 | b10_a6[13] = 0xc8; | 1982 | data[1] = (u8)((iffreq >> 8) & 0xff); |
1606 | iffreq = MAKE_IFFREQ_CONFIG(4.80); | 1983 | data[2] = (u8)(iffreq & 0xff); |
1607 | b10_d7 = 0x00; | 1984 | cxd2841er_write_regs(priv, I2C_SLVT, 0xB6, data, 3); |
1985 | /* System bandwidth setting */ | ||
1986 | cxd2841er_set_reg_bits( | ||
1987 | priv, I2C_SLVT, 0xD7, 0x00, 0x07); | ||
1608 | break; | 1988 | break; |
1609 | case 7000000: | 1989 | case 7000000: |
1610 | /* bank 0x20, reg 0x9f */ | 1990 | /* <Timing Recovery setting> */ |
1611 | b20_9f[0] = 0x14; | 1991 | cxd2841er_write_regs(priv, I2C_SLVT, |
1612 | b20_9f[1] = 0x80; | 1992 | 0x9F, nominalRate7bw[priv->xtal], 5); |
1613 | b20_9f[2] = 0x00; | 1993 | |
1614 | b20_9f[3] = 0x00; | 1994 | /* Set SLV-T Bank : 0x27 */ |
1615 | b20_9f[4] = 0x00; | 1995 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x27); |
1616 | /* bank 0x10, reg 0xa6 */ | 1996 | cxd2841er_set_reg_bits(priv, I2C_SLVT, |
1617 | b10_a6[0] = 0x2C; | 1997 | 0x7a, 0x00, 0x0f); |
1618 | b10_a6[1] = 0xBD; | 1998 | |
1619 | b10_a6[2] = 0x02; | 1999 | /* Set SLV-T Bank : 0x10 */ |
1620 | b10_a6[3] = 0xCF; | 2000 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); |
1621 | b10_a6[4] = 0x04; | 2001 | |
1622 | b10_a6[5] = 0xF8; | 2002 | /* Group delay equaliser settings for |
1623 | b10_a6[6] = 0x23; | 2003 | * ASCOT2D, ASCOT2E and ASCOT3 tuners |
1624 | b10_a6[7] = 0xA6; | 2004 | */ |
1625 | b10_a6[8] = 0x29; | 2005 | cxd2841er_write_regs(priv, I2C_SLVT, |
1626 | b10_a6[9] = 0xB0; | 2006 | 0xA6, itbCoef7bw[priv->xtal], 14); |
1627 | b10_a6[10] = 0x26; | 2007 | /* <IF freq setting> */ |
1628 | b10_a6[11] = 0xA9; | 2008 | iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 4.20); |
1629 | b10_a6[12] = 0x21; | 2009 | data[0] = (u8) ((iffreq >> 16) & 0xff); |
1630 | b10_a6[13] = 0xA5; | 2010 | data[1] = (u8)((iffreq >> 8) & 0xff); |
1631 | iffreq = MAKE_IFFREQ_CONFIG(4.2); | 2011 | data[2] = (u8)(iffreq & 0xff); |
1632 | b10_d7 = 0x02; | 2012 | cxd2841er_write_regs(priv, I2C_SLVT, 0xB6, data, 3); |
2013 | /* System bandwidth setting */ | ||
2014 | cxd2841er_set_reg_bits( | ||
2015 | priv, I2C_SLVT, 0xD7, 0x02, 0x07); | ||
1633 | break; | 2016 | break; |
1634 | case 6000000: | 2017 | case 6000000: |
1635 | /* bank 0x20, reg 0x9f */ | 2018 | /* <Timing Recovery setting> */ |
1636 | b20_9f[0] = 0x17; | 2019 | cxd2841er_write_regs(priv, I2C_SLVT, |
1637 | b20_9f[1] = 0xEA; | 2020 | 0x9F, nominalRate6bw[priv->xtal], 5); |
1638 | b20_9f[2] = 0xAA; | 2021 | |
1639 | b20_9f[3] = 0xAA; | 2022 | /* Set SLV-T Bank : 0x27 */ |
1640 | b20_9f[4] = 0xAA; | 2023 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x27); |
1641 | /* bank 0x10, reg 0xa6 */ | 2024 | cxd2841er_set_reg_bits(priv, I2C_SLVT, |
1642 | b10_a6[0] = 0x27; | 2025 | 0x7a, 0x00, 0x0f); |
1643 | b10_a6[1] = 0xA7; | 2026 | |
1644 | b10_a6[2] = 0x28; | 2027 | /* Set SLV-T Bank : 0x10 */ |
1645 | b10_a6[3] = 0xB3; | 2028 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); |
1646 | b10_a6[4] = 0x02; | 2029 | |
1647 | b10_a6[5] = 0xF0; | 2030 | /* Group delay equaliser settings for |
1648 | b10_a6[6] = 0x01; | 2031 | * ASCOT2D, ASCOT2E and ASCOT3 tuners |
1649 | b10_a6[7] = 0xE8; | 2032 | */ |
1650 | b10_a6[8] = 0x00; | 2033 | cxd2841er_write_regs(priv, I2C_SLVT, |
1651 | b10_a6[9] = 0xCF; | 2034 | 0xA6, itbCoef6bw[priv->xtal], 14); |
1652 | b10_a6[10] = 0x00; | 2035 | /* <IF freq setting> */ |
1653 | b10_a6[11] = 0xE6; | 2036 | iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 3.60); |
1654 | b10_a6[12] = 0x23; | 2037 | data[0] = (u8) ((iffreq >> 16) & 0xff); |
1655 | b10_a6[13] = 0xA4; | 2038 | data[1] = (u8)((iffreq >> 8) & 0xff); |
1656 | iffreq = MAKE_IFFREQ_CONFIG(3.6); | 2039 | data[2] = (u8)(iffreq & 0xff); |
1657 | b10_d7 = 0x04; | 2040 | cxd2841er_write_regs(priv, I2C_SLVT, 0xB6, data, 3); |
2041 | /* System bandwidth setting */ | ||
2042 | cxd2841er_set_reg_bits( | ||
2043 | priv, I2C_SLVT, 0xD7, 0x04, 0x07); | ||
1658 | break; | 2044 | break; |
1659 | case 5000000: | 2045 | case 5000000: |
1660 | /* bank 0x20, reg 0x9f */ | 2046 | /* <Timing Recovery setting> */ |
1661 | b20_9f[0] = 0x1C; | 2047 | cxd2841er_write_regs(priv, I2C_SLVT, |
1662 | b20_9f[1] = 0xB3; | 2048 | 0x9F, nominalRate5bw[priv->xtal], 5); |
1663 | b20_9f[2] = 0x33; | 2049 | |
1664 | b20_9f[3] = 0x33; | 2050 | /* Set SLV-T Bank : 0x27 */ |
1665 | b20_9f[4] = 0x33; | 2051 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x27); |
1666 | /* bank 0x10, reg 0xa6 */ | 2052 | cxd2841er_set_reg_bits(priv, I2C_SLVT, |
1667 | b10_a6[0] = 0x27; | 2053 | 0x7a, 0x00, 0x0f); |
1668 | b10_a6[1] = 0xA7; | 2054 | |
1669 | b10_a6[2] = 0x28; | 2055 | /* Set SLV-T Bank : 0x10 */ |
1670 | b10_a6[3] = 0xB3; | 2056 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); |
1671 | b10_a6[4] = 0x02; | 2057 | |
1672 | b10_a6[5] = 0xF0; | 2058 | /* Group delay equaliser settings for |
1673 | b10_a6[6] = 0x01; | 2059 | * ASCOT2D, ASCOT2E and ASCOT3 tuners |
1674 | b10_a6[7] = 0xE8; | 2060 | */ |
1675 | b10_a6[8] = 0x00; | 2061 | cxd2841er_write_regs(priv, I2C_SLVT, |
1676 | b10_a6[9] = 0xCF; | 2062 | 0xA6, itbCoef5bw[priv->xtal], 14); |
1677 | b10_a6[10] = 0x00; | 2063 | /* <IF freq setting> */ |
1678 | b10_a6[11] = 0xE6; | 2064 | iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 3.60); |
1679 | b10_a6[12] = 0x23; | 2065 | data[0] = (u8) ((iffreq >> 16) & 0xff); |
1680 | b10_a6[13] = 0xA4; | 2066 | data[1] = (u8)((iffreq >> 8) & 0xff); |
1681 | iffreq = MAKE_IFFREQ_CONFIG(3.6); | 2067 | data[2] = (u8)(iffreq & 0xff); |
1682 | b10_d7 = 0x06; | 2068 | cxd2841er_write_regs(priv, I2C_SLVT, 0xB6, data, 3); |
2069 | /* System bandwidth setting */ | ||
2070 | cxd2841er_set_reg_bits( | ||
2071 | priv, I2C_SLVT, 0xD7, 0x06, 0x07); | ||
1683 | break; | 2072 | break; |
1684 | case 1712000: | 2073 | case 1712000: |
1685 | /* bank 0x20, reg 0x9f */ | 2074 | /* <Timing Recovery setting> */ |
1686 | b20_9f[0] = 0x58; | 2075 | cxd2841er_write_regs(priv, I2C_SLVT, |
1687 | b20_9f[1] = 0xE2; | 2076 | 0x9F, nominalRate17bw[priv->xtal], 5); |
1688 | b20_9f[2] = 0xAF; | 2077 | |
1689 | b20_9f[3] = 0xE0; | 2078 | /* Set SLV-T Bank : 0x27 */ |
1690 | b20_9f[4] = 0xBC; | 2079 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x27); |
1691 | /* bank 0x10, reg 0xa6 */ | 2080 | cxd2841er_set_reg_bits(priv, I2C_SLVT, |
1692 | b10_a6[0] = 0x25; | 2081 | 0x7a, 0x03, 0x0f); |
1693 | b10_a6[1] = 0xA0; | 2082 | |
1694 | b10_a6[2] = 0x36; | 2083 | /* Set SLV-T Bank : 0x10 */ |
1695 | b10_a6[3] = 0x8D; | 2084 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); |
1696 | b10_a6[4] = 0x2E; | 2085 | |
1697 | b10_a6[5] = 0x94; | 2086 | /* Group delay equaliser settings for |
1698 | b10_a6[6] = 0x28; | 2087 | * ASCOT2D, ASCOT2E and ASCOT3 tuners |
1699 | b10_a6[7] = 0x9B; | 2088 | */ |
1700 | b10_a6[8] = 0x32; | 2089 | cxd2841er_write_regs(priv, I2C_SLVT, |
1701 | b10_a6[9] = 0x90; | 2090 | 0xA6, itbCoef17bw[priv->xtal], 14); |
1702 | b10_a6[10] = 0x2C; | 2091 | /* <IF freq setting> */ |
1703 | b10_a6[11] = 0x9D; | 2092 | iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 3.50); |
1704 | b10_a6[12] = 0x29; | 2093 | data[0] = (u8) ((iffreq >> 16) & 0xff); |
1705 | b10_a6[13] = 0x99; | 2094 | data[1] = (u8)((iffreq >> 8) & 0xff); |
1706 | iffreq = MAKE_IFFREQ_CONFIG(3.5); | 2095 | data[2] = (u8)(iffreq & 0xff); |
1707 | b10_d7 = 0x03; | 2096 | cxd2841er_write_regs(priv, I2C_SLVT, 0xB6, data, 3); |
2097 | /* System bandwidth setting */ | ||
2098 | cxd2841er_set_reg_bits( | ||
2099 | priv, I2C_SLVT, 0xD7, 0x03, 0x07); | ||
1708 | break; | 2100 | break; |
1709 | default: | 2101 | default: |
1710 | return -EINVAL; | 2102 | return -EINVAL; |
1711 | } | 2103 | } |
1712 | /* Set SLV-T Bank : 0x20 */ | ||
1713 | cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x20); | ||
1714 | cxd2841er_write_regs(priv, I2C_SLVT, 0x9f, b20_9f, sizeof(b20_9f)); | ||
1715 | /* Set SLV-T Bank : 0x27 */ | ||
1716 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x27); | ||
1717 | cxd2841er_set_reg_bits( | ||
1718 | priv, I2C_SLVT, 0x7a, | ||
1719 | (bandwidth == 1712000 ? 0x03 : 0x00), 0x0f); | ||
1720 | /* Set SLV-T Bank : 0x10 */ | ||
1721 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); | ||
1722 | /* Group delay equaliser sett. for ASCOT2E */ | ||
1723 | cxd2841er_write_regs(priv, I2C_SLVT, 0xa6, b10_a6, sizeof(b10_a6)); | ||
1724 | /* <IF freq setting> */ | ||
1725 | b10_b6[0] = (u8) ((iffreq >> 16) & 0xff); | ||
1726 | b10_b6[1] = (u8)((iffreq >> 8) & 0xff); | ||
1727 | b10_b6[2] = (u8)(iffreq & 0xff); | ||
1728 | cxd2841er_write_regs(priv, I2C_SLVT, 0xb6, b10_b6, sizeof(b10_b6)); | ||
1729 | /* System bandwidth setting */ | ||
1730 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xd7, b10_d7, 0x07); | ||
1731 | return 0; | 2104 | return 0; |
1732 | } | 2105 | } |
1733 | 2106 | ||
1734 | static int cxd2841er_sleep_tc_to_active_t_band( | 2107 | static int cxd2841er_sleep_tc_to_active_t_band( |
1735 | struct cxd2841er_priv *priv, u32 bandwidth) | 2108 | struct cxd2841er_priv *priv, u32 bandwidth) |
1736 | { | 2109 | { |
1737 | u8 b13_9c[2] = { 0x01, 0x14 }; | 2110 | u8 data[MAX_WRITE_REGSIZE]; |
1738 | u8 bw8mhz_b10_9f[] = { 0x11, 0xF0, 0x00, 0x00, 0x00 }; | ||
1739 | u8 bw8mhz_b10_a6[] = { 0x26, 0xAF, 0x06, 0xCD, 0x13, 0xBB, | ||
1740 | 0x28, 0xBA, 0x23, 0xA9, 0x1F, 0xA8, 0x2C, 0xC8 }; | ||
1741 | u8 bw8mhz_b10_d9[] = { 0x01, 0xE0 }; | ||
1742 | u8 bw8mhz_b17_38[] = { 0x01, 0x02 }; | ||
1743 | u8 bw7mhz_b10_9f[] = { 0x14, 0x80, 0x00, 0x00, 0x00 }; | ||
1744 | u8 bw7mhz_b10_a6[] = { 0x2C, 0xBD, 0x02, 0xCF, 0x04, 0xF8, | ||
1745 | 0x23, 0xA6, 0x29, 0xB0, 0x26, 0xA9, 0x21, 0xA5 }; | ||
1746 | u8 bw7mhz_b10_d9[] = { 0x12, 0xF8 }; | ||
1747 | u8 bw7mhz_b17_38[] = { 0x00, 0x03 }; | ||
1748 | u8 bw6mhz_b10_9f[] = { 0x17, 0xEA, 0xAA, 0xAA, 0xAA }; | ||
1749 | u8 bw6mhz_b10_a6[] = { 0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, | ||
1750 | 0x01, 0xE8, 0x00, 0xCF, 0x00, 0xE6, 0x23, 0xA4 }; | ||
1751 | u8 bw6mhz_b10_d9[] = { 0x1F, 0xDC }; | ||
1752 | u8 bw6mhz_b17_38[] = { 0x00, 0x03 }; | ||
1753 | u8 bw5mhz_b10_9f[] = { 0x1C, 0xB3, 0x33, 0x33, 0x33 }; | ||
1754 | u8 bw5mhz_b10_a6[] = { 0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, | ||
1755 | 0x01, 0xE8, 0x00, 0xCF, 0x00, 0xE6, 0x23, 0xA4 }; | ||
1756 | u8 bw5mhz_b10_d9[] = { 0x26, 0x3C }; | ||
1757 | u8 bw5mhz_b17_38[] = { 0x00, 0x03 }; | ||
1758 | u8 b10_b6[3]; | ||
1759 | u8 d7val; | ||
1760 | u32 iffreq; | 2111 | u32 iffreq; |
1761 | u8 *b10_9f; | 2112 | u8 nominalRate8bw[3][5] = { |
1762 | u8 *b10_a6; | 2113 | /* TRCG Nominal Rate [37:0] */ |
1763 | u8 *b10_d9; | 2114 | {0x11, 0xF0, 0x00, 0x00, 0x00}, /* 20.5MHz XTal */ |
1764 | u8 *b17_38; | 2115 | {0x15, 0x00, 0x00, 0x00, 0x00}, /* 24MHz XTal */ |
2116 | {0x11, 0xF0, 0x00, 0x00, 0x00} /* 41MHz XTal */ | ||
2117 | }; | ||
2118 | u8 nominalRate7bw[3][5] = { | ||
2119 | /* TRCG Nominal Rate [37:0] */ | ||
2120 | {0x14, 0x80, 0x00, 0x00, 0x00}, /* 20.5MHz XTal */ | ||
2121 | {0x18, 0x00, 0x00, 0x00, 0x00}, /* 24MHz XTal */ | ||
2122 | {0x14, 0x80, 0x00, 0x00, 0x00} /* 41MHz XTal */ | ||
2123 | }; | ||
2124 | u8 nominalRate6bw[3][5] = { | ||
2125 | /* TRCG Nominal Rate [37:0] */ | ||
2126 | {0x17, 0xEA, 0xAA, 0xAA, 0xAA}, /* 20.5MHz XTal */ | ||
2127 | {0x1C, 0x00, 0x00, 0x00, 0x00}, /* 24MHz XTal */ | ||
2128 | {0x17, 0xEA, 0xAA, 0xAA, 0xAA} /* 41MHz XTal */ | ||
2129 | }; | ||
2130 | u8 nominalRate5bw[3][5] = { | ||
2131 | /* TRCG Nominal Rate [37:0] */ | ||
2132 | {0x1C, 0xB3, 0x33, 0x33, 0x33}, /* 20.5MHz XTal */ | ||
2133 | {0x21, 0x99, 0x99, 0x99, 0x99}, /* 24MHz XTal */ | ||
2134 | {0x1C, 0xB3, 0x33, 0x33, 0x33} /* 41MHz XTal */ | ||
2135 | }; | ||
1765 | 2136 | ||
1766 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | 2137 | u8 itbCoef8bw[3][14] = { |
2138 | {0x26, 0xAF, 0x06, 0xCD, 0x13, 0xBB, 0x28, 0xBA, 0x23, 0xA9, | ||
2139 | 0x1F, 0xA8, 0x2C, 0xC8}, /* 20.5MHz XTal */ | ||
2140 | {0x2F, 0xBA, 0x28, 0x9B, 0x28, 0x9D, 0x28, 0xA1, 0x29, 0xA5, | ||
2141 | 0x2A, 0xAC, 0x29, 0xB5}, /* 24MHz XTal */ | ||
2142 | {0x26, 0xAF, 0x06, 0xCD, 0x13, 0xBB, 0x28, 0xBA, 0x23, 0xA9, | ||
2143 | 0x1F, 0xA8, 0x2C, 0xC8} /* 41MHz XTal */ | ||
2144 | }; | ||
2145 | u8 itbCoef7bw[3][14] = { | ||
2146 | {0x2C, 0xBD, 0x02, 0xCF, 0x04, 0xF8, 0x23, 0xA6, 0x29, 0xB0, | ||
2147 | 0x26, 0xA9, 0x21, 0xA5}, /* 20.5MHz XTal */ | ||
2148 | {0x30, 0xB1, 0x29, 0x9A, 0x28, 0x9C, 0x28, 0xA0, 0x29, 0xA2, | ||
2149 | 0x2B, 0xA6, 0x2B, 0xAD}, /* 24MHz XTal */ | ||
2150 | {0x2C, 0xBD, 0x02, 0xCF, 0x04, 0xF8, 0x23, 0xA6, 0x29, 0xB0, | ||
2151 | 0x26, 0xA9, 0x21, 0xA5} /* 41MHz XTal */ | ||
2152 | }; | ||
2153 | u8 itbCoef6bw[3][14] = { | ||
2154 | {0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, 0x00, 0xCF, | ||
2155 | 0x00, 0xE6, 0x23, 0xA4}, /* 20.5MHz XTal */ | ||
2156 | {0x31, 0xA8, 0x29, 0x9B, 0x27, 0x9C, 0x28, 0x9E, 0x29, 0xA4, | ||
2157 | 0x29, 0xA2, 0x29, 0xA8}, /* 24MHz XTal */ | ||
2158 | {0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, 0x00, 0xCF, | ||
2159 | 0x00, 0xE6, 0x23, 0xA4} /* 41MHz XTal */ | ||
2160 | }; | ||
2161 | u8 itbCoef5bw[3][14] = { | ||
2162 | {0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, 0x00, 0xCF, | ||
2163 | 0x00, 0xE6, 0x23, 0xA4}, /* 20.5MHz XTal */ | ||
2164 | {0x31, 0xA8, 0x29, 0x9B, 0x27, 0x9C, 0x28, 0x9E, 0x29, 0xA4, | ||
2165 | 0x29, 0xA2, 0x29, 0xA8}, /* 24MHz XTal */ | ||
2166 | {0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, 0x00, 0xCF, | ||
2167 | 0x00, 0xE6, 0x23, 0xA4} /* 41MHz XTal */ | ||
2168 | }; | ||
2169 | |||
2170 | /* Set SLV-T Bank : 0x13 */ | ||
1767 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x13); | 2171 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x13); |
1768 | /* Echo performance optimization setting */ | 2172 | /* Echo performance optimization setting */ |
1769 | cxd2841er_write_regs(priv, I2C_SLVT, 0x9c, b13_9c, sizeof(b13_9c)); | 2173 | data[0] = 0x01; |
2174 | data[1] = 0x14; | ||
2175 | cxd2841er_write_regs(priv, I2C_SLVT, 0x9C, data, 2); | ||
2176 | |||
2177 | /* Set SLV-T Bank : 0x10 */ | ||
1770 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); | 2178 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); |
1771 | 2179 | ||
1772 | switch (bandwidth) { | 2180 | switch (bandwidth) { |
1773 | case 8000000: | 2181 | case 8000000: |
1774 | b10_9f = bw8mhz_b10_9f; | 2182 | /* <Timing Recovery setting> */ |
1775 | b10_a6 = bw8mhz_b10_a6; | 2183 | cxd2841er_write_regs(priv, I2C_SLVT, |
1776 | b10_d9 = bw8mhz_b10_d9; | 2184 | 0x9F, nominalRate8bw[priv->xtal], 5); |
1777 | b17_38 = bw8mhz_b17_38; | 2185 | /* Group delay equaliser settings for |
1778 | d7val = 0; | 2186 | * ASCOT2D, ASCOT2E and ASCOT3 tuners |
1779 | iffreq = MAKE_IFFREQ_CONFIG(4.80); | 2187 | */ |
2188 | cxd2841er_write_regs(priv, I2C_SLVT, | ||
2189 | 0xA6, itbCoef8bw[priv->xtal], 14); | ||
2190 | /* <IF freq setting> */ | ||
2191 | iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 4.80); | ||
2192 | data[0] = (u8) ((iffreq >> 16) & 0xff); | ||
2193 | data[1] = (u8)((iffreq >> 8) & 0xff); | ||
2194 | data[2] = (u8)(iffreq & 0xff); | ||
2195 | cxd2841er_write_regs(priv, I2C_SLVT, 0xB6, data, 3); | ||
2196 | /* System bandwidth setting */ | ||
2197 | cxd2841er_set_reg_bits( | ||
2198 | priv, I2C_SLVT, 0xD7, 0x00, 0x07); | ||
2199 | |||
2200 | /* Demod core latency setting */ | ||
2201 | if (priv->xtal == SONY_XTAL_24000) { | ||
2202 | data[0] = 0x15; | ||
2203 | data[1] = 0x28; | ||
2204 | } else { | ||
2205 | data[0] = 0x01; | ||
2206 | data[1] = 0xE0; | ||
2207 | } | ||
2208 | cxd2841er_write_regs(priv, I2C_SLVT, 0xD9, data, 2); | ||
2209 | |||
2210 | /* Notch filter setting */ | ||
2211 | data[0] = 0x01; | ||
2212 | data[1] = 0x02; | ||
2213 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x17); | ||
2214 | cxd2841er_write_regs(priv, I2C_SLVT, 0x38, data, 2); | ||
1780 | break; | 2215 | break; |
1781 | case 7000000: | 2216 | case 7000000: |
1782 | b10_9f = bw7mhz_b10_9f; | 2217 | /* <Timing Recovery setting> */ |
1783 | b10_a6 = bw7mhz_b10_a6; | 2218 | cxd2841er_write_regs(priv, I2C_SLVT, |
1784 | b10_d9 = bw7mhz_b10_d9; | 2219 | 0x9F, nominalRate7bw[priv->xtal], 5); |
1785 | b17_38 = bw7mhz_b17_38; | 2220 | /* Group delay equaliser settings for |
1786 | d7val = 2; | 2221 | * ASCOT2D, ASCOT2E and ASCOT3 tuners |
1787 | iffreq = MAKE_IFFREQ_CONFIG(4.20); | 2222 | */ |
2223 | cxd2841er_write_regs(priv, I2C_SLVT, | ||
2224 | 0xA6, itbCoef7bw[priv->xtal], 14); | ||
2225 | /* <IF freq setting> */ | ||
2226 | iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 4.20); | ||
2227 | data[0] = (u8) ((iffreq >> 16) & 0xff); | ||
2228 | data[1] = (u8)((iffreq >> 8) & 0xff); | ||
2229 | data[2] = (u8)(iffreq & 0xff); | ||
2230 | cxd2841er_write_regs(priv, I2C_SLVT, 0xB6, data, 3); | ||
2231 | /* System bandwidth setting */ | ||
2232 | cxd2841er_set_reg_bits( | ||
2233 | priv, I2C_SLVT, 0xD7, 0x02, 0x07); | ||
2234 | |||
2235 | /* Demod core latency setting */ | ||
2236 | if (priv->xtal == SONY_XTAL_24000) { | ||
2237 | data[0] = 0x1F; | ||
2238 | data[1] = 0xF8; | ||
2239 | } else { | ||
2240 | data[0] = 0x12; | ||
2241 | data[1] = 0xF8; | ||
2242 | } | ||
2243 | cxd2841er_write_regs(priv, I2C_SLVT, 0xD9, data, 2); | ||
2244 | |||
2245 | /* Notch filter setting */ | ||
2246 | data[0] = 0x00; | ||
2247 | data[1] = 0x03; | ||
2248 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x17); | ||
2249 | cxd2841er_write_regs(priv, I2C_SLVT, 0x38, data, 2); | ||
1788 | break; | 2250 | break; |
1789 | case 6000000: | 2251 | case 6000000: |
1790 | b10_9f = bw6mhz_b10_9f; | 2252 | /* <Timing Recovery setting> */ |
1791 | b10_a6 = bw6mhz_b10_a6; | 2253 | cxd2841er_write_regs(priv, I2C_SLVT, |
1792 | b10_d9 = bw6mhz_b10_d9; | 2254 | 0x9F, nominalRate6bw[priv->xtal], 5); |
1793 | b17_38 = bw6mhz_b17_38; | 2255 | /* Group delay equaliser settings for |
1794 | d7val = 4; | 2256 | * ASCOT2D, ASCOT2E and ASCOT3 tuners |
1795 | iffreq = MAKE_IFFREQ_CONFIG(3.60); | 2257 | */ |
2258 | cxd2841er_write_regs(priv, I2C_SLVT, | ||
2259 | 0xA6, itbCoef6bw[priv->xtal], 14); | ||
2260 | /* <IF freq setting> */ | ||
2261 | iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 3.60); | ||
2262 | data[0] = (u8) ((iffreq >> 16) & 0xff); | ||
2263 | data[1] = (u8)((iffreq >> 8) & 0xff); | ||
2264 | data[2] = (u8)(iffreq & 0xff); | ||
2265 | cxd2841er_write_regs(priv, I2C_SLVT, 0xB6, data, 3); | ||
2266 | /* System bandwidth setting */ | ||
2267 | cxd2841er_set_reg_bits( | ||
2268 | priv, I2C_SLVT, 0xD7, 0x04, 0x07); | ||
2269 | |||
2270 | /* Demod core latency setting */ | ||
2271 | if (priv->xtal == SONY_XTAL_24000) { | ||
2272 | data[0] = 0x25; | ||
2273 | data[1] = 0x4C; | ||
2274 | } else { | ||
2275 | data[0] = 0x1F; | ||
2276 | data[1] = 0xDC; | ||
2277 | } | ||
2278 | cxd2841er_write_regs(priv, I2C_SLVT, 0xD9, data, 2); | ||
2279 | |||
2280 | /* Notch filter setting */ | ||
2281 | data[0] = 0x00; | ||
2282 | data[1] = 0x03; | ||
2283 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x17); | ||
2284 | cxd2841er_write_regs(priv, I2C_SLVT, 0x38, data, 2); | ||
1796 | break; | 2285 | break; |
1797 | case 5000000: | 2286 | case 5000000: |
1798 | b10_9f = bw5mhz_b10_9f; | 2287 | /* <Timing Recovery setting> */ |
1799 | b10_a6 = bw5mhz_b10_a6; | 2288 | cxd2841er_write_regs(priv, I2C_SLVT, |
1800 | b10_d9 = bw5mhz_b10_d9; | 2289 | 0x9F, nominalRate5bw[priv->xtal], 5); |
1801 | b17_38 = bw5mhz_b17_38; | 2290 | /* Group delay equaliser settings for |
1802 | d7val = 6; | 2291 | * ASCOT2D, ASCOT2E and ASCOT3 tuners |
1803 | iffreq = MAKE_IFFREQ_CONFIG(3.60); | 2292 | */ |
2293 | cxd2841er_write_regs(priv, I2C_SLVT, | ||
2294 | 0xA6, itbCoef5bw[priv->xtal], 14); | ||
2295 | /* <IF freq setting> */ | ||
2296 | iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 3.60); | ||
2297 | data[0] = (u8) ((iffreq >> 16) & 0xff); | ||
2298 | data[1] = (u8)((iffreq >> 8) & 0xff); | ||
2299 | data[2] = (u8)(iffreq & 0xff); | ||
2300 | cxd2841er_write_regs(priv, I2C_SLVT, 0xB6, data, 3); | ||
2301 | /* System bandwidth setting */ | ||
2302 | cxd2841er_set_reg_bits( | ||
2303 | priv, I2C_SLVT, 0xD7, 0x06, 0x07); | ||
2304 | |||
2305 | /* Demod core latency setting */ | ||
2306 | if (priv->xtal == SONY_XTAL_24000) { | ||
2307 | data[0] = 0x2C; | ||
2308 | data[1] = 0xC2; | ||
2309 | } else { | ||
2310 | data[0] = 0x26; | ||
2311 | data[1] = 0x3C; | ||
2312 | } | ||
2313 | cxd2841er_write_regs(priv, I2C_SLVT, 0xD9, data, 2); | ||
2314 | |||
2315 | /* Notch filter setting */ | ||
2316 | data[0] = 0x00; | ||
2317 | data[1] = 0x03; | ||
2318 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x17); | ||
2319 | cxd2841er_write_regs(priv, I2C_SLVT, 0x38, data, 2); | ||
2320 | break; | ||
2321 | } | ||
2322 | |||
2323 | return 0; | ||
2324 | } | ||
2325 | |||
2326 | static int cxd2841er_sleep_tc_to_active_i_band( | ||
2327 | struct cxd2841er_priv *priv, u32 bandwidth) | ||
2328 | { | ||
2329 | u32 iffreq; | ||
2330 | u8 data[3]; | ||
2331 | |||
2332 | /* TRCG Nominal Rate */ | ||
2333 | u8 nominalRate8bw[3][5] = { | ||
2334 | {0x00, 0x00, 0x00, 0x00, 0x00}, /* 20.5MHz XTal */ | ||
2335 | {0x11, 0xB8, 0x00, 0x00, 0x00}, /* 24MHz XTal */ | ||
2336 | {0x00, 0x00, 0x00, 0x00, 0x00} /* 41MHz XTal */ | ||
2337 | }; | ||
2338 | |||
2339 | u8 nominalRate7bw[3][5] = { | ||
2340 | {0x00, 0x00, 0x00, 0x00, 0x00}, /* 20.5MHz XTal */ | ||
2341 | {0x14, 0x40, 0x00, 0x00, 0x00}, /* 24MHz XTal */ | ||
2342 | {0x00, 0x00, 0x00, 0x00, 0x00} /* 41MHz XTal */ | ||
2343 | }; | ||
2344 | |||
2345 | u8 nominalRate6bw[3][5] = { | ||
2346 | {0x14, 0x2E, 0x00, 0x00, 0x00}, /* 20.5MHz XTal */ | ||
2347 | {0x17, 0xA0, 0x00, 0x00, 0x00}, /* 24MHz XTal */ | ||
2348 | {0x14, 0x2E, 0x00, 0x00, 0x00} /* 41MHz XTal */ | ||
2349 | }; | ||
2350 | |||
2351 | u8 itbCoef8bw[3][14] = { | ||
2352 | {0x00}, /* 20.5MHz XTal */ | ||
2353 | {0x2F, 0xBA, 0x28, 0x9B, 0x28, 0x9D, 0x28, 0xA1, 0x29, | ||
2354 | 0xA5, 0x2A, 0xAC, 0x29, 0xB5}, /* 24MHz Xtal */ | ||
2355 | {0x0}, /* 41MHz XTal */ | ||
2356 | }; | ||
2357 | |||
2358 | u8 itbCoef7bw[3][14] = { | ||
2359 | {0x00}, /* 20.5MHz XTal */ | ||
2360 | {0x30, 0xB1, 0x29, 0x9A, 0x28, 0x9C, 0x28, 0xA0, 0x29, | ||
2361 | 0xA2, 0x2B, 0xA6, 0x2B, 0xAD}, /* 24MHz Xtal */ | ||
2362 | {0x00}, /* 41MHz XTal */ | ||
2363 | }; | ||
2364 | |||
2365 | u8 itbCoef6bw[3][14] = { | ||
2366 | {0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, 0x00, | ||
2367 | 0xCF, 0x00, 0xE6, 0x23, 0xA4}, /* 20.5MHz XTal */ | ||
2368 | {0x31, 0xA8, 0x29, 0x9B, 0x27, 0x9C, 0x28, 0x9E, 0x29, | ||
2369 | 0xA4, 0x29, 0xA2, 0x29, 0xA8}, /* 24MHz Xtal */ | ||
2370 | {0x27, 0xA7, 0x28, 0xB3, 0x02, 0xF0, 0x01, 0xE8, 0x00, | ||
2371 | 0xCF, 0x00, 0xE6, 0x23, 0xA4}, /* 41MHz XTal */ | ||
2372 | }; | ||
2373 | |||
2374 | dev_dbg(&priv->i2c->dev, "%s() bandwidth=%u\n", __func__, bandwidth); | ||
2375 | /* Set SLV-T Bank : 0x10 */ | ||
2376 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); | ||
2377 | |||
2378 | /* 20.5/41MHz Xtal support is not available | ||
2379 | * on ISDB-T 7MHzBW and 8MHzBW | ||
2380 | */ | ||
2381 | if (priv->xtal != SONY_XTAL_24000 && bandwidth > 6000000) { | ||
2382 | dev_err(&priv->i2c->dev, | ||
2383 | "%s(): bandwidth %d supported only for 24MHz xtal\n", | ||
2384 | __func__, bandwidth); | ||
2385 | return -EINVAL; | ||
2386 | } | ||
2387 | |||
2388 | switch (bandwidth) { | ||
2389 | case 8000000: | ||
2390 | /* TRCG Nominal Rate */ | ||
2391 | cxd2841er_write_regs(priv, I2C_SLVT, | ||
2392 | 0x9F, nominalRate8bw[priv->xtal], 5); | ||
2393 | /* Group delay equaliser settings for ASCOT tuners optimized */ | ||
2394 | cxd2841er_write_regs(priv, I2C_SLVT, | ||
2395 | 0xA6, itbCoef8bw[priv->xtal], 14); | ||
2396 | |||
2397 | /* IF freq setting */ | ||
2398 | iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 4.75); | ||
2399 | data[0] = (u8) ((iffreq >> 16) & 0xff); | ||
2400 | data[1] = (u8)((iffreq >> 8) & 0xff); | ||
2401 | data[2] = (u8)(iffreq & 0xff); | ||
2402 | cxd2841er_write_regs(priv, I2C_SLVT, 0xB6, data, 3); | ||
2403 | |||
2404 | /* System bandwidth setting */ | ||
2405 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xd7, 0x0, 0x7); | ||
2406 | |||
2407 | /* Demod core latency setting */ | ||
2408 | data[0] = 0x13; | ||
2409 | data[1] = 0xFC; | ||
2410 | cxd2841er_write_regs(priv, I2C_SLVT, 0xD9, data, 2); | ||
2411 | |||
2412 | /* Acquisition optimization setting */ | ||
2413 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x12); | ||
2414 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x71, 0x03, 0x07); | ||
2415 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x15); | ||
2416 | cxd2841er_write_reg(priv, I2C_SLVT, 0xBE, 0x03); | ||
2417 | break; | ||
2418 | case 7000000: | ||
2419 | /* TRCG Nominal Rate */ | ||
2420 | cxd2841er_write_regs(priv, I2C_SLVT, | ||
2421 | 0x9F, nominalRate7bw[priv->xtal], 5); | ||
2422 | /* Group delay equaliser settings for ASCOT tuners optimized */ | ||
2423 | cxd2841er_write_regs(priv, I2C_SLVT, | ||
2424 | 0xA6, itbCoef7bw[priv->xtal], 14); | ||
2425 | |||
2426 | /* IF freq setting */ | ||
2427 | iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 4.15); | ||
2428 | data[0] = (u8) ((iffreq >> 16) & 0xff); | ||
2429 | data[1] = (u8)((iffreq >> 8) & 0xff); | ||
2430 | data[2] = (u8)(iffreq & 0xff); | ||
2431 | cxd2841er_write_regs(priv, I2C_SLVT, 0xB6, data, 3); | ||
2432 | |||
2433 | /* System bandwidth setting */ | ||
2434 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xd7, 0x02, 0x7); | ||
2435 | |||
2436 | /* Demod core latency setting */ | ||
2437 | data[0] = 0x1A; | ||
2438 | data[1] = 0xFA; | ||
2439 | cxd2841er_write_regs(priv, I2C_SLVT, 0xD9, data, 2); | ||
2440 | |||
2441 | /* Acquisition optimization setting */ | ||
2442 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x12); | ||
2443 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x71, 0x03, 0x07); | ||
2444 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x15); | ||
2445 | cxd2841er_write_reg(priv, I2C_SLVT, 0xBE, 0x02); | ||
2446 | break; | ||
2447 | case 6000000: | ||
2448 | /* TRCG Nominal Rate */ | ||
2449 | cxd2841er_write_regs(priv, I2C_SLVT, | ||
2450 | 0x9F, nominalRate6bw[priv->xtal], 5); | ||
2451 | /* Group delay equaliser settings for ASCOT tuners optimized */ | ||
2452 | cxd2841er_write_regs(priv, I2C_SLVT, | ||
2453 | 0xA6, itbCoef6bw[priv->xtal], 14); | ||
2454 | |||
2455 | /* IF freq setting */ | ||
2456 | iffreq = MAKE_IFFREQ_CONFIG_XTAL(priv->xtal, 3.55); | ||
2457 | data[0] = (u8) ((iffreq >> 16) & 0xff); | ||
2458 | data[1] = (u8)((iffreq >> 8) & 0xff); | ||
2459 | data[2] = (u8)(iffreq & 0xff); | ||
2460 | cxd2841er_write_regs(priv, I2C_SLVT, 0xB6, data, 3); | ||
2461 | |||
2462 | /* System bandwidth setting */ | ||
2463 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xd7, 0x04, 0x7); | ||
2464 | |||
2465 | /* Demod core latency setting */ | ||
2466 | if (priv->xtal == SONY_XTAL_24000) { | ||
2467 | data[0] = 0x1F; | ||
2468 | data[1] = 0x79; | ||
2469 | } else { | ||
2470 | data[0] = 0x1A; | ||
2471 | data[1] = 0xE2; | ||
2472 | } | ||
2473 | cxd2841er_write_regs(priv, I2C_SLVT, 0xD9, data, 2); | ||
2474 | |||
2475 | /* Acquisition optimization setting */ | ||
2476 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x12); | ||
2477 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x71, 0x07, 0x07); | ||
2478 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x15); | ||
2479 | cxd2841er_write_reg(priv, I2C_SLVT, 0xBE, 0x02); | ||
1804 | break; | 2480 | break; |
1805 | default: | 2481 | default: |
1806 | dev_dbg(&priv->i2c->dev, "%s(): invalid bandwidth %d\n", | 2482 | dev_dbg(&priv->i2c->dev, "%s(): invalid bandwidth %d\n", |
1807 | __func__, bandwidth); | 2483 | __func__, bandwidth); |
1808 | return -EINVAL; | 2484 | return -EINVAL; |
1809 | } | 2485 | } |
1810 | /* <IF freq setting> */ | ||
1811 | b10_b6[0] = (u8) ((iffreq >> 16) & 0xff); | ||
1812 | b10_b6[1] = (u8)((iffreq >> 8) & 0xff); | ||
1813 | b10_b6[2] = (u8)(iffreq & 0xff); | ||
1814 | cxd2841er_write_regs( | ||
1815 | priv, I2C_SLVT, 0x9f, b10_9f, sizeof(bw8mhz_b10_9f)); | ||
1816 | cxd2841er_write_regs( | ||
1817 | priv, I2C_SLVT, 0xa6, b10_a6, sizeof(bw8mhz_b10_a6)); | ||
1818 | cxd2841er_write_regs(priv, I2C_SLVT, 0xb6, b10_b6, sizeof(b10_b6)); | ||
1819 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xd7, d7val, 0x7); | ||
1820 | cxd2841er_write_regs( | ||
1821 | priv, I2C_SLVT, 0xd9, b10_d9, sizeof(bw8mhz_b10_d9)); | ||
1822 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x17); | ||
1823 | cxd2841er_write_regs( | ||
1824 | priv, I2C_SLVT, 0x38, b17_38, sizeof(bw8mhz_b17_38)); | ||
1825 | return 0; | 2486 | return 0; |
1826 | } | 2487 | } |
1827 | 2488 | ||
@@ -1837,7 +2498,7 @@ static int cxd2841er_sleep_tc_to_active_c_band(struct cxd2841er_priv *priv, | |||
1837 | u8 b10_b6[3]; | 2498 | u8 b10_b6[3]; |
1838 | u32 iffreq; | 2499 | u32 iffreq; |
1839 | 2500 | ||
1840 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | 2501 | dev_dbg(&priv->i2c->dev, "%s() bw=%d\n", __func__, bandwidth); |
1841 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); | 2502 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); |
1842 | switch (bandwidth) { | 2503 | switch (bandwidth) { |
1843 | case 8000000: | 2504 | case 8000000: |
@@ -1854,7 +2515,7 @@ static int cxd2841er_sleep_tc_to_active_c_band(struct cxd2841er_priv *priv, | |||
1854 | iffreq = MAKE_IFFREQ_CONFIG(3.7); | 2515 | iffreq = MAKE_IFFREQ_CONFIG(3.7); |
1855 | break; | 2516 | break; |
1856 | default: | 2517 | default: |
1857 | dev_dbg(&priv->i2c->dev, "%s(): unsupported bandwidth %d\n", | 2518 | dev_err(&priv->i2c->dev, "%s(): unsupported bandwidth %d\n", |
1858 | __func__, bandwidth); | 2519 | __func__, bandwidth); |
1859 | return -EINVAL; | 2520 | return -EINVAL; |
1860 | } | 2521 | } |
@@ -1902,6 +2563,7 @@ static int cxd2841er_sleep_tc_to_active_t(struct cxd2841er_priv *priv, | |||
1902 | u32 bandwidth) | 2563 | u32 bandwidth) |
1903 | { | 2564 | { |
1904 | u8 data[2] = { 0x09, 0x54 }; | 2565 | u8 data[2] = { 0x09, 0x54 }; |
2566 | u8 data24m[3] = {0xDC, 0x6C, 0x00}; | ||
1905 | 2567 | ||
1906 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | 2568 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); |
1907 | cxd2841er_set_ts_clock_mode(priv, SYS_DVBT); | 2569 | cxd2841er_set_ts_clock_mode(priv, SYS_DVBT); |
@@ -1919,7 +2581,11 @@ static int cxd2841er_sleep_tc_to_active_t(struct cxd2841er_priv *priv, | |||
1919 | cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00); | 2581 | cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00); |
1920 | /* Enable ADC 1 */ | 2582 | /* Enable ADC 1 */ |
1921 | cxd2841er_write_reg(priv, I2C_SLVT, 0x41, 0x1a); | 2583 | cxd2841er_write_reg(priv, I2C_SLVT, 0x41, 0x1a); |
1922 | /* xtal freq 20.5MHz */ | 2584 | /* Enable ADC 2 & 3 */ |
2585 | if (priv->xtal == SONY_XTAL_41000) { | ||
2586 | data[0] = 0x0A; | ||
2587 | data[1] = 0xD4; | ||
2588 | } | ||
1923 | cxd2841er_write_regs(priv, I2C_SLVT, 0x43, data, 2); | 2589 | cxd2841er_write_regs(priv, I2C_SLVT, 0x43, data, 2); |
1924 | /* Enable ADC 4 */ | 2590 | /* Enable ADC 4 */ |
1925 | cxd2841er_write_reg(priv, I2C_SLVX, 0x18, 0x00); | 2591 | cxd2841er_write_reg(priv, I2C_SLVX, 0x18, 0x00); |
@@ -1947,6 +2613,15 @@ static int cxd2841er_sleep_tc_to_active_t(struct cxd2841er_priv *priv, | |||
1947 | /* TSIF setting */ | 2613 | /* TSIF setting */ |
1948 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xce, 0x01, 0x01); | 2614 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xce, 0x01, 0x01); |
1949 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xcf, 0x01, 0x01); | 2615 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xcf, 0x01, 0x01); |
2616 | |||
2617 | if (priv->xtal == SONY_XTAL_24000) { | ||
2618 | /* Set SLV-T Bank : 0x10 */ | ||
2619 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); | ||
2620 | cxd2841er_write_reg(priv, I2C_SLVT, 0xBF, 0x60); | ||
2621 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x18); | ||
2622 | cxd2841er_write_regs(priv, I2C_SLVT, 0x24, data24m, 3); | ||
2623 | } | ||
2624 | |||
1950 | cxd2841er_sleep_tc_to_active_t_band(priv, bandwidth); | 2625 | cxd2841er_sleep_tc_to_active_t_band(priv, bandwidth); |
1951 | /* Set SLV-T Bank : 0x00 */ | 2626 | /* Set SLV-T Bank : 0x00 */ |
1952 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00); | 2627 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00); |
@@ -1961,7 +2636,7 @@ static int cxd2841er_sleep_tc_to_active_t(struct cxd2841er_priv *priv, | |||
1961 | static int cxd2841er_sleep_tc_to_active_t2(struct cxd2841er_priv *priv, | 2636 | static int cxd2841er_sleep_tc_to_active_t2(struct cxd2841er_priv *priv, |
1962 | u32 bandwidth) | 2637 | u32 bandwidth) |
1963 | { | 2638 | { |
1964 | u8 data[2] = { 0x09, 0x54 }; | 2639 | u8 data[MAX_WRITE_REGSIZE]; |
1965 | 2640 | ||
1966 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | 2641 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); |
1967 | cxd2841er_set_ts_clock_mode(priv, SYS_DVBT2); | 2642 | cxd2841er_set_ts_clock_mode(priv, SYS_DVBT2); |
@@ -1974,12 +2649,21 @@ static int cxd2841er_sleep_tc_to_active_t2(struct cxd2841er_priv *priv, | |||
1974 | /* Enable demod clock */ | 2649 | /* Enable demod clock */ |
1975 | cxd2841er_write_reg(priv, I2C_SLVT, 0x2c, 0x01); | 2650 | cxd2841er_write_reg(priv, I2C_SLVT, 0x2c, 0x01); |
1976 | /* Disable RF level monitor */ | 2651 | /* Disable RF level monitor */ |
2652 | cxd2841er_write_reg(priv, I2C_SLVT, 0x59, 0x00); | ||
1977 | cxd2841er_write_reg(priv, I2C_SLVT, 0x2f, 0x00); | 2653 | cxd2841er_write_reg(priv, I2C_SLVT, 0x2f, 0x00); |
1978 | /* Enable ADC clock */ | 2654 | /* Enable ADC clock */ |
1979 | cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00); | 2655 | cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00); |
1980 | /* Enable ADC 1 */ | 2656 | /* Enable ADC 1 */ |
1981 | cxd2841er_write_reg(priv, I2C_SLVT, 0x41, 0x1a); | 2657 | cxd2841er_write_reg(priv, I2C_SLVT, 0x41, 0x1a); |
1982 | /* xtal freq 20.5MHz */ | 2658 | |
2659 | if (priv->xtal == SONY_XTAL_41000) { | ||
2660 | data[0] = 0x0A; | ||
2661 | data[1] = 0xD4; | ||
2662 | } else { | ||
2663 | data[0] = 0x09; | ||
2664 | data[1] = 0x54; | ||
2665 | } | ||
2666 | |||
1983 | cxd2841er_write_regs(priv, I2C_SLVT, 0x43, data, 2); | 2667 | cxd2841er_write_regs(priv, I2C_SLVT, 0x43, data, 2); |
1984 | /* Enable ADC 4 */ | 2668 | /* Enable ADC 4 */ |
1985 | cxd2841er_write_reg(priv, I2C_SLVX, 0x18, 0x00); | 2669 | cxd2841er_write_reg(priv, I2C_SLVX, 0x18, 0x00); |
@@ -2002,6 +2686,10 @@ static int cxd2841er_sleep_tc_to_active_t2(struct cxd2841er_priv *priv, | |||
2002 | /* Set SLV-T Bank : 0x2b */ | 2686 | /* Set SLV-T Bank : 0x2b */ |
2003 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x2b); | 2687 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x2b); |
2004 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x76, 0x20, 0x70); | 2688 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x76, 0x20, 0x70); |
2689 | /* Set SLV-T Bank : 0x23 */ | ||
2690 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x23); | ||
2691 | /* L1 Control setting */ | ||
2692 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xE6, 0x00, 0x03); | ||
2005 | /* Set SLV-T Bank : 0x00 */ | 2693 | /* Set SLV-T Bank : 0x00 */ |
2006 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00); | 2694 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00); |
2007 | /* TSIF setting */ | 2695 | /* TSIF setting */ |
@@ -2020,6 +2708,72 @@ static int cxd2841er_sleep_tc_to_active_t2(struct cxd2841er_priv *priv, | |||
2020 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x2b); | 2708 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x2b); |
2021 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x11, 0x20, 0x3f); | 2709 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x11, 0x20, 0x3f); |
2022 | 2710 | ||
2711 | /* 24MHz Xtal setting */ | ||
2712 | if (priv->xtal == SONY_XTAL_24000) { | ||
2713 | /* Set SLV-T Bank : 0x11 */ | ||
2714 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x11); | ||
2715 | data[0] = 0xEB; | ||
2716 | data[1] = 0x03; | ||
2717 | data[2] = 0x3B; | ||
2718 | cxd2841er_write_regs(priv, I2C_SLVT, 0x33, data, 3); | ||
2719 | |||
2720 | /* Set SLV-T Bank : 0x20 */ | ||
2721 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x20); | ||
2722 | data[0] = 0x5E; | ||
2723 | data[1] = 0x5E; | ||
2724 | data[2] = 0x47; | ||
2725 | cxd2841er_write_regs(priv, I2C_SLVT, 0x95, data, 3); | ||
2726 | |||
2727 | cxd2841er_write_reg(priv, I2C_SLVT, 0x99, 0x18); | ||
2728 | |||
2729 | data[0] = 0x3F; | ||
2730 | data[1] = 0xFF; | ||
2731 | cxd2841er_write_regs(priv, I2C_SLVT, 0xD9, data, 2); | ||
2732 | |||
2733 | /* Set SLV-T Bank : 0x24 */ | ||
2734 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x24); | ||
2735 | data[0] = 0x0B; | ||
2736 | data[1] = 0x72; | ||
2737 | cxd2841er_write_regs(priv, I2C_SLVT, 0x34, data, 2); | ||
2738 | |||
2739 | data[0] = 0x93; | ||
2740 | data[1] = 0xF3; | ||
2741 | data[2] = 0x00; | ||
2742 | cxd2841er_write_regs(priv, I2C_SLVT, 0xD2, data, 3); | ||
2743 | |||
2744 | data[0] = 0x05; | ||
2745 | data[1] = 0xB8; | ||
2746 | data[2] = 0xD8; | ||
2747 | cxd2841er_write_regs(priv, I2C_SLVT, 0xDD, data, 3); | ||
2748 | |||
2749 | cxd2841er_write_reg(priv, I2C_SLVT, 0xE0, 0x00); | ||
2750 | |||
2751 | /* Set SLV-T Bank : 0x25 */ | ||
2752 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x25); | ||
2753 | cxd2841er_write_reg(priv, I2C_SLVT, 0xED, 0x60); | ||
2754 | |||
2755 | /* Set SLV-T Bank : 0x27 */ | ||
2756 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x27); | ||
2757 | cxd2841er_write_reg(priv, I2C_SLVT, 0xFA, 0x34); | ||
2758 | |||
2759 | /* Set SLV-T Bank : 0x2B */ | ||
2760 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x2B); | ||
2761 | cxd2841er_write_reg(priv, I2C_SLVT, 0x4B, 0x2F); | ||
2762 | cxd2841er_write_reg(priv, I2C_SLVT, 0x9E, 0x0E); | ||
2763 | |||
2764 | /* Set SLV-T Bank : 0x2D */ | ||
2765 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x2D); | ||
2766 | data[0] = 0x89; | ||
2767 | data[1] = 0x89; | ||
2768 | cxd2841er_write_regs(priv, I2C_SLVT, 0x24, data, 2); | ||
2769 | |||
2770 | /* Set SLV-T Bank : 0x5E */ | ||
2771 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x5E); | ||
2772 | data[0] = 0x24; | ||
2773 | data[1] = 0x95; | ||
2774 | cxd2841er_write_regs(priv, I2C_SLVT, 0x8C, data, 2); | ||
2775 | } | ||
2776 | |||
2023 | cxd2841er_sleep_tc_to_active_t2_band(priv, bandwidth); | 2777 | cxd2841er_sleep_tc_to_active_t2_band(priv, bandwidth); |
2024 | 2778 | ||
2025 | /* Set SLV-T Bank : 0x00 */ | 2779 | /* Set SLV-T Bank : 0x00 */ |
@@ -2032,6 +2786,84 @@ static int cxd2841er_sleep_tc_to_active_t2(struct cxd2841er_priv *priv, | |||
2032 | return 0; | 2786 | return 0; |
2033 | } | 2787 | } |
2034 | 2788 | ||
2789 | /* ISDB-Tb part */ | ||
2790 | static int cxd2841er_sleep_tc_to_active_i(struct cxd2841er_priv *priv, | ||
2791 | u32 bandwidth) | ||
2792 | { | ||
2793 | u8 data[2] = { 0x09, 0x54 }; | ||
2794 | u8 data24m[2] = {0x60, 0x00}; | ||
2795 | u8 data24m2[3] = {0xB7, 0x1B, 0x00}; | ||
2796 | |||
2797 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | ||
2798 | cxd2841er_set_ts_clock_mode(priv, SYS_DVBT); | ||
2799 | /* Set SLV-X Bank : 0x00 */ | ||
2800 | cxd2841er_write_reg(priv, I2C_SLVX, 0x00, 0x00); | ||
2801 | /* Set demod mode */ | ||
2802 | cxd2841er_write_reg(priv, I2C_SLVX, 0x17, 0x06); | ||
2803 | /* Set SLV-T Bank : 0x00 */ | ||
2804 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00); | ||
2805 | /* Enable demod clock */ | ||
2806 | cxd2841er_write_reg(priv, I2C_SLVT, 0x2c, 0x01); | ||
2807 | /* Enable RF level monitor */ | ||
2808 | cxd2841er_write_reg(priv, I2C_SLVT, 0x2f, 0x01); | ||
2809 | cxd2841er_write_reg(priv, I2C_SLVT, 0x59, 0x01); | ||
2810 | /* Enable ADC clock */ | ||
2811 | cxd2841er_write_reg(priv, I2C_SLVT, 0x30, 0x00); | ||
2812 | /* Enable ADC 1 */ | ||
2813 | cxd2841er_write_reg(priv, I2C_SLVT, 0x41, 0x1a); | ||
2814 | /* xtal freq 20.5MHz or 24M */ | ||
2815 | cxd2841er_write_regs(priv, I2C_SLVT, 0x43, data, 2); | ||
2816 | /* Enable ADC 4 */ | ||
2817 | cxd2841er_write_reg(priv, I2C_SLVX, 0x18, 0x00); | ||
2818 | /* ASCOT setting ON */ | ||
2819 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xa5, 0x01, 0x01); | ||
2820 | /* FEC Auto Recovery setting */ | ||
2821 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x30, 0x01, 0x01); | ||
2822 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x31, 0x00, 0x01); | ||
2823 | /* ISDB-T initial setting */ | ||
2824 | /* Set SLV-T Bank : 0x00 */ | ||
2825 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00); | ||
2826 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xce, 0x00, 0x01); | ||
2827 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xcf, 0x00, 0x01); | ||
2828 | /* Set SLV-T Bank : 0x10 */ | ||
2829 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); | ||
2830 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x69, 0x04, 0x07); | ||
2831 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x6B, 0x03, 0x07); | ||
2832 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x9D, 0x50, 0xFF); | ||
2833 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xD3, 0x06, 0x1F); | ||
2834 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xED, 0x00, 0x01); | ||
2835 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xE2, 0xCE, 0x80); | ||
2836 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xF2, 0x13, 0x10); | ||
2837 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xDE, 0x2E, 0x3F); | ||
2838 | /* Set SLV-T Bank : 0x15 */ | ||
2839 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x15); | ||
2840 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xDE, 0x02, 0x03); | ||
2841 | /* Set SLV-T Bank : 0x1E */ | ||
2842 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x1E); | ||
2843 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x73, 0x68, 0xFF); | ||
2844 | /* Set SLV-T Bank : 0x63 */ | ||
2845 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x63); | ||
2846 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x81, 0x00, 0x01); | ||
2847 | |||
2848 | /* for xtal 24MHz */ | ||
2849 | /* Set SLV-T Bank : 0x10 */ | ||
2850 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); | ||
2851 | cxd2841er_write_regs(priv, I2C_SLVT, 0xBF, data24m, 2); | ||
2852 | /* Set SLV-T Bank : 0x60 */ | ||
2853 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x60); | ||
2854 | cxd2841er_write_regs(priv, I2C_SLVT, 0xA8, data24m2, 3); | ||
2855 | |||
2856 | cxd2841er_sleep_tc_to_active_i_band(priv, bandwidth); | ||
2857 | /* Set SLV-T Bank : 0x00 */ | ||
2858 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00); | ||
2859 | /* Disable HiZ Setting 1 */ | ||
2860 | cxd2841er_write_reg(priv, I2C_SLVT, 0x80, 0x28); | ||
2861 | /* Disable HiZ Setting 2 */ | ||
2862 | cxd2841er_write_reg(priv, I2C_SLVT, 0x81, 0x00); | ||
2863 | priv->state = STATE_ACTIVE_TC; | ||
2864 | return 0; | ||
2865 | } | ||
2866 | |||
2035 | static int cxd2841er_sleep_tc_to_active_c(struct cxd2841er_priv *priv, | 2867 | static int cxd2841er_sleep_tc_to_active_c(struct cxd2841er_priv *priv, |
2036 | u32 bandwidth) | 2868 | u32 bandwidth) |
2037 | { | 2869 | { |
@@ -2079,7 +2911,7 @@ static int cxd2841er_sleep_tc_to_active_c(struct cxd2841er_priv *priv, | |||
2079 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xce, 0x01, 0x01); | 2911 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xce, 0x01, 0x01); |
2080 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xcf, 0x01, 0x01); | 2912 | cxd2841er_set_reg_bits(priv, I2C_SLVT, 0xcf, 0x01, 0x01); |
2081 | 2913 | ||
2082 | cxd2841er_sleep_tc_to_active_c_band(priv, 8000000); | 2914 | cxd2841er_sleep_tc_to_active_c_band(priv, bandwidth); |
2083 | /* Set SLV-T Bank : 0x00 */ | 2915 | /* Set SLV-T Bank : 0x00 */ |
2084 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00); | 2916 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x00); |
2085 | /* Disable HiZ Setting 1 */ | 2917 | /* Disable HiZ Setting 1 */ |
@@ -2142,10 +2974,10 @@ static int cxd2841er_set_frontend_s(struct dvb_frontend *fe) | |||
2142 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; | 2974 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; |
2143 | u32 symbol_rate = p->symbol_rate/1000; | 2975 | u32 symbol_rate = p->symbol_rate/1000; |
2144 | 2976 | ||
2145 | dev_dbg(&priv->i2c->dev, "%s(): %s frequency=%d symbol_rate=%d\n", | 2977 | dev_dbg(&priv->i2c->dev, "%s(): %s frequency=%d symbol_rate=%d xtal=%d\n", |
2146 | __func__, | 2978 | __func__, |
2147 | (p->delivery_system == SYS_DVBS ? "DVB-S" : "DVB-S2"), | 2979 | (p->delivery_system == SYS_DVBS ? "DVB-S" : "DVB-S2"), |
2148 | p->frequency, symbol_rate); | 2980 | p->frequency, symbol_rate, priv->xtal); |
2149 | switch (priv->state) { | 2981 | switch (priv->state) { |
2150 | case STATE_SLEEP_S: | 2982 | case STATE_SLEEP_S: |
2151 | ret = cxd2841er_sleep_s_to_active_s( | 2983 | ret = cxd2841er_sleep_s_to_active_s( |
@@ -2199,7 +3031,8 @@ static int cxd2841er_set_frontend_tc(struct dvb_frontend *fe) | |||
2199 | struct cxd2841er_priv *priv = fe->demodulator_priv; | 3031 | struct cxd2841er_priv *priv = fe->demodulator_priv; |
2200 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; | 3032 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; |
2201 | 3033 | ||
2202 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | 3034 | dev_dbg(&priv->i2c->dev, "%s() delivery_system=%d bandwidth_hz=%d\n", |
3035 | __func__, p->delivery_system, p->bandwidth_hz); | ||
2203 | if (p->delivery_system == SYS_DVBT) { | 3036 | if (p->delivery_system == SYS_DVBT) { |
2204 | priv->system = SYS_DVBT; | 3037 | priv->system = SYS_DVBT; |
2205 | switch (priv->state) { | 3038 | switch (priv->state) { |
@@ -2233,9 +3066,33 @@ static int cxd2841er_set_frontend_tc(struct dvb_frontend *fe) | |||
2233 | __func__, priv->state); | 3066 | __func__, priv->state); |
2234 | ret = -EINVAL; | 3067 | ret = -EINVAL; |
2235 | } | 3068 | } |
3069 | } else if (p->delivery_system == SYS_ISDBT) { | ||
3070 | priv->system = SYS_ISDBT; | ||
3071 | switch (priv->state) { | ||
3072 | case STATE_SLEEP_TC: | ||
3073 | ret = cxd2841er_sleep_tc_to_active_i( | ||
3074 | priv, p->bandwidth_hz); | ||
3075 | break; | ||
3076 | case STATE_ACTIVE_TC: | ||
3077 | ret = cxd2841er_retune_active(priv, p); | ||
3078 | break; | ||
3079 | default: | ||
3080 | dev_dbg(&priv->i2c->dev, "%s(): invalid state %d\n", | ||
3081 | __func__, priv->state); | ||
3082 | ret = -EINVAL; | ||
3083 | } | ||
2236 | } else if (p->delivery_system == SYS_DVBC_ANNEX_A || | 3084 | } else if (p->delivery_system == SYS_DVBC_ANNEX_A || |
2237 | p->delivery_system == SYS_DVBC_ANNEX_C) { | 3085 | p->delivery_system == SYS_DVBC_ANNEX_C) { |
2238 | priv->system = SYS_DVBC_ANNEX_A; | 3086 | priv->system = SYS_DVBC_ANNEX_A; |
3087 | /* correct bandwidth */ | ||
3088 | if (p->bandwidth_hz != 6000000 && | ||
3089 | p->bandwidth_hz != 7000000 && | ||
3090 | p->bandwidth_hz != 8000000) { | ||
3091 | p->bandwidth_hz = 8000000; | ||
3092 | dev_dbg(&priv->i2c->dev, "%s(): forcing bandwidth to %d\n", | ||
3093 | __func__, p->bandwidth_hz); | ||
3094 | } | ||
3095 | |||
2239 | switch (priv->state) { | 3096 | switch (priv->state) { |
2240 | case STATE_SLEEP_TC: | 3097 | case STATE_SLEEP_TC: |
2241 | ret = cxd2841er_sleep_tc_to_active_c( | 3098 | ret = cxd2841er_sleep_tc_to_active_c( |
@@ -2321,7 +3178,8 @@ static int cxd2841er_tune_tc(struct dvb_frontend *fe, | |||
2321 | struct cxd2841er_priv *priv = fe->demodulator_priv; | 3178 | struct cxd2841er_priv *priv = fe->demodulator_priv; |
2322 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; | 3179 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; |
2323 | 3180 | ||
2324 | dev_dbg(&priv->i2c->dev, "%s(): re_tune %d\n", __func__, re_tune); | 3181 | dev_dbg(&priv->i2c->dev, "%s(): re_tune %d bandwidth=%d\n", __func__, |
3182 | re_tune, p->bandwidth_hz); | ||
2325 | if (re_tune) { | 3183 | if (re_tune) { |
2326 | ret = cxd2841er_set_frontend_tc(fe); | 3184 | ret = cxd2841er_set_frontend_tc(fe); |
2327 | if (ret) | 3185 | if (ret) |
@@ -2329,7 +3187,16 @@ static int cxd2841er_tune_tc(struct dvb_frontend *fe, | |||
2329 | cxd2841er_read_status_tc(fe, status); | 3187 | cxd2841er_read_status_tc(fe, status); |
2330 | if (*status & FE_HAS_LOCK) { | 3188 | if (*status & FE_HAS_LOCK) { |
2331 | switch (priv->system) { | 3189 | switch (priv->system) { |
3190 | case SYS_ISDBT: | ||
3191 | ret = cxd2841er_get_carrier_offset_i( | ||
3192 | priv, p->bandwidth_hz, | ||
3193 | &carrier_offset); | ||
3194 | break; | ||
2332 | case SYS_DVBT: | 3195 | case SYS_DVBT: |
3196 | ret = cxd2841er_get_carrier_offset_t( | ||
3197 | priv, p->bandwidth_hz, | ||
3198 | &carrier_offset); | ||
3199 | break; | ||
2333 | case SYS_DVBT2: | 3200 | case SYS_DVBT2: |
2334 | ret = cxd2841er_get_carrier_offset_t2( | 3201 | ret = cxd2841er_get_carrier_offset_t2( |
2335 | priv, p->bandwidth_hz, | 3202 | priv, p->bandwidth_hz, |
@@ -2382,6 +3249,9 @@ static int cxd2841er_sleep_tc(struct dvb_frontend *fe) | |||
2382 | case SYS_DVBT2: | 3249 | case SYS_DVBT2: |
2383 | cxd2841er_active_t2_to_sleep_tc(priv); | 3250 | cxd2841er_active_t2_to_sleep_tc(priv); |
2384 | break; | 3251 | break; |
3252 | case SYS_ISDBT: | ||
3253 | cxd2841er_active_i_to_sleep_tc(priv); | ||
3254 | break; | ||
2385 | case SYS_DVBC_ANNEX_A: | 3255 | case SYS_DVBC_ANNEX_A: |
2386 | cxd2841er_active_c_to_sleep_tc(priv); | 3256 | cxd2841er_active_c_to_sleep_tc(priv); |
2387 | break; | 3257 | break; |
@@ -2516,6 +3386,18 @@ static int cxd2841er_init_s(struct dvb_frontend *fe) | |||
2516 | { | 3386 | { |
2517 | struct cxd2841er_priv *priv = fe->demodulator_priv; | 3387 | struct cxd2841er_priv *priv = fe->demodulator_priv; |
2518 | 3388 | ||
3389 | /* sanity. force demod to SHUTDOWN state */ | ||
3390 | if (priv->state == STATE_SLEEP_S) { | ||
3391 | dev_dbg(&priv->i2c->dev, "%s() forcing sleep->shutdown\n", | ||
3392 | __func__); | ||
3393 | cxd2841er_sleep_s_to_shutdown(priv); | ||
3394 | } else if (priv->state == STATE_ACTIVE_S) { | ||
3395 | dev_dbg(&priv->i2c->dev, "%s() forcing active->sleep->shutdown\n", | ||
3396 | __func__); | ||
3397 | cxd2841er_active_s_to_sleep_s(priv); | ||
3398 | cxd2841er_sleep_s_to_shutdown(priv); | ||
3399 | } | ||
3400 | |||
2519 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | 3401 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); |
2520 | cxd2841er_shutdown_to_sleep_s(priv); | 3402 | cxd2841er_shutdown_to_sleep_s(priv); |
2521 | /* SONY_DEMOD_CONFIG_SAT_IFAGCNEG set to 1 */ | 3403 | /* SONY_DEMOD_CONFIG_SAT_IFAGCNEG set to 1 */ |
@@ -2527,8 +3409,10 @@ static int cxd2841er_init_s(struct dvb_frontend *fe) | |||
2527 | static int cxd2841er_init_tc(struct dvb_frontend *fe) | 3409 | static int cxd2841er_init_tc(struct dvb_frontend *fe) |
2528 | { | 3410 | { |
2529 | struct cxd2841er_priv *priv = fe->demodulator_priv; | 3411 | struct cxd2841er_priv *priv = fe->demodulator_priv; |
3412 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; | ||
2530 | 3413 | ||
2531 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | 3414 | dev_dbg(&priv->i2c->dev, "%s() bandwidth_hz=%d\n", |
3415 | __func__, p->bandwidth_hz); | ||
2532 | cxd2841er_shutdown_to_sleep_tc(priv); | 3416 | cxd2841er_shutdown_to_sleep_tc(priv); |
2533 | /* SONY_DEMOD_CONFIG_IFAGCNEG = 1 */ | 3417 | /* SONY_DEMOD_CONFIG_IFAGCNEG = 1 */ |
2534 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); | 3418 | cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x10); |
@@ -2542,8 +3426,7 @@ static int cxd2841er_init_tc(struct dvb_frontend *fe) | |||
2542 | } | 3426 | } |
2543 | 3427 | ||
2544 | static struct dvb_frontend_ops cxd2841er_dvbs_s2_ops; | 3428 | static struct dvb_frontend_ops cxd2841er_dvbs_s2_ops; |
2545 | static struct dvb_frontend_ops cxd2841er_dvbt_t2_ops; | 3429 | static struct dvb_frontend_ops cxd2841er_t_c_ops; |
2546 | static struct dvb_frontend_ops cxd2841er_dvbc_ops; | ||
2547 | 3430 | ||
2548 | static struct dvb_frontend *cxd2841er_attach(struct cxd2841er_config *cfg, | 3431 | static struct dvb_frontend *cxd2841er_attach(struct cxd2841er_config *cfg, |
2549 | struct i2c_adapter *i2c, | 3432 | struct i2c_adapter *i2c, |
@@ -2551,6 +3434,7 @@ static struct dvb_frontend *cxd2841er_attach(struct cxd2841er_config *cfg, | |||
2551 | { | 3434 | { |
2552 | u8 chip_id = 0; | 3435 | u8 chip_id = 0; |
2553 | const char *type; | 3436 | const char *type; |
3437 | const char *name; | ||
2554 | struct cxd2841er_priv *priv = NULL; | 3438 | struct cxd2841er_priv *priv = NULL; |
2555 | 3439 | ||
2556 | /* allocate memory for the internal state */ | 3440 | /* allocate memory for the internal state */ |
@@ -2561,46 +3445,49 @@ static struct dvb_frontend *cxd2841er_attach(struct cxd2841er_config *cfg, | |||
2561 | priv->config = cfg; | 3445 | priv->config = cfg; |
2562 | priv->i2c_addr_slvx = (cfg->i2c_addr + 4) >> 1; | 3446 | priv->i2c_addr_slvx = (cfg->i2c_addr + 4) >> 1; |
2563 | priv->i2c_addr_slvt = (cfg->i2c_addr) >> 1; | 3447 | priv->i2c_addr_slvt = (cfg->i2c_addr) >> 1; |
2564 | /* create dvb_frontend */ | 3448 | priv->xtal = cfg->xtal; |
2565 | switch (system) { | ||
2566 | case SYS_DVBS: | ||
2567 | memcpy(&priv->frontend.ops, | ||
2568 | &cxd2841er_dvbs_s2_ops, | ||
2569 | sizeof(struct dvb_frontend_ops)); | ||
2570 | type = "S/S2"; | ||
2571 | break; | ||
2572 | case SYS_DVBT: | ||
2573 | memcpy(&priv->frontend.ops, | ||
2574 | &cxd2841er_dvbt_t2_ops, | ||
2575 | sizeof(struct dvb_frontend_ops)); | ||
2576 | type = "T/T2"; | ||
2577 | break; | ||
2578 | case SYS_DVBC_ANNEX_A: | ||
2579 | memcpy(&priv->frontend.ops, | ||
2580 | &cxd2841er_dvbc_ops, | ||
2581 | sizeof(struct dvb_frontend_ops)); | ||
2582 | type = "C/C2"; | ||
2583 | break; | ||
2584 | default: | ||
2585 | kfree(priv); | ||
2586 | return NULL; | ||
2587 | } | ||
2588 | priv->frontend.demodulator_priv = priv; | 3449 | priv->frontend.demodulator_priv = priv; |
2589 | dev_info(&priv->i2c->dev, | 3450 | dev_info(&priv->i2c->dev, |
2590 | "%s(): attaching CXD2841ER DVB-%s frontend\n", | ||
2591 | __func__, type); | ||
2592 | dev_info(&priv->i2c->dev, | ||
2593 | "%s(): I2C adapter %p SLVX addr %x SLVT addr %x\n", | 3451 | "%s(): I2C adapter %p SLVX addr %x SLVT addr %x\n", |
2594 | __func__, priv->i2c, | 3452 | __func__, priv->i2c, |
2595 | priv->i2c_addr_slvx, priv->i2c_addr_slvt); | 3453 | priv->i2c_addr_slvx, priv->i2c_addr_slvt); |
2596 | chip_id = cxd2841er_chip_id(priv); | 3454 | chip_id = cxd2841er_chip_id(priv); |
2597 | if (chip_id != CXD2841ER_CHIP_ID) { | 3455 | switch (chip_id) { |
3456 | case CXD2841ER_CHIP_ID: | ||
3457 | snprintf(cxd2841er_t_c_ops.info.name, 128, | ||
3458 | "Sony CXD2841ER DVB-T/T2/C demodulator"); | ||
3459 | name = "CXD2841ER"; | ||
3460 | break; | ||
3461 | case CXD2854ER_CHIP_ID: | ||
3462 | snprintf(cxd2841er_t_c_ops.info.name, 128, | ||
3463 | "Sony CXD2854ER DVB-T/T2/C and ISDB-T demodulator"); | ||
3464 | cxd2841er_t_c_ops.delsys[3] = SYS_ISDBT; | ||
3465 | name = "CXD2854ER"; | ||
3466 | break; | ||
3467 | default: | ||
2598 | dev_err(&priv->i2c->dev, "%s(): invalid chip ID 0x%02x\n", | 3468 | dev_err(&priv->i2c->dev, "%s(): invalid chip ID 0x%02x\n", |
2599 | __func__, chip_id); | 3469 | __func__, chip_id); |
2600 | priv->frontend.demodulator_priv = NULL; | 3470 | priv->frontend.demodulator_priv = NULL; |
2601 | kfree(priv); | 3471 | kfree(priv); |
2602 | return NULL; | 3472 | return NULL; |
2603 | } | 3473 | } |
3474 | |||
3475 | /* create dvb_frontend */ | ||
3476 | if (system == SYS_DVBS) { | ||
3477 | memcpy(&priv->frontend.ops, | ||
3478 | &cxd2841er_dvbs_s2_ops, | ||
3479 | sizeof(struct dvb_frontend_ops)); | ||
3480 | type = "S/S2"; | ||
3481 | } else { | ||
3482 | memcpy(&priv->frontend.ops, | ||
3483 | &cxd2841er_t_c_ops, | ||
3484 | sizeof(struct dvb_frontend_ops)); | ||
3485 | type = "T/T2/C/ISDB-T"; | ||
3486 | } | ||
3487 | |||
3488 | dev_info(&priv->i2c->dev, | ||
3489 | "%s(): attaching %s DVB-%s frontend\n", | ||
3490 | __func__, name, type); | ||
2604 | dev_info(&priv->i2c->dev, "%s(): chip ID 0x%02x OK.\n", | 3491 | dev_info(&priv->i2c->dev, "%s(): chip ID 0x%02x OK.\n", |
2605 | __func__, chip_id); | 3492 | __func__, chip_id); |
2606 | return &priv->frontend; | 3493 | return &priv->frontend; |
@@ -2613,19 +3500,12 @@ struct dvb_frontend *cxd2841er_attach_s(struct cxd2841er_config *cfg, | |||
2613 | } | 3500 | } |
2614 | EXPORT_SYMBOL(cxd2841er_attach_s); | 3501 | EXPORT_SYMBOL(cxd2841er_attach_s); |
2615 | 3502 | ||
2616 | struct dvb_frontend *cxd2841er_attach_t(struct cxd2841er_config *cfg, | 3503 | struct dvb_frontend *cxd2841er_attach_t_c(struct cxd2841er_config *cfg, |
2617 | struct i2c_adapter *i2c) | 3504 | struct i2c_adapter *i2c) |
2618 | { | 3505 | { |
2619 | return cxd2841er_attach(cfg, i2c, SYS_DVBT); | 3506 | return cxd2841er_attach(cfg, i2c, 0); |
2620 | } | 3507 | } |
2621 | EXPORT_SYMBOL(cxd2841er_attach_t); | 3508 | EXPORT_SYMBOL(cxd2841er_attach_t_c); |
2622 | |||
2623 | struct dvb_frontend *cxd2841er_attach_c(struct cxd2841er_config *cfg, | ||
2624 | struct i2c_adapter *i2c) | ||
2625 | { | ||
2626 | return cxd2841er_attach(cfg, i2c, SYS_DVBC_ANNEX_A); | ||
2627 | } | ||
2628 | EXPORT_SYMBOL(cxd2841er_attach_c); | ||
2629 | 3509 | ||
2630 | static struct dvb_frontend_ops cxd2841er_dvbs_s2_ops = { | 3510 | static struct dvb_frontend_ops cxd2841er_dvbs_s2_ops = { |
2631 | .delsys = { SYS_DVBS, SYS_DVBS2 }, | 3511 | .delsys = { SYS_DVBS, SYS_DVBS2 }, |
@@ -2655,10 +3535,10 @@ static struct dvb_frontend_ops cxd2841er_dvbs_s2_ops = { | |||
2655 | .tune = cxd2841er_tune_s | 3535 | .tune = cxd2841er_tune_s |
2656 | }; | 3536 | }; |
2657 | 3537 | ||
2658 | static struct dvb_frontend_ops cxd2841er_dvbt_t2_ops = { | 3538 | static struct dvb_frontend_ops cxd2841er_t_c_ops = { |
2659 | .delsys = { SYS_DVBT, SYS_DVBT2 }, | 3539 | .delsys = { SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A }, |
2660 | .info = { | 3540 | .info = { |
2661 | .name = "Sony CXD2841ER DVB-T/T2 demodulator", | 3541 | .name = "", /* will set in attach function */ |
2662 | .caps = FE_CAN_FEC_1_2 | | 3542 | .caps = FE_CAN_FEC_1_2 | |
2663 | FE_CAN_FEC_2_3 | | 3543 | FE_CAN_FEC_2_3 | |
2664 | FE_CAN_FEC_3_4 | | 3544 | FE_CAN_FEC_3_4 | |
@@ -2691,37 +3571,6 @@ static struct dvb_frontend_ops cxd2841er_dvbt_t2_ops = { | |||
2691 | .get_frontend_algo = cxd2841er_get_algo | 3571 | .get_frontend_algo = cxd2841er_get_algo |
2692 | }; | 3572 | }; |
2693 | 3573 | ||
2694 | static struct dvb_frontend_ops cxd2841er_dvbc_ops = { | 3574 | MODULE_DESCRIPTION("Sony CXD2841ER/CXD2854ER DVB-C/C2/T/T2/S/S2 demodulator driver"); |
2695 | .delsys = { SYS_DVBC_ANNEX_A }, | 3575 | MODULE_AUTHOR("Sergey Kozlov <serjk@netup.ru>, Abylay Ospan <aospan@netup.ru>"); |
2696 | .info = { | ||
2697 | .name = "Sony CXD2841ER DVB-C demodulator", | ||
2698 | .caps = FE_CAN_FEC_1_2 | | ||
2699 | FE_CAN_FEC_2_3 | | ||
2700 | FE_CAN_FEC_3_4 | | ||
2701 | FE_CAN_FEC_5_6 | | ||
2702 | FE_CAN_FEC_7_8 | | ||
2703 | FE_CAN_FEC_AUTO | | ||
2704 | FE_CAN_QAM_16 | | ||
2705 | FE_CAN_QAM_32 | | ||
2706 | FE_CAN_QAM_64 | | ||
2707 | FE_CAN_QAM_128 | | ||
2708 | FE_CAN_QAM_256 | | ||
2709 | FE_CAN_QAM_AUTO | | ||
2710 | FE_CAN_INVERSION_AUTO, | ||
2711 | .frequency_min = 42000000, | ||
2712 | .frequency_max = 1002000000 | ||
2713 | }, | ||
2714 | .init = cxd2841er_init_tc, | ||
2715 | .sleep = cxd2841er_sleep_tc, | ||
2716 | .release = cxd2841er_release, | ||
2717 | .set_frontend = cxd2841er_set_frontend_tc, | ||
2718 | .get_frontend = cxd2841er_get_frontend, | ||
2719 | .read_status = cxd2841er_read_status_tc, | ||
2720 | .tune = cxd2841er_tune_tc, | ||
2721 | .i2c_gate_ctrl = cxd2841er_i2c_gate_ctrl, | ||
2722 | .get_frontend_algo = cxd2841er_get_algo, | ||
2723 | }; | ||
2724 | |||
2725 | MODULE_DESCRIPTION("Sony CXD2841ER DVB-C/C2/T/T2/S/S2 demodulator driver"); | ||
2726 | MODULE_AUTHOR("Sergey Kozlov <serjk@netup.ru>"); | ||
2727 | MODULE_LICENSE("GPL"); | 3576 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/media/dvb-frontends/cxd2841er.h b/drivers/media/dvb-frontends/cxd2841er.h index 3472bdd58949..62ad5f07390b 100644 --- a/drivers/media/dvb-frontends/cxd2841er.h +++ b/drivers/media/dvb-frontends/cxd2841er.h | |||
@@ -25,41 +25,39 @@ | |||
25 | #include <linux/kconfig.h> | 25 | #include <linux/kconfig.h> |
26 | #include <linux/dvb/frontend.h> | 26 | #include <linux/dvb/frontend.h> |
27 | 27 | ||
28 | enum cxd2841er_xtal { | ||
29 | SONY_XTAL_20500, /* 20.5 MHz */ | ||
30 | SONY_XTAL_24000, /* 24 MHz */ | ||
31 | SONY_XTAL_41000 /* 41 MHz */ | ||
32 | }; | ||
33 | |||
28 | struct cxd2841er_config { | 34 | struct cxd2841er_config { |
29 | u8 i2c_addr; | 35 | u8 i2c_addr; |
36 | enum cxd2841er_xtal xtal; | ||
30 | }; | 37 | }; |
31 | 38 | ||
32 | #if IS_REACHABLE(CONFIG_DVB_CXD2841ER) | 39 | #if IS_REACHABLE(CONFIG_DVB_CXD2841ER) |
33 | extern struct dvb_frontend *cxd2841er_attach_s(struct cxd2841er_config *cfg, | 40 | extern struct dvb_frontend *cxd2841er_attach_s(struct cxd2841er_config *cfg, |
34 | struct i2c_adapter *i2c); | 41 | struct i2c_adapter *i2c); |
35 | 42 | ||
36 | extern struct dvb_frontend *cxd2841er_attach_t(struct cxd2841er_config *cfg, | 43 | extern struct dvb_frontend *cxd2841er_attach_t_c(struct cxd2841er_config *cfg, |
37 | struct i2c_adapter *i2c); | ||
38 | |||
39 | extern struct dvb_frontend *cxd2841er_attach_c(struct cxd2841er_config *cfg, | ||
40 | struct i2c_adapter *i2c); | 44 | struct i2c_adapter *i2c); |
41 | #else | 45 | #else |
42 | static inline struct dvb_frontend *cxd2841er_attach_s( | 46 | static inline struct dvb_frontend *cxd2841er_attach_s( |
43 | struct cxd2841er_config *cfg, | 47 | struct cxd2841er_config *cfg, |
44 | struct i2c_adapter *i2c) | 48 | struct i2c_adapter *i2c) |
45 | { | 49 | { |
46 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | 50 | pr_warn("%s: driver disabled by Kconfig\n", __func__); |
47 | return NULL; | 51 | return NULL; |
48 | } | 52 | } |
49 | 53 | ||
50 | static inline struct dvb_frontend *cxd2841er_attach_t( | 54 | static inline struct dvb_frontend *cxd2841er_attach_t_c( |
51 | struct cxd2841er_config *cfg, struct i2c_adapter *i2c) | 55 | struct cxd2841er_config *cfg, struct i2c_adapter *i2c) |
52 | { | 56 | { |
53 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | 57 | pr_warn("%s: driver disabled by Kconfig\n", __func__); |
54 | return NULL; | 58 | return NULL; |
55 | } | 59 | } |
56 | 60 | ||
57 | static inline struct dvb_frontend *cxd2841er_attach_c( | ||
58 | struct cxd2841er_config *cfg, struct i2c_adapter *i2c) | ||
59 | { | ||
60 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
61 | return NULL; | ||
62 | } | ||
63 | #endif | 61 | #endif |
64 | 62 | ||
65 | #endif | 63 | #endif |
diff --git a/drivers/media/dvb-frontends/cxd2841er_priv.h b/drivers/media/dvb-frontends/cxd2841er_priv.h index 33e2f495277b..0bbce451149f 100644 --- a/drivers/media/dvb-frontends/cxd2841er_priv.h +++ b/drivers/media/dvb-frontends/cxd2841er_priv.h | |||
@@ -26,6 +26,7 @@ | |||
26 | #define I2C_SLVT 1 | 26 | #define I2C_SLVT 1 |
27 | 27 | ||
28 | #define CXD2841ER_CHIP_ID 0xa7 | 28 | #define CXD2841ER_CHIP_ID 0xa7 |
29 | #define CXD2854ER_CHIP_ID 0xc1 | ||
29 | 30 | ||
30 | #define CXD2841ER_DVBS_POLLING_INVL 10 | 31 | #define CXD2841ER_DVBS_POLLING_INVL 10 |
31 | 32 | ||
diff --git a/drivers/media/dvb-frontends/ds3000.c b/drivers/media/dvb-frontends/ds3000.c index addffc33993a..447b518e287a 100644 --- a/drivers/media/dvb-frontends/ds3000.c +++ b/drivers/media/dvb-frontends/ds3000.c | |||
@@ -959,6 +959,15 @@ static int ds3000_set_frontend(struct dvb_frontend *fe) | |||
959 | /* enable ac coupling */ | 959 | /* enable ac coupling */ |
960 | ds3000_writereg(state, 0x25, 0x8a); | 960 | ds3000_writereg(state, 0x25, 0x8a); |
961 | 961 | ||
962 | if ((c->symbol_rate < ds3000_ops.info.symbol_rate_min) || | ||
963 | (c->symbol_rate > ds3000_ops.info.symbol_rate_max)) { | ||
964 | dprintk("%s() symbol_rate %u out of range (%u ... %u)\n", | ||
965 | __func__, c->symbol_rate, | ||
966 | ds3000_ops.info.symbol_rate_min, | ||
967 | ds3000_ops.info.symbol_rate_max); | ||
968 | return -EINVAL; | ||
969 | } | ||
970 | |||
962 | /* enhance symbol rate performance */ | 971 | /* enhance symbol rate performance */ |
963 | if ((c->symbol_rate / 1000) <= 5000) { | 972 | if ((c->symbol_rate / 1000) <= 5000) { |
964 | value = 29777 / (c->symbol_rate / 1000) + 1; | 973 | value = 29777 / (c->symbol_rate / 1000) + 1; |
diff --git a/drivers/media/dvb-frontends/helene.c b/drivers/media/dvb-frontends/helene.c new file mode 100644 index 000000000000..97a8982740a6 --- /dev/null +++ b/drivers/media/dvb-frontends/helene.c | |||
@@ -0,0 +1,1042 @@ | |||
1 | /* | ||
2 | * helene.c | ||
3 | * | ||
4 | * Sony HELENE DVB-S/S2 DVB-T/T2 DVB-C/C2 ISDB-T/S tuner driver (CXD2858ER) | ||
5 | * | ||
6 | * Copyright 2012 Sony Corporation | ||
7 | * Copyright (C) 2014 NetUP Inc. | ||
8 | * Copyright (C) 2014 Abylay Ospan <aospan@netup.ru> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | */ | ||
20 | |||
21 | #include <linux/slab.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/dvb/frontend.h> | ||
24 | #include <linux/types.h> | ||
25 | #include "helene.h" | ||
26 | #include "dvb_frontend.h" | ||
27 | |||
28 | #define MAX_WRITE_REGSIZE 20 | ||
29 | |||
30 | enum helene_state { | ||
31 | STATE_UNKNOWN, | ||
32 | STATE_SLEEP, | ||
33 | STATE_ACTIVE | ||
34 | }; | ||
35 | |||
36 | struct helene_priv { | ||
37 | u32 frequency; | ||
38 | u8 i2c_address; | ||
39 | struct i2c_adapter *i2c; | ||
40 | enum helene_state state; | ||
41 | void *set_tuner_data; | ||
42 | int (*set_tuner)(void *, int); | ||
43 | enum helene_xtal xtal; | ||
44 | }; | ||
45 | |||
46 | #define TERR_INTERNAL_LOOPFILTER_AVAILABLE(tv_system) \ | ||
47 | (((tv_system) != SONY_HELENE_DTV_DVBC_6) && \ | ||
48 | ((tv_system) != SONY_HELENE_DTV_DVBC_8)\ | ||
49 | && ((tv_system) != SONY_HELENE_DTV_DVBC2_6) && \ | ||
50 | ((tv_system) != SONY_HELENE_DTV_DVBC2_8)) | ||
51 | |||
52 | #define HELENE_AUTO 0xff | ||
53 | #define HELENE_OFFSET(ofs) ((u8)(ofs) & 0x1F) | ||
54 | #define HELENE_BW_6 0x00 | ||
55 | #define HELENE_BW_7 0x01 | ||
56 | #define HELENE_BW_8 0x02 | ||
57 | #define HELENE_BW_1_7 0x03 | ||
58 | |||
59 | enum helene_tv_system_t { | ||
60 | SONY_HELENE_TV_SYSTEM_UNKNOWN, | ||
61 | /* Terrestrial Analog */ | ||
62 | SONY_HELENE_ATV_MN_EIAJ, | ||
63 | /**< System-M (Japan) (IF: Fp=5.75MHz in default) */ | ||
64 | SONY_HELENE_ATV_MN_SAP, | ||
65 | /**< System-M (US) (IF: Fp=5.75MHz in default) */ | ||
66 | SONY_HELENE_ATV_MN_A2, | ||
67 | /**< System-M (Korea) (IF: Fp=5.9MHz in default) */ | ||
68 | SONY_HELENE_ATV_BG, | ||
69 | /**< System-B/G (IF: Fp=7.3MHz in default) */ | ||
70 | SONY_HELENE_ATV_I, | ||
71 | /**< System-I (IF: Fp=7.85MHz in default) */ | ||
72 | SONY_HELENE_ATV_DK, | ||
73 | /**< System-D/K (IF: Fp=7.85MHz in default) */ | ||
74 | SONY_HELENE_ATV_L, | ||
75 | /**< System-L (IF: Fp=7.85MHz in default) */ | ||
76 | SONY_HELENE_ATV_L_DASH, | ||
77 | /**< System-L DASH (IF: Fp=2.2MHz in default) */ | ||
78 | /* Terrestrial/Cable Digital */ | ||
79 | SONY_HELENE_DTV_8VSB, | ||
80 | /**< ATSC 8VSB (IF: Fc=3.7MHz in default) */ | ||
81 | SONY_HELENE_DTV_QAM, | ||
82 | /**< US QAM (IF: Fc=3.7MHz in default) */ | ||
83 | SONY_HELENE_DTV_ISDBT_6, | ||
84 | /**< ISDB-T 6MHzBW (IF: Fc=3.55MHz in default) */ | ||
85 | SONY_HELENE_DTV_ISDBT_7, | ||
86 | /**< ISDB-T 7MHzBW (IF: Fc=4.15MHz in default) */ | ||
87 | SONY_HELENE_DTV_ISDBT_8, | ||
88 | /**< ISDB-T 8MHzBW (IF: Fc=4.75MHz in default) */ | ||
89 | SONY_HELENE_DTV_DVBT_5, | ||
90 | /**< DVB-T 5MHzBW (IF: Fc=3.6MHz in default) */ | ||
91 | SONY_HELENE_DTV_DVBT_6, | ||
92 | /**< DVB-T 6MHzBW (IF: Fc=3.6MHz in default) */ | ||
93 | SONY_HELENE_DTV_DVBT_7, | ||
94 | /**< DVB-T 7MHzBW (IF: Fc=4.2MHz in default) */ | ||
95 | SONY_HELENE_DTV_DVBT_8, | ||
96 | /**< DVB-T 8MHzBW (IF: Fc=4.8MHz in default) */ | ||
97 | SONY_HELENE_DTV_DVBT2_1_7, | ||
98 | /**< DVB-T2 1.7MHzBW (IF: Fc=3.5MHz in default) */ | ||
99 | SONY_HELENE_DTV_DVBT2_5, | ||
100 | /**< DVB-T2 5MHzBW (IF: Fc=3.6MHz in default) */ | ||
101 | SONY_HELENE_DTV_DVBT2_6, | ||
102 | /**< DVB-T2 6MHzBW (IF: Fc=3.6MHz in default) */ | ||
103 | SONY_HELENE_DTV_DVBT2_7, | ||
104 | /**< DVB-T2 7MHzBW (IF: Fc=4.2MHz in default) */ | ||
105 | SONY_HELENE_DTV_DVBT2_8, | ||
106 | /**< DVB-T2 8MHzBW (IF: Fc=4.8MHz in default) */ | ||
107 | SONY_HELENE_DTV_DVBC_6, | ||
108 | /**< DVB-C 6MHzBW (IF: Fc=3.7MHz in default) */ | ||
109 | SONY_HELENE_DTV_DVBC_8, | ||
110 | /**< DVB-C 8MHzBW (IF: Fc=4.9MHz in default) */ | ||
111 | SONY_HELENE_DTV_DVBC2_6, | ||
112 | /**< DVB-C2 6MHzBW (IF: Fc=3.7MHz in default) */ | ||
113 | SONY_HELENE_DTV_DVBC2_8, | ||
114 | /**< DVB-C2 8MHzBW (IF: Fc=4.9MHz in default) */ | ||
115 | SONY_HELENE_DTV_DTMB, | ||
116 | /**< DTMB (IF: Fc=5.1MHz in default) */ | ||
117 | /* Satellite */ | ||
118 | SONY_HELENE_STV_ISDBS, | ||
119 | /**< ISDB-S */ | ||
120 | SONY_HELENE_STV_DVBS, | ||
121 | /**< DVB-S */ | ||
122 | SONY_HELENE_STV_DVBS2, | ||
123 | /**< DVB-S2 */ | ||
124 | |||
125 | SONY_HELENE_ATV_MIN = SONY_HELENE_ATV_MN_EIAJ, | ||
126 | /**< Minimum analog terrestrial system */ | ||
127 | SONY_HELENE_ATV_MAX = SONY_HELENE_ATV_L_DASH, | ||
128 | /**< Maximum analog terrestrial system */ | ||
129 | SONY_HELENE_DTV_MIN = SONY_HELENE_DTV_8VSB, | ||
130 | /**< Minimum digital terrestrial system */ | ||
131 | SONY_HELENE_DTV_MAX = SONY_HELENE_DTV_DTMB, | ||
132 | /**< Maximum digital terrestrial system */ | ||
133 | SONY_HELENE_TERR_TV_SYSTEM_NUM, | ||
134 | /**< Number of supported terrestrial broadcasting system */ | ||
135 | SONY_HELENE_STV_MIN = SONY_HELENE_STV_ISDBS, | ||
136 | /**< Minimum satellite system */ | ||
137 | SONY_HELENE_STV_MAX = SONY_HELENE_STV_DVBS2 | ||
138 | /**< Maximum satellite system */ | ||
139 | }; | ||
140 | |||
141 | struct helene_terr_adjust_param_t { | ||
142 | /* < Addr:0x69 Bit[6:4] : RFVGA gain. | ||
143 | * 0xFF means Auto. (RF_GAIN_SEL = 1) | ||
144 | */ | ||
145 | uint8_t RF_GAIN; | ||
146 | /* < Addr:0x69 Bit[3:0] : IF_BPF gain. | ||
147 | */ | ||
148 | uint8_t IF_BPF_GC; | ||
149 | /* < Addr:0x6B Bit[3:0] : RF overload | ||
150 | * RF input detect level. (FRF <= 172MHz) | ||
151 | */ | ||
152 | uint8_t RFOVLD_DET_LV1_VL; | ||
153 | /* < Addr:0x6B Bit[3:0] : RF overload | ||
154 | * RF input detect level. (172MHz < FRF <= 464MHz) | ||
155 | */ | ||
156 | uint8_t RFOVLD_DET_LV1_VH; | ||
157 | /* < Addr:0x6B Bit[3:0] : RF overload | ||
158 | * RF input detect level. (FRF > 464MHz) | ||
159 | */ | ||
160 | uint8_t RFOVLD_DET_LV1_U; | ||
161 | /* < Addr:0x6C Bit[2:0] : | ||
162 | * Internal RFAGC detect level. (FRF <= 172MHz) | ||
163 | */ | ||
164 | uint8_t IFOVLD_DET_LV_VL; | ||
165 | /* < Addr:0x6C Bit[2:0] : | ||
166 | * Internal RFAGC detect level. (172MHz < FRF <= 464MHz) | ||
167 | */ | ||
168 | uint8_t IFOVLD_DET_LV_VH; | ||
169 | /* < Addr:0x6C Bit[2:0] : | ||
170 | * Internal RFAGC detect level. (FRF > 464MHz) | ||
171 | */ | ||
172 | uint8_t IFOVLD_DET_LV_U; | ||
173 | /* < Addr:0x6D Bit[5:4] : | ||
174 | * IF filter center offset. | ||
175 | */ | ||
176 | uint8_t IF_BPF_F0; | ||
177 | /* < Addr:0x6D Bit[1:0] : | ||
178 | * 6MHzBW(0x00) or 7MHzBW(0x01) | ||
179 | * or 8MHzBW(0x02) or 1.7MHzBW(0x03) | ||
180 | */ | ||
181 | uint8_t BW; | ||
182 | /* < Addr:0x6E Bit[4:0] : | ||
183 | * 5bit signed. IF offset (kHz) = FIF_OFFSET x 50 | ||
184 | */ | ||
185 | uint8_t FIF_OFFSET; | ||
186 | /* < Addr:0x6F Bit[4:0] : | ||
187 | * 5bit signed. BW offset (kHz) = | ||
188 | * BW_OFFSET x 50 (BW_OFFSET x 10 in 1.7MHzBW) | ||
189 | */ | ||
190 | uint8_t BW_OFFSET; | ||
191 | /* < Addr:0x9C Bit[0] : | ||
192 | * Local polarity. (0: Upper Local, 1: Lower Local) | ||
193 | */ | ||
194 | uint8_t IS_LOWERLOCAL; | ||
195 | }; | ||
196 | |||
197 | static const struct helene_terr_adjust_param_t | ||
198 | terr_params[SONY_HELENE_TERR_TV_SYSTEM_NUM] = { | ||
199 | /*< SONY_HELENE_TV_SYSTEM_UNKNOWN */ | ||
200 | {HELENE_AUTO, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
201 | HELENE_BW_6, HELENE_OFFSET(0), HELENE_OFFSET(0), 0x00}, | ||
202 | /* Analog */ | ||
203 | /**< SONY_HELENE_ATV_MN_EIAJ (System-M (Japan)) */ | ||
204 | {HELENE_AUTO, 0x05, 0x03, 0x06, 0x03, 0x01, 0x01, 0x01, 0x00, | ||
205 | HELENE_BW_6, HELENE_OFFSET(0), HELENE_OFFSET(1), 0x00}, | ||
206 | /**< SONY_HELENE_ATV_MN_SAP (System-M (US)) */ | ||
207 | {HELENE_AUTO, 0x05, 0x03, 0x06, 0x03, 0x01, 0x01, 0x01, 0x00, | ||
208 | HELENE_BW_6, HELENE_OFFSET(0), HELENE_OFFSET(1), 0x00}, | ||
209 | {HELENE_AUTO, 0x05, 0x03, 0x06, 0x03, 0x01, 0x01, 0x01, 0x00, | ||
210 | HELENE_BW_6, HELENE_OFFSET(3), HELENE_OFFSET(1), 0x00}, | ||
211 | /**< SONY_HELENE_ATV_MN_A2 (System-M (Korea)) */ | ||
212 | {HELENE_AUTO, 0x05, 0x03, 0x06, 0x03, 0x01, 0x01, 0x01, 0x00, | ||
213 | HELENE_BW_7, HELENE_OFFSET(11), HELENE_OFFSET(5), 0x00}, | ||
214 | /**< SONY_HELENE_ATV_BG (System-B/G) */ | ||
215 | {HELENE_AUTO, 0x05, 0x03, 0x06, 0x03, 0x01, 0x01, 0x01, 0x00, | ||
216 | HELENE_BW_8, HELENE_OFFSET(2), HELENE_OFFSET(-3), 0x00}, | ||
217 | /**< SONY_HELENE_ATV_I (System-I) */ | ||
218 | {HELENE_AUTO, 0x05, 0x03, 0x06, 0x03, 0x01, 0x01, 0x01, 0x00, | ||
219 | HELENE_BW_8, HELENE_OFFSET(2), HELENE_OFFSET(-3), 0x00}, | ||
220 | /**< SONY_HELENE_ATV_DK (System-D/K) */ | ||
221 | {HELENE_AUTO, 0x03, 0x04, 0x0A, 0x04, 0x04, 0x04, 0x04, 0x00, | ||
222 | HELENE_BW_8, HELENE_OFFSET(2), HELENE_OFFSET(-3), 0x00}, | ||
223 | /**< SONY_HELENE_ATV_L (System-L) */ | ||
224 | {HELENE_AUTO, 0x03, 0x04, 0x0A, 0x04, 0x04, 0x04, 0x04, 0x00, | ||
225 | HELENE_BW_8, HELENE_OFFSET(-1), HELENE_OFFSET(4), 0x00}, | ||
226 | /**< SONY_HELENE_ATV_L_DASH (System-L DASH) */ | ||
227 | /* Digital */ | ||
228 | {HELENE_AUTO, 0x09, 0x0B, 0x0B, 0x0B, 0x03, 0x03, 0x03, 0x00, | ||
229 | HELENE_BW_6, HELENE_OFFSET(-6), HELENE_OFFSET(-3), 0x00}, | ||
230 | /**< SONY_HELENE_DTV_8VSB (ATSC 8VSB) */ | ||
231 | {HELENE_AUTO, 0x09, 0x0B, 0x0B, 0x0B, 0x02, 0x02, 0x02, 0x00, | ||
232 | HELENE_BW_6, HELENE_OFFSET(-6), HELENE_OFFSET(-3), 0x00}, | ||
233 | /**< SONY_HELENE_DTV_QAM (US QAM) */ | ||
234 | {HELENE_AUTO, 0x09, 0x0B, 0x0B, 0x0B, 0x02, 0x02, 0x02, 0x00, | ||
235 | HELENE_BW_6, HELENE_OFFSET(-9), HELENE_OFFSET(-5), 0x00}, | ||
236 | /**< SONY_HELENE_DTV_ISDBT_6 (ISDB-T 6MHzBW) */ | ||
237 | {HELENE_AUTO, 0x09, 0x0B, 0x0B, 0x0B, 0x02, 0x02, 0x02, 0x00, | ||
238 | HELENE_BW_7, HELENE_OFFSET(-7), HELENE_OFFSET(-6), 0x00}, | ||
239 | /**< SONY_HELENE_DTV_ISDBT_7 (ISDB-T 7MHzBW) */ | ||
240 | {HELENE_AUTO, 0x09, 0x0B, 0x0B, 0x0B, 0x02, 0x02, 0x02, 0x00, | ||
241 | HELENE_BW_8, HELENE_OFFSET(-5), HELENE_OFFSET(-7), 0x00}, | ||
242 | /**< SONY_HELENE_DTV_ISDBT_8 (ISDB-T 8MHzBW) */ | ||
243 | {HELENE_AUTO, 0x09, 0x0B, 0x0B, 0x0B, 0x02, 0x02, 0x02, 0x00, | ||
244 | HELENE_BW_6, HELENE_OFFSET(-8), HELENE_OFFSET(-3), 0x00}, | ||
245 | /**< SONY_HELENE_DTV_DVBT_5 (DVB-T 5MHzBW) */ | ||
246 | {HELENE_AUTO, 0x09, 0x0B, 0x0B, 0x0B, 0x02, 0x02, 0x02, 0x00, | ||
247 | HELENE_BW_6, HELENE_OFFSET(-8), HELENE_OFFSET(-3), 0x00}, | ||
248 | /**< SONY_HELENE_DTV_DVBT_6 (DVB-T 6MHzBW) */ | ||
249 | {HELENE_AUTO, 0x09, 0x0B, 0x0B, 0x0B, 0x02, 0x02, 0x02, 0x00, | ||
250 | HELENE_BW_7, HELENE_OFFSET(-6), HELENE_OFFSET(-5), 0x00}, | ||
251 | /**< SONY_HELENE_DTV_DVBT_7 (DVB-T 7MHzBW) */ | ||
252 | {HELENE_AUTO, 0x09, 0x0B, 0x0B, 0x0B, 0x02, 0x02, 0x02, 0x00, | ||
253 | HELENE_BW_8, HELENE_OFFSET(-4), HELENE_OFFSET(-6), 0x00}, | ||
254 | /**< SONY_HELENE_DTV_DVBT_8 (DVB-T 8MHzBW) */ | ||
255 | {HELENE_AUTO, 0x09, 0x0B, 0x0B, 0x0B, 0x02, 0x02, 0x02, 0x00, | ||
256 | HELENE_BW_1_7, HELENE_OFFSET(-10), HELENE_OFFSET(-10), 0x00}, | ||
257 | /**< SONY_HELENE_DTV_DVBT2_1_7 (DVB-T2 1.7MHzBW) */ | ||
258 | {HELENE_AUTO, 0x09, 0x0B, 0x0B, 0x0B, 0x02, 0x02, 0x02, 0x00, | ||
259 | HELENE_BW_6, HELENE_OFFSET(-8), HELENE_OFFSET(-3), 0x00}, | ||
260 | /**< SONY_HELENE_DTV_DVBT2_5 (DVB-T2 5MHzBW) */ | ||
261 | {HELENE_AUTO, 0x09, 0x0B, 0x0B, 0x0B, 0x02, 0x02, 0x02, 0x00, | ||
262 | HELENE_BW_6, HELENE_OFFSET(-8), HELENE_OFFSET(-3), 0x00}, | ||
263 | /**< SONY_HELENE_DTV_DVBT2_6 (DVB-T2 6MHzBW) */ | ||
264 | {HELENE_AUTO, 0x09, 0x0B, 0x0B, 0x0B, 0x02, 0x02, 0x02, 0x00, | ||
265 | HELENE_BW_7, HELENE_OFFSET(-6), HELENE_OFFSET(-5), 0x00}, | ||
266 | /**< SONY_HELENE_DTV_DVBT2_7 (DVB-T2 7MHzBW) */ | ||
267 | {HELENE_AUTO, 0x09, 0x0B, 0x0B, 0x0B, 0x02, 0x02, 0x02, 0x00, | ||
268 | HELENE_BW_8, HELENE_OFFSET(-4), HELENE_OFFSET(-6), 0x00}, | ||
269 | /**< SONY_HELENE_DTV_DVBT2_8 (DVB-T2 8MHzBW) */ | ||
270 | {HELENE_AUTO, 0x05, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x00, | ||
271 | HELENE_BW_6, HELENE_OFFSET(-6), HELENE_OFFSET(-4), 0x00}, | ||
272 | /**< SONY_HELENE_DTV_DVBC_6 (DVB-C 6MHzBW) */ | ||
273 | {HELENE_AUTO, 0x05, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x00, | ||
274 | HELENE_BW_8, HELENE_OFFSET(-2), HELENE_OFFSET(-3), 0x00}, | ||
275 | /**< SONY_HELENE_DTV_DVBC_8 (DVB-C 8MHzBW) */ | ||
276 | {HELENE_AUTO, 0x03, 0x09, 0x09, 0x09, 0x02, 0x02, 0x02, 0x00, | ||
277 | HELENE_BW_6, HELENE_OFFSET(-6), HELENE_OFFSET(-2), 0x00}, | ||
278 | /**< SONY_HELENE_DTV_DVBC2_6 (DVB-C2 6MHzBW) */ | ||
279 | {HELENE_AUTO, 0x03, 0x09, 0x09, 0x09, 0x02, 0x02, 0x02, 0x00, | ||
280 | HELENE_BW_8, HELENE_OFFSET(-2), HELENE_OFFSET(0), 0x00}, | ||
281 | /**< SONY_HELENE_DTV_DVBC2_8 (DVB-C2 8MHzBW) */ | ||
282 | {HELENE_AUTO, 0x04, 0x0B, 0x0B, 0x0B, 0x02, 0x02, 0x02, 0x00, | ||
283 | HELENE_BW_8, HELENE_OFFSET(2), HELENE_OFFSET(1), 0x00} | ||
284 | /**< SONY_HELENE_DTV_DTMB (DTMB) */ | ||
285 | }; | ||
286 | |||
287 | static void helene_i2c_debug(struct helene_priv *priv, | ||
288 | u8 reg, u8 write, const u8 *data, u32 len) | ||
289 | { | ||
290 | dev_dbg(&priv->i2c->dev, "helene: I2C %s reg 0x%02x size %d\n", | ||
291 | (write == 0 ? "read" : "write"), reg, len); | ||
292 | print_hex_dump_bytes("helene: I2C data: ", | ||
293 | DUMP_PREFIX_OFFSET, data, len); | ||
294 | } | ||
295 | |||
296 | static int helene_write_regs(struct helene_priv *priv, | ||
297 | u8 reg, const u8 *data, u32 len) | ||
298 | { | ||
299 | int ret; | ||
300 | u8 buf[MAX_WRITE_REGSIZE + 1]; | ||
301 | struct i2c_msg msg[1] = { | ||
302 | { | ||
303 | .addr = priv->i2c_address, | ||
304 | .flags = 0, | ||
305 | .len = len + 1, | ||
306 | .buf = buf, | ||
307 | } | ||
308 | }; | ||
309 | |||
310 | if (len + 1 > sizeof(buf)) { | ||
311 | dev_warn(&priv->i2c->dev, | ||
312 | "wr reg=%04x: len=%d vs %Zu is too big!\n", | ||
313 | reg, len + 1, sizeof(buf)); | ||
314 | return -E2BIG; | ||
315 | } | ||
316 | |||
317 | helene_i2c_debug(priv, reg, 1, data, len); | ||
318 | buf[0] = reg; | ||
319 | memcpy(&buf[1], data, len); | ||
320 | ret = i2c_transfer(priv->i2c, msg, 1); | ||
321 | if (ret >= 0 && ret != 1) | ||
322 | ret = -EREMOTEIO; | ||
323 | if (ret < 0) { | ||
324 | dev_warn(&priv->i2c->dev, | ||
325 | "%s: i2c wr failed=%d reg=%02x len=%d\n", | ||
326 | KBUILD_MODNAME, ret, reg, len); | ||
327 | return ret; | ||
328 | } | ||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | static int helene_write_reg(struct helene_priv *priv, u8 reg, u8 val) | ||
333 | { | ||
334 | return helene_write_regs(priv, reg, &val, 1); | ||
335 | } | ||
336 | |||
337 | static int helene_read_regs(struct helene_priv *priv, | ||
338 | u8 reg, u8 *val, u32 len) | ||
339 | { | ||
340 | int ret; | ||
341 | struct i2c_msg msg[2] = { | ||
342 | { | ||
343 | .addr = priv->i2c_address, | ||
344 | .flags = 0, | ||
345 | .len = 1, | ||
346 | .buf = ®, | ||
347 | }, { | ||
348 | .addr = priv->i2c_address, | ||
349 | .flags = I2C_M_RD, | ||
350 | .len = len, | ||
351 | .buf = val, | ||
352 | } | ||
353 | }; | ||
354 | |||
355 | ret = i2c_transfer(priv->i2c, &msg[0], 1); | ||
356 | if (ret >= 0 && ret != 1) | ||
357 | ret = -EREMOTEIO; | ||
358 | if (ret < 0) { | ||
359 | dev_warn(&priv->i2c->dev, | ||
360 | "%s: I2C rw failed=%d addr=%02x reg=%02x\n", | ||
361 | KBUILD_MODNAME, ret, priv->i2c_address, reg); | ||
362 | return ret; | ||
363 | } | ||
364 | ret = i2c_transfer(priv->i2c, &msg[1], 1); | ||
365 | if (ret >= 0 && ret != 1) | ||
366 | ret = -EREMOTEIO; | ||
367 | if (ret < 0) { | ||
368 | dev_warn(&priv->i2c->dev, | ||
369 | "%s: i2c rd failed=%d addr=%02x reg=%02x\n", | ||
370 | KBUILD_MODNAME, ret, priv->i2c_address, reg); | ||
371 | return ret; | ||
372 | } | ||
373 | helene_i2c_debug(priv, reg, 0, val, len); | ||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | static int helene_read_reg(struct helene_priv *priv, u8 reg, u8 *val) | ||
378 | { | ||
379 | return helene_read_regs(priv, reg, val, 1); | ||
380 | } | ||
381 | |||
382 | static int helene_set_reg_bits(struct helene_priv *priv, | ||
383 | u8 reg, u8 data, u8 mask) | ||
384 | { | ||
385 | int res; | ||
386 | u8 rdata; | ||
387 | |||
388 | if (mask != 0xff) { | ||
389 | res = helene_read_reg(priv, reg, &rdata); | ||
390 | if (res != 0) | ||
391 | return res; | ||
392 | data = ((data & mask) | (rdata & (mask ^ 0xFF))); | ||
393 | } | ||
394 | return helene_write_reg(priv, reg, data); | ||
395 | } | ||
396 | |||
397 | static int helene_enter_power_save(struct helene_priv *priv) | ||
398 | { | ||
399 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | ||
400 | if (priv->state == STATE_SLEEP) | ||
401 | return 0; | ||
402 | |||
403 | /* Standby setting for CPU */ | ||
404 | helene_write_reg(priv, 0x88, 0x0); | ||
405 | |||
406 | /* Standby setting for internal logic block */ | ||
407 | helene_write_reg(priv, 0x87, 0xC0); | ||
408 | |||
409 | priv->state = STATE_SLEEP; | ||
410 | return 0; | ||
411 | } | ||
412 | |||
413 | static int helene_leave_power_save(struct helene_priv *priv) | ||
414 | { | ||
415 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | ||
416 | if (priv->state == STATE_ACTIVE) | ||
417 | return 0; | ||
418 | |||
419 | /* Standby setting for internal logic block */ | ||
420 | helene_write_reg(priv, 0x87, 0xC4); | ||
421 | |||
422 | /* Standby setting for CPU */ | ||
423 | helene_write_reg(priv, 0x88, 0x40); | ||
424 | |||
425 | priv->state = STATE_ACTIVE; | ||
426 | return 0; | ||
427 | } | ||
428 | |||
429 | static int helene_init(struct dvb_frontend *fe) | ||
430 | { | ||
431 | struct helene_priv *priv = fe->tuner_priv; | ||
432 | |||
433 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | ||
434 | return helene_leave_power_save(priv); | ||
435 | } | ||
436 | |||
437 | static int helene_release(struct dvb_frontend *fe) | ||
438 | { | ||
439 | struct helene_priv *priv = fe->tuner_priv; | ||
440 | |||
441 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | ||
442 | kfree(fe->tuner_priv); | ||
443 | fe->tuner_priv = NULL; | ||
444 | return 0; | ||
445 | } | ||
446 | |||
447 | static int helene_sleep(struct dvb_frontend *fe) | ||
448 | { | ||
449 | struct helene_priv *priv = fe->tuner_priv; | ||
450 | |||
451 | dev_dbg(&priv->i2c->dev, "%s()\n", __func__); | ||
452 | helene_enter_power_save(priv); | ||
453 | return 0; | ||
454 | } | ||
455 | |||
456 | static enum helene_tv_system_t helene_get_tv_system(struct dvb_frontend *fe) | ||
457 | { | ||
458 | enum helene_tv_system_t system = SONY_HELENE_TV_SYSTEM_UNKNOWN; | ||
459 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; | ||
460 | struct helene_priv *priv = fe->tuner_priv; | ||
461 | |||
462 | if (p->delivery_system == SYS_DVBT) { | ||
463 | if (p->bandwidth_hz <= 5000000) | ||
464 | system = SONY_HELENE_DTV_DVBT_5; | ||
465 | else if (p->bandwidth_hz <= 6000000) | ||
466 | system = SONY_HELENE_DTV_DVBT_6; | ||
467 | else if (p->bandwidth_hz <= 7000000) | ||
468 | system = SONY_HELENE_DTV_DVBT_7; | ||
469 | else if (p->bandwidth_hz <= 8000000) | ||
470 | system = SONY_HELENE_DTV_DVBT_8; | ||
471 | else { | ||
472 | system = SONY_HELENE_DTV_DVBT_8; | ||
473 | p->bandwidth_hz = 8000000; | ||
474 | } | ||
475 | } else if (p->delivery_system == SYS_DVBT2) { | ||
476 | if (p->bandwidth_hz <= 5000000) | ||
477 | system = SONY_HELENE_DTV_DVBT2_5; | ||
478 | else if (p->bandwidth_hz <= 6000000) | ||
479 | system = SONY_HELENE_DTV_DVBT2_6; | ||
480 | else if (p->bandwidth_hz <= 7000000) | ||
481 | system = SONY_HELENE_DTV_DVBT2_7; | ||
482 | else if (p->bandwidth_hz <= 8000000) | ||
483 | system = SONY_HELENE_DTV_DVBT2_8; | ||
484 | else { | ||
485 | system = SONY_HELENE_DTV_DVBT2_8; | ||
486 | p->bandwidth_hz = 8000000; | ||
487 | } | ||
488 | } else if (p->delivery_system == SYS_DVBS) { | ||
489 | system = SONY_HELENE_STV_DVBS; | ||
490 | } else if (p->delivery_system == SYS_DVBS2) { | ||
491 | system = SONY_HELENE_STV_DVBS2; | ||
492 | } else if (p->delivery_system == SYS_ISDBS) { | ||
493 | system = SONY_HELENE_STV_ISDBS; | ||
494 | } else if (p->delivery_system == SYS_ISDBT) { | ||
495 | if (p->bandwidth_hz <= 6000000) | ||
496 | system = SONY_HELENE_DTV_ISDBT_6; | ||
497 | else if (p->bandwidth_hz <= 7000000) | ||
498 | system = SONY_HELENE_DTV_ISDBT_7; | ||
499 | else if (p->bandwidth_hz <= 8000000) | ||
500 | system = SONY_HELENE_DTV_ISDBT_8; | ||
501 | else { | ||
502 | system = SONY_HELENE_DTV_ISDBT_8; | ||
503 | p->bandwidth_hz = 8000000; | ||
504 | } | ||
505 | } else if (p->delivery_system == SYS_DVBC_ANNEX_A) { | ||
506 | if (p->bandwidth_hz <= 6000000) | ||
507 | system = SONY_HELENE_DTV_DVBC_6; | ||
508 | else if (p->bandwidth_hz <= 8000000) | ||
509 | system = SONY_HELENE_DTV_DVBC_8; | ||
510 | } | ||
511 | dev_dbg(&priv->i2c->dev, | ||
512 | "%s(): HELENE DTV system %d (delsys %d, bandwidth %d)\n", | ||
513 | __func__, (int)system, p->delivery_system, | ||
514 | p->bandwidth_hz); | ||
515 | return system; | ||
516 | } | ||
517 | |||
518 | static int helene_set_params_s(struct dvb_frontend *fe) | ||
519 | { | ||
520 | u8 data[MAX_WRITE_REGSIZE]; | ||
521 | u32 frequency; | ||
522 | enum helene_tv_system_t tv_system; | ||
523 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; | ||
524 | struct helene_priv *priv = fe->tuner_priv; | ||
525 | int frequencykHz = p->frequency; | ||
526 | uint32_t frequency4kHz = 0; | ||
527 | u32 symbol_rate = p->symbol_rate/1000; | ||
528 | |||
529 | dev_dbg(&priv->i2c->dev, "%s(): tune frequency %dkHz sr=%uKsps\n", | ||
530 | __func__, frequencykHz, symbol_rate); | ||
531 | tv_system = helene_get_tv_system(fe); | ||
532 | |||
533 | if (tv_system == SONY_HELENE_TV_SYSTEM_UNKNOWN) { | ||
534 | dev_err(&priv->i2c->dev, "%s(): unknown DTV system\n", | ||
535 | __func__); | ||
536 | return -EINVAL; | ||
537 | } | ||
538 | /* RF switch turn to satellite */ | ||
539 | if (priv->set_tuner) | ||
540 | priv->set_tuner(priv->set_tuner_data, 0); | ||
541 | frequency = roundup(p->frequency / 1000, 1); | ||
542 | |||
543 | /* Disable IF signal output */ | ||
544 | helene_write_reg(priv, 0x15, 0x02); | ||
545 | |||
546 | /* RFIN matching in power save (Sat) reset */ | ||
547 | helene_write_reg(priv, 0x43, 0x06); | ||
548 | |||
549 | /* Analog block setting (0x6A, 0x6B) */ | ||
550 | data[0] = 0x00; | ||
551 | data[1] = 0x00; | ||
552 | helene_write_regs(priv, 0x6A, data, 2); | ||
553 | helene_write_reg(priv, 0x75, 0x99); | ||
554 | helene_write_reg(priv, 0x9D, 0x00); | ||
555 | |||
556 | /* Tuning setting for CPU (0x61) */ | ||
557 | helene_write_reg(priv, 0x61, 0x07); | ||
558 | |||
559 | /* Satellite mode select (0x01) */ | ||
560 | helene_write_reg(priv, 0x01, 0x01); | ||
561 | |||
562 | /* Clock enable for internal logic block, CPU wake-up (0x04, 0x05) */ | ||
563 | data[0] = 0xC4; | ||
564 | data[1] = 0x40; | ||
565 | |||
566 | switch (priv->xtal) { | ||
567 | case SONY_HELENE_XTAL_16000: | ||
568 | data[2] = 0x02; | ||
569 | break; | ||
570 | case SONY_HELENE_XTAL_20500: | ||
571 | data[2] = 0x02; | ||
572 | break; | ||
573 | case SONY_HELENE_XTAL_24000: | ||
574 | data[2] = 0x03; | ||
575 | break; | ||
576 | case SONY_HELENE_XTAL_41000: | ||
577 | data[2] = 0x05; | ||
578 | break; | ||
579 | default: | ||
580 | dev_err(&priv->i2c->dev, "%s(): unknown xtal %d\n", | ||
581 | __func__, priv->xtal); | ||
582 | return -EINVAL; | ||
583 | } | ||
584 | |||
585 | /* Setting for analog block (0x07). LOOPFILTER INTERNAL */ | ||
586 | data[3] = 0x80; | ||
587 | |||
588 | /* Tuning setting for analog block | ||
589 | * (0x08, 0x09, 0x0A, 0x0B). LOOPFILTER INTERNAL | ||
590 | */ | ||
591 | if (priv->xtal == SONY_HELENE_XTAL_20500) | ||
592 | data[4] = 0x58; | ||
593 | else | ||
594 | data[4] = 0x70; | ||
595 | |||
596 | data[5] = 0x1E; | ||
597 | data[6] = 0x02; | ||
598 | data[7] = 0x24; | ||
599 | |||
600 | /* Enable for analog block (0x0C, 0x0D, 0x0E). SAT LNA ON */ | ||
601 | data[8] = 0x0F; | ||
602 | data[8] |= 0xE0; /* POWERSAVE_TERR_RF_ACTIVE */ | ||
603 | data[9] = 0x02; | ||
604 | data[10] = 0x1E; | ||
605 | |||
606 | /* Setting for LPF cutoff frequency (0x0F) */ | ||
607 | switch (tv_system) { | ||
608 | case SONY_HELENE_STV_ISDBS: | ||
609 | data[11] = 0x22; /* 22MHz */ | ||
610 | break; | ||
611 | case SONY_HELENE_STV_DVBS: | ||
612 | if (symbol_rate <= 4000) | ||
613 | data[11] = 0x05; | ||
614 | else if (symbol_rate <= 10000) | ||
615 | data[11] = (uint8_t)((symbol_rate * 47 | ||
616 | + (40000-1)) / 40000); | ||
617 | else | ||
618 | data[11] = (uint8_t)((symbol_rate * 27 | ||
619 | + (40000-1)) / 40000 + 5); | ||
620 | |||
621 | if (data[11] > 36) | ||
622 | data[11] = 36; /* 5 <= lpf_cutoff <= 36 is valid */ | ||
623 | break; | ||
624 | case SONY_HELENE_STV_DVBS2: | ||
625 | if (symbol_rate <= 4000) | ||
626 | data[11] = 0x05; | ||
627 | else if (symbol_rate <= 10000) | ||
628 | data[11] = (uint8_t)((symbol_rate * 11 | ||
629 | + (10000-1)) / 10000); | ||
630 | else | ||
631 | data[11] = (uint8_t)((symbol_rate * 3 | ||
632 | + (5000-1)) / 5000 + 5); | ||
633 | |||
634 | if (data[11] > 36) | ||
635 | data[11] = 36; /* 5 <= lpf_cutoff <= 36 is valid */ | ||
636 | break; | ||
637 | default: | ||
638 | dev_err(&priv->i2c->dev, "%s(): unknown standard %d\n", | ||
639 | __func__, tv_system); | ||
640 | return -EINVAL; | ||
641 | } | ||
642 | |||
643 | /* RF tuning frequency setting (0x10, 0x11, 0x12) */ | ||
644 | frequency4kHz = (frequencykHz + 2) / 4; | ||
645 | data[12] = (uint8_t)(frequency4kHz & 0xFF); /* FRF_L */ | ||
646 | data[13] = (uint8_t)((frequency4kHz >> 8) & 0xFF); /* FRF_M */ | ||
647 | /* FRF_H (bit[3:0]) */ | ||
648 | data[14] = (uint8_t)((frequency4kHz >> 16) & 0x0F); | ||
649 | |||
650 | /* Tuning command (0x13) */ | ||
651 | data[15] = 0xFF; | ||
652 | |||
653 | /* Setting for IQOUT_LIMIT (0x14) 0.75Vpp */ | ||
654 | data[16] = 0x00; | ||
655 | |||
656 | /* Enable IQ output (0x15) */ | ||
657 | data[17] = 0x01; | ||
658 | |||
659 | helene_write_regs(priv, 0x04, data, 18); | ||
660 | |||
661 | dev_dbg(&priv->i2c->dev, "%s(): tune done\n", | ||
662 | __func__); | ||
663 | |||
664 | priv->frequency = frequency; | ||
665 | return 0; | ||
666 | } | ||
667 | |||
668 | static int helene_set_params(struct dvb_frontend *fe) | ||
669 | { | ||
670 | u8 data[MAX_WRITE_REGSIZE]; | ||
671 | u32 frequency; | ||
672 | enum helene_tv_system_t tv_system; | ||
673 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; | ||
674 | struct helene_priv *priv = fe->tuner_priv; | ||
675 | int frequencykHz = p->frequency / 1000; | ||
676 | |||
677 | dev_dbg(&priv->i2c->dev, "%s(): tune frequency %dkHz\n", | ||
678 | __func__, frequencykHz); | ||
679 | tv_system = helene_get_tv_system(fe); | ||
680 | |||
681 | if (tv_system == SONY_HELENE_TV_SYSTEM_UNKNOWN) { | ||
682 | dev_dbg(&priv->i2c->dev, "%s(): unknown DTV system\n", | ||
683 | __func__); | ||
684 | return -EINVAL; | ||
685 | } | ||
686 | if (priv->set_tuner) | ||
687 | priv->set_tuner(priv->set_tuner_data, 1); | ||
688 | frequency = roundup(p->frequency / 1000, 25); | ||
689 | |||
690 | /* mode select */ | ||
691 | helene_write_reg(priv, 0x01, 0x00); | ||
692 | |||
693 | /* Disable IF signal output */ | ||
694 | helene_write_reg(priv, 0x74, 0x02); | ||
695 | |||
696 | if (priv->state == STATE_SLEEP) | ||
697 | helene_leave_power_save(priv); | ||
698 | |||
699 | /* Initial setting for internal analog block (0x91, 0x92) */ | ||
700 | if ((tv_system == SONY_HELENE_DTV_DVBC_6) || | ||
701 | (tv_system == SONY_HELENE_DTV_DVBC_8)) { | ||
702 | data[0] = 0x16; | ||
703 | data[1] = 0x26; | ||
704 | } else { | ||
705 | data[0] = 0x10; | ||
706 | data[1] = 0x20; | ||
707 | } | ||
708 | helene_write_regs(priv, 0x91, data, 2); | ||
709 | |||
710 | /* Setting for analog block */ | ||
711 | if (TERR_INTERNAL_LOOPFILTER_AVAILABLE(tv_system)) | ||
712 | data[0] = 0x90; | ||
713 | else | ||
714 | data[0] = 0x00; | ||
715 | |||
716 | /* Setting for local polarity (0x9D) */ | ||
717 | data[1] = (uint8_t)(terr_params[tv_system].IS_LOWERLOCAL & 0x01); | ||
718 | helene_write_regs(priv, 0x9C, data, 2); | ||
719 | |||
720 | /* Enable for analog block */ | ||
721 | data[0] = 0xEE; | ||
722 | data[1] = 0x02; | ||
723 | data[2] = 0x1E; | ||
724 | data[3] = 0x67; /* Tuning setting for CPU */ | ||
725 | |||
726 | /* Setting for PLL reference divider for xtal=24MHz */ | ||
727 | if ((tv_system == SONY_HELENE_DTV_DVBC_6) || | ||
728 | (tv_system == SONY_HELENE_DTV_DVBC_8)) | ||
729 | data[4] = 0x18; | ||
730 | else | ||
731 | data[4] = 0x03; | ||
732 | |||
733 | /* Tuning setting for analog block */ | ||
734 | if (TERR_INTERNAL_LOOPFILTER_AVAILABLE(tv_system)) { | ||
735 | data[5] = 0x38; | ||
736 | data[6] = 0x1E; | ||
737 | data[7] = 0x02; | ||
738 | data[8] = 0x24; | ||
739 | } else if ((tv_system == SONY_HELENE_DTV_DVBC_6) || | ||
740 | (tv_system == SONY_HELENE_DTV_DVBC_8)) { | ||
741 | data[5] = 0x1C; | ||
742 | data[6] = 0x78; | ||
743 | data[7] = 0x08; | ||
744 | data[8] = 0x1C; | ||
745 | } else { | ||
746 | data[5] = 0xB4; | ||
747 | data[6] = 0x78; | ||
748 | data[7] = 0x08; | ||
749 | data[8] = 0x30; | ||
750 | } | ||
751 | helene_write_regs(priv, 0x5E, data, 9); | ||
752 | |||
753 | /* LT_AMP_EN should be 0 */ | ||
754 | helene_set_reg_bits(priv, 0x67, 0x0, 0x02); | ||
755 | |||
756 | /* Setting for IFOUT_LIMIT */ | ||
757 | data[0] = 0x00; /* 1.5Vpp */ | ||
758 | |||
759 | /* RF_GAIN setting */ | ||
760 | if (terr_params[tv_system].RF_GAIN == HELENE_AUTO) | ||
761 | data[1] = 0x80; /* RF_GAIN_SEL = 1 */ | ||
762 | else | ||
763 | data[1] = (uint8_t)((terr_params[tv_system].RF_GAIN | ||
764 | << 4) & 0x70); | ||
765 | |||
766 | /* IF_BPF_GC setting */ | ||
767 | data[1] |= (uint8_t)(terr_params[tv_system].IF_BPF_GC & 0x0F); | ||
768 | |||
769 | /* Setting for internal RFAGC (0x6A, 0x6B, 0x6C) */ | ||
770 | data[2] = 0x00; | ||
771 | if (frequencykHz <= 172000) { | ||
772 | data[3] = (uint8_t)(terr_params[tv_system].RFOVLD_DET_LV1_VL | ||
773 | & 0x0F); | ||
774 | data[4] = (uint8_t)(terr_params[tv_system].IFOVLD_DET_LV_VL | ||
775 | & 0x07); | ||
776 | } else if (frequencykHz <= 464000) { | ||
777 | data[3] = (uint8_t)(terr_params[tv_system].RFOVLD_DET_LV1_VH | ||
778 | & 0x0F); | ||
779 | data[4] = (uint8_t)(terr_params[tv_system].IFOVLD_DET_LV_VH | ||
780 | & 0x07); | ||
781 | } else { | ||
782 | data[3] = (uint8_t)(terr_params[tv_system].RFOVLD_DET_LV1_U | ||
783 | & 0x0F); | ||
784 | data[4] = (uint8_t)(terr_params[tv_system].IFOVLD_DET_LV_U | ||
785 | & 0x07); | ||
786 | } | ||
787 | data[4] |= 0x20; | ||
788 | |||
789 | /* Setting for IF frequency and bandwidth */ | ||
790 | |||
791 | /* IF filter center frequency offset (IF_BPF_F0) (0x6D) */ | ||
792 | data[5] = (uint8_t)((terr_params[tv_system].IF_BPF_F0 << 4) & 0x30); | ||
793 | |||
794 | /* IF filter band width (BW) (0x6D) */ | ||
795 | data[5] |= (uint8_t)(terr_params[tv_system].BW & 0x03); | ||
796 | |||
797 | /* IF frequency offset value (FIF_OFFSET) (0x6E) */ | ||
798 | data[6] = (uint8_t)(terr_params[tv_system].FIF_OFFSET & 0x1F); | ||
799 | |||
800 | /* IF band width offset value (BW_OFFSET) (0x6F) */ | ||
801 | data[7] = (uint8_t)(terr_params[tv_system].BW_OFFSET & 0x1F); | ||
802 | |||
803 | /* RF tuning frequency setting (0x70, 0x71, 0x72) */ | ||
804 | data[8] = (uint8_t)(frequencykHz & 0xFF); /* FRF_L */ | ||
805 | data[9] = (uint8_t)((frequencykHz >> 8) & 0xFF); /* FRF_M */ | ||
806 | data[10] = (uint8_t)((frequencykHz >> 16) | ||
807 | & 0x0F); /* FRF_H (bit[3:0]) */ | ||
808 | |||
809 | /* Tuning command */ | ||
810 | data[11] = 0xFF; | ||
811 | |||
812 | /* Enable IF output, AGC and IFOUT pin selection (0x74) */ | ||
813 | data[12] = 0x01; | ||
814 | |||
815 | if ((tv_system == SONY_HELENE_DTV_DVBC_6) || | ||
816 | (tv_system == SONY_HELENE_DTV_DVBC_8)) { | ||
817 | data[13] = 0xD9; | ||
818 | data[14] = 0x0F; | ||
819 | data[15] = 0x24; | ||
820 | data[16] = 0x87; | ||
821 | } else { | ||
822 | data[13] = 0x99; | ||
823 | data[14] = 0x00; | ||
824 | data[15] = 0x24; | ||
825 | data[16] = 0x87; | ||
826 | } | ||
827 | |||
828 | helene_write_regs(priv, 0x68, data, 17); | ||
829 | |||
830 | dev_dbg(&priv->i2c->dev, "%s(): tune done\n", | ||
831 | __func__); | ||
832 | |||
833 | priv->frequency = frequency; | ||
834 | return 0; | ||
835 | } | ||
836 | |||
837 | static int helene_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
838 | { | ||
839 | struct helene_priv *priv = fe->tuner_priv; | ||
840 | |||
841 | *frequency = priv->frequency * 1000; | ||
842 | return 0; | ||
843 | } | ||
844 | |||
845 | static struct dvb_tuner_ops helene_tuner_ops = { | ||
846 | .info = { | ||
847 | .name = "Sony HELENE Ter tuner", | ||
848 | .frequency_min = 1000000, | ||
849 | .frequency_max = 1200000000, | ||
850 | .frequency_step = 25000, | ||
851 | }, | ||
852 | .init = helene_init, | ||
853 | .release = helene_release, | ||
854 | .sleep = helene_sleep, | ||
855 | .set_params = helene_set_params, | ||
856 | .get_frequency = helene_get_frequency, | ||
857 | }; | ||
858 | |||
859 | static struct dvb_tuner_ops helene_tuner_ops_s = { | ||
860 | .info = { | ||
861 | .name = "Sony HELENE Sat tuner", | ||
862 | .frequency_min = 500000, | ||
863 | .frequency_max = 2500000, | ||
864 | .frequency_step = 1000, | ||
865 | }, | ||
866 | .init = helene_init, | ||
867 | .release = helene_release, | ||
868 | .sleep = helene_sleep, | ||
869 | .set_params = helene_set_params_s, | ||
870 | .get_frequency = helene_get_frequency, | ||
871 | }; | ||
872 | |||
873 | /* power-on tuner | ||
874 | * call once after reset | ||
875 | */ | ||
876 | static int helene_x_pon(struct helene_priv *priv) | ||
877 | { | ||
878 | /* RFIN matching in power save (terrestrial) = ACTIVE */ | ||
879 | /* RFIN matching in power save (satellite) = ACTIVE */ | ||
880 | u8 dataT[] = { 0x06, 0x00, 0x02, 0x00 }; | ||
881 | /* SAT_RF_ACTIVE = true, lnaOff = false, terrRfActive = true */ | ||
882 | u8 dataS[] = { 0x05, 0x06 }; | ||
883 | u8 cdata[] = {0x7A, 0x01}; | ||
884 | u8 data[20]; | ||
885 | u8 rdata[2]; | ||
886 | |||
887 | /* mode select */ | ||
888 | helene_write_reg(priv, 0x01, 0x00); | ||
889 | |||
890 | helene_write_reg(priv, 0x67, dataT[3]); | ||
891 | helene_write_reg(priv, 0x43, dataS[1]); | ||
892 | helene_write_regs(priv, 0x5E, dataT, 3); | ||
893 | helene_write_reg(priv, 0x0C, dataS[0]); | ||
894 | |||
895 | /* Initial setting for internal logic block */ | ||
896 | helene_write_regs(priv, 0x99, cdata, sizeof(cdata)); | ||
897 | |||
898 | /* 0x81 - 0x94 */ | ||
899 | data[0] = 0x18; /* xtal 24 MHz */ | ||
900 | data[1] = (uint8_t)(0x80 | (0x04 & 0x1F)); /* 4 x 25 = 100uA */ | ||
901 | data[2] = (uint8_t)(0x80 | (0x26 & 0x7F)); /* 38 x 0.25 = 9.5pF */ | ||
902 | data[3] = 0x80; /* REFOUT signal output 500mVpp */ | ||
903 | data[4] = 0x00; /* GPIO settings */ | ||
904 | data[5] = 0x00; /* GPIO settings */ | ||
905 | data[6] = 0xC4; /* Clock enable for internal logic block */ | ||
906 | data[7] = 0x40; /* Start CPU boot-up */ | ||
907 | data[8] = 0x10; /* For burst-write */ | ||
908 | |||
909 | /* Setting for internal RFAGC */ | ||
910 | data[9] = 0x00; | ||
911 | data[10] = 0x45; | ||
912 | data[11] = 0x75; | ||
913 | |||
914 | data[12] = 0x07; /* Setting for analog block */ | ||
915 | |||
916 | /* Initial setting for internal analog block */ | ||
917 | data[13] = 0x1C; | ||
918 | data[14] = 0x3F; | ||
919 | data[15] = 0x02; | ||
920 | data[16] = 0x10; | ||
921 | data[17] = 0x20; | ||
922 | data[18] = 0x0A; | ||
923 | data[19] = 0x00; | ||
924 | |||
925 | helene_write_regs(priv, 0x81, data, sizeof(data)); | ||
926 | |||
927 | /* Setting for internal RFAGC */ | ||
928 | helene_write_reg(priv, 0x9B, 0x00); | ||
929 | |||
930 | msleep(20); | ||
931 | |||
932 | /* Check CPU_STT/CPU_ERR */ | ||
933 | helene_read_regs(priv, 0x1A, rdata, sizeof(rdata)); | ||
934 | |||
935 | if (rdata[0] != 0x00) { | ||
936 | dev_err(&priv->i2c->dev, | ||
937 | "HELENE tuner CPU error 0x%x\n", rdata[0]); | ||
938 | return -EIO; | ||
939 | } | ||
940 | |||
941 | /* VCO current setting */ | ||
942 | cdata[0] = 0x90; | ||
943 | cdata[1] = 0x06; | ||
944 | helene_write_regs(priv, 0x17, cdata, sizeof(cdata)); | ||
945 | msleep(20); | ||
946 | helene_read_reg(priv, 0x19, data); | ||
947 | helene_write_reg(priv, 0x95, (uint8_t)((data[0] >> 4) & 0x0F)); | ||
948 | |||
949 | /* Disable IF signal output */ | ||
950 | helene_write_reg(priv, 0x74, 0x02); | ||
951 | |||
952 | /* Standby setting for CPU */ | ||
953 | helene_write_reg(priv, 0x88, 0x00); | ||
954 | |||
955 | /* Standby setting for internal logic block */ | ||
956 | helene_write_reg(priv, 0x87, 0xC0); | ||
957 | |||
958 | /* Load capacitance control setting for crystal oscillator */ | ||
959 | helene_write_reg(priv, 0x80, 0x01); | ||
960 | |||
961 | /* Satellite initial setting */ | ||
962 | cdata[0] = 0x07; | ||
963 | cdata[1] = 0x00; | ||
964 | helene_write_regs(priv, 0x41, cdata, sizeof(cdata)); | ||
965 | |||
966 | dev_info(&priv->i2c->dev, | ||
967 | "HELENE tuner x_pon done\n"); | ||
968 | |||
969 | return 0; | ||
970 | } | ||
971 | |||
972 | struct dvb_frontend *helene_attach_s(struct dvb_frontend *fe, | ||
973 | const struct helene_config *config, | ||
974 | struct i2c_adapter *i2c) | ||
975 | { | ||
976 | struct helene_priv *priv = NULL; | ||
977 | |||
978 | priv = kzalloc(sizeof(struct helene_priv), GFP_KERNEL); | ||
979 | if (priv == NULL) | ||
980 | return NULL; | ||
981 | priv->i2c_address = (config->i2c_address >> 1); | ||
982 | priv->i2c = i2c; | ||
983 | priv->set_tuner_data = config->set_tuner_priv; | ||
984 | priv->set_tuner = config->set_tuner_callback; | ||
985 | priv->xtal = config->xtal; | ||
986 | |||
987 | if (fe->ops.i2c_gate_ctrl) | ||
988 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
989 | |||
990 | if (helene_x_pon(priv) != 0) | ||
991 | return NULL; | ||
992 | |||
993 | if (fe->ops.i2c_gate_ctrl) | ||
994 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
995 | |||
996 | memcpy(&fe->ops.tuner_ops, &helene_tuner_ops_s, | ||
997 | sizeof(struct dvb_tuner_ops)); | ||
998 | fe->tuner_priv = priv; | ||
999 | dev_info(&priv->i2c->dev, | ||
1000 | "Sony HELENE Sat attached on addr=%x at I2C adapter %p\n", | ||
1001 | priv->i2c_address, priv->i2c); | ||
1002 | return fe; | ||
1003 | } | ||
1004 | EXPORT_SYMBOL(helene_attach_s); | ||
1005 | |||
1006 | struct dvb_frontend *helene_attach(struct dvb_frontend *fe, | ||
1007 | const struct helene_config *config, | ||
1008 | struct i2c_adapter *i2c) | ||
1009 | { | ||
1010 | struct helene_priv *priv = NULL; | ||
1011 | |||
1012 | priv = kzalloc(sizeof(struct helene_priv), GFP_KERNEL); | ||
1013 | if (priv == NULL) | ||
1014 | return NULL; | ||
1015 | priv->i2c_address = (config->i2c_address >> 1); | ||
1016 | priv->i2c = i2c; | ||
1017 | priv->set_tuner_data = config->set_tuner_priv; | ||
1018 | priv->set_tuner = config->set_tuner_callback; | ||
1019 | priv->xtal = config->xtal; | ||
1020 | |||
1021 | if (fe->ops.i2c_gate_ctrl) | ||
1022 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
1023 | |||
1024 | if (helene_x_pon(priv) != 0) | ||
1025 | return NULL; | ||
1026 | |||
1027 | if (fe->ops.i2c_gate_ctrl) | ||
1028 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
1029 | |||
1030 | memcpy(&fe->ops.tuner_ops, &helene_tuner_ops, | ||
1031 | sizeof(struct dvb_tuner_ops)); | ||
1032 | fe->tuner_priv = priv; | ||
1033 | dev_info(&priv->i2c->dev, | ||
1034 | "Sony HELENE Ter attached on addr=%x at I2C adapter %p\n", | ||
1035 | priv->i2c_address, priv->i2c); | ||
1036 | return fe; | ||
1037 | } | ||
1038 | EXPORT_SYMBOL(helene_attach); | ||
1039 | |||
1040 | MODULE_DESCRIPTION("Sony HELENE Sat/Ter tuner driver"); | ||
1041 | MODULE_AUTHOR("Abylay Ospan <aospan@netup.ru>"); | ||
1042 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/dvb-frontends/helene.h b/drivers/media/dvb-frontends/helene.h new file mode 100644 index 000000000000..e1b9224cfc55 --- /dev/null +++ b/drivers/media/dvb-frontends/helene.h | |||
@@ -0,0 +1,79 @@ | |||
1 | /* | ||
2 | * helene.h | ||
3 | * | ||
4 | * Sony HELENE DVB-S/S2/T/T2/C/C2/ISDB-T/S tuner driver (CXD2858ER) | ||
5 | * | ||
6 | * Copyright 2012 Sony Corporation | ||
7 | * Copyright (C) 2014 NetUP Inc. | ||
8 | * Copyright (C) 2014 Abylay Ospan <aospan@netup.ru> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | */ | ||
20 | |||
21 | #ifndef __DVB_HELENE_H__ | ||
22 | #define __DVB_HELENE_H__ | ||
23 | |||
24 | #include <linux/kconfig.h> | ||
25 | #include <linux/dvb/frontend.h> | ||
26 | #include <linux/i2c.h> | ||
27 | |||
28 | enum helene_xtal { | ||
29 | SONY_HELENE_XTAL_16000, /* 16 MHz */ | ||
30 | SONY_HELENE_XTAL_20500, /* 20.5 MHz */ | ||
31 | SONY_HELENE_XTAL_24000, /* 24 MHz */ | ||
32 | SONY_HELENE_XTAL_41000 /* 41 MHz */ | ||
33 | }; | ||
34 | |||
35 | /** | ||
36 | * struct helene_config - the configuration of 'Helene' tuner driver | ||
37 | * @i2c_address: I2C address of the tuner | ||
38 | * @xtal_freq_mhz: Oscillator frequency, MHz | ||
39 | * @set_tuner_priv: Callback function private context | ||
40 | * @set_tuner_callback: Callback function that notifies the parent driver | ||
41 | * which tuner is active now | ||
42 | */ | ||
43 | struct helene_config { | ||
44 | u8 i2c_address; | ||
45 | u8 xtal_freq_mhz; | ||
46 | void *set_tuner_priv; | ||
47 | int (*set_tuner_callback)(void *, int); | ||
48 | enum helene_xtal xtal; | ||
49 | }; | ||
50 | |||
51 | #if IS_REACHABLE(CONFIG_DVB_HELENE) | ||
52 | extern struct dvb_frontend *helene_attach(struct dvb_frontend *fe, | ||
53 | const struct helene_config *config, | ||
54 | struct i2c_adapter *i2c); | ||
55 | #else | ||
56 | static inline struct dvb_frontend *helene_attach(struct dvb_frontend *fe, | ||
57 | const struct helene_config *config, | ||
58 | struct i2c_adapter *i2c) | ||
59 | { | ||
60 | pr_warn("%s: driver disabled by Kconfig\n", __func__); | ||
61 | return NULL; | ||
62 | } | ||
63 | #endif | ||
64 | |||
65 | #if IS_REACHABLE(CONFIG_DVB_HELENE) | ||
66 | extern struct dvb_frontend *helene_attach_s(struct dvb_frontend *fe, | ||
67 | const struct helene_config *config, | ||
68 | struct i2c_adapter *i2c); | ||
69 | #else | ||
70 | static inline struct dvb_frontend *helene_attach_s(struct dvb_frontend *fe, | ||
71 | const struct helene_config *config, | ||
72 | struct i2c_adapter *i2c) | ||
73 | { | ||
74 | pr_warn("%s: driver disabled by Kconfig\n", __func__); | ||
75 | return NULL; | ||
76 | } | ||
77 | #endif | ||
78 | |||
79 | #endif | ||
diff --git a/drivers/media/dvb-frontends/horus3a.c b/drivers/media/dvb-frontends/horus3a.c index 000606af70f7..a98bca5270d9 100644 --- a/drivers/media/dvb-frontends/horus3a.c +++ b/drivers/media/dvb-frontends/horus3a.c | |||
@@ -66,7 +66,7 @@ static int horus3a_write_regs(struct horus3a_priv *priv, | |||
66 | } | 66 | } |
67 | }; | 67 | }; |
68 | 68 | ||
69 | if (len + 1 >= sizeof(buf)) { | 69 | if (len + 1 > sizeof(buf)) { |
70 | dev_warn(&priv->i2c->dev,"wr reg=%04x: len=%d is too big!\n", | 70 | dev_warn(&priv->i2c->dev,"wr reg=%04x: len=%d is too big!\n", |
71 | reg, len + 1); | 71 | reg, len + 1); |
72 | return -E2BIG; | 72 | return -E2BIG; |
@@ -272,24 +272,6 @@ static int horus3a_set_params(struct dvb_frontend *fe) | |||
272 | if (fc_lpf > 36) | 272 | if (fc_lpf > 36) |
273 | fc_lpf = 36; | 273 | fc_lpf = 36; |
274 | } else if (p->delivery_system == SYS_DVBS2) { | 274 | } else if (p->delivery_system == SYS_DVBS2) { |
275 | int rolloff; | ||
276 | |||
277 | switch (p->rolloff) { | ||
278 | case ROLLOFF_35: | ||
279 | rolloff = 35; | ||
280 | break; | ||
281 | case ROLLOFF_25: | ||
282 | rolloff = 25; | ||
283 | break; | ||
284 | case ROLLOFF_20: | ||
285 | rolloff = 20; | ||
286 | break; | ||
287 | case ROLLOFF_AUTO: | ||
288 | default: | ||
289 | dev_err(&priv->i2c->dev, | ||
290 | "horus3a: auto roll-off is not supported\n"); | ||
291 | return -EINVAL; | ||
292 | } | ||
293 | /* | 275 | /* |
294 | * SR <= 4.5: | 276 | * SR <= 4.5: |
295 | * fc_lpf = 5 | 277 | * fc_lpf = 5 |
@@ -302,11 +284,9 @@ static int horus3a_set_params(struct dvb_frontend *fe) | |||
302 | if (symbol_rate <= 4500) | 284 | if (symbol_rate <= 4500) |
303 | fc_lpf = 5; | 285 | fc_lpf = 5; |
304 | else if (symbol_rate <= 10000) | 286 | else if (symbol_rate <= 10000) |
305 | fc_lpf = (u8)DIV_ROUND_UP( | 287 | fc_lpf = (u8)((symbol_rate * 11 + (10000-1)) / 10000); |
306 | symbol_rate * (200 + rolloff), 200000); | ||
307 | else | 288 | else |
308 | fc_lpf = (u8)DIV_ROUND_UP( | 289 | fc_lpf = (u8)((symbol_rate * 3 + (5000-1)) / 5000 + 5); |
309 | symbol_rate * (100 + rolloff), 200000) + 5; | ||
310 | /* 5 <= fc_lpf <= 36 is valid */ | 290 | /* 5 <= fc_lpf <= 36 is valid */ |
311 | if (fc_lpf > 36) | 291 | if (fc_lpf > 36) |
312 | fc_lpf = 36; | 292 | fc_lpf = 36; |
diff --git a/drivers/media/dvb-frontends/m88rs2000.c b/drivers/media/dvb-frontends/m88rs2000.c index a09b12313a73..ef79a4ec31e2 100644 --- a/drivers/media/dvb-frontends/m88rs2000.c +++ b/drivers/media/dvb-frontends/m88rs2000.c | |||
@@ -609,7 +609,7 @@ static int m88rs2000_set_frontend(struct dvb_frontend *fe) | |||
609 | { | 609 | { |
610 | struct m88rs2000_state *state = fe->demodulator_priv; | 610 | struct m88rs2000_state *state = fe->demodulator_priv; |
611 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | 611 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
612 | enum fe_status status; | 612 | enum fe_status status = 0; |
613 | int i, ret = 0; | 613 | int i, ret = 0; |
614 | u32 tuner_freq; | 614 | u32 tuner_freq; |
615 | s16 offset = 0; | 615 | s16 offset = 0; |
diff --git a/drivers/staging/media/mn88472/mn88472.c b/drivers/media/dvb-frontends/mn88472.c index 7ea749cf19f9..18fb2df1e2bd 100644 --- a/drivers/staging/media/mn88472/mn88472.c +++ b/drivers/media/dvb-frontends/mn88472.c | |||
@@ -17,28 +17,90 @@ | |||
17 | #include "mn88472_priv.h" | 17 | #include "mn88472_priv.h" |
18 | 18 | ||
19 | static int mn88472_get_tune_settings(struct dvb_frontend *fe, | 19 | static int mn88472_get_tune_settings(struct dvb_frontend *fe, |
20 | struct dvb_frontend_tune_settings *s) | 20 | struct dvb_frontend_tune_settings *s) |
21 | { | 21 | { |
22 | s->min_delay_ms = 800; | 22 | s->min_delay_ms = 1000; |
23 | return 0; | 23 | return 0; |
24 | } | 24 | } |
25 | 25 | ||
26 | static int mn88472_read_status(struct dvb_frontend *fe, enum fe_status *status) | ||
27 | { | ||
28 | struct i2c_client *client = fe->demodulator_priv; | ||
29 | struct mn88472_dev *dev = i2c_get_clientdata(client); | ||
30 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
31 | int ret; | ||
32 | unsigned int utmp; | ||
33 | |||
34 | if (!dev->active) { | ||
35 | ret = -EAGAIN; | ||
36 | goto err; | ||
37 | } | ||
38 | |||
39 | switch (c->delivery_system) { | ||
40 | case SYS_DVBT: | ||
41 | ret = regmap_read(dev->regmap[0], 0x7f, &utmp); | ||
42 | if (ret) | ||
43 | goto err; | ||
44 | if ((utmp & 0x0f) >= 0x09) | ||
45 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | | ||
46 | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; | ||
47 | else | ||
48 | *status = 0; | ||
49 | break; | ||
50 | case SYS_DVBT2: | ||
51 | ret = regmap_read(dev->regmap[2], 0x92, &utmp); | ||
52 | if (ret) | ||
53 | goto err; | ||
54 | if ((utmp & 0x0f) >= 0x0d) | ||
55 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | | ||
56 | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; | ||
57 | else if ((utmp & 0x0f) >= 0x0a) | ||
58 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | | ||
59 | FE_HAS_VITERBI; | ||
60 | else if ((utmp & 0x0f) >= 0x07) | ||
61 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; | ||
62 | else | ||
63 | *status = 0; | ||
64 | break; | ||
65 | case SYS_DVBC_ANNEX_A: | ||
66 | ret = regmap_read(dev->regmap[1], 0x84, &utmp); | ||
67 | if (ret) | ||
68 | goto err; | ||
69 | if ((utmp & 0x0f) >= 0x08) | ||
70 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | | ||
71 | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; | ||
72 | else | ||
73 | *status = 0; | ||
74 | break; | ||
75 | default: | ||
76 | ret = -EINVAL; | ||
77 | goto err; | ||
78 | } | ||
79 | |||
80 | return 0; | ||
81 | err: | ||
82 | dev_dbg(&client->dev, "failed=%d\n", ret); | ||
83 | return ret; | ||
84 | } | ||
85 | |||
26 | static int mn88472_set_frontend(struct dvb_frontend *fe) | 86 | static int mn88472_set_frontend(struct dvb_frontend *fe) |
27 | { | 87 | { |
28 | struct i2c_client *client = fe->demodulator_priv; | 88 | struct i2c_client *client = fe->demodulator_priv; |
29 | struct mn88472_dev *dev = i2c_get_clientdata(client); | 89 | struct mn88472_dev *dev = i2c_get_clientdata(client); |
30 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | 90 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
31 | int ret, i; | 91 | int ret, i; |
32 | u32 if_frequency = 0; | 92 | unsigned int utmp; |
33 | u64 tmp; | 93 | u32 if_frequency; |
34 | u8 delivery_system_val, if_val[3], bw_val[7], bw_val2; | 94 | u8 buf[3], delivery_system_val, bandwidth_val, *bandwidth_vals_ptr; |
95 | u8 reg_bank0_b4_val, reg_bank0_cd_val, reg_bank0_d4_val; | ||
96 | u8 reg_bank0_d6_val; | ||
35 | 97 | ||
36 | dev_dbg(&client->dev, | 98 | dev_dbg(&client->dev, |
37 | "delivery_system=%d modulation=%d frequency=%d symbol_rate=%d inversion=%d\n", | 99 | "delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%d stream_id=%d\n", |
38 | c->delivery_system, c->modulation, | 100 | c->delivery_system, c->modulation, c->frequency, |
39 | c->frequency, c->symbol_rate, c->inversion); | 101 | c->bandwidth_hz, c->symbol_rate, c->inversion, c->stream_id); |
40 | 102 | ||
41 | if (!dev->warm) { | 103 | if (!dev->active) { |
42 | ret = -EAGAIN; | 104 | ret = -EAGAIN; |
43 | goto err; | 105 | goto err; |
44 | } | 106 | } |
@@ -46,39 +108,64 @@ static int mn88472_set_frontend(struct dvb_frontend *fe) | |||
46 | switch (c->delivery_system) { | 108 | switch (c->delivery_system) { |
47 | case SYS_DVBT: | 109 | case SYS_DVBT: |
48 | delivery_system_val = 0x02; | 110 | delivery_system_val = 0x02; |
111 | reg_bank0_b4_val = 0x00; | ||
112 | reg_bank0_cd_val = 0x1f; | ||
113 | reg_bank0_d4_val = 0x0a; | ||
114 | reg_bank0_d6_val = 0x48; | ||
49 | break; | 115 | break; |
50 | case SYS_DVBT2: | 116 | case SYS_DVBT2: |
51 | delivery_system_val = 0x03; | 117 | delivery_system_val = 0x03; |
118 | reg_bank0_b4_val = 0xf6; | ||
119 | reg_bank0_cd_val = 0x01; | ||
120 | reg_bank0_d4_val = 0x09; | ||
121 | reg_bank0_d6_val = 0x46; | ||
52 | break; | 122 | break; |
53 | case SYS_DVBC_ANNEX_A: | 123 | case SYS_DVBC_ANNEX_A: |
54 | delivery_system_val = 0x04; | 124 | delivery_system_val = 0x04; |
125 | reg_bank0_b4_val = 0x00; | ||
126 | reg_bank0_cd_val = 0x17; | ||
127 | reg_bank0_d4_val = 0x09; | ||
128 | reg_bank0_d6_val = 0x48; | ||
55 | break; | 129 | break; |
56 | default: | 130 | default: |
57 | ret = -EINVAL; | 131 | ret = -EINVAL; |
58 | goto err; | 132 | goto err; |
59 | } | 133 | } |
60 | 134 | ||
61 | if (c->bandwidth_hz <= 5000000) { | 135 | switch (c->delivery_system) { |
62 | memcpy(bw_val, "\xe5\x99\x9a\x1b\xa9\x1b\xa9", 7); | 136 | case SYS_DVBT: |
63 | bw_val2 = 0x03; | 137 | case SYS_DVBT2: |
64 | } else if (c->bandwidth_hz <= 6000000) { | 138 | switch (c->bandwidth_hz) { |
65 | /* IF 3570000 Hz, BW 6000000 Hz */ | 139 | case 5000000: |
66 | memcpy(bw_val, "\xbf\x55\x55\x15\x6b\x15\x6b", 7); | 140 | bandwidth_vals_ptr = "\xe5\x99\x9a\x1b\xa9\x1b\xa9"; |
67 | bw_val2 = 0x02; | 141 | bandwidth_val = 0x03; |
68 | } else if (c->bandwidth_hz <= 7000000) { | 142 | break; |
69 | /* IF 4570000 Hz, BW 7000000 Hz */ | 143 | case 6000000: |
70 | memcpy(bw_val, "\xa4\x00\x00\x0f\x2c\x0f\x2c", 7); | 144 | bandwidth_vals_ptr = "\xbf\x55\x55\x15\x6b\x15\x6b"; |
71 | bw_val2 = 0x01; | 145 | bandwidth_val = 0x02; |
72 | } else if (c->bandwidth_hz <= 8000000) { | 146 | break; |
73 | /* IF 4570000 Hz, BW 8000000 Hz */ | 147 | case 7000000: |
74 | memcpy(bw_val, "\x8f\x80\x00\x08\xee\x08\xee", 7); | 148 | bandwidth_vals_ptr = "\xa4\x00\x00\x0f\x2c\x0f\x2c"; |
75 | bw_val2 = 0x00; | 149 | bandwidth_val = 0x01; |
76 | } else { | 150 | break; |
77 | ret = -EINVAL; | 151 | case 8000000: |
78 | goto err; | 152 | bandwidth_vals_ptr = "\x8f\x80\x00\x08\xee\x08\xee"; |
153 | bandwidth_val = 0x00; | ||
154 | break; | ||
155 | default: | ||
156 | ret = -EINVAL; | ||
157 | goto err; | ||
158 | } | ||
159 | break; | ||
160 | case SYS_DVBC_ANNEX_A: | ||
161 | bandwidth_vals_ptr = NULL; | ||
162 | bandwidth_val = 0x00; | ||
163 | break; | ||
164 | default: | ||
165 | break; | ||
79 | } | 166 | } |
80 | 167 | ||
81 | /* program tuner */ | 168 | /* Program tuner */ |
82 | if (fe->ops.tuner_ops.set_params) { | 169 | if (fe->ops.tuner_ops.set_params) { |
83 | ret = fe->ops.tuner_ops.set_params(fe); | 170 | ret = fe->ops.tuner_ops.set_params(fe); |
84 | if (ret) | 171 | if (ret) |
@@ -91,20 +178,10 @@ static int mn88472_set_frontend(struct dvb_frontend *fe) | |||
91 | goto err; | 178 | goto err; |
92 | 179 | ||
93 | dev_dbg(&client->dev, "get_if_frequency=%d\n", if_frequency); | 180 | dev_dbg(&client->dev, "get_if_frequency=%d\n", if_frequency); |
94 | } | 181 | } else { |
95 | 182 | ret = -EINVAL; | |
96 | /* Calculate IF registers ( (1<<24)*IF / Xtal ) */ | ||
97 | tmp = div_u64(if_frequency * (u64)(1<<24) + (dev->xtal / 2), | ||
98 | dev->xtal); | ||
99 | if_val[0] = (tmp >> 16) & 0xff; | ||
100 | if_val[1] = (tmp >> 8) & 0xff; | ||
101 | if_val[2] = (tmp >> 0) & 0xff; | ||
102 | |||
103 | ret = regmap_write(dev->regmap[2], 0xfb, 0x13); | ||
104 | ret = regmap_write(dev->regmap[2], 0xef, 0x13); | ||
105 | ret = regmap_write(dev->regmap[2], 0xf9, 0x13); | ||
106 | if (ret) | ||
107 | goto err; | 183 | goto err; |
184 | } | ||
108 | 185 | ||
109 | ret = regmap_write(dev->regmap[2], 0x00, 0x66); | 186 | ret = regmap_write(dev->regmap[2], 0x00, 0x66); |
110 | if (ret) | 187 | if (ret) |
@@ -118,157 +195,81 @@ static int mn88472_set_frontend(struct dvb_frontend *fe) | |||
118 | ret = regmap_write(dev->regmap[2], 0x03, delivery_system_val); | 195 | ret = regmap_write(dev->regmap[2], 0x03, delivery_system_val); |
119 | if (ret) | 196 | if (ret) |
120 | goto err; | 197 | goto err; |
121 | ret = regmap_write(dev->regmap[2], 0x04, bw_val2); | 198 | ret = regmap_write(dev->regmap[2], 0x04, bandwidth_val); |
122 | if (ret) | 199 | if (ret) |
123 | goto err; | 200 | goto err; |
124 | 201 | ||
125 | for (i = 0; i < sizeof(if_val); i++) { | 202 | /* IF */ |
126 | ret = regmap_write(dev->regmap[2], 0x10 + i, if_val[i]); | 203 | utmp = DIV_ROUND_CLOSEST_ULL((u64)if_frequency * 0x1000000, dev->clk); |
204 | buf[0] = (utmp >> 16) & 0xff; | ||
205 | buf[1] = (utmp >> 8) & 0xff; | ||
206 | buf[2] = (utmp >> 0) & 0xff; | ||
207 | for (i = 0; i < 3; i++) { | ||
208 | ret = regmap_write(dev->regmap[2], 0x10 + i, buf[i]); | ||
127 | if (ret) | 209 | if (ret) |
128 | goto err; | 210 | goto err; |
129 | } | 211 | } |
130 | 212 | ||
131 | for (i = 0; i < sizeof(bw_val); i++) { | 213 | /* Bandwidth */ |
132 | ret = regmap_write(dev->regmap[2], 0x13 + i, bw_val[i]); | 214 | if (bandwidth_vals_ptr) { |
133 | if (ret) | 215 | for (i = 0; i < 7; i++) { |
134 | goto err; | 216 | ret = regmap_write(dev->regmap[2], 0x13 + i, |
217 | bandwidth_vals_ptr[i]); | ||
218 | if (ret) | ||
219 | goto err; | ||
220 | } | ||
135 | } | 221 | } |
136 | 222 | ||
223 | ret = regmap_write(dev->regmap[0], 0xb4, reg_bank0_b4_val); | ||
224 | if (ret) | ||
225 | goto err; | ||
226 | ret = regmap_write(dev->regmap[0], 0xcd, reg_bank0_cd_val); | ||
227 | if (ret) | ||
228 | goto err; | ||
229 | ret = regmap_write(dev->regmap[0], 0xd4, reg_bank0_d4_val); | ||
230 | if (ret) | ||
231 | goto err; | ||
232 | ret = regmap_write(dev->regmap[0], 0xd6, reg_bank0_d6_val); | ||
233 | if (ret) | ||
234 | goto err; | ||
235 | |||
137 | switch (c->delivery_system) { | 236 | switch (c->delivery_system) { |
138 | case SYS_DVBT: | 237 | case SYS_DVBT: |
139 | ret = regmap_write(dev->regmap[0], 0x07, 0x26); | 238 | ret = regmap_write(dev->regmap[0], 0x07, 0x26); |
140 | ret = regmap_write(dev->regmap[0], 0xb0, 0x0a); | 239 | if (ret) |
141 | ret = regmap_write(dev->regmap[0], 0xb4, 0x00); | 240 | goto err; |
142 | ret = regmap_write(dev->regmap[0], 0xcd, 0x1f); | ||
143 | ret = regmap_write(dev->regmap[0], 0xd4, 0x0a); | ||
144 | ret = regmap_write(dev->regmap[0], 0xd6, 0x48); | ||
145 | ret = regmap_write(dev->regmap[0], 0x00, 0xba); | 241 | ret = regmap_write(dev->regmap[0], 0x00, 0xba); |
242 | if (ret) | ||
243 | goto err; | ||
146 | ret = regmap_write(dev->regmap[0], 0x01, 0x13); | 244 | ret = regmap_write(dev->regmap[0], 0x01, 0x13); |
147 | if (ret) | 245 | if (ret) |
148 | goto err; | 246 | goto err; |
149 | break; | 247 | break; |
150 | case SYS_DVBT2: | 248 | case SYS_DVBT2: |
151 | ret = regmap_write(dev->regmap[2], 0x2b, 0x13); | 249 | ret = regmap_write(dev->regmap[2], 0x2b, 0x13); |
250 | if (ret) | ||
251 | goto err; | ||
152 | ret = regmap_write(dev->regmap[2], 0x4f, 0x05); | 252 | ret = regmap_write(dev->regmap[2], 0x4f, 0x05); |
253 | if (ret) | ||
254 | goto err; | ||
153 | ret = regmap_write(dev->regmap[1], 0xf6, 0x05); | 255 | ret = regmap_write(dev->regmap[1], 0xf6, 0x05); |
154 | ret = regmap_write(dev->regmap[0], 0xb0, 0x0a); | ||
155 | ret = regmap_write(dev->regmap[0], 0xb4, 0xf6); | ||
156 | ret = regmap_write(dev->regmap[0], 0xcd, 0x01); | ||
157 | ret = regmap_write(dev->regmap[0], 0xd4, 0x09); | ||
158 | ret = regmap_write(dev->regmap[0], 0xd6, 0x46); | ||
159 | ret = regmap_write(dev->regmap[2], 0x30, 0x80); | ||
160 | ret = regmap_write(dev->regmap[2], 0x32, 0x00); | ||
161 | if (ret) | 256 | if (ret) |
162 | goto err; | 257 | goto err; |
163 | break; | 258 | ret = regmap_write(dev->regmap[2], 0x32, c->stream_id); |
164 | case SYS_DVBC_ANNEX_A: | ||
165 | ret = regmap_write(dev->regmap[0], 0xb0, 0x0b); | ||
166 | ret = regmap_write(dev->regmap[0], 0xb4, 0x00); | ||
167 | ret = regmap_write(dev->regmap[0], 0xcd, 0x17); | ||
168 | ret = regmap_write(dev->regmap[0], 0xd4, 0x09); | ||
169 | ret = regmap_write(dev->regmap[0], 0xd6, 0x48); | ||
170 | ret = regmap_write(dev->regmap[1], 0x00, 0xb0); | ||
171 | if (ret) | 259 | if (ret) |
172 | goto err; | 260 | goto err; |
173 | break; | 261 | break; |
174 | default: | 262 | case SYS_DVBC_ANNEX_A: |
175 | ret = -EINVAL; | ||
176 | goto err; | ||
177 | } | ||
178 | |||
179 | ret = regmap_write(dev->regmap[0], 0x46, 0x00); | ||
180 | ret = regmap_write(dev->regmap[0], 0xae, 0x00); | ||
181 | |||
182 | switch (dev->ts_mode) { | ||
183 | case SERIAL_TS_MODE: | ||
184 | ret = regmap_write(dev->regmap[2], 0x08, 0x1d); | ||
185 | break; | ||
186 | case PARALLEL_TS_MODE: | ||
187 | ret = regmap_write(dev->regmap[2], 0x08, 0x00); | ||
188 | break; | 263 | break; |
189 | default: | 264 | default: |
190 | dev_dbg(&client->dev, "ts_mode error: %d\n", dev->ts_mode); | ||
191 | ret = -EINVAL; | ||
192 | goto err; | ||
193 | } | ||
194 | |||
195 | switch (dev->ts_clock) { | ||
196 | case VARIABLE_TS_CLOCK: | ||
197 | ret = regmap_write(dev->regmap[0], 0xd9, 0xe3); | ||
198 | break; | 265 | break; |
199 | case FIXED_TS_CLOCK: | ||
200 | ret = regmap_write(dev->regmap[0], 0xd9, 0xe1); | ||
201 | break; | ||
202 | default: | ||
203 | dev_dbg(&client->dev, "ts_clock error: %d\n", dev->ts_clock); | ||
204 | ret = -EINVAL; | ||
205 | goto err; | ||
206 | } | 266 | } |
207 | 267 | ||
208 | /* Reset demod */ | 268 | /* Reset FSM */ |
209 | ret = regmap_write(dev->regmap[2], 0xf8, 0x9f); | 269 | ret = regmap_write(dev->regmap[2], 0xf8, 0x9f); |
210 | if (ret) | 270 | if (ret) |
211 | goto err; | 271 | goto err; |
212 | 272 | ||
213 | dev->delivery_system = c->delivery_system; | ||
214 | |||
215 | return 0; | ||
216 | err: | ||
217 | dev_dbg(&client->dev, "failed=%d\n", ret); | ||
218 | return ret; | ||
219 | } | ||
220 | |||
221 | static int mn88472_read_status(struct dvb_frontend *fe, enum fe_status *status) | ||
222 | { | ||
223 | struct i2c_client *client = fe->demodulator_priv; | ||
224 | struct mn88472_dev *dev = i2c_get_clientdata(client); | ||
225 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
226 | int ret; | ||
227 | unsigned int utmp; | ||
228 | int lock = 0; | ||
229 | |||
230 | *status = 0; | ||
231 | |||
232 | if (!dev->warm) { | ||
233 | ret = -EAGAIN; | ||
234 | goto err; | ||
235 | } | ||
236 | |||
237 | switch (c->delivery_system) { | ||
238 | case SYS_DVBT: | ||
239 | ret = regmap_read(dev->regmap[0], 0x7F, &utmp); | ||
240 | if (ret) | ||
241 | goto err; | ||
242 | if ((utmp & 0xF) >= 0x09) | ||
243 | lock = 1; | ||
244 | break; | ||
245 | case SYS_DVBT2: | ||
246 | ret = regmap_read(dev->regmap[2], 0x92, &utmp); | ||
247 | if (ret) | ||
248 | goto err; | ||
249 | if ((utmp & 0xF) >= 0x07) | ||
250 | *status |= FE_HAS_SIGNAL; | ||
251 | if ((utmp & 0xF) >= 0x0a) | ||
252 | *status |= FE_HAS_CARRIER; | ||
253 | if ((utmp & 0xF) >= 0x0d) | ||
254 | *status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; | ||
255 | break; | ||
256 | case SYS_DVBC_ANNEX_A: | ||
257 | ret = regmap_read(dev->regmap[1], 0x84, &utmp); | ||
258 | if (ret) | ||
259 | goto err; | ||
260 | if ((utmp & 0xF) >= 0x08) | ||
261 | lock = 1; | ||
262 | break; | ||
263 | default: | ||
264 | ret = -EINVAL; | ||
265 | goto err; | ||
266 | } | ||
267 | |||
268 | if (lock) | ||
269 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | | ||
270 | FE_HAS_SYNC | FE_HAS_LOCK; | ||
271 | |||
272 | return 0; | 273 | return 0; |
273 | err: | 274 | err: |
274 | dev_dbg(&client->dev, "failed=%d\n", ret); | 275 | dev_dbg(&client->dev, "failed=%d\n", ret); |
@@ -279,93 +280,107 @@ static int mn88472_init(struct dvb_frontend *fe) | |||
279 | { | 280 | { |
280 | struct i2c_client *client = fe->demodulator_priv; | 281 | struct i2c_client *client = fe->demodulator_priv; |
281 | struct mn88472_dev *dev = i2c_get_clientdata(client); | 282 | struct mn88472_dev *dev = i2c_get_clientdata(client); |
282 | int ret, len, remaining; | 283 | int ret, len, rem; |
283 | const struct firmware *fw = NULL; | 284 | unsigned int utmp; |
284 | u8 *fw_file = MN88472_FIRMWARE; | 285 | const struct firmware *firmware; |
285 | unsigned int tmp; | 286 | const char *name = MN88472_FIRMWARE; |
286 | 287 | ||
287 | dev_dbg(&client->dev, "\n"); | 288 | dev_dbg(&client->dev, "\n"); |
288 | 289 | ||
289 | /* set cold state by default */ | 290 | /* Power up */ |
290 | dev->warm = false; | ||
291 | |||
292 | /* power on */ | ||
293 | ret = regmap_write(dev->regmap[2], 0x05, 0x00); | 291 | ret = regmap_write(dev->regmap[2], 0x05, 0x00); |
294 | if (ret) | 292 | if (ret) |
295 | goto err; | 293 | goto err; |
296 | 294 | ret = regmap_write(dev->regmap[2], 0x0b, 0x00); | |
297 | ret = regmap_bulk_write(dev->regmap[2], 0x0b, "\x00\x00", 2); | ||
298 | if (ret) | 295 | if (ret) |
299 | goto err; | 296 | goto err; |
300 | 297 | ret = regmap_write(dev->regmap[2], 0x0c, 0x00); | |
301 | /* check if firmware is already running */ | ||
302 | ret = regmap_read(dev->regmap[0], 0xf5, &tmp); | ||
303 | if (ret) | 298 | if (ret) |
304 | goto err; | 299 | goto err; |
305 | 300 | ||
306 | if (!(tmp & 0x1)) { | 301 | /* Check if firmware is already running */ |
307 | dev_info(&client->dev, "firmware already running\n"); | 302 | ret = regmap_read(dev->regmap[0], 0xf5, &utmp); |
308 | dev->warm = true; | 303 | if (ret) |
309 | return 0; | 304 | goto err; |
310 | } | 305 | if (!(utmp & 0x01)) |
306 | goto warm; | ||
311 | 307 | ||
312 | /* request the firmware, this will block and timeout */ | 308 | ret = request_firmware(&firmware, name, &client->dev); |
313 | ret = request_firmware(&fw, fw_file, &client->dev); | ||
314 | if (ret) { | 309 | if (ret) { |
315 | dev_err(&client->dev, "firmare file '%s' not found\n", | 310 | dev_err(&client->dev, "firmware file '%s' not found\n", name); |
316 | fw_file); | ||
317 | goto err; | 311 | goto err; |
318 | } | 312 | } |
319 | 313 | ||
320 | dev_info(&client->dev, "downloading firmware from file '%s'\n", | 314 | dev_info(&client->dev, "downloading firmware from file '%s'\n", name); |
321 | fw_file); | ||
322 | 315 | ||
323 | ret = regmap_write(dev->regmap[0], 0xf5, 0x03); | 316 | ret = regmap_write(dev->regmap[0], 0xf5, 0x03); |
324 | if (ret) | 317 | if (ret) |
325 | goto firmware_release; | 318 | goto err_release_firmware; |
326 | |||
327 | for (remaining = fw->size; remaining > 0; | ||
328 | remaining -= (dev->i2c_wr_max - 1)) { | ||
329 | len = remaining; | ||
330 | if (len > (dev->i2c_wr_max - 1)) | ||
331 | len = dev->i2c_wr_max - 1; | ||
332 | 319 | ||
320 | for (rem = firmware->size; rem > 0; rem -= (dev->i2c_write_max - 1)) { | ||
321 | len = min(dev->i2c_write_max - 1, rem); | ||
333 | ret = regmap_bulk_write(dev->regmap[0], 0xf6, | 322 | ret = regmap_bulk_write(dev->regmap[0], 0xf6, |
334 | &fw->data[fw->size - remaining], len); | 323 | &firmware->data[firmware->size - rem], |
324 | len); | ||
335 | if (ret) { | 325 | if (ret) { |
336 | dev_err(&client->dev, | 326 | dev_err(&client->dev, "firmware download failed %d\n", |
337 | "firmware download failed=%d\n", ret); | 327 | ret); |
338 | goto firmware_release; | 328 | goto err_release_firmware; |
339 | } | 329 | } |
340 | } | 330 | } |
341 | 331 | ||
342 | /* parity check of firmware */ | 332 | /* Parity check of firmware */ |
343 | ret = regmap_read(dev->regmap[0], 0xf8, &tmp); | 333 | ret = regmap_read(dev->regmap[0], 0xf8, &utmp); |
344 | if (ret) { | 334 | if (ret) |
345 | dev_err(&client->dev, | 335 | goto err_release_firmware; |
346 | "parity reg read failed=%d\n", ret); | 336 | if (utmp & 0x10) { |
347 | goto firmware_release; | 337 | ret = -EINVAL; |
348 | } | 338 | dev_err(&client->dev, "firmware did not run\n"); |
349 | if (tmp & 0x10) { | 339 | goto err_release_firmware; |
350 | dev_err(&client->dev, | ||
351 | "firmware parity check failed=0x%x\n", tmp); | ||
352 | goto firmware_release; | ||
353 | } | 340 | } |
354 | dev_err(&client->dev, "firmware parity check succeeded=0x%x\n", tmp); | ||
355 | 341 | ||
356 | ret = regmap_write(dev->regmap[0], 0xf5, 0x00); | 342 | ret = regmap_write(dev->regmap[0], 0xf5, 0x00); |
357 | if (ret) | 343 | if (ret) |
358 | goto firmware_release; | 344 | goto err_release_firmware; |
345 | |||
346 | release_firmware(firmware); | ||
347 | warm: | ||
348 | /* TS config */ | ||
349 | switch (dev->ts_mode) { | ||
350 | case SERIAL_TS_MODE: | ||
351 | utmp = 0x1d; | ||
352 | break; | ||
353 | case PARALLEL_TS_MODE: | ||
354 | utmp = 0x00; | ||
355 | break; | ||
356 | default: | ||
357 | ret = -EINVAL; | ||
358 | goto err; | ||
359 | } | ||
360 | ret = regmap_write(dev->regmap[2], 0x08, utmp); | ||
361 | if (ret) | ||
362 | goto err; | ||
359 | 363 | ||
360 | release_firmware(fw); | 364 | switch (dev->ts_clk) { |
361 | fw = NULL; | 365 | case VARIABLE_TS_CLOCK: |
366 | utmp = 0xe3; | ||
367 | break; | ||
368 | case FIXED_TS_CLOCK: | ||
369 | utmp = 0xe1; | ||
370 | break; | ||
371 | default: | ||
372 | ret = -EINVAL; | ||
373 | goto err; | ||
374 | } | ||
375 | ret = regmap_write(dev->regmap[0], 0xd9, utmp); | ||
376 | if (ret) | ||
377 | goto err; | ||
362 | 378 | ||
363 | /* warm state */ | 379 | dev->active = true; |
364 | dev->warm = true; | ||
365 | 380 | ||
366 | return 0; | 381 | return 0; |
367 | firmware_release: | 382 | err_release_firmware: |
368 | release_firmware(fw); | 383 | release_firmware(firmware); |
369 | err: | 384 | err: |
370 | dev_dbg(&client->dev, "failed=%d\n", ret); | 385 | dev_dbg(&client->dev, "failed=%d\n", ret); |
371 | return ret; | 386 | return ret; |
@@ -379,18 +394,17 @@ static int mn88472_sleep(struct dvb_frontend *fe) | |||
379 | 394 | ||
380 | dev_dbg(&client->dev, "\n"); | 395 | dev_dbg(&client->dev, "\n"); |
381 | 396 | ||
382 | /* power off */ | 397 | /* Power down */ |
398 | ret = regmap_write(dev->regmap[2], 0x0c, 0x30); | ||
399 | if (ret) | ||
400 | goto err; | ||
383 | ret = regmap_write(dev->regmap[2], 0x0b, 0x30); | 401 | ret = regmap_write(dev->regmap[2], 0x0b, 0x30); |
384 | |||
385 | if (ret) | 402 | if (ret) |
386 | goto err; | 403 | goto err; |
387 | |||
388 | ret = regmap_write(dev->regmap[2], 0x05, 0x3e); | 404 | ret = regmap_write(dev->regmap[2], 0x05, 0x3e); |
389 | if (ret) | 405 | if (ret) |
390 | goto err; | 406 | goto err; |
391 | 407 | ||
392 | dev->delivery_system = SYS_UNDEFINED; | ||
393 | |||
394 | return 0; | 408 | return 0; |
395 | err: | 409 | err: |
396 | dev_dbg(&client->dev, "failed=%d\n", ret); | 410 | dev_dbg(&client->dev, "failed=%d\n", ret); |
@@ -434,10 +448,19 @@ static struct dvb_frontend_ops mn88472_ops = { | |||
434 | .read_status = mn88472_read_status, | 448 | .read_status = mn88472_read_status, |
435 | }; | 449 | }; |
436 | 450 | ||
451 | static struct dvb_frontend *mn88472_get_dvb_frontend(struct i2c_client *client) | ||
452 | { | ||
453 | struct mn88472_dev *dev = i2c_get_clientdata(client); | ||
454 | |||
455 | dev_dbg(&client->dev, "\n"); | ||
456 | |||
457 | return &dev->fe; | ||
458 | } | ||
459 | |||
437 | static int mn88472_probe(struct i2c_client *client, | 460 | static int mn88472_probe(struct i2c_client *client, |
438 | const struct i2c_device_id *id) | 461 | const struct i2c_device_id *id) |
439 | { | 462 | { |
440 | struct mn88472_config *config = client->dev.platform_data; | 463 | struct mn88472_config *pdata = client->dev.platform_data; |
441 | struct mn88472_dev *dev; | 464 | struct mn88472_dev *dev; |
442 | int ret; | 465 | int ret; |
443 | unsigned int utmp; | 466 | unsigned int utmp; |
@@ -448,23 +471,16 @@ static int mn88472_probe(struct i2c_client *client, | |||
448 | 471 | ||
449 | dev_dbg(&client->dev, "\n"); | 472 | dev_dbg(&client->dev, "\n"); |
450 | 473 | ||
451 | /* Caller really need to provide pointer for frontend we create. */ | ||
452 | if (config->fe == NULL) { | ||
453 | dev_err(&client->dev, "frontend pointer not defined\n"); | ||
454 | ret = -EINVAL; | ||
455 | goto err; | ||
456 | } | ||
457 | |||
458 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | 474 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); |
459 | if (!dev) { | 475 | if (!dev) { |
460 | ret = -ENOMEM; | 476 | ret = -ENOMEM; |
461 | goto err; | 477 | goto err; |
462 | } | 478 | } |
463 | 479 | ||
464 | dev->i2c_wr_max = config->i2c_wr_max; | 480 | dev->i2c_write_max = pdata->i2c_wr_max ? pdata->i2c_wr_max : ~0; |
465 | dev->xtal = config->xtal; | 481 | dev->clk = pdata->xtal; |
466 | dev->ts_mode = config->ts_mode; | 482 | dev->ts_mode = pdata->ts_mode; |
467 | dev->ts_clock = config->ts_clock; | 483 | dev->ts_clk = pdata->ts_clock; |
468 | dev->client[0] = client; | 484 | dev->client[0] = client; |
469 | dev->regmap[0] = regmap_init_i2c(dev->client[0], ®map_config); | 485 | dev->regmap[0] = regmap_init_i2c(dev->client[0], ®map_config); |
470 | if (IS_ERR(dev->regmap[0])) { | 486 | if (IS_ERR(dev->regmap[0])) { |
@@ -472,15 +488,25 @@ static int mn88472_probe(struct i2c_client *client, | |||
472 | goto err_kfree; | 488 | goto err_kfree; |
473 | } | 489 | } |
474 | 490 | ||
475 | /* check demod answers to I2C */ | 491 | /* Check demod answers with correct chip id */ |
476 | ret = regmap_read(dev->regmap[0], 0x00, &utmp); | 492 | ret = regmap_read(dev->regmap[0], 0xff, &utmp); |
477 | if (ret) | 493 | if (ret) |
478 | goto err_regmap_0_regmap_exit; | 494 | goto err_regmap_0_regmap_exit; |
479 | 495 | ||
496 | dev_dbg(&client->dev, "chip id=%02x\n", utmp); | ||
497 | |||
498 | if (utmp != 0x02) { | ||
499 | ret = -ENODEV; | ||
500 | goto err_regmap_0_regmap_exit; | ||
501 | } | ||
502 | |||
480 | /* | 503 | /* |
481 | * Chip has three I2C addresses for different register pages. Used | 504 | * Chip has three I2C addresses for different register banks. Used |
482 | * addresses are 0x18, 0x1a and 0x1c. We register two dummy clients, | 505 | * addresses are 0x18, 0x1a and 0x1c. We register two dummy clients, |
483 | * 0x1a and 0x1c, in order to get own I2C client for each register page. | 506 | * 0x1a and 0x1c, in order to get own I2C client for each register bank. |
507 | * | ||
508 | * Also, register bank 2 do not support sequential I/O. Only single | ||
509 | * register write or read is allowed to that bank. | ||
484 | */ | 510 | */ |
485 | dev->client[1] = i2c_new_dummy(client->adapter, 0x1a); | 511 | dev->client[1] = i2c_new_dummy(client->adapter, 0x1a); |
486 | if (!dev->client[1]) { | 512 | if (!dev->client[1]) { |
@@ -510,15 +536,25 @@ static int mn88472_probe(struct i2c_client *client, | |||
510 | } | 536 | } |
511 | i2c_set_clientdata(dev->client[2], dev); | 537 | i2c_set_clientdata(dev->client[2], dev); |
512 | 538 | ||
513 | /* create dvb_frontend */ | 539 | /* Sleep because chip is active by default */ |
540 | ret = regmap_write(dev->regmap[2], 0x05, 0x3e); | ||
541 | if (ret) | ||
542 | goto err_regmap_2_regmap_exit; | ||
543 | |||
544 | /* Create dvb frontend */ | ||
514 | memcpy(&dev->fe.ops, &mn88472_ops, sizeof(struct dvb_frontend_ops)); | 545 | memcpy(&dev->fe.ops, &mn88472_ops, sizeof(struct dvb_frontend_ops)); |
515 | dev->fe.demodulator_priv = client; | 546 | dev->fe.demodulator_priv = client; |
516 | *config->fe = &dev->fe; | 547 | *pdata->fe = &dev->fe; |
517 | i2c_set_clientdata(client, dev); | 548 | i2c_set_clientdata(client, dev); |
518 | 549 | ||
519 | dev_info(&client->dev, "Panasonic MN88472 successfully attached\n"); | 550 | /* Setup callbacks */ |
520 | return 0; | 551 | pdata->get_dvb_frontend = mn88472_get_dvb_frontend; |
521 | 552 | ||
553 | dev_info(&client->dev, "Panasonic MN88472 successfully identified\n"); | ||
554 | |||
555 | return 0; | ||
556 | err_regmap_2_regmap_exit: | ||
557 | regmap_exit(dev->regmap[2]); | ||
522 | err_client_2_i2c_unregister_device: | 558 | err_client_2_i2c_unregister_device: |
523 | i2c_unregister_device(dev->client[2]); | 559 | i2c_unregister_device(dev->client[2]); |
524 | err_regmap_1_regmap_exit: | 560 | err_regmap_1_regmap_exit: |
@@ -561,11 +597,12 @@ MODULE_DEVICE_TABLE(i2c, mn88472_id_table); | |||
561 | 597 | ||
562 | static struct i2c_driver mn88472_driver = { | 598 | static struct i2c_driver mn88472_driver = { |
563 | .driver = { | 599 | .driver = { |
564 | .name = "mn88472", | 600 | .name = "mn88472", |
601 | .suppress_bind_attrs = true, | ||
565 | }, | 602 | }, |
566 | .probe = mn88472_probe, | 603 | .probe = mn88472_probe, |
567 | .remove = mn88472_remove, | 604 | .remove = mn88472_remove, |
568 | .id_table = mn88472_id_table, | 605 | .id_table = mn88472_id_table, |
569 | }; | 606 | }; |
570 | 607 | ||
571 | module_i2c_driver(mn88472_driver); | 608 | module_i2c_driver(mn88472_driver); |
diff --git a/drivers/media/dvb-frontends/mn88472.h b/drivers/media/dvb-frontends/mn88472.h index 095294d292f3..323632523876 100644 --- a/drivers/media/dvb-frontends/mn88472.h +++ b/drivers/media/dvb-frontends/mn88472.h | |||
@@ -19,23 +19,33 @@ | |||
19 | 19 | ||
20 | #include <linux/dvb/frontend.h> | 20 | #include <linux/dvb/frontend.h> |
21 | 21 | ||
22 | enum ts_clock { | 22 | /** |
23 | VARIABLE_TS_CLOCK, | 23 | * struct mn88472_config - Platform data for the mn88472 driver |
24 | FIXED_TS_CLOCK, | 24 | * @xtal: Clock frequency. |
25 | }; | 25 | * @ts_mode: TS mode. |
26 | * @ts_clock: TS clock config. | ||
27 | * @i2c_wr_max: Max number of bytes driver writes to I2C at once. | ||
28 | * @get_dvb_frontend: Get DVB frontend. | ||
29 | */ | ||
26 | 30 | ||
27 | enum ts_mode { | 31 | /* Define old names for backward compatibility */ |
28 | SERIAL_TS_MODE, | 32 | #define VARIABLE_TS_CLOCK MN88472_TS_CLK_VARIABLE |
29 | PARALLEL_TS_MODE, | 33 | #define FIXED_TS_CLOCK MN88472_TS_CLK_FIXED |
30 | }; | 34 | #define SERIAL_TS_MODE MN88472_TS_MODE_SERIAL |
35 | #define PARALLEL_TS_MODE MN88472_TS_MODE_PARALLEL | ||
31 | 36 | ||
32 | struct mn88472_config { | 37 | struct mn88472_config { |
33 | /* | 38 | unsigned int xtal; |
34 | * Max num of bytes given I2C adapter could write at once. | 39 | |
35 | * Default: none | 40 | #define MN88472_TS_MODE_SERIAL 0 |
36 | */ | 41 | #define MN88472_TS_MODE_PARALLEL 1 |
37 | u16 i2c_wr_max; | 42 | int ts_mode; |
38 | 43 | ||
44 | #define MN88472_TS_CLK_FIXED 0 | ||
45 | #define MN88472_TS_CLK_VARIABLE 1 | ||
46 | int ts_clock; | ||
47 | |||
48 | u16 i2c_wr_max; | ||
39 | 49 | ||
40 | /* Everything after that is returned by the driver. */ | 50 | /* Everything after that is returned by the driver. */ |
41 | 51 | ||
@@ -43,14 +53,7 @@ struct mn88472_config { | |||
43 | * DVB frontend. | 53 | * DVB frontend. |
44 | */ | 54 | */ |
45 | struct dvb_frontend **fe; | 55 | struct dvb_frontend **fe; |
46 | 56 | struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *); | |
47 | /* | ||
48 | * Xtal frequency. | ||
49 | * Hz | ||
50 | */ | ||
51 | u32 xtal; | ||
52 | int ts_mode; | ||
53 | int ts_clock; | ||
54 | }; | 57 | }; |
55 | 58 | ||
56 | #endif | 59 | #endif |
diff --git a/drivers/staging/media/mn88472/mn88472_priv.h b/drivers/media/dvb-frontends/mn88472_priv.h index 1a0de9e46b66..cdf2597a25d1 100644 --- a/drivers/staging/media/mn88472/mn88472_priv.h +++ b/drivers/media/dvb-frontends/mn88472_priv.h | |||
@@ -28,12 +28,11 @@ struct mn88472_dev { | |||
28 | struct i2c_client *client[3]; | 28 | struct i2c_client *client[3]; |
29 | struct regmap *regmap[3]; | 29 | struct regmap *regmap[3]; |
30 | struct dvb_frontend fe; | 30 | struct dvb_frontend fe; |
31 | u16 i2c_wr_max; | 31 | u16 i2c_write_max; |
32 | enum fe_delivery_system delivery_system; | 32 | unsigned int clk; |
33 | bool warm; /* FW running */ | 33 | unsigned int active:1; |
34 | u32 xtal; | 34 | unsigned int ts_mode:1; |
35 | int ts_mode; | 35 | unsigned int ts_clk:1; |
36 | int ts_clock; | ||
37 | }; | 36 | }; |
38 | 37 | ||
39 | #endif | 38 | #endif |
diff --git a/drivers/media/dvb-frontends/mn88473.c b/drivers/media/dvb-frontends/mn88473.c index 6c5d592161d4..451974a1d7ed 100644 --- a/drivers/media/dvb-frontends/mn88473.c +++ b/drivers/media/dvb-frontends/mn88473.c | |||
@@ -330,7 +330,7 @@ static int mn88473_init(struct dvb_frontend *fe) | |||
330 | /* Request the firmware, this will block and timeout */ | 330 | /* Request the firmware, this will block and timeout */ |
331 | ret = request_firmware(&fw, name, &client->dev); | 331 | ret = request_firmware(&fw, name, &client->dev); |
332 | if (ret) { | 332 | if (ret) { |
333 | dev_err(&client->dev, "firmare file '%s' not found\n", name); | 333 | dev_err(&client->dev, "firmware file '%s' not found\n", name); |
334 | goto err; | 334 | goto err; |
335 | } | 335 | } |
336 | 336 | ||
@@ -536,7 +536,7 @@ static int mn88473_probe(struct i2c_client *client, | |||
536 | /* Sleep because chip is active by default */ | 536 | /* Sleep because chip is active by default */ |
537 | ret = regmap_write(dev->regmap[2], 0x05, 0x3e); | 537 | ret = regmap_write(dev->regmap[2], 0x05, 0x3e); |
538 | if (ret) | 538 | if (ret) |
539 | goto err_client_2_i2c_unregister_device; | 539 | goto err_regmap_2_regmap_exit; |
540 | 540 | ||
541 | /* Create dvb frontend */ | 541 | /* Create dvb frontend */ |
542 | memcpy(&dev->frontend.ops, &mn88473_ops, sizeof(dev->frontend.ops)); | 542 | memcpy(&dev->frontend.ops, &mn88473_ops, sizeof(dev->frontend.ops)); |
@@ -547,7 +547,8 @@ static int mn88473_probe(struct i2c_client *client, | |||
547 | dev_info(&client->dev, "Panasonic MN88473 successfully identified\n"); | 547 | dev_info(&client->dev, "Panasonic MN88473 successfully identified\n"); |
548 | 548 | ||
549 | return 0; | 549 | return 0; |
550 | 550 | err_regmap_2_regmap_exit: | |
551 | regmap_exit(dev->regmap[2]); | ||
551 | err_client_2_i2c_unregister_device: | 552 | err_client_2_i2c_unregister_device: |
552 | i2c_unregister_device(dev->client[2]); | 553 | i2c_unregister_device(dev->client[2]); |
553 | err_regmap_1_regmap_exit: | 554 | err_regmap_1_regmap_exit: |
diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c index bfb6beedd40b..c16c69e9d26c 100644 --- a/drivers/media/dvb-frontends/rtl2832.c +++ b/drivers/media/dvb-frontends/rtl2832.c | |||
@@ -947,6 +947,8 @@ static int rtl2832_slave_ts_ctrl(struct i2c_client *client, bool enable) | |||
947 | goto err; | 947 | goto err; |
948 | } | 948 | } |
949 | 949 | ||
950 | dev->slave_ts = enable; | ||
951 | |||
950 | return 0; | 952 | return 0; |
951 | err: | 953 | err: |
952 | dev_dbg(&client->dev, "failed=%d\n", ret); | 954 | dev_dbg(&client->dev, "failed=%d\n", ret); |
@@ -960,7 +962,7 @@ static int rtl2832_pid_filter_ctrl(struct dvb_frontend *fe, int onoff) | |||
960 | int ret; | 962 | int ret; |
961 | u8 u8tmp; | 963 | u8 u8tmp; |
962 | 964 | ||
963 | dev_dbg(&client->dev, "onoff=%d\n", onoff); | 965 | dev_dbg(&client->dev, "onoff=%d, slave_ts=%d\n", onoff, dev->slave_ts); |
964 | 966 | ||
965 | /* enable / disable PID filter */ | 967 | /* enable / disable PID filter */ |
966 | if (onoff) | 968 | if (onoff) |
@@ -968,7 +970,10 @@ static int rtl2832_pid_filter_ctrl(struct dvb_frontend *fe, int onoff) | |||
968 | else | 970 | else |
969 | u8tmp = 0x00; | 971 | u8tmp = 0x00; |
970 | 972 | ||
971 | ret = regmap_update_bits(dev->regmap, 0x061, 0xc0, u8tmp); | 973 | if (dev->slave_ts) |
974 | ret = regmap_update_bits(dev->regmap, 0x021, 0xc0, u8tmp); | ||
975 | else | ||
976 | ret = regmap_update_bits(dev->regmap, 0x061, 0xc0, u8tmp); | ||
972 | if (ret) | 977 | if (ret) |
973 | goto err; | 978 | goto err; |
974 | 979 | ||
@@ -986,8 +991,8 @@ static int rtl2832_pid_filter(struct dvb_frontend *fe, u8 index, u16 pid, | |||
986 | int ret; | 991 | int ret; |
987 | u8 buf[4]; | 992 | u8 buf[4]; |
988 | 993 | ||
989 | dev_dbg(&client->dev, "index=%d pid=%04x onoff=%d\n", | 994 | dev_dbg(&client->dev, "index=%d pid=%04x onoff=%d slave_ts=%d\n", |
990 | index, pid, onoff); | 995 | index, pid, onoff, dev->slave_ts); |
991 | 996 | ||
992 | /* skip invalid PIDs (0x2000) */ | 997 | /* skip invalid PIDs (0x2000) */ |
993 | if (pid > 0x1fff || index > 32) | 998 | if (pid > 0x1fff || index > 32) |
@@ -1003,14 +1008,22 @@ static int rtl2832_pid_filter(struct dvb_frontend *fe, u8 index, u16 pid, | |||
1003 | buf[1] = (dev->filters >> 8) & 0xff; | 1008 | buf[1] = (dev->filters >> 8) & 0xff; |
1004 | buf[2] = (dev->filters >> 16) & 0xff; | 1009 | buf[2] = (dev->filters >> 16) & 0xff; |
1005 | buf[3] = (dev->filters >> 24) & 0xff; | 1010 | buf[3] = (dev->filters >> 24) & 0xff; |
1006 | ret = regmap_bulk_write(dev->regmap, 0x062, buf, 4); | 1011 | |
1012 | if (dev->slave_ts) | ||
1013 | ret = regmap_bulk_write(dev->regmap, 0x022, buf, 4); | ||
1014 | else | ||
1015 | ret = regmap_bulk_write(dev->regmap, 0x062, buf, 4); | ||
1007 | if (ret) | 1016 | if (ret) |
1008 | goto err; | 1017 | goto err; |
1009 | 1018 | ||
1010 | /* add PID */ | 1019 | /* add PID */ |
1011 | buf[0] = (pid >> 8) & 0xff; | 1020 | buf[0] = (pid >> 8) & 0xff; |
1012 | buf[1] = (pid >> 0) & 0xff; | 1021 | buf[1] = (pid >> 0) & 0xff; |
1013 | ret = regmap_bulk_write(dev->regmap, 0x066 + 2 * index, buf, 2); | 1022 | |
1023 | if (dev->slave_ts) | ||
1024 | ret = regmap_bulk_write(dev->regmap, 0x026 + 2 * index, buf, 2); | ||
1025 | else | ||
1026 | ret = regmap_bulk_write(dev->regmap, 0x066 + 2 * index, buf, 2); | ||
1014 | if (ret) | 1027 | if (ret) |
1015 | goto err; | 1028 | goto err; |
1016 | 1029 | ||
diff --git a/drivers/media/dvb-frontends/rtl2832_priv.h b/drivers/media/dvb-frontends/rtl2832_priv.h index c1a8a69e9015..9a6d01a9c690 100644 --- a/drivers/media/dvb-frontends/rtl2832_priv.h +++ b/drivers/media/dvb-frontends/rtl2832_priv.h | |||
@@ -44,6 +44,7 @@ struct rtl2832_dev { | |||
44 | bool sleeping; | 44 | bool sleeping; |
45 | struct delayed_work i2c_gate_work; | 45 | struct delayed_work i2c_gate_work; |
46 | unsigned long filters; /* PID filter */ | 46 | unsigned long filters; /* PID filter */ |
47 | bool slave_ts; | ||
47 | }; | 48 | }; |
48 | 49 | ||
49 | struct rtl2832_reg_entry { | 50 | struct rtl2832_reg_entry { |
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index a1cd50f331f1..1795abeda658 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c | |||
@@ -423,7 +423,7 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd, | |||
423 | unsigned long arg) | 423 | unsigned long arg) |
424 | { | 424 | { |
425 | struct media_devnode *devnode = media_devnode_data(filp); | 425 | struct media_devnode *devnode = media_devnode_data(filp); |
426 | struct media_device *dev = to_media_device(devnode); | 426 | struct media_device *dev = devnode->media_dev; |
427 | long ret; | 427 | long ret; |
428 | 428 | ||
429 | mutex_lock(&dev->graph_mutex); | 429 | mutex_lock(&dev->graph_mutex); |
@@ -495,7 +495,7 @@ static long media_device_compat_ioctl(struct file *filp, unsigned int cmd, | |||
495 | unsigned long arg) | 495 | unsigned long arg) |
496 | { | 496 | { |
497 | struct media_devnode *devnode = media_devnode_data(filp); | 497 | struct media_devnode *devnode = media_devnode_data(filp); |
498 | struct media_device *dev = to_media_device(devnode); | 498 | struct media_device *dev = devnode->media_dev; |
499 | long ret; | 499 | long ret; |
500 | 500 | ||
501 | switch (cmd) { | 501 | switch (cmd) { |
@@ -531,7 +531,8 @@ static const struct media_file_operations media_device_fops = { | |||
531 | static ssize_t show_model(struct device *cd, | 531 | static ssize_t show_model(struct device *cd, |
532 | struct device_attribute *attr, char *buf) | 532 | struct device_attribute *attr, char *buf) |
533 | { | 533 | { |
534 | struct media_device *mdev = to_media_device(to_media_devnode(cd)); | 534 | struct media_devnode *devnode = to_media_devnode(cd); |
535 | struct media_device *mdev = devnode->media_dev; | ||
535 | 536 | ||
536 | return sprintf(buf, "%.*s\n", (int)sizeof(mdev->model), mdev->model); | 537 | return sprintf(buf, "%.*s\n", (int)sizeof(mdev->model), mdev->model); |
537 | } | 538 | } |
@@ -704,23 +705,35 @@ EXPORT_SYMBOL_GPL(media_device_cleanup); | |||
704 | int __must_check __media_device_register(struct media_device *mdev, | 705 | int __must_check __media_device_register(struct media_device *mdev, |
705 | struct module *owner) | 706 | struct module *owner) |
706 | { | 707 | { |
708 | struct media_devnode *devnode; | ||
707 | int ret; | 709 | int ret; |
708 | 710 | ||
711 | devnode = kzalloc(sizeof(*devnode), GFP_KERNEL); | ||
712 | if (!devnode) | ||
713 | return -ENOMEM; | ||
714 | |||
709 | /* Register the device node. */ | 715 | /* Register the device node. */ |
710 | mdev->devnode.fops = &media_device_fops; | 716 | mdev->devnode = devnode; |
711 | mdev->devnode.parent = mdev->dev; | 717 | devnode->fops = &media_device_fops; |
712 | mdev->devnode.release = media_device_release; | 718 | devnode->parent = mdev->dev; |
719 | devnode->release = media_device_release; | ||
713 | 720 | ||
714 | /* Set version 0 to indicate user-space that the graph is static */ | 721 | /* Set version 0 to indicate user-space that the graph is static */ |
715 | mdev->topology_version = 0; | 722 | mdev->topology_version = 0; |
716 | 723 | ||
717 | ret = media_devnode_register(&mdev->devnode, owner); | 724 | ret = media_devnode_register(mdev, devnode, owner); |
718 | if (ret < 0) | 725 | if (ret < 0) { |
726 | /* devnode free is handled in media_devnode_*() */ | ||
727 | mdev->devnode = NULL; | ||
719 | return ret; | 728 | return ret; |
729 | } | ||
720 | 730 | ||
721 | ret = device_create_file(&mdev->devnode.dev, &dev_attr_model); | 731 | ret = device_create_file(&devnode->dev, &dev_attr_model); |
722 | if (ret < 0) { | 732 | if (ret < 0) { |
723 | media_devnode_unregister(&mdev->devnode); | 733 | /* devnode free is handled in media_devnode_*() */ |
734 | mdev->devnode = NULL; | ||
735 | media_devnode_unregister_prepare(devnode); | ||
736 | media_devnode_unregister(devnode); | ||
724 | return ret; | 737 | return ret; |
725 | } | 738 | } |
726 | 739 | ||
@@ -771,11 +784,14 @@ void media_device_unregister(struct media_device *mdev) | |||
771 | mutex_lock(&mdev->graph_mutex); | 784 | mutex_lock(&mdev->graph_mutex); |
772 | 785 | ||
773 | /* Check if mdev was ever registered at all */ | 786 | /* Check if mdev was ever registered at all */ |
774 | if (!media_devnode_is_registered(&mdev->devnode)) { | 787 | if (!media_devnode_is_registered(mdev->devnode)) { |
775 | mutex_unlock(&mdev->graph_mutex); | 788 | mutex_unlock(&mdev->graph_mutex); |
776 | return; | 789 | return; |
777 | } | 790 | } |
778 | 791 | ||
792 | /* Clear the devnode register bit to avoid races with media dev open */ | ||
793 | media_devnode_unregister_prepare(mdev->devnode); | ||
794 | |||
779 | /* Remove all entities from the media device */ | 795 | /* Remove all entities from the media device */ |
780 | list_for_each_entry_safe(entity, next, &mdev->entities, graph_obj.list) | 796 | list_for_each_entry_safe(entity, next, &mdev->entities, graph_obj.list) |
781 | __media_device_unregister_entity(entity); | 797 | __media_device_unregister_entity(entity); |
@@ -794,9 +810,12 @@ void media_device_unregister(struct media_device *mdev) | |||
794 | 810 | ||
795 | mutex_unlock(&mdev->graph_mutex); | 811 | mutex_unlock(&mdev->graph_mutex); |
796 | 812 | ||
797 | device_remove_file(&mdev->devnode.dev, &dev_attr_model); | 813 | dev_dbg(mdev->dev, "Media device unregistered\n"); |
798 | dev_dbg(mdev->dev, "Media device unregistering\n"); | 814 | |
799 | media_devnode_unregister(&mdev->devnode); | 815 | device_remove_file(&mdev->devnode->dev, &dev_attr_model); |
816 | media_devnode_unregister(mdev->devnode); | ||
817 | /* devnode free is handled in media_devnode_*() */ | ||
818 | mdev->devnode = NULL; | ||
800 | } | 819 | } |
801 | EXPORT_SYMBOL_GPL(media_device_unregister); | 820 | EXPORT_SYMBOL_GPL(media_device_unregister); |
802 | 821 | ||
diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c index b66dc9d0766b..f2772ba6f611 100644 --- a/drivers/media/media-devnode.c +++ b/drivers/media/media-devnode.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include <linux/uaccess.h> | 44 | #include <linux/uaccess.h> |
45 | 45 | ||
46 | #include <media/media-devnode.h> | 46 | #include <media/media-devnode.h> |
47 | #include <media/media-device.h> | ||
47 | 48 | ||
48 | #define MEDIA_NUM_DEVICES 256 | 49 | #define MEDIA_NUM_DEVICES 256 |
49 | #define MEDIA_NAME "media" | 50 | #define MEDIA_NAME "media" |
@@ -59,21 +60,19 @@ static DECLARE_BITMAP(media_devnode_nums, MEDIA_NUM_DEVICES); | |||
59 | /* Called when the last user of the media device exits. */ | 60 | /* Called when the last user of the media device exits. */ |
60 | static void media_devnode_release(struct device *cd) | 61 | static void media_devnode_release(struct device *cd) |
61 | { | 62 | { |
62 | struct media_devnode *mdev = to_media_devnode(cd); | 63 | struct media_devnode *devnode = to_media_devnode(cd); |
63 | 64 | ||
64 | mutex_lock(&media_devnode_lock); | 65 | mutex_lock(&media_devnode_lock); |
65 | |||
66 | /* Delete the cdev on this minor as well */ | ||
67 | cdev_del(&mdev->cdev); | ||
68 | |||
69 | /* Mark device node number as free */ | 66 | /* Mark device node number as free */ |
70 | clear_bit(mdev->minor, media_devnode_nums); | 67 | clear_bit(devnode->minor, media_devnode_nums); |
71 | |||
72 | mutex_unlock(&media_devnode_lock); | 68 | mutex_unlock(&media_devnode_lock); |
73 | 69 | ||
74 | /* Release media_devnode and perform other cleanups as needed. */ | 70 | /* Release media_devnode and perform other cleanups as needed. */ |
75 | if (mdev->release) | 71 | if (devnode->release) |
76 | mdev->release(mdev); | 72 | devnode->release(devnode); |
73 | |||
74 | kfree(devnode); | ||
75 | pr_debug("%s: Media Devnode Deallocated\n", __func__); | ||
77 | } | 76 | } |
78 | 77 | ||
79 | static struct bus_type media_bus_type = { | 78 | static struct bus_type media_bus_type = { |
@@ -83,37 +82,37 @@ static struct bus_type media_bus_type = { | |||
83 | static ssize_t media_read(struct file *filp, char __user *buf, | 82 | static ssize_t media_read(struct file *filp, char __user *buf, |
84 | size_t sz, loff_t *off) | 83 | size_t sz, loff_t *off) |
85 | { | 84 | { |
86 | struct media_devnode *mdev = media_devnode_data(filp); | 85 | struct media_devnode *devnode = media_devnode_data(filp); |
87 | 86 | ||
88 | if (!mdev->fops->read) | 87 | if (!devnode->fops->read) |
89 | return -EINVAL; | 88 | return -EINVAL; |
90 | if (!media_devnode_is_registered(mdev)) | 89 | if (!media_devnode_is_registered(devnode)) |
91 | return -EIO; | 90 | return -EIO; |
92 | return mdev->fops->read(filp, buf, sz, off); | 91 | return devnode->fops->read(filp, buf, sz, off); |
93 | } | 92 | } |
94 | 93 | ||
95 | static ssize_t media_write(struct file *filp, const char __user *buf, | 94 | static ssize_t media_write(struct file *filp, const char __user *buf, |
96 | size_t sz, loff_t *off) | 95 | size_t sz, loff_t *off) |
97 | { | 96 | { |
98 | struct media_devnode *mdev = media_devnode_data(filp); | 97 | struct media_devnode *devnode = media_devnode_data(filp); |
99 | 98 | ||
100 | if (!mdev->fops->write) | 99 | if (!devnode->fops->write) |
101 | return -EINVAL; | 100 | return -EINVAL; |
102 | if (!media_devnode_is_registered(mdev)) | 101 | if (!media_devnode_is_registered(devnode)) |
103 | return -EIO; | 102 | return -EIO; |
104 | return mdev->fops->write(filp, buf, sz, off); | 103 | return devnode->fops->write(filp, buf, sz, off); |
105 | } | 104 | } |
106 | 105 | ||
107 | static unsigned int media_poll(struct file *filp, | 106 | static unsigned int media_poll(struct file *filp, |
108 | struct poll_table_struct *poll) | 107 | struct poll_table_struct *poll) |
109 | { | 108 | { |
110 | struct media_devnode *mdev = media_devnode_data(filp); | 109 | struct media_devnode *devnode = media_devnode_data(filp); |
111 | 110 | ||
112 | if (!media_devnode_is_registered(mdev)) | 111 | if (!media_devnode_is_registered(devnode)) |
113 | return POLLERR | POLLHUP; | 112 | return POLLERR | POLLHUP; |
114 | if (!mdev->fops->poll) | 113 | if (!devnode->fops->poll) |
115 | return DEFAULT_POLLMASK; | 114 | return DEFAULT_POLLMASK; |
116 | return mdev->fops->poll(filp, poll); | 115 | return devnode->fops->poll(filp, poll); |
117 | } | 116 | } |
118 | 117 | ||
119 | static long | 118 | static long |
@@ -121,12 +120,12 @@ __media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg, | |||
121 | long (*ioctl_func)(struct file *filp, unsigned int cmd, | 120 | long (*ioctl_func)(struct file *filp, unsigned int cmd, |
122 | unsigned long arg)) | 121 | unsigned long arg)) |
123 | { | 122 | { |
124 | struct media_devnode *mdev = media_devnode_data(filp); | 123 | struct media_devnode *devnode = media_devnode_data(filp); |
125 | 124 | ||
126 | if (!ioctl_func) | 125 | if (!ioctl_func) |
127 | return -ENOTTY; | 126 | return -ENOTTY; |
128 | 127 | ||
129 | if (!media_devnode_is_registered(mdev)) | 128 | if (!media_devnode_is_registered(devnode)) |
130 | return -EIO; | 129 | return -EIO; |
131 | 130 | ||
132 | return ioctl_func(filp, cmd, arg); | 131 | return ioctl_func(filp, cmd, arg); |
@@ -134,9 +133,9 @@ __media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg, | |||
134 | 133 | ||
135 | static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | 134 | static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
136 | { | 135 | { |
137 | struct media_devnode *mdev = media_devnode_data(filp); | 136 | struct media_devnode *devnode = media_devnode_data(filp); |
138 | 137 | ||
139 | return __media_ioctl(filp, cmd, arg, mdev->fops->ioctl); | 138 | return __media_ioctl(filp, cmd, arg, devnode->fops->ioctl); |
140 | } | 139 | } |
141 | 140 | ||
142 | #ifdef CONFIG_COMPAT | 141 | #ifdef CONFIG_COMPAT |
@@ -144,9 +143,9 @@ static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
144 | static long media_compat_ioctl(struct file *filp, unsigned int cmd, | 143 | static long media_compat_ioctl(struct file *filp, unsigned int cmd, |
145 | unsigned long arg) | 144 | unsigned long arg) |
146 | { | 145 | { |
147 | struct media_devnode *mdev = media_devnode_data(filp); | 146 | struct media_devnode *devnode = media_devnode_data(filp); |
148 | 147 | ||
149 | return __media_ioctl(filp, cmd, arg, mdev->fops->compat_ioctl); | 148 | return __media_ioctl(filp, cmd, arg, devnode->fops->compat_ioctl); |
150 | } | 149 | } |
151 | 150 | ||
152 | #endif /* CONFIG_COMPAT */ | 151 | #endif /* CONFIG_COMPAT */ |
@@ -154,7 +153,7 @@ static long media_compat_ioctl(struct file *filp, unsigned int cmd, | |||
154 | /* Override for the open function */ | 153 | /* Override for the open function */ |
155 | static int media_open(struct inode *inode, struct file *filp) | 154 | static int media_open(struct inode *inode, struct file *filp) |
156 | { | 155 | { |
157 | struct media_devnode *mdev; | 156 | struct media_devnode *devnode; |
158 | int ret; | 157 | int ret; |
159 | 158 | ||
160 | /* Check if the media device is available. This needs to be done with | 159 | /* Check if the media device is available. This needs to be done with |
@@ -164,23 +163,23 @@ static int media_open(struct inode *inode, struct file *filp) | |||
164 | * a crash. | 163 | * a crash. |
165 | */ | 164 | */ |
166 | mutex_lock(&media_devnode_lock); | 165 | mutex_lock(&media_devnode_lock); |
167 | mdev = container_of(inode->i_cdev, struct media_devnode, cdev); | 166 | devnode = container_of(inode->i_cdev, struct media_devnode, cdev); |
168 | /* return ENXIO if the media device has been removed | 167 | /* return ENXIO if the media device has been removed |
169 | already or if it is not registered anymore. */ | 168 | already or if it is not registered anymore. */ |
170 | if (!media_devnode_is_registered(mdev)) { | 169 | if (!media_devnode_is_registered(devnode)) { |
171 | mutex_unlock(&media_devnode_lock); | 170 | mutex_unlock(&media_devnode_lock); |
172 | return -ENXIO; | 171 | return -ENXIO; |
173 | } | 172 | } |
174 | /* and increase the device refcount */ | 173 | /* and increase the device refcount */ |
175 | get_device(&mdev->dev); | 174 | get_device(&devnode->dev); |
176 | mutex_unlock(&media_devnode_lock); | 175 | mutex_unlock(&media_devnode_lock); |
177 | 176 | ||
178 | filp->private_data = mdev; | 177 | filp->private_data = devnode; |
179 | 178 | ||
180 | if (mdev->fops->open) { | 179 | if (devnode->fops->open) { |
181 | ret = mdev->fops->open(filp); | 180 | ret = devnode->fops->open(filp); |
182 | if (ret) { | 181 | if (ret) { |
183 | put_device(&mdev->dev); | 182 | put_device(&devnode->dev); |
184 | filp->private_data = NULL; | 183 | filp->private_data = NULL; |
185 | return ret; | 184 | return ret; |
186 | } | 185 | } |
@@ -192,16 +191,18 @@ static int media_open(struct inode *inode, struct file *filp) | |||
192 | /* Override for the release function */ | 191 | /* Override for the release function */ |
193 | static int media_release(struct inode *inode, struct file *filp) | 192 | static int media_release(struct inode *inode, struct file *filp) |
194 | { | 193 | { |
195 | struct media_devnode *mdev = media_devnode_data(filp); | 194 | struct media_devnode *devnode = media_devnode_data(filp); |
196 | 195 | ||
197 | if (mdev->fops->release) | 196 | if (devnode->fops->release) |
198 | mdev->fops->release(filp); | 197 | devnode->fops->release(filp); |
199 | 198 | ||
200 | filp->private_data = NULL; | 199 | filp->private_data = NULL; |
201 | 200 | ||
202 | /* decrease the refcount unconditionally since the release() | 201 | /* decrease the refcount unconditionally since the release() |
203 | return value is ignored. */ | 202 | return value is ignored. */ |
204 | put_device(&mdev->dev); | 203 | put_device(&devnode->dev); |
204 | |||
205 | pr_debug("%s: Media Release\n", __func__); | ||
205 | return 0; | 206 | return 0; |
206 | } | 207 | } |
207 | 208 | ||
@@ -219,7 +220,8 @@ static const struct file_operations media_devnode_fops = { | |||
219 | .llseek = no_llseek, | 220 | .llseek = no_llseek, |
220 | }; | 221 | }; |
221 | 222 | ||
222 | int __must_check media_devnode_register(struct media_devnode *mdev, | 223 | int __must_check media_devnode_register(struct media_device *mdev, |
224 | struct media_devnode *devnode, | ||
223 | struct module *owner) | 225 | struct module *owner) |
224 | { | 226 | { |
225 | int minor; | 227 | int minor; |
@@ -231,61 +233,80 @@ int __must_check media_devnode_register(struct media_devnode *mdev, | |||
231 | if (minor == MEDIA_NUM_DEVICES) { | 233 | if (minor == MEDIA_NUM_DEVICES) { |
232 | mutex_unlock(&media_devnode_lock); | 234 | mutex_unlock(&media_devnode_lock); |
233 | pr_err("could not get a free minor\n"); | 235 | pr_err("could not get a free minor\n"); |
236 | kfree(devnode); | ||
234 | return -ENFILE; | 237 | return -ENFILE; |
235 | } | 238 | } |
236 | 239 | ||
237 | set_bit(minor, media_devnode_nums); | 240 | set_bit(minor, media_devnode_nums); |
238 | mutex_unlock(&media_devnode_lock); | 241 | mutex_unlock(&media_devnode_lock); |
239 | 242 | ||
240 | mdev->minor = minor; | 243 | devnode->minor = minor; |
244 | devnode->media_dev = mdev; | ||
245 | |||
246 | /* Part 1: Initialize dev now to use dev.kobj for cdev.kobj.parent */ | ||
247 | devnode->dev.bus = &media_bus_type; | ||
248 | devnode->dev.devt = MKDEV(MAJOR(media_dev_t), devnode->minor); | ||
249 | devnode->dev.release = media_devnode_release; | ||
250 | if (devnode->parent) | ||
251 | devnode->dev.parent = devnode->parent; | ||
252 | dev_set_name(&devnode->dev, "media%d", devnode->minor); | ||
253 | device_initialize(&devnode->dev); | ||
241 | 254 | ||
242 | /* Part 2: Initialize and register the character device */ | 255 | /* Part 2: Initialize and register the character device */ |
243 | cdev_init(&mdev->cdev, &media_devnode_fops); | 256 | cdev_init(&devnode->cdev, &media_devnode_fops); |
244 | mdev->cdev.owner = owner; | 257 | devnode->cdev.owner = owner; |
258 | devnode->cdev.kobj.parent = &devnode->dev.kobj; | ||
245 | 259 | ||
246 | ret = cdev_add(&mdev->cdev, MKDEV(MAJOR(media_dev_t), mdev->minor), 1); | 260 | ret = cdev_add(&devnode->cdev, MKDEV(MAJOR(media_dev_t), devnode->minor), 1); |
247 | if (ret < 0) { | 261 | if (ret < 0) { |
248 | pr_err("%s: cdev_add failed\n", __func__); | 262 | pr_err("%s: cdev_add failed\n", __func__); |
249 | goto error; | 263 | goto cdev_add_error; |
250 | } | 264 | } |
251 | 265 | ||
252 | /* Part 3: Register the media device */ | 266 | /* Part 3: Add the media device */ |
253 | mdev->dev.bus = &media_bus_type; | 267 | ret = device_add(&devnode->dev); |
254 | mdev->dev.devt = MKDEV(MAJOR(media_dev_t), mdev->minor); | ||
255 | mdev->dev.release = media_devnode_release; | ||
256 | if (mdev->parent) | ||
257 | mdev->dev.parent = mdev->parent; | ||
258 | dev_set_name(&mdev->dev, "media%d", mdev->minor); | ||
259 | ret = device_register(&mdev->dev); | ||
260 | if (ret < 0) { | 268 | if (ret < 0) { |
261 | pr_err("%s: device_register failed\n", __func__); | 269 | pr_err("%s: device_add failed\n", __func__); |
262 | goto error; | 270 | goto device_add_error; |
263 | } | 271 | } |
264 | 272 | ||
265 | /* Part 4: Activate this minor. The char device can now be used. */ | 273 | /* Part 4: Activate this minor. The char device can now be used. */ |
266 | set_bit(MEDIA_FLAG_REGISTERED, &mdev->flags); | 274 | set_bit(MEDIA_FLAG_REGISTERED, &devnode->flags); |
267 | 275 | ||
268 | return 0; | 276 | return 0; |
269 | 277 | ||
270 | error: | 278 | device_add_error: |
279 | cdev_del(&devnode->cdev); | ||
280 | cdev_add_error: | ||
271 | mutex_lock(&media_devnode_lock); | 281 | mutex_lock(&media_devnode_lock); |
272 | cdev_del(&mdev->cdev); | 282 | clear_bit(devnode->minor, media_devnode_nums); |
273 | clear_bit(mdev->minor, media_devnode_nums); | 283 | devnode->media_dev = NULL; |
274 | mutex_unlock(&media_devnode_lock); | 284 | mutex_unlock(&media_devnode_lock); |
275 | 285 | ||
286 | put_device(&devnode->dev); | ||
276 | return ret; | 287 | return ret; |
277 | } | 288 | } |
278 | 289 | ||
279 | void media_devnode_unregister(struct media_devnode *mdev) | 290 | void media_devnode_unregister_prepare(struct media_devnode *devnode) |
280 | { | 291 | { |
281 | /* Check if mdev was ever registered at all */ | 292 | /* Check if devnode was ever registered at all */ |
282 | if (!media_devnode_is_registered(mdev)) | 293 | if (!media_devnode_is_registered(devnode)) |
283 | return; | 294 | return; |
284 | 295 | ||
285 | mutex_lock(&media_devnode_lock); | 296 | mutex_lock(&media_devnode_lock); |
286 | clear_bit(MEDIA_FLAG_REGISTERED, &mdev->flags); | 297 | clear_bit(MEDIA_FLAG_REGISTERED, &devnode->flags); |
298 | mutex_unlock(&media_devnode_lock); | ||
299 | } | ||
300 | |||
301 | void media_devnode_unregister(struct media_devnode *devnode) | ||
302 | { | ||
303 | mutex_lock(&media_devnode_lock); | ||
304 | /* Delete the cdev on this minor as well */ | ||
305 | cdev_del(&devnode->cdev); | ||
287 | mutex_unlock(&media_devnode_lock); | 306 | mutex_unlock(&media_devnode_lock); |
288 | device_unregister(&mdev->dev); | 307 | device_del(&devnode->dev); |
308 | devnode->media_dev = NULL; | ||
309 | put_device(&devnode->dev); | ||
289 | } | 310 | } |
290 | 311 | ||
291 | /* | 312 | /* |
diff --git a/drivers/media/pci/netup_unidvb/Kconfig b/drivers/media/pci/netup_unidvb/Kconfig index f277b0b10c2d..0ad37714c7fd 100644 --- a/drivers/media/pci/netup_unidvb/Kconfig +++ b/drivers/media/pci/netup_unidvb/Kconfig | |||
@@ -5,8 +5,13 @@ config DVB_NETUP_UNIDVB | |||
5 | select VIDEOBUF2_VMALLOC | 5 | select VIDEOBUF2_VMALLOC |
6 | select DVB_HORUS3A if MEDIA_SUBDRV_AUTOSELECT | 6 | select DVB_HORUS3A if MEDIA_SUBDRV_AUTOSELECT |
7 | select DVB_ASCOT2E if MEDIA_SUBDRV_AUTOSELECT | 7 | select DVB_ASCOT2E if MEDIA_SUBDRV_AUTOSELECT |
8 | select DVB_HELENE if MEDIA_SUBDRV_AUTOSELECT | ||
8 | select DVB_LNBH25 if MEDIA_SUBDRV_AUTOSELECT | 9 | select DVB_LNBH25 if MEDIA_SUBDRV_AUTOSELECT |
9 | select DVB_CXD2841ER if MEDIA_SUBDRV_AUTOSELECT | 10 | select DVB_CXD2841ER if MEDIA_SUBDRV_AUTOSELECT |
10 | ---help--- | 11 | ---help--- |
11 | Support for NetUP PCI express Universal DVB card. | 12 | Support for NetUP PCI express Universal DVB card. |
12 | 13 | help | |
14 | Say Y when you want to support NetUP Dual Universal DVB card | ||
15 | Card can receive two independent streams in following standards: | ||
16 | DVB-S/S2, T/T2, C/C2 | ||
17 | Two CI slots available for CAM modules. | ||
diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb.h b/drivers/media/pci/netup_unidvb/netup_unidvb.h index a67b28111905..39b08ecda1fc 100644 --- a/drivers/media/pci/netup_unidvb/netup_unidvb.h +++ b/drivers/media/pci/netup_unidvb/netup_unidvb.h | |||
@@ -50,6 +50,15 @@ | |||
50 | #define NETUP_UNIDVB_IRQ_CAM0 (1 << 11) | 50 | #define NETUP_UNIDVB_IRQ_CAM0 (1 << 11) |
51 | #define NETUP_UNIDVB_IRQ_CAM1 (1 << 12) | 51 | #define NETUP_UNIDVB_IRQ_CAM1 (1 << 12) |
52 | 52 | ||
53 | /* NetUP Universal DVB card hardware revisions and it's PCI device id's: | ||
54 | * 1.3 - CXD2841ER demod, ASCOT2E and HORUS3A tuners | ||
55 | * 1.4 - CXD2854ER demod, HELENE tuner | ||
56 | */ | ||
57 | enum netup_hw_rev { | ||
58 | NETUP_HW_REV_1_3 = 0x18F6, | ||
59 | NETUP_HW_REV_1_4 = 0x18F7 | ||
60 | }; | ||
61 | |||
53 | struct netup_dma { | 62 | struct netup_dma { |
54 | u8 num; | 63 | u8 num; |
55 | spinlock_t lock; | 64 | spinlock_t lock; |
@@ -119,6 +128,7 @@ struct netup_unidvb_dev { | |||
119 | struct netup_dma dma[2]; | 128 | struct netup_dma dma[2]; |
120 | struct netup_ci_state ci[2]; | 129 | struct netup_ci_state ci[2]; |
121 | struct netup_spi *spi; | 130 | struct netup_spi *spi; |
131 | enum netup_hw_rev rev; | ||
122 | }; | 132 | }; |
123 | 133 | ||
124 | int netup_i2c_register(struct netup_unidvb_dev *ndev); | 134 | int netup_i2c_register(struct netup_unidvb_dev *ndev); |
diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb_ci.c b/drivers/media/pci/netup_unidvb/netup_unidvb_ci.c index f46ffac66ee9..f535270c2116 100644 --- a/drivers/media/pci/netup_unidvb/netup_unidvb_ci.c +++ b/drivers/media/pci/netup_unidvb/netup_unidvb_ci.c | |||
@@ -147,7 +147,7 @@ static int netup_unidvb_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221, | |||
147 | { | 147 | { |
148 | struct netup_ci_state *state = en50221->data; | 148 | struct netup_ci_state *state = en50221->data; |
149 | struct netup_unidvb_dev *dev = state->dev; | 149 | struct netup_unidvb_dev *dev = state->dev; |
150 | u8 val = *((u8 __force *)state->membase8_io + addr); | 150 | u8 val = *((u8 __force *)state->membase8_config + addr); |
151 | 151 | ||
152 | dev_dbg(&dev->pci_dev->dev, | 152 | dev_dbg(&dev->pci_dev->dev, |
153 | "%s(): addr=0x%x val=0x%x\n", __func__, addr, val); | 153 | "%s(): addr=0x%x val=0x%x\n", __func__, addr, val); |
@@ -162,7 +162,7 @@ static int netup_unidvb_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221, | |||
162 | 162 | ||
163 | dev_dbg(&dev->pci_dev->dev, | 163 | dev_dbg(&dev->pci_dev->dev, |
164 | "%s(): addr=0x%x data=0x%x\n", __func__, addr, data); | 164 | "%s(): addr=0x%x data=0x%x\n", __func__, addr, data); |
165 | *((u8 __force *)state->membase8_io + addr) = data; | 165 | *((u8 __force *)state->membase8_config + addr) = data; |
166 | return 0; | 166 | return 0; |
167 | } | 167 | } |
168 | 168 | ||
diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c index 2b667b315913..d278d4e151a0 100644 --- a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c +++ b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include "cxd2841er.h" | 34 | #include "cxd2841er.h" |
35 | #include "horus3a.h" | 35 | #include "horus3a.h" |
36 | #include "ascot2e.h" | 36 | #include "ascot2e.h" |
37 | #include "helene.h" | ||
37 | #include "lnbh25.h" | 38 | #include "lnbh25.h" |
38 | 39 | ||
39 | static int spi_enable; | 40 | static int spi_enable; |
@@ -120,7 +121,8 @@ static int netup_unidvb_tuner_ctrl(void *priv, int is_dvb_tc); | |||
120 | static void netup_unidvb_queue_cleanup(struct netup_dma *dma); | 121 | static void netup_unidvb_queue_cleanup(struct netup_dma *dma); |
121 | 122 | ||
122 | static struct cxd2841er_config demod_config = { | 123 | static struct cxd2841er_config demod_config = { |
123 | .i2c_addr = 0xc8 | 124 | .i2c_addr = 0xc8, |
125 | .xtal = SONY_XTAL_24000 | ||
124 | }; | 126 | }; |
125 | 127 | ||
126 | static struct horus3a_config horus3a_conf = { | 128 | static struct horus3a_config horus3a_conf = { |
@@ -134,6 +136,12 @@ static struct ascot2e_config ascot2e_conf = { | |||
134 | .set_tuner_callback = netup_unidvb_tuner_ctrl | 136 | .set_tuner_callback = netup_unidvb_tuner_ctrl |
135 | }; | 137 | }; |
136 | 138 | ||
139 | static struct helene_config helene_conf = { | ||
140 | .i2c_address = 0xc0, | ||
141 | .xtal = SONY_HELENE_XTAL_24000, | ||
142 | .set_tuner_callback = netup_unidvb_tuner_ctrl | ||
143 | }; | ||
144 | |||
137 | static struct lnbh25_config lnbh25_conf = { | 145 | static struct lnbh25_config lnbh25_conf = { |
138 | .i2c_address = 0x10, | 146 | .i2c_address = 0x10, |
139 | .data2_config = LNBH25_TEN | LNBH25_EXTM | 147 | .data2_config = LNBH25_TEN | LNBH25_EXTM |
@@ -152,6 +160,11 @@ static int netup_unidvb_tuner_ctrl(void *priv, int is_dvb_tc) | |||
152 | __func__, dma->num, is_dvb_tc); | 160 | __func__, dma->num, is_dvb_tc); |
153 | reg = readb(ndev->bmmio0 + GPIO_REG_IO); | 161 | reg = readb(ndev->bmmio0 + GPIO_REG_IO); |
154 | mask = (dma->num == 0) ? GPIO_RFA_CTL : GPIO_RFB_CTL; | 162 | mask = (dma->num == 0) ? GPIO_RFA_CTL : GPIO_RFB_CTL; |
163 | |||
164 | /* inverted tuner control in hw rev. 1.4 */ | ||
165 | if (ndev->rev == NETUP_HW_REV_1_4) | ||
166 | is_dvb_tc = !is_dvb_tc; | ||
167 | |||
155 | if (!is_dvb_tc) | 168 | if (!is_dvb_tc) |
156 | reg |= mask; | 169 | reg |= mask; |
157 | else | 170 | else |
@@ -372,7 +385,15 @@ static int netup_unidvb_queue_init(struct netup_dma *dma, | |||
372 | static int netup_unidvb_dvb_init(struct netup_unidvb_dev *ndev, | 385 | static int netup_unidvb_dvb_init(struct netup_unidvb_dev *ndev, |
373 | int num) | 386 | int num) |
374 | { | 387 | { |
375 | struct vb2_dvb_frontend *fe0, *fe1, *fe2; | 388 | int fe_count = 2; |
389 | int i = 0; | ||
390 | struct vb2_dvb_frontend *fes[2]; | ||
391 | u8 fe_name[32]; | ||
392 | |||
393 | if (ndev->rev == NETUP_HW_REV_1_3) | ||
394 | demod_config.xtal = SONY_XTAL_20500; | ||
395 | else | ||
396 | demod_config.xtal = SONY_XTAL_24000; | ||
376 | 397 | ||
377 | if (num < 0 || num > 1) { | 398 | if (num < 0 || num > 1) { |
378 | dev_dbg(&ndev->pci_dev->dev, | 399 | dev_dbg(&ndev->pci_dev->dev, |
@@ -381,84 +402,96 @@ static int netup_unidvb_dvb_init(struct netup_unidvb_dev *ndev, | |||
381 | } | 402 | } |
382 | mutex_init(&ndev->frontends[num].lock); | 403 | mutex_init(&ndev->frontends[num].lock); |
383 | INIT_LIST_HEAD(&ndev->frontends[num].felist); | 404 | INIT_LIST_HEAD(&ndev->frontends[num].felist); |
384 | if (vb2_dvb_alloc_frontend(&ndev->frontends[num], 1) == NULL || | 405 | |
385 | vb2_dvb_alloc_frontend( | 406 | for (i = 0; i < fe_count; i++) { |
386 | &ndev->frontends[num], 2) == NULL || | 407 | if (vb2_dvb_alloc_frontend(&ndev->frontends[num], i+1) |
387 | vb2_dvb_alloc_frontend( | 408 | == NULL) { |
388 | &ndev->frontends[num], 3) == NULL) { | 409 | dev_err(&ndev->pci_dev->dev, |
389 | dev_dbg(&ndev->pci_dev->dev, | 410 | "%s(): unable to allocate vb2_dvb_frontend\n", |
390 | "%s(): unable to allocate vb2_dvb_frontend\n", | 411 | __func__); |
391 | __func__); | 412 | return -ENOMEM; |
392 | return -ENOMEM; | 413 | } |
393 | } | 414 | } |
394 | fe0 = vb2_dvb_get_frontend(&ndev->frontends[num], 1); | 415 | |
395 | fe1 = vb2_dvb_get_frontend(&ndev->frontends[num], 2); | 416 | for (i = 0; i < fe_count; i++) { |
396 | fe2 = vb2_dvb_get_frontend(&ndev->frontends[num], 3); | 417 | fes[i] = vb2_dvb_get_frontend(&ndev->frontends[num], i+1); |
397 | if (fe0 == NULL || fe1 == NULL || fe2 == NULL) { | 418 | if (fes[i] == NULL) { |
398 | dev_dbg(&ndev->pci_dev->dev, | 419 | dev_err(&ndev->pci_dev->dev, |
399 | "%s(): frontends has not been allocated\n", __func__); | 420 | "%s(): frontends has not been allocated\n", |
400 | return -EINVAL; | 421 | __func__); |
422 | return -EINVAL; | ||
423 | } | ||
424 | } | ||
425 | |||
426 | for (i = 0; i < fe_count; i++) { | ||
427 | netup_unidvb_queue_init(&ndev->dma[num], &fes[i]->dvb.dvbq); | ||
428 | snprintf(fe_name, sizeof(fe_name), "netup_fe%d", i); | ||
429 | fes[i]->dvb.name = fe_name; | ||
401 | } | 430 | } |
402 | netup_unidvb_queue_init(&ndev->dma[num], &fe0->dvb.dvbq); | 431 | |
403 | netup_unidvb_queue_init(&ndev->dma[num], &fe1->dvb.dvbq); | 432 | fes[0]->dvb.frontend = dvb_attach(cxd2841er_attach_s, |
404 | netup_unidvb_queue_init(&ndev->dma[num], &fe2->dvb.dvbq); | ||
405 | fe0->dvb.name = "netup_fe0"; | ||
406 | fe1->dvb.name = "netup_fe1"; | ||
407 | fe2->dvb.name = "netup_fe2"; | ||
408 | fe0->dvb.frontend = dvb_attach(cxd2841er_attach_s, | ||
409 | &demod_config, &ndev->i2c[num].adap); | 433 | &demod_config, &ndev->i2c[num].adap); |
410 | if (fe0->dvb.frontend == NULL) { | 434 | if (fes[0]->dvb.frontend == NULL) { |
411 | dev_dbg(&ndev->pci_dev->dev, | 435 | dev_dbg(&ndev->pci_dev->dev, |
412 | "%s(): unable to attach DVB-S/S2 frontend\n", | 436 | "%s(): unable to attach DVB-S/S2 frontend\n", |
413 | __func__); | 437 | __func__); |
414 | goto frontend_detach; | 438 | goto frontend_detach; |
415 | } | 439 | } |
416 | horus3a_conf.set_tuner_priv = &ndev->dma[num]; | 440 | |
417 | if (!dvb_attach(horus3a_attach, fe0->dvb.frontend, | 441 | if (ndev->rev == NETUP_HW_REV_1_3) { |
418 | &horus3a_conf, &ndev->i2c[num].adap)) { | 442 | horus3a_conf.set_tuner_priv = &ndev->dma[num]; |
419 | dev_dbg(&ndev->pci_dev->dev, | 443 | if (!dvb_attach(horus3a_attach, fes[0]->dvb.frontend, |
420 | "%s(): unable to attach DVB-S/S2 tuner frontend\n", | 444 | &horus3a_conf, &ndev->i2c[num].adap)) { |
421 | __func__); | 445 | dev_dbg(&ndev->pci_dev->dev, |
422 | goto frontend_detach; | 446 | "%s(): unable to attach HORUS3A DVB-S/S2 tuner frontend\n", |
447 | __func__); | ||
448 | goto frontend_detach; | ||
449 | } | ||
450 | } else { | ||
451 | helene_conf.set_tuner_priv = &ndev->dma[num]; | ||
452 | if (!dvb_attach(helene_attach_s, fes[0]->dvb.frontend, | ||
453 | &helene_conf, &ndev->i2c[num].adap)) { | ||
454 | dev_err(&ndev->pci_dev->dev, | ||
455 | "%s(): unable to attach HELENE DVB-S/S2 tuner frontend\n", | ||
456 | __func__); | ||
457 | goto frontend_detach; | ||
458 | } | ||
423 | } | 459 | } |
424 | if (!dvb_attach(lnbh25_attach, fe0->dvb.frontend, | 460 | |
461 | if (!dvb_attach(lnbh25_attach, fes[0]->dvb.frontend, | ||
425 | &lnbh25_conf, &ndev->i2c[num].adap)) { | 462 | &lnbh25_conf, &ndev->i2c[num].adap)) { |
426 | dev_dbg(&ndev->pci_dev->dev, | 463 | dev_dbg(&ndev->pci_dev->dev, |
427 | "%s(): unable to attach SEC frontend\n", __func__); | 464 | "%s(): unable to attach SEC frontend\n", __func__); |
428 | goto frontend_detach; | 465 | goto frontend_detach; |
429 | } | 466 | } |
467 | |||
430 | /* DVB-T/T2 frontend */ | 468 | /* DVB-T/T2 frontend */ |
431 | fe1->dvb.frontend = dvb_attach(cxd2841er_attach_t, | 469 | fes[1]->dvb.frontend = dvb_attach(cxd2841er_attach_t_c, |
432 | &demod_config, &ndev->i2c[num].adap); | 470 | &demod_config, &ndev->i2c[num].adap); |
433 | if (fe1->dvb.frontend == NULL) { | 471 | if (fes[1]->dvb.frontend == NULL) { |
434 | dev_dbg(&ndev->pci_dev->dev, | ||
435 | "%s(): unable to attach DVB-T frontend\n", __func__); | ||
436 | goto frontend_detach; | ||
437 | } | ||
438 | fe1->dvb.frontend->id = 1; | ||
439 | ascot2e_conf.set_tuner_priv = &ndev->dma[num]; | ||
440 | if (!dvb_attach(ascot2e_attach, fe1->dvb.frontend, | ||
441 | &ascot2e_conf, &ndev->i2c[num].adap)) { | ||
442 | dev_dbg(&ndev->pci_dev->dev, | ||
443 | "%s(): unable to attach DVB-T tuner frontend\n", | ||
444 | __func__); | ||
445 | goto frontend_detach; | ||
446 | } | ||
447 | /* DVB-C/C2 frontend */ | ||
448 | fe2->dvb.frontend = dvb_attach(cxd2841er_attach_c, | ||
449 | &demod_config, &ndev->i2c[num].adap); | ||
450 | if (fe2->dvb.frontend == NULL) { | ||
451 | dev_dbg(&ndev->pci_dev->dev, | 472 | dev_dbg(&ndev->pci_dev->dev, |
452 | "%s(): unable to attach DVB-C frontend\n", __func__); | 473 | "%s(): unable to attach Ter frontend\n", __func__); |
453 | goto frontend_detach; | 474 | goto frontend_detach; |
454 | } | 475 | } |
455 | fe2->dvb.frontend->id = 2; | 476 | fes[1]->dvb.frontend->id = 1; |
456 | if (!dvb_attach(ascot2e_attach, fe2->dvb.frontend, | 477 | if (ndev->rev == NETUP_HW_REV_1_3) { |
457 | &ascot2e_conf, &ndev->i2c[num].adap)) { | 478 | ascot2e_conf.set_tuner_priv = &ndev->dma[num]; |
458 | dev_dbg(&ndev->pci_dev->dev, | 479 | if (!dvb_attach(ascot2e_attach, fes[1]->dvb.frontend, |
459 | "%s(): unable to attach DVB-T/C tuner frontend\n", | 480 | &ascot2e_conf, &ndev->i2c[num].adap)) { |
460 | __func__); | 481 | dev_dbg(&ndev->pci_dev->dev, |
461 | goto frontend_detach; | 482 | "%s(): unable to attach Ter tuner frontend\n", |
483 | __func__); | ||
484 | goto frontend_detach; | ||
485 | } | ||
486 | } else { | ||
487 | helene_conf.set_tuner_priv = &ndev->dma[num]; | ||
488 | if (!dvb_attach(helene_attach, fes[1]->dvb.frontend, | ||
489 | &helene_conf, &ndev->i2c[num].adap)) { | ||
490 | dev_err(&ndev->pci_dev->dev, | ||
491 | "%s(): unable to attach HELENE Ter tuner frontend\n", | ||
492 | __func__); | ||
493 | goto frontend_detach; | ||
494 | } | ||
462 | } | 495 | } |
463 | 496 | ||
464 | if (vb2_dvb_register_bus(&ndev->frontends[num], | 497 | if (vb2_dvb_register_bus(&ndev->frontends[num], |
@@ -730,7 +763,7 @@ static int netup_unidvb_request_mmio(struct pci_dev *pci_dev) | |||
730 | static int netup_unidvb_request_modules(struct device *dev) | 763 | static int netup_unidvb_request_modules(struct device *dev) |
731 | { | 764 | { |
732 | static const char * const modules[] = { | 765 | static const char * const modules[] = { |
733 | "lnbh25", "ascot2e", "horus3a", "cxd2841er", NULL | 766 | "lnbh25", "ascot2e", "horus3a", "cxd2841er", "helene", NULL |
734 | }; | 767 | }; |
735 | const char * const *curr_mod = modules; | 768 | const char * const *curr_mod = modules; |
736 | int err; | 769 | int err; |
@@ -774,6 +807,16 @@ static int netup_unidvb_initdev(struct pci_dev *pci_dev, | |||
774 | if (!ndev) | 807 | if (!ndev) |
775 | goto dev_alloc_err; | 808 | goto dev_alloc_err; |
776 | 809 | ||
810 | /* detect hardware revision */ | ||
811 | if (pci_dev->device == NETUP_HW_REV_1_3) | ||
812 | ndev->rev = NETUP_HW_REV_1_3; | ||
813 | else | ||
814 | ndev->rev = NETUP_HW_REV_1_4; | ||
815 | |||
816 | dev_info(&pci_dev->dev, | ||
817 | "%s(): board (0x%x) hardware revision 0x%x\n", | ||
818 | __func__, pci_dev->device, ndev->rev); | ||
819 | |||
777 | ndev->old_fw = old_firmware; | 820 | ndev->old_fw = old_firmware; |
778 | ndev->wq = create_singlethread_workqueue(NETUP_UNIDVB_NAME); | 821 | ndev->wq = create_singlethread_workqueue(NETUP_UNIDVB_NAME); |
779 | if (!ndev->wq) { | 822 | if (!ndev->wq) { |
@@ -972,7 +1015,8 @@ static void netup_unidvb_finidev(struct pci_dev *pci_dev) | |||
972 | 1015 | ||
973 | 1016 | ||
974 | static struct pci_device_id netup_unidvb_pci_tbl[] = { | 1017 | static struct pci_device_id netup_unidvb_pci_tbl[] = { |
975 | { PCI_DEVICE(0x1b55, 0x18f6) }, | 1018 | { PCI_DEVICE(0x1b55, 0x18f6) }, /* hw rev. 1.3 */ |
1019 | { PCI_DEVICE(0x1b55, 0x18f7) }, /* hw rev. 1.4 */ | ||
976 | { 0, } | 1020 | { 0, } |
977 | }; | 1021 | }; |
978 | MODULE_DEVICE_TABLE(pci, netup_unidvb_pci_tbl); | 1022 | MODULE_DEVICE_TABLE(pci, netup_unidvb_pci_tbl); |
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 84e041c0a70e..9d0a3ffe36d2 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig | |||
@@ -110,6 +110,7 @@ source "drivers/media/platform/exynos4-is/Kconfig" | |||
110 | source "drivers/media/platform/s5p-tv/Kconfig" | 110 | source "drivers/media/platform/s5p-tv/Kconfig" |
111 | source "drivers/media/platform/am437x/Kconfig" | 111 | source "drivers/media/platform/am437x/Kconfig" |
112 | source "drivers/media/platform/xilinx/Kconfig" | 112 | source "drivers/media/platform/xilinx/Kconfig" |
113 | source "drivers/media/platform/rcar-vin/Kconfig" | ||
113 | 114 | ||
114 | config VIDEO_TI_CAL | 115 | config VIDEO_TI_CAL |
115 | tristate "TI CAL (Camera Adaptation Layer) driver" | 116 | tristate "TI CAL (Camera Adaptation Layer) driver" |
@@ -247,10 +248,24 @@ config VIDEO_RENESAS_JPU | |||
247 | To compile this driver as a module, choose M here: the module | 248 | To compile this driver as a module, choose M here: the module |
248 | will be called rcar_jpu. | 249 | will be called rcar_jpu. |
249 | 250 | ||
251 | config VIDEO_RENESAS_FCP | ||
252 | tristate "Renesas Frame Compression Processor" | ||
253 | depends on ARCH_RENESAS || COMPILE_TEST | ||
254 | depends on OF | ||
255 | ---help--- | ||
256 | This is a driver for the Renesas Frame Compression Processor (FCP). | ||
257 | The FCP is a companion module of video processing modules in the | ||
258 | Renesas R-Car Gen3 SoCs. It handles memory access for the codec, | ||
259 | VSP and FDP modules. | ||
260 | |||
261 | To compile this driver as a module, choose M here: the module | ||
262 | will be called rcar-fcp. | ||
263 | |||
250 | config VIDEO_RENESAS_VSP1 | 264 | config VIDEO_RENESAS_VSP1 |
251 | tristate "Renesas VSP1 Video Processing Engine" | 265 | tristate "Renesas VSP1 Video Processing Engine" |
252 | depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA | 266 | depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA |
253 | depends on (ARCH_RENESAS && OF) || COMPILE_TEST | 267 | depends on (ARCH_RENESAS && OF) || COMPILE_TEST |
268 | depends on !ARM64 || VIDEO_RENESAS_FCP | ||
254 | select VIDEOBUF2_DMA_CONTIG | 269 | select VIDEOBUF2_DMA_CONTIG |
255 | ---help--- | 270 | ---help--- |
256 | This is a V4L2 driver for the Renesas VSP1 video processing engine. | 271 | This is a V4L2 driver for the Renesas VSP1 video processing engine. |
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index bbb7bd1eb268..c83800a74a2d 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile | |||
@@ -46,6 +46,7 @@ obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o | |||
46 | 46 | ||
47 | obj-$(CONFIG_SOC_CAMERA) += soc_camera/ | 47 | obj-$(CONFIG_SOC_CAMERA) += soc_camera/ |
48 | 48 | ||
49 | obj-$(CONFIG_VIDEO_RENESAS_FCP) += rcar-fcp.o | ||
49 | obj-$(CONFIG_VIDEO_RENESAS_JPU) += rcar_jpu.o | 50 | obj-$(CONFIG_VIDEO_RENESAS_JPU) += rcar_jpu.o |
50 | obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1/ | 51 | obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1/ |
51 | 52 | ||
@@ -55,4 +56,6 @@ obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x/ | |||
55 | 56 | ||
56 | obj-$(CONFIG_VIDEO_XILINX) += xilinx/ | 57 | obj-$(CONFIG_VIDEO_XILINX) += xilinx/ |
57 | 58 | ||
59 | obj-$(CONFIG_VIDEO_RCAR_VIN) += rcar-vin/ | ||
60 | |||
58 | ccflags-y += -I$(srctree)/drivers/media/i2c | 61 | ccflags-y += -I$(srctree)/drivers/media/i2c |
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index c04973669a47..c9d2009c2476 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c | |||
@@ -1124,6 +1124,7 @@ static int gsc_probe(struct platform_device *pdev) | |||
1124 | goto err_m2m; | 1124 | goto err_m2m; |
1125 | 1125 | ||
1126 | /* Initialize continious memory allocator */ | 1126 | /* Initialize continious memory allocator */ |
1127 | vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); | ||
1127 | gsc->alloc_ctx = vb2_dma_contig_init_ctx(dev); | 1128 | gsc->alloc_ctx = vb2_dma_contig_init_ctx(dev); |
1128 | if (IS_ERR(gsc->alloc_ctx)) { | 1129 | if (IS_ERR(gsc->alloc_ctx)) { |
1129 | ret = PTR_ERR(gsc->alloc_ctx); | 1130 | ret = PTR_ERR(gsc->alloc_ctx); |
@@ -1153,6 +1154,7 @@ static int gsc_remove(struct platform_device *pdev) | |||
1153 | v4l2_device_unregister(&gsc->v4l2_dev); | 1154 | v4l2_device_unregister(&gsc->v4l2_dev); |
1154 | 1155 | ||
1155 | vb2_dma_contig_cleanup_ctx(gsc->alloc_ctx); | 1156 | vb2_dma_contig_cleanup_ctx(gsc->alloc_ctx); |
1157 | vb2_dma_contig_clear_max_seg_size(&pdev->dev); | ||
1156 | pm_runtime_disable(&pdev->dev); | 1158 | pm_runtime_disable(&pdev->dev); |
1157 | gsc_clk_put(gsc); | 1159 | gsc_clk_put(gsc); |
1158 | 1160 | ||
diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c index b1c1cea82a27..368f44f24d4c 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.c +++ b/drivers/media/platform/exynos4-is/fimc-core.c | |||
@@ -1019,6 +1019,7 @@ static int fimc_probe(struct platform_device *pdev) | |||
1019 | } | 1019 | } |
1020 | 1020 | ||
1021 | /* Initialize contiguous memory allocator */ | 1021 | /* Initialize contiguous memory allocator */ |
1022 | vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); | ||
1022 | fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev); | 1023 | fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev); |
1023 | if (IS_ERR(fimc->alloc_ctx)) { | 1024 | if (IS_ERR(fimc->alloc_ctx)) { |
1024 | ret = PTR_ERR(fimc->alloc_ctx); | 1025 | ret = PTR_ERR(fimc->alloc_ctx); |
@@ -1124,6 +1125,7 @@ static int fimc_remove(struct platform_device *pdev) | |||
1124 | 1125 | ||
1125 | fimc_unregister_capture_subdev(fimc); | 1126 | fimc_unregister_capture_subdev(fimc); |
1126 | vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx); | 1127 | vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx); |
1128 | vb2_dma_contig_clear_max_seg_size(&pdev->dev); | ||
1127 | 1129 | ||
1128 | clk_disable(fimc->clock[CLK_BUS]); | 1130 | clk_disable(fimc->clock[CLK_BUS]); |
1129 | fimc_clk_put(fimc); | 1131 | fimc_clk_put(fimc); |
diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c index 979c388ebf60..bd98b56318b7 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.c +++ b/drivers/media/platform/exynos4-is/fimc-is.c | |||
@@ -847,6 +847,7 @@ static int fimc_is_probe(struct platform_device *pdev) | |||
847 | if (ret < 0) | 847 | if (ret < 0) |
848 | goto err_pm; | 848 | goto err_pm; |
849 | 849 | ||
850 | vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); | ||
850 | is->alloc_ctx = vb2_dma_contig_init_ctx(dev); | 851 | is->alloc_ctx = vb2_dma_contig_init_ctx(dev); |
851 | if (IS_ERR(is->alloc_ctx)) { | 852 | if (IS_ERR(is->alloc_ctx)) { |
852 | ret = PTR_ERR(is->alloc_ctx); | 853 | ret = PTR_ERR(is->alloc_ctx); |
@@ -940,6 +941,7 @@ static int fimc_is_remove(struct platform_device *pdev) | |||
940 | free_irq(is->irq, is); | 941 | free_irq(is->irq, is); |
941 | fimc_is_unregister_subdevs(is); | 942 | fimc_is_unregister_subdevs(is); |
942 | vb2_dma_contig_cleanup_ctx(is->alloc_ctx); | 943 | vb2_dma_contig_cleanup_ctx(is->alloc_ctx); |
944 | vb2_dma_contig_clear_max_seg_size(dev); | ||
943 | fimc_is_put_clocks(is); | 945 | fimc_is_put_clocks(is); |
944 | fimc_is_debugfs_remove(is); | 946 | fimc_is_debugfs_remove(is); |
945 | release_firmware(is->fw.f_w); | 947 | release_firmware(is->fw.f_w); |
diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index dc1b929f7a33..27cb620cb714 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c | |||
@@ -1551,6 +1551,7 @@ static int fimc_lite_probe(struct platform_device *pdev) | |||
1551 | goto err_sd; | 1551 | goto err_sd; |
1552 | } | 1552 | } |
1553 | 1553 | ||
1554 | vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); | ||
1554 | fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev); | 1555 | fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev); |
1555 | if (IS_ERR(fimc->alloc_ctx)) { | 1556 | if (IS_ERR(fimc->alloc_ctx)) { |
1556 | ret = PTR_ERR(fimc->alloc_ctx); | 1557 | ret = PTR_ERR(fimc->alloc_ctx); |
@@ -1652,6 +1653,7 @@ static int fimc_lite_remove(struct platform_device *pdev) | |||
1652 | pm_runtime_set_suspended(dev); | 1653 | pm_runtime_set_suspended(dev); |
1653 | fimc_lite_unregister_capture_subdev(fimc); | 1654 | fimc_lite_unregister_capture_subdev(fimc); |
1654 | vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx); | 1655 | vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx); |
1656 | vb2_dma_contig_clear_max_seg_size(dev); | ||
1655 | fimc_lite_clk_put(fimc); | 1657 | fimc_lite_clk_put(fimc); |
1656 | 1658 | ||
1657 | dev_info(dev, "Driver unloaded\n"); | 1659 | dev_info(dev, "Driver unloaded\n"); |
diff --git a/drivers/media/platform/rcar-fcp.c b/drivers/media/platform/rcar-fcp.c new file mode 100644 index 000000000000..6a7bcc3028b1 --- /dev/null +++ b/drivers/media/platform/rcar-fcp.c | |||
@@ -0,0 +1,181 @@ | |||
1 | /* | ||
2 | * rcar-fcp.c -- R-Car Frame Compression Processor Driver | ||
3 | * | ||
4 | * Copyright (C) 2016 Renesas Electronics Corporation | ||
5 | * | ||
6 | * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/device.h> | ||
15 | #include <linux/list.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/mutex.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <linux/pm_runtime.h> | ||
20 | #include <linux/slab.h> | ||
21 | |||
22 | #include <media/rcar-fcp.h> | ||
23 | |||
24 | struct rcar_fcp_device { | ||
25 | struct list_head list; | ||
26 | struct device *dev; | ||
27 | }; | ||
28 | |||
29 | static LIST_HEAD(fcp_devices); | ||
30 | static DEFINE_MUTEX(fcp_lock); | ||
31 | |||
32 | /* ----------------------------------------------------------------------------- | ||
33 | * Public API | ||
34 | */ | ||
35 | |||
36 | /** | ||
37 | * rcar_fcp_get - Find and acquire a reference to an FCP instance | ||
38 | * @np: Device node of the FCP instance | ||
39 | * | ||
40 | * Search the list of registered FCP instances for the instance corresponding to | ||
41 | * the given device node. | ||
42 | * | ||
43 | * Return a pointer to the FCP instance, or an ERR_PTR if the instance can't be | ||
44 | * found. | ||
45 | */ | ||
46 | struct rcar_fcp_device *rcar_fcp_get(const struct device_node *np) | ||
47 | { | ||
48 | struct rcar_fcp_device *fcp; | ||
49 | |||
50 | mutex_lock(&fcp_lock); | ||
51 | |||
52 | list_for_each_entry(fcp, &fcp_devices, list) { | ||
53 | if (fcp->dev->of_node != np) | ||
54 | continue; | ||
55 | |||
56 | /* | ||
57 | * Make sure the module won't be unloaded behind our back. This | ||
58 | * is a poor man's safety net, the module should really not be | ||
59 | * unloaded while FCP users can be active. | ||
60 | */ | ||
61 | if (!try_module_get(fcp->dev->driver->owner)) | ||
62 | fcp = NULL; | ||
63 | |||
64 | goto done; | ||
65 | } | ||
66 | |||
67 | fcp = ERR_PTR(-EPROBE_DEFER); | ||
68 | |||
69 | done: | ||
70 | mutex_unlock(&fcp_lock); | ||
71 | return fcp; | ||
72 | } | ||
73 | EXPORT_SYMBOL_GPL(rcar_fcp_get); | ||
74 | |||
75 | /** | ||
76 | * rcar_fcp_put - Release a reference to an FCP instance | ||
77 | * @fcp: The FCP instance | ||
78 | * | ||
79 | * Release the FCP instance acquired by a call to rcar_fcp_get(). | ||
80 | */ | ||
81 | void rcar_fcp_put(struct rcar_fcp_device *fcp) | ||
82 | { | ||
83 | if (fcp) | ||
84 | module_put(fcp->dev->driver->owner); | ||
85 | } | ||
86 | EXPORT_SYMBOL_GPL(rcar_fcp_put); | ||
87 | |||
88 | /** | ||
89 | * rcar_fcp_enable - Enable an FCP | ||
90 | * @fcp: The FCP instance | ||
91 | * | ||
92 | * Before any memory access through an FCP is performed by a module, the FCP | ||
93 | * must be enabled by a call to this function. The enable calls are reference | ||
94 | * counted, each successful call must be followed by one rcar_fcp_disable() | ||
95 | * call when no more memory transfer can occur through the FCP. | ||
96 | * | ||
97 | * Return 0 on success or a negative error code if an error occurs. The enable | ||
98 | * reference count isn't increased when this function returns an error. | ||
99 | */ | ||
100 | int rcar_fcp_enable(struct rcar_fcp_device *fcp) | ||
101 | { | ||
102 | if (!fcp) | ||
103 | return 0; | ||
104 | |||
105 | return pm_runtime_get_sync(fcp->dev); | ||
106 | } | ||
107 | EXPORT_SYMBOL_GPL(rcar_fcp_enable); | ||
108 | |||
109 | /** | ||
110 | * rcar_fcp_disable - Disable an FCP | ||
111 | * @fcp: The FCP instance | ||
112 | * | ||
113 | * This function is the counterpart of rcar_fcp_enable(). As enable calls are | ||
114 | * reference counted a disable call may not disable the FCP synchronously. | ||
115 | */ | ||
116 | void rcar_fcp_disable(struct rcar_fcp_device *fcp) | ||
117 | { | ||
118 | if (fcp) | ||
119 | pm_runtime_put(fcp->dev); | ||
120 | } | ||
121 | EXPORT_SYMBOL_GPL(rcar_fcp_disable); | ||
122 | |||
123 | /* ----------------------------------------------------------------------------- | ||
124 | * Platform Driver | ||
125 | */ | ||
126 | |||
127 | static int rcar_fcp_probe(struct platform_device *pdev) | ||
128 | { | ||
129 | struct rcar_fcp_device *fcp; | ||
130 | |||
131 | fcp = devm_kzalloc(&pdev->dev, sizeof(*fcp), GFP_KERNEL); | ||
132 | if (fcp == NULL) | ||
133 | return -ENOMEM; | ||
134 | |||
135 | fcp->dev = &pdev->dev; | ||
136 | |||
137 | pm_runtime_enable(&pdev->dev); | ||
138 | |||
139 | mutex_lock(&fcp_lock); | ||
140 | list_add_tail(&fcp->list, &fcp_devices); | ||
141 | mutex_unlock(&fcp_lock); | ||
142 | |||
143 | platform_set_drvdata(pdev, fcp); | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | static int rcar_fcp_remove(struct platform_device *pdev) | ||
149 | { | ||
150 | struct rcar_fcp_device *fcp = platform_get_drvdata(pdev); | ||
151 | |||
152 | mutex_lock(&fcp_lock); | ||
153 | list_del(&fcp->list); | ||
154 | mutex_unlock(&fcp_lock); | ||
155 | |||
156 | pm_runtime_disable(&pdev->dev); | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static const struct of_device_id rcar_fcp_of_match[] = { | ||
162 | { .compatible = "renesas,fcpv" }, | ||
163 | { }, | ||
164 | }; | ||
165 | |||
166 | static struct platform_driver rcar_fcp_platform_driver = { | ||
167 | .probe = rcar_fcp_probe, | ||
168 | .remove = rcar_fcp_remove, | ||
169 | .driver = { | ||
170 | .name = "rcar-fcp", | ||
171 | .of_match_table = rcar_fcp_of_match, | ||
172 | .suppress_bind_attrs = true, | ||
173 | }, | ||
174 | }; | ||
175 | |||
176 | module_platform_driver(rcar_fcp_platform_driver); | ||
177 | |||
178 | MODULE_ALIAS("rcar-fcp"); | ||
179 | MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); | ||
180 | MODULE_DESCRIPTION("Renesas FCP Driver"); | ||
181 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/platform/rcar-vin/Kconfig b/drivers/media/platform/rcar-vin/Kconfig new file mode 100644 index 000000000000..b2ff2d4e8bb1 --- /dev/null +++ b/drivers/media/platform/rcar-vin/Kconfig | |||
@@ -0,0 +1,11 @@ | |||
1 | config VIDEO_RCAR_VIN | ||
2 | tristate "R-Car Video Input (VIN) Driver" | ||
3 | depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && OF && HAS_DMA | ||
4 | depends on ARCH_RENESAS || COMPILE_TEST | ||
5 | select VIDEOBUF2_DMA_CONTIG | ||
6 | ---help--- | ||
7 | Support for Renesas R-Car Video Input (VIN) driver. | ||
8 | Supports R-Car Gen2 SoCs. | ||
9 | |||
10 | To compile this driver as a module, choose M here: the | ||
11 | module will be called rcar-vin. | ||
diff --git a/drivers/media/platform/rcar-vin/Makefile b/drivers/media/platform/rcar-vin/Makefile new file mode 100644 index 000000000000..48c5632c21dc --- /dev/null +++ b/drivers/media/platform/rcar-vin/Makefile | |||
@@ -0,0 +1,3 @@ | |||
1 | rcar-vin-objs = rcar-core.o rcar-dma.o rcar-v4l2.o | ||
2 | |||
3 | obj-$(CONFIG_VIDEO_RCAR_VIN) += rcar-vin.o | ||
diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c new file mode 100644 index 000000000000..4b2007b73463 --- /dev/null +++ b/drivers/media/platform/rcar-vin/rcar-core.c | |||
@@ -0,0 +1,334 @@ | |||
1 | /* | ||
2 | * Driver for Renesas R-Car VIN | ||
3 | * | ||
4 | * Copyright (C) 2016 Renesas Electronics Corp. | ||
5 | * Copyright (C) 2011-2013 Renesas Solutions Corp. | ||
6 | * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com> | ||
7 | * Copyright (C) 2008 Magnus Damm | ||
8 | * | ||
9 | * Based on the soc-camera rcar_vin driver | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/of.h> | ||
19 | #include <linux/of_device.h> | ||
20 | #include <linux/of_graph.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/pm_runtime.h> | ||
23 | |||
24 | #include <media/v4l2-of.h> | ||
25 | |||
26 | #include "rcar-vin.h" | ||
27 | |||
28 | /* ----------------------------------------------------------------------------- | ||
29 | * Async notifier | ||
30 | */ | ||
31 | |||
32 | #define notifier_to_vin(n) container_of(n, struct rvin_dev, notifier) | ||
33 | |||
34 | static int rvin_mbus_supported(struct rvin_dev *vin) | ||
35 | { | ||
36 | struct v4l2_subdev *sd; | ||
37 | struct v4l2_subdev_mbus_code_enum code = { | ||
38 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
39 | }; | ||
40 | |||
41 | sd = vin_to_source(vin); | ||
42 | |||
43 | code.index = 0; | ||
44 | while (!v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code)) { | ||
45 | code.index++; | ||
46 | switch (code.code) { | ||
47 | case MEDIA_BUS_FMT_YUYV8_1X16: | ||
48 | case MEDIA_BUS_FMT_YUYV8_2X8: | ||
49 | case MEDIA_BUS_FMT_YUYV10_2X10: | ||
50 | case MEDIA_BUS_FMT_RGB888_1X24: | ||
51 | vin->source.code = code.code; | ||
52 | vin_dbg(vin, "Found supported media bus format: %d\n", | ||
53 | vin->source.code); | ||
54 | return true; | ||
55 | default: | ||
56 | break; | ||
57 | } | ||
58 | } | ||
59 | |||
60 | return false; | ||
61 | } | ||
62 | |||
63 | static int rvin_graph_notify_complete(struct v4l2_async_notifier *notifier) | ||
64 | { | ||
65 | struct rvin_dev *vin = notifier_to_vin(notifier); | ||
66 | int ret; | ||
67 | |||
68 | ret = v4l2_device_register_subdev_nodes(&vin->v4l2_dev); | ||
69 | if (ret < 0) { | ||
70 | vin_err(vin, "Failed to register subdev nodes\n"); | ||
71 | return ret; | ||
72 | } | ||
73 | |||
74 | if (!rvin_mbus_supported(vin)) { | ||
75 | vin_err(vin, "No supported mediabus format found\n"); | ||
76 | return -EINVAL; | ||
77 | } | ||
78 | |||
79 | return rvin_v4l2_probe(vin); | ||
80 | } | ||
81 | |||
82 | static void rvin_graph_notify_unbind(struct v4l2_async_notifier *notifier, | ||
83 | struct v4l2_subdev *sd, | ||
84 | struct v4l2_async_subdev *asd) | ||
85 | { | ||
86 | struct rvin_dev *vin = notifier_to_vin(notifier); | ||
87 | |||
88 | rvin_v4l2_remove(vin); | ||
89 | } | ||
90 | |||
91 | static int rvin_graph_notify_bound(struct v4l2_async_notifier *notifier, | ||
92 | struct v4l2_subdev *subdev, | ||
93 | struct v4l2_async_subdev *asd) | ||
94 | { | ||
95 | struct rvin_dev *vin = notifier_to_vin(notifier); | ||
96 | |||
97 | vin_dbg(vin, "subdev %s bound\n", subdev->name); | ||
98 | |||
99 | vin->entity.entity = &subdev->entity; | ||
100 | vin->entity.subdev = subdev; | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | static int rvin_graph_parse(struct rvin_dev *vin, | ||
106 | struct device_node *node) | ||
107 | { | ||
108 | struct device_node *remote; | ||
109 | struct device_node *ep = NULL; | ||
110 | struct device_node *next; | ||
111 | int ret = 0; | ||
112 | |||
113 | while (1) { | ||
114 | next = of_graph_get_next_endpoint(node, ep); | ||
115 | if (!next) | ||
116 | break; | ||
117 | |||
118 | of_node_put(ep); | ||
119 | ep = next; | ||
120 | |||
121 | remote = of_graph_get_remote_port_parent(ep); | ||
122 | if (!remote) { | ||
123 | ret = -EINVAL; | ||
124 | break; | ||
125 | } | ||
126 | |||
127 | /* Skip entities that we have already processed. */ | ||
128 | if (remote == vin->dev->of_node) { | ||
129 | of_node_put(remote); | ||
130 | continue; | ||
131 | } | ||
132 | |||
133 | /* Remote node to connect */ | ||
134 | if (!vin->entity.node) { | ||
135 | vin->entity.node = remote; | ||
136 | vin->entity.asd.match_type = V4L2_ASYNC_MATCH_OF; | ||
137 | vin->entity.asd.match.of.node = remote; | ||
138 | ret++; | ||
139 | } | ||
140 | } | ||
141 | |||
142 | of_node_put(ep); | ||
143 | |||
144 | return ret; | ||
145 | } | ||
146 | |||
147 | static int rvin_graph_init(struct rvin_dev *vin) | ||
148 | { | ||
149 | struct v4l2_async_subdev **subdevs = NULL; | ||
150 | int ret; | ||
151 | |||
152 | /* Parse the graph to extract a list of subdevice DT nodes. */ | ||
153 | ret = rvin_graph_parse(vin, vin->dev->of_node); | ||
154 | if (ret < 0) { | ||
155 | vin_err(vin, "Graph parsing failed\n"); | ||
156 | goto done; | ||
157 | } | ||
158 | |||
159 | if (!ret) { | ||
160 | vin_err(vin, "No subdev found in graph\n"); | ||
161 | goto done; | ||
162 | } | ||
163 | |||
164 | if (ret != 1) { | ||
165 | vin_err(vin, "More then one subdev found in graph\n"); | ||
166 | goto done; | ||
167 | } | ||
168 | |||
169 | /* Register the subdevices notifier. */ | ||
170 | subdevs = devm_kzalloc(vin->dev, sizeof(*subdevs), GFP_KERNEL); | ||
171 | if (subdevs == NULL) { | ||
172 | ret = -ENOMEM; | ||
173 | goto done; | ||
174 | } | ||
175 | |||
176 | subdevs[0] = &vin->entity.asd; | ||
177 | |||
178 | vin->notifier.subdevs = subdevs; | ||
179 | vin->notifier.num_subdevs = 1; | ||
180 | vin->notifier.bound = rvin_graph_notify_bound; | ||
181 | vin->notifier.unbind = rvin_graph_notify_unbind; | ||
182 | vin->notifier.complete = rvin_graph_notify_complete; | ||
183 | |||
184 | ret = v4l2_async_notifier_register(&vin->v4l2_dev, &vin->notifier); | ||
185 | if (ret < 0) { | ||
186 | vin_err(vin, "Notifier registration failed\n"); | ||
187 | goto done; | ||
188 | } | ||
189 | |||
190 | ret = 0; | ||
191 | |||
192 | done: | ||
193 | if (ret < 0) { | ||
194 | v4l2_async_notifier_unregister(&vin->notifier); | ||
195 | of_node_put(vin->entity.node); | ||
196 | } | ||
197 | |||
198 | return ret; | ||
199 | } | ||
200 | |||
201 | /* ----------------------------------------------------------------------------- | ||
202 | * Platform Device Driver | ||
203 | */ | ||
204 | |||
205 | static const struct of_device_id rvin_of_id_table[] = { | ||
206 | { .compatible = "renesas,vin-r8a7794", .data = (void *)RCAR_GEN2 }, | ||
207 | { .compatible = "renesas,vin-r8a7793", .data = (void *)RCAR_GEN2 }, | ||
208 | { .compatible = "renesas,vin-r8a7791", .data = (void *)RCAR_GEN2 }, | ||
209 | { .compatible = "renesas,vin-r8a7790", .data = (void *)RCAR_GEN2 }, | ||
210 | { .compatible = "renesas,vin-r8a7779", .data = (void *)RCAR_H1 }, | ||
211 | { .compatible = "renesas,vin-r8a7778", .data = (void *)RCAR_M1 }, | ||
212 | { }, | ||
213 | }; | ||
214 | MODULE_DEVICE_TABLE(of, rvin_of_id_table); | ||
215 | |||
216 | static int rvin_parse_dt(struct rvin_dev *vin) | ||
217 | { | ||
218 | const struct of_device_id *match; | ||
219 | struct v4l2_of_endpoint ep; | ||
220 | struct device_node *np; | ||
221 | int ret; | ||
222 | |||
223 | match = of_match_device(of_match_ptr(rvin_of_id_table), vin->dev); | ||
224 | if (!match) | ||
225 | return -ENODEV; | ||
226 | |||
227 | vin->chip = (enum chip_id)match->data; | ||
228 | |||
229 | np = of_graph_get_next_endpoint(vin->dev->of_node, NULL); | ||
230 | if (!np) { | ||
231 | vin_err(vin, "Could not find endpoint\n"); | ||
232 | return -EINVAL; | ||
233 | } | ||
234 | |||
235 | ret = v4l2_of_parse_endpoint(np, &ep); | ||
236 | if (ret) { | ||
237 | vin_err(vin, "Could not parse endpoint\n"); | ||
238 | return ret; | ||
239 | } | ||
240 | |||
241 | of_node_put(np); | ||
242 | |||
243 | vin->mbus_cfg.type = ep.bus_type; | ||
244 | |||
245 | switch (vin->mbus_cfg.type) { | ||
246 | case V4L2_MBUS_PARALLEL: | ||
247 | vin->mbus_cfg.flags = ep.bus.parallel.flags; | ||
248 | break; | ||
249 | case V4L2_MBUS_BT656: | ||
250 | vin->mbus_cfg.flags = 0; | ||
251 | break; | ||
252 | default: | ||
253 | vin_err(vin, "Unknown media bus type\n"); | ||
254 | return -EINVAL; | ||
255 | } | ||
256 | |||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | static int rcar_vin_probe(struct platform_device *pdev) | ||
261 | { | ||
262 | struct rvin_dev *vin; | ||
263 | struct resource *mem; | ||
264 | int irq, ret; | ||
265 | |||
266 | vin = devm_kzalloc(&pdev->dev, sizeof(*vin), GFP_KERNEL); | ||
267 | if (!vin) | ||
268 | return -ENOMEM; | ||
269 | |||
270 | vin->dev = &pdev->dev; | ||
271 | |||
272 | ret = rvin_parse_dt(vin); | ||
273 | if (ret) | ||
274 | return ret; | ||
275 | |||
276 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
277 | if (mem == NULL) | ||
278 | return -EINVAL; | ||
279 | |||
280 | vin->base = devm_ioremap_resource(vin->dev, mem); | ||
281 | if (IS_ERR(vin->base)) | ||
282 | return PTR_ERR(vin->base); | ||
283 | |||
284 | irq = platform_get_irq(pdev, 0); | ||
285 | if (irq <= 0) | ||
286 | return ret; | ||
287 | |||
288 | ret = rvin_dma_probe(vin, irq); | ||
289 | if (ret) | ||
290 | return ret; | ||
291 | |||
292 | ret = rvin_graph_init(vin); | ||
293 | if (ret < 0) | ||
294 | goto error; | ||
295 | |||
296 | pm_suspend_ignore_children(&pdev->dev, true); | ||
297 | pm_runtime_enable(&pdev->dev); | ||
298 | |||
299 | platform_set_drvdata(pdev, vin); | ||
300 | |||
301 | return 0; | ||
302 | error: | ||
303 | rvin_dma_remove(vin); | ||
304 | |||
305 | return ret; | ||
306 | } | ||
307 | |||
308 | static int rcar_vin_remove(struct platform_device *pdev) | ||
309 | { | ||
310 | struct rvin_dev *vin = platform_get_drvdata(pdev); | ||
311 | |||
312 | pm_runtime_disable(&pdev->dev); | ||
313 | |||
314 | v4l2_async_notifier_unregister(&vin->notifier); | ||
315 | |||
316 | rvin_dma_remove(vin); | ||
317 | |||
318 | return 0; | ||
319 | } | ||
320 | |||
321 | static struct platform_driver rcar_vin_driver = { | ||
322 | .driver = { | ||
323 | .name = "rcar-vin", | ||
324 | .of_match_table = rvin_of_id_table, | ||
325 | }, | ||
326 | .probe = rcar_vin_probe, | ||
327 | .remove = rcar_vin_remove, | ||
328 | }; | ||
329 | |||
330 | module_platform_driver(rcar_vin_driver); | ||
331 | |||
332 | MODULE_AUTHOR("Niklas Söderlund <niklas.soderlund@ragnatech.se>"); | ||
333 | MODULE_DESCRIPTION("Renesas R-Car VIN camera host driver"); | ||
334 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c new file mode 100644 index 000000000000..dad3b031f778 --- /dev/null +++ b/drivers/media/platform/rcar-vin/rcar-dma.c | |||
@@ -0,0 +1,1196 @@ | |||
1 | /* | ||
2 | * Driver for Renesas R-Car VIN | ||
3 | * | ||
4 | * Copyright (C) 2016 Renesas Electronics Corp. | ||
5 | * Copyright (C) 2011-2013 Renesas Solutions Corp. | ||
6 | * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com> | ||
7 | * Copyright (C) 2008 Magnus Damm | ||
8 | * | ||
9 | * Based on the soc-camera rcar_vin driver | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | */ | ||
16 | |||
17 | #include <linux/delay.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | |||
20 | #include <media/videobuf2-dma-contig.h> | ||
21 | |||
22 | #include "rcar-vin.h" | ||
23 | |||
24 | /* ----------------------------------------------------------------------------- | ||
25 | * HW Functions | ||
26 | */ | ||
27 | |||
28 | /* Register offsets for R-Car VIN */ | ||
29 | #define VNMC_REG 0x00 /* Video n Main Control Register */ | ||
30 | #define VNMS_REG 0x04 /* Video n Module Status Register */ | ||
31 | #define VNFC_REG 0x08 /* Video n Frame Capture Register */ | ||
32 | #define VNSLPRC_REG 0x0C /* Video n Start Line Pre-Clip Register */ | ||
33 | #define VNELPRC_REG 0x10 /* Video n End Line Pre-Clip Register */ | ||
34 | #define VNSPPRC_REG 0x14 /* Video n Start Pixel Pre-Clip Register */ | ||
35 | #define VNEPPRC_REG 0x18 /* Video n End Pixel Pre-Clip Register */ | ||
36 | #define VNSLPOC_REG 0x1C /* Video n Start Line Post-Clip Register */ | ||
37 | #define VNELPOC_REG 0x20 /* Video n End Line Post-Clip Register */ | ||
38 | #define VNSPPOC_REG 0x24 /* Video n Start Pixel Post-Clip Register */ | ||
39 | #define VNEPPOC_REG 0x28 /* Video n End Pixel Post-Clip Register */ | ||
40 | #define VNIS_REG 0x2C /* Video n Image Stride Register */ | ||
41 | #define VNMB_REG(m) (0x30 + ((m) << 2)) /* Video n Memory Base m Register */ | ||
42 | #define VNIE_REG 0x40 /* Video n Interrupt Enable Register */ | ||
43 | #define VNINTS_REG 0x44 /* Video n Interrupt Status Register */ | ||
44 | #define VNSI_REG 0x48 /* Video n Scanline Interrupt Register */ | ||
45 | #define VNMTC_REG 0x4C /* Video n Memory Transfer Control Register */ | ||
46 | #define VNYS_REG 0x50 /* Video n Y Scale Register */ | ||
47 | #define VNXS_REG 0x54 /* Video n X Scale Register */ | ||
48 | #define VNDMR_REG 0x58 /* Video n Data Mode Register */ | ||
49 | #define VNDMR2_REG 0x5C /* Video n Data Mode Register 2 */ | ||
50 | #define VNUVAOF_REG 0x60 /* Video n UV Address Offset Register */ | ||
51 | #define VNC1A_REG 0x80 /* Video n Coefficient Set C1A Register */ | ||
52 | #define VNC1B_REG 0x84 /* Video n Coefficient Set C1B Register */ | ||
53 | #define VNC1C_REG 0x88 /* Video n Coefficient Set C1C Register */ | ||
54 | #define VNC2A_REG 0x90 /* Video n Coefficient Set C2A Register */ | ||
55 | #define VNC2B_REG 0x94 /* Video n Coefficient Set C2B Register */ | ||
56 | #define VNC2C_REG 0x98 /* Video n Coefficient Set C2C Register */ | ||
57 | #define VNC3A_REG 0xA0 /* Video n Coefficient Set C3A Register */ | ||
58 | #define VNC3B_REG 0xA4 /* Video n Coefficient Set C3B Register */ | ||
59 | #define VNC3C_REG 0xA8 /* Video n Coefficient Set C3C Register */ | ||
60 | #define VNC4A_REG 0xB0 /* Video n Coefficient Set C4A Register */ | ||
61 | #define VNC4B_REG 0xB4 /* Video n Coefficient Set C4B Register */ | ||
62 | #define VNC4C_REG 0xB8 /* Video n Coefficient Set C4C Register */ | ||
63 | #define VNC5A_REG 0xC0 /* Video n Coefficient Set C5A Register */ | ||
64 | #define VNC5B_REG 0xC4 /* Video n Coefficient Set C5B Register */ | ||
65 | #define VNC5C_REG 0xC8 /* Video n Coefficient Set C5C Register */ | ||
66 | #define VNC6A_REG 0xD0 /* Video n Coefficient Set C6A Register */ | ||
67 | #define VNC6B_REG 0xD4 /* Video n Coefficient Set C6B Register */ | ||
68 | #define VNC6C_REG 0xD8 /* Video n Coefficient Set C6C Register */ | ||
69 | #define VNC7A_REG 0xE0 /* Video n Coefficient Set C7A Register */ | ||
70 | #define VNC7B_REG 0xE4 /* Video n Coefficient Set C7B Register */ | ||
71 | #define VNC7C_REG 0xE8 /* Video n Coefficient Set C7C Register */ | ||
72 | #define VNC8A_REG 0xF0 /* Video n Coefficient Set C8A Register */ | ||
73 | #define VNC8B_REG 0xF4 /* Video n Coefficient Set C8B Register */ | ||
74 | #define VNC8C_REG 0xF8 /* Video n Coefficient Set C8C Register */ | ||
75 | |||
76 | |||
77 | /* Register bit fields for R-Car VIN */ | ||
78 | /* Video n Main Control Register bits */ | ||
79 | #define VNMC_FOC (1 << 21) | ||
80 | #define VNMC_YCAL (1 << 19) | ||
81 | #define VNMC_INF_YUV8_BT656 (0 << 16) | ||
82 | #define VNMC_INF_YUV8_BT601 (1 << 16) | ||
83 | #define VNMC_INF_YUV10_BT656 (2 << 16) | ||
84 | #define VNMC_INF_YUV10_BT601 (3 << 16) | ||
85 | #define VNMC_INF_YUV16 (5 << 16) | ||
86 | #define VNMC_INF_RGB888 (6 << 16) | ||
87 | #define VNMC_VUP (1 << 10) | ||
88 | #define VNMC_IM_ODD (0 << 3) | ||
89 | #define VNMC_IM_ODD_EVEN (1 << 3) | ||
90 | #define VNMC_IM_EVEN (2 << 3) | ||
91 | #define VNMC_IM_FULL (3 << 3) | ||
92 | #define VNMC_BPS (1 << 1) | ||
93 | #define VNMC_ME (1 << 0) | ||
94 | |||
95 | /* Video n Module Status Register bits */ | ||
96 | #define VNMS_FBS_MASK (3 << 3) | ||
97 | #define VNMS_FBS_SHIFT 3 | ||
98 | #define VNMS_AV (1 << 1) | ||
99 | #define VNMS_CA (1 << 0) | ||
100 | |||
101 | /* Video n Frame Capture Register bits */ | ||
102 | #define VNFC_C_FRAME (1 << 1) | ||
103 | #define VNFC_S_FRAME (1 << 0) | ||
104 | |||
105 | /* Video n Interrupt Enable Register bits */ | ||
106 | #define VNIE_FIE (1 << 4) | ||
107 | #define VNIE_EFE (1 << 1) | ||
108 | |||
109 | /* Video n Data Mode Register bits */ | ||
110 | #define VNDMR_EXRGB (1 << 8) | ||
111 | #define VNDMR_BPSM (1 << 4) | ||
112 | #define VNDMR_DTMD_YCSEP (1 << 1) | ||
113 | #define VNDMR_DTMD_ARGB1555 (1 << 0) | ||
114 | |||
115 | /* Video n Data Mode Register 2 bits */ | ||
116 | #define VNDMR2_VPS (1 << 30) | ||
117 | #define VNDMR2_HPS (1 << 29) | ||
118 | #define VNDMR2_FTEV (1 << 17) | ||
119 | #define VNDMR2_VLV(n) ((n & 0xf) << 12) | ||
120 | |||
121 | static void rvin_write(struct rvin_dev *vin, u32 value, u32 offset) | ||
122 | { | ||
123 | iowrite32(value, vin->base + offset); | ||
124 | } | ||
125 | |||
126 | static u32 rvin_read(struct rvin_dev *vin, u32 offset) | ||
127 | { | ||
128 | return ioread32(vin->base + offset); | ||
129 | } | ||
130 | |||
131 | static int rvin_setup(struct rvin_dev *vin) | ||
132 | { | ||
133 | u32 vnmc, dmr, dmr2, interrupts; | ||
134 | bool progressive = false, output_is_yuv = false, input_is_yuv = false; | ||
135 | |||
136 | switch (vin->format.field) { | ||
137 | case V4L2_FIELD_TOP: | ||
138 | vnmc = VNMC_IM_ODD; | ||
139 | break; | ||
140 | case V4L2_FIELD_BOTTOM: | ||
141 | vnmc = VNMC_IM_EVEN; | ||
142 | break; | ||
143 | case V4L2_FIELD_INTERLACED: | ||
144 | case V4L2_FIELD_INTERLACED_TB: | ||
145 | vnmc = VNMC_IM_FULL; | ||
146 | break; | ||
147 | case V4L2_FIELD_INTERLACED_BT: | ||
148 | vnmc = VNMC_IM_FULL | VNMC_FOC; | ||
149 | break; | ||
150 | case V4L2_FIELD_NONE: | ||
151 | if (vin->continuous) { | ||
152 | vnmc = VNMC_IM_ODD_EVEN; | ||
153 | progressive = true; | ||
154 | } else { | ||
155 | vnmc = VNMC_IM_ODD; | ||
156 | } | ||
157 | break; | ||
158 | default: | ||
159 | vnmc = VNMC_IM_ODD; | ||
160 | break; | ||
161 | } | ||
162 | |||
163 | /* | ||
164 | * Input interface | ||
165 | */ | ||
166 | switch (vin->source.code) { | ||
167 | case MEDIA_BUS_FMT_YUYV8_1X16: | ||
168 | /* BT.601/BT.1358 16bit YCbCr422 */ | ||
169 | vnmc |= VNMC_INF_YUV16; | ||
170 | input_is_yuv = true; | ||
171 | break; | ||
172 | case MEDIA_BUS_FMT_YUYV8_2X8: | ||
173 | /* BT.656 8bit YCbCr422 or BT.601 8bit YCbCr422 */ | ||
174 | vnmc |= vin->mbus_cfg.type == V4L2_MBUS_BT656 ? | ||
175 | VNMC_INF_YUV8_BT656 : VNMC_INF_YUV8_BT601; | ||
176 | input_is_yuv = true; | ||
177 | break; | ||
178 | case MEDIA_BUS_FMT_RGB888_1X24: | ||
179 | vnmc |= VNMC_INF_RGB888; | ||
180 | break; | ||
181 | case MEDIA_BUS_FMT_YUYV10_2X10: | ||
182 | /* BT.656 10bit YCbCr422 or BT.601 10bit YCbCr422 */ | ||
183 | vnmc |= vin->mbus_cfg.type == V4L2_MBUS_BT656 ? | ||
184 | VNMC_INF_YUV10_BT656 : VNMC_INF_YUV10_BT601; | ||
185 | input_is_yuv = true; | ||
186 | break; | ||
187 | default: | ||
188 | break; | ||
189 | } | ||
190 | |||
191 | /* Enable VSYNC Field Toogle mode after one VSYNC input */ | ||
192 | dmr2 = VNDMR2_FTEV | VNDMR2_VLV(1); | ||
193 | |||
194 | /* Hsync Signal Polarity Select */ | ||
195 | if (!(vin->mbus_cfg.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) | ||
196 | dmr2 |= VNDMR2_HPS; | ||
197 | |||
198 | /* Vsync Signal Polarity Select */ | ||
199 | if (!(vin->mbus_cfg.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) | ||
200 | dmr2 |= VNDMR2_VPS; | ||
201 | |||
202 | /* | ||
203 | * Output format | ||
204 | */ | ||
205 | switch (vin->format.pixelformat) { | ||
206 | case V4L2_PIX_FMT_NV16: | ||
207 | rvin_write(vin, | ||
208 | ALIGN(vin->format.width * vin->format.height, 0x80), | ||
209 | VNUVAOF_REG); | ||
210 | dmr = VNDMR_DTMD_YCSEP; | ||
211 | output_is_yuv = true; | ||
212 | break; | ||
213 | case V4L2_PIX_FMT_YUYV: | ||
214 | dmr = VNDMR_BPSM; | ||
215 | output_is_yuv = true; | ||
216 | break; | ||
217 | case V4L2_PIX_FMT_UYVY: | ||
218 | dmr = 0; | ||
219 | output_is_yuv = true; | ||
220 | break; | ||
221 | case V4L2_PIX_FMT_XRGB555: | ||
222 | dmr = VNDMR_DTMD_ARGB1555; | ||
223 | break; | ||
224 | case V4L2_PIX_FMT_RGB565: | ||
225 | dmr = 0; | ||
226 | break; | ||
227 | case V4L2_PIX_FMT_XBGR32: | ||
228 | if (vin->chip == RCAR_GEN2 || vin->chip == RCAR_H1) { | ||
229 | dmr = VNDMR_EXRGB; | ||
230 | break; | ||
231 | } | ||
232 | /* fall through */ | ||
233 | default: | ||
234 | vin_err(vin, "Invalid pixelformat (0x%x)\n", | ||
235 | vin->format.pixelformat); | ||
236 | return -EINVAL; | ||
237 | } | ||
238 | |||
239 | /* Always update on field change */ | ||
240 | vnmc |= VNMC_VUP; | ||
241 | |||
242 | /* If input and output use the same colorspace, use bypass mode */ | ||
243 | if (input_is_yuv == output_is_yuv) | ||
244 | vnmc |= VNMC_BPS; | ||
245 | |||
246 | /* Progressive or interlaced mode */ | ||
247 | interrupts = progressive ? VNIE_FIE : VNIE_EFE; | ||
248 | |||
249 | /* Ack interrupts */ | ||
250 | rvin_write(vin, interrupts, VNINTS_REG); | ||
251 | /* Enable interrupts */ | ||
252 | rvin_write(vin, interrupts, VNIE_REG); | ||
253 | /* Start capturing */ | ||
254 | rvin_write(vin, dmr, VNDMR_REG); | ||
255 | rvin_write(vin, dmr2, VNDMR2_REG); | ||
256 | |||
257 | /* Enable module */ | ||
258 | rvin_write(vin, vnmc | VNMC_ME, VNMC_REG); | ||
259 | |||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | static void rvin_capture_on(struct rvin_dev *vin) | ||
264 | { | ||
265 | vin_dbg(vin, "Capture on in %s mode\n", | ||
266 | vin->continuous ? "continuous" : "single"); | ||
267 | |||
268 | if (vin->continuous) | ||
269 | /* Continuous Frame Capture Mode */ | ||
270 | rvin_write(vin, VNFC_C_FRAME, VNFC_REG); | ||
271 | else | ||
272 | /* Single Frame Capture Mode */ | ||
273 | rvin_write(vin, VNFC_S_FRAME, VNFC_REG); | ||
274 | } | ||
275 | |||
276 | static void rvin_capture_off(struct rvin_dev *vin) | ||
277 | { | ||
278 | /* Set continuous & single transfer off */ | ||
279 | rvin_write(vin, 0, VNFC_REG); | ||
280 | } | ||
281 | |||
282 | static int rvin_capture_start(struct rvin_dev *vin) | ||
283 | { | ||
284 | int ret; | ||
285 | |||
286 | rvin_crop_scale_comp(vin); | ||
287 | |||
288 | ret = rvin_setup(vin); | ||
289 | if (ret) | ||
290 | return ret; | ||
291 | |||
292 | rvin_capture_on(vin); | ||
293 | |||
294 | return 0; | ||
295 | } | ||
296 | |||
297 | static void rvin_capture_stop(struct rvin_dev *vin) | ||
298 | { | ||
299 | rvin_capture_off(vin); | ||
300 | |||
301 | /* Disable module */ | ||
302 | rvin_write(vin, rvin_read(vin, VNMC_REG) & ~VNMC_ME, VNMC_REG); | ||
303 | } | ||
304 | |||
305 | static void rvin_disable_interrupts(struct rvin_dev *vin) | ||
306 | { | ||
307 | rvin_write(vin, 0, VNIE_REG); | ||
308 | } | ||
309 | |||
310 | static u32 rvin_get_interrupt_status(struct rvin_dev *vin) | ||
311 | { | ||
312 | return rvin_read(vin, VNINTS_REG); | ||
313 | } | ||
314 | |||
315 | static void rvin_ack_interrupt(struct rvin_dev *vin) | ||
316 | { | ||
317 | rvin_write(vin, rvin_read(vin, VNINTS_REG), VNINTS_REG); | ||
318 | } | ||
319 | |||
320 | static bool rvin_capture_active(struct rvin_dev *vin) | ||
321 | { | ||
322 | return rvin_read(vin, VNMS_REG) & VNMS_CA; | ||
323 | } | ||
324 | |||
325 | static int rvin_get_active_slot(struct rvin_dev *vin) | ||
326 | { | ||
327 | if (vin->continuous) | ||
328 | return (rvin_read(vin, VNMS_REG) & VNMS_FBS_MASK) | ||
329 | >> VNMS_FBS_SHIFT; | ||
330 | |||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | static void rvin_set_slot_addr(struct rvin_dev *vin, int slot, dma_addr_t addr) | ||
335 | { | ||
336 | const struct rvin_video_format *fmt; | ||
337 | int offsetx, offsety; | ||
338 | dma_addr_t offset; | ||
339 | |||
340 | fmt = rvin_format_from_pixel(vin->format.pixelformat); | ||
341 | |||
342 | /* | ||
343 | * There is no HW support for composition do the beast we can | ||
344 | * by modifying the buffer offset | ||
345 | */ | ||
346 | offsetx = vin->compose.left * fmt->bpp; | ||
347 | offsety = vin->compose.top * vin->format.bytesperline; | ||
348 | offset = addr + offsetx + offsety; | ||
349 | |||
350 | /* | ||
351 | * The address needs to be 128 bytes aligned. Driver should never accept | ||
352 | * settings that do not satisfy this in the first place... | ||
353 | */ | ||
354 | if (WARN_ON((offsetx | offsety | offset) & HW_BUFFER_MASK)) | ||
355 | return; | ||
356 | |||
357 | rvin_write(vin, offset, VNMB_REG(slot)); | ||
358 | } | ||
359 | |||
360 | /* ----------------------------------------------------------------------------- | ||
361 | * Crop and Scaling Gen2 | ||
362 | */ | ||
363 | |||
364 | struct vin_coeff { | ||
365 | unsigned short xs_value; | ||
366 | u32 coeff_set[24]; | ||
367 | }; | ||
368 | |||
369 | static const struct vin_coeff vin_coeff_set[] = { | ||
370 | { 0x0000, { | ||
371 | 0x00000000, 0x00000000, 0x00000000, | ||
372 | 0x00000000, 0x00000000, 0x00000000, | ||
373 | 0x00000000, 0x00000000, 0x00000000, | ||
374 | 0x00000000, 0x00000000, 0x00000000, | ||
375 | 0x00000000, 0x00000000, 0x00000000, | ||
376 | 0x00000000, 0x00000000, 0x00000000, | ||
377 | 0x00000000, 0x00000000, 0x00000000, | ||
378 | 0x00000000, 0x00000000, 0x00000000 }, | ||
379 | }, | ||
380 | { 0x1000, { | ||
381 | 0x000fa400, 0x000fa400, 0x09625902, | ||
382 | 0x000003f8, 0x00000403, 0x3de0d9f0, | ||
383 | 0x001fffed, 0x00000804, 0x3cc1f9c3, | ||
384 | 0x001003de, 0x00000c01, 0x3cb34d7f, | ||
385 | 0x002003d2, 0x00000c00, 0x3d24a92d, | ||
386 | 0x00200bca, 0x00000bff, 0x3df600d2, | ||
387 | 0x002013cc, 0x000007ff, 0x3ed70c7e, | ||
388 | 0x00100fde, 0x00000000, 0x3f87c036 }, | ||
389 | }, | ||
390 | { 0x1200, { | ||
391 | 0x002ffff1, 0x002ffff1, 0x02a0a9c8, | ||
392 | 0x002003e7, 0x001ffffa, 0x000185bc, | ||
393 | 0x002007dc, 0x000003ff, 0x3e52859c, | ||
394 | 0x00200bd4, 0x00000002, 0x3d53996b, | ||
395 | 0x00100fd0, 0x00000403, 0x3d04ad2d, | ||
396 | 0x00000bd5, 0x00000403, 0x3d35ace7, | ||
397 | 0x3ff003e4, 0x00000801, 0x3dc674a1, | ||
398 | 0x3fffe800, 0x00000800, 0x3e76f461 }, | ||
399 | }, | ||
400 | { 0x1400, { | ||
401 | 0x00100be3, 0x00100be3, 0x04d1359a, | ||
402 | 0x00000fdb, 0x002003ed, 0x0211fd93, | ||
403 | 0x00000fd6, 0x002003f4, 0x0002d97b, | ||
404 | 0x000007d6, 0x002ffffb, 0x3e93b956, | ||
405 | 0x3ff003da, 0x001003ff, 0x3db49926, | ||
406 | 0x3fffefe9, 0x00100001, 0x3d655cee, | ||
407 | 0x3fffd400, 0x00000003, 0x3d65f4b6, | ||
408 | 0x000fb421, 0x00000402, 0x3dc6547e }, | ||
409 | }, | ||
410 | { 0x1600, { | ||
411 | 0x00000bdd, 0x00000bdd, 0x06519578, | ||
412 | 0x3ff007da, 0x00000be3, 0x03c24973, | ||
413 | 0x3ff003d9, 0x00000be9, 0x01b30d5f, | ||
414 | 0x3ffff7df, 0x001003f1, 0x0003c542, | ||
415 | 0x000fdfec, 0x001003f7, 0x3ec4711d, | ||
416 | 0x000fc400, 0x002ffffd, 0x3df504f1, | ||
417 | 0x001fa81a, 0x002ffc00, 0x3d957cc2, | ||
418 | 0x002f8c3c, 0x00100000, 0x3db5c891 }, | ||
419 | }, | ||
420 | { 0x1800, { | ||
421 | 0x3ff003dc, 0x3ff003dc, 0x0791e558, | ||
422 | 0x000ff7dd, 0x3ff007de, 0x05328554, | ||
423 | 0x000fe7e3, 0x3ff00be2, 0x03232546, | ||
424 | 0x000fd7ee, 0x000007e9, 0x0143bd30, | ||
425 | 0x001fb800, 0x000007ee, 0x00044511, | ||
426 | 0x002fa015, 0x000007f4, 0x3ef4bcee, | ||
427 | 0x002f8832, 0x001003f9, 0x3e4514c7, | ||
428 | 0x001f7853, 0x001003fd, 0x3de54c9f }, | ||
429 | }, | ||
430 | { 0x1a00, { | ||
431 | 0x000fefe0, 0x000fefe0, 0x08721d3c, | ||
432 | 0x001fdbe7, 0x000ffbde, 0x0652a139, | ||
433 | 0x001fcbf0, 0x000003df, 0x0463292e, | ||
434 | 0x002fb3ff, 0x3ff007e3, 0x0293a91d, | ||
435 | 0x002f9c12, 0x3ff00be7, 0x01241905, | ||
436 | 0x001f8c29, 0x000007ed, 0x3fe470eb, | ||
437 | 0x000f7c46, 0x000007f2, 0x3f04b8ca, | ||
438 | 0x3fef7865, 0x000007f6, 0x3e74e4a8 }, | ||
439 | }, | ||
440 | { 0x1c00, { | ||
441 | 0x001fd3e9, 0x001fd3e9, 0x08f23d26, | ||
442 | 0x002fbff3, 0x001fe3e4, 0x0712ad23, | ||
443 | 0x002fa800, 0x000ff3e0, 0x05631d1b, | ||
444 | 0x001f9810, 0x000ffbe1, 0x03b3890d, | ||
445 | 0x000f8c23, 0x000003e3, 0x0233e8fa, | ||
446 | 0x3fef843b, 0x000003e7, 0x00f430e4, | ||
447 | 0x3fbf8456, 0x3ff00bea, 0x00046cc8, | ||
448 | 0x3f8f8c72, 0x3ff00bef, 0x3f3490ac }, | ||
449 | }, | ||
450 | { 0x1e00, { | ||
451 | 0x001fbbf4, 0x001fbbf4, 0x09425112, | ||
452 | 0x001fa800, 0x002fc7ed, 0x0792b110, | ||
453 | 0x000f980e, 0x001fdbe6, 0x0613110a, | ||
454 | 0x3fff8c20, 0x001fe7e3, 0x04a368fd, | ||
455 | 0x3fcf8c33, 0x000ff7e2, 0x0343b8ed, | ||
456 | 0x3f9f8c4a, 0x000fffe3, 0x0203f8da, | ||
457 | 0x3f5f9c61, 0x000003e6, 0x00e428c5, | ||
458 | 0x3f1fb07b, 0x000003eb, 0x3fe440af }, | ||
459 | }, | ||
460 | { 0x2000, { | ||
461 | 0x000fa400, 0x000fa400, 0x09625902, | ||
462 | 0x3fff980c, 0x001fb7f5, 0x0812b0ff, | ||
463 | 0x3fdf901c, 0x001fc7ed, 0x06b2fcfa, | ||
464 | 0x3faf902d, 0x001fd3e8, 0x055348f1, | ||
465 | 0x3f7f983f, 0x001fe3e5, 0x04038ce3, | ||
466 | 0x3f3fa454, 0x001fefe3, 0x02e3c8d1, | ||
467 | 0x3f0fb86a, 0x001ff7e4, 0x01c3e8c0, | ||
468 | 0x3ecfd880, 0x000fffe6, 0x00c404ac }, | ||
469 | }, | ||
470 | { 0x2200, { | ||
471 | 0x3fdf9c0b, 0x3fdf9c0b, 0x09725cf4, | ||
472 | 0x3fbf9818, 0x3fffa400, 0x0842a8f1, | ||
473 | 0x3f8f9827, 0x000fb3f7, 0x0702f0ec, | ||
474 | 0x3f5fa037, 0x000fc3ef, 0x05d330e4, | ||
475 | 0x3f2fac49, 0x001fcfea, 0x04a364d9, | ||
476 | 0x3effc05c, 0x001fdbe7, 0x038394ca, | ||
477 | 0x3ecfdc6f, 0x001fe7e6, 0x0273b0bb, | ||
478 | 0x3ea00083, 0x001fefe6, 0x0183c0a9 }, | ||
479 | }, | ||
480 | { 0x2400, { | ||
481 | 0x3f9fa014, 0x3f9fa014, 0x098260e6, | ||
482 | 0x3f7f9c23, 0x3fcf9c0a, 0x08629ce5, | ||
483 | 0x3f4fa431, 0x3fefa400, 0x0742d8e1, | ||
484 | 0x3f1fb440, 0x3fffb3f8, 0x062310d9, | ||
485 | 0x3eefc850, 0x000fbbf2, 0x050340d0, | ||
486 | 0x3ecfe062, 0x000fcbec, 0x041364c2, | ||
487 | 0x3ea00073, 0x001fd3ea, 0x03037cb5, | ||
488 | 0x3e902086, 0x001fdfe8, 0x022388a5 }, | ||
489 | }, | ||
490 | { 0x2600, { | ||
491 | 0x3f5fa81e, 0x3f5fa81e, 0x096258da, | ||
492 | 0x3f3fac2b, 0x3f8fa412, 0x088290d8, | ||
493 | 0x3f0fbc38, 0x3fafa408, 0x0772c8d5, | ||
494 | 0x3eefcc47, 0x3fcfa800, 0x0672f4ce, | ||
495 | 0x3ecfe456, 0x3fefaffa, 0x05531cc6, | ||
496 | 0x3eb00066, 0x3fffbbf3, 0x047334bb, | ||
497 | 0x3ea01c77, 0x000fc7ee, 0x039348ae, | ||
498 | 0x3ea04486, 0x000fd3eb, 0x02b350a1 }, | ||
499 | }, | ||
500 | { 0x2800, { | ||
501 | 0x3f2fb426, 0x3f2fb426, 0x094250ce, | ||
502 | 0x3f0fc032, 0x3f4fac1b, 0x086284cd, | ||
503 | 0x3eefd040, 0x3f7fa811, 0x0782acc9, | ||
504 | 0x3ecfe84c, 0x3f9fa807, 0x06a2d8c4, | ||
505 | 0x3eb0005b, 0x3fbfac00, 0x05b2f4bc, | ||
506 | 0x3eb0186a, 0x3fdfb3fa, 0x04c308b4, | ||
507 | 0x3eb04077, 0x3fefbbf4, 0x03f31ca8, | ||
508 | 0x3ec06884, 0x000fbff2, 0x03031c9e }, | ||
509 | }, | ||
510 | { 0x2a00, { | ||
511 | 0x3f0fc42d, 0x3f0fc42d, 0x090240c4, | ||
512 | 0x3eefd439, 0x3f2fb822, 0x08526cc2, | ||
513 | 0x3edfe845, 0x3f4fb018, 0x078294bf, | ||
514 | 0x3ec00051, 0x3f6fac0f, 0x06b2b4bb, | ||
515 | 0x3ec0185f, 0x3f8fac07, 0x05e2ccb4, | ||
516 | 0x3ec0386b, 0x3fafac00, 0x0502e8ac, | ||
517 | 0x3ed05c77, 0x3fcfb3fb, 0x0432f0a3, | ||
518 | 0x3ef08482, 0x3fdfbbf6, 0x0372f898 }, | ||
519 | }, | ||
520 | { 0x2c00, { | ||
521 | 0x3eefdc31, 0x3eefdc31, 0x08e238b8, | ||
522 | 0x3edfec3d, 0x3f0fc828, 0x082258b9, | ||
523 | 0x3ed00049, 0x3f1fc01e, 0x077278b6, | ||
524 | 0x3ed01455, 0x3f3fb815, 0x06c294b2, | ||
525 | 0x3ed03460, 0x3f5fb40d, 0x0602acac, | ||
526 | 0x3ef0506c, 0x3f7fb006, 0x0542c0a4, | ||
527 | 0x3f107476, 0x3f9fb400, 0x0472c89d, | ||
528 | 0x3f309c80, 0x3fbfb7fc, 0x03b2cc94 }, | ||
529 | }, | ||
530 | { 0x2e00, { | ||
531 | 0x3eefec37, 0x3eefec37, 0x088220b0, | ||
532 | 0x3ee00041, 0x3effdc2d, 0x07f244ae, | ||
533 | 0x3ee0144c, 0x3f0fd023, 0x07625cad, | ||
534 | 0x3ef02c57, 0x3f1fc81a, 0x06c274a9, | ||
535 | 0x3f004861, 0x3f3fbc13, 0x060288a6, | ||
536 | 0x3f20686b, 0x3f5fb80c, 0x05529c9e, | ||
537 | 0x3f408c74, 0x3f6fb805, 0x04b2ac96, | ||
538 | 0x3f80ac7e, 0x3f8fb800, 0x0402ac8e }, | ||
539 | }, | ||
540 | { 0x3000, { | ||
541 | 0x3ef0003a, 0x3ef0003a, 0x084210a6, | ||
542 | 0x3ef01045, 0x3effec32, 0x07b228a7, | ||
543 | 0x3f00284e, 0x3f0fdc29, 0x073244a4, | ||
544 | 0x3f104058, 0x3f0fd420, 0x06a258a2, | ||
545 | 0x3f305c62, 0x3f2fc818, 0x0612689d, | ||
546 | 0x3f508069, 0x3f3fc011, 0x05728496, | ||
547 | 0x3f80a072, 0x3f4fc00a, 0x04d28c90, | ||
548 | 0x3fc0c07b, 0x3f6fbc04, 0x04429088 }, | ||
549 | }, | ||
550 | { 0x3200, { | ||
551 | 0x3f00103e, 0x3f00103e, 0x07f1fc9e, | ||
552 | 0x3f102447, 0x3f000035, 0x0782149d, | ||
553 | 0x3f203c4f, 0x3f0ff02c, 0x07122c9c, | ||
554 | 0x3f405458, 0x3f0fe424, 0x06924099, | ||
555 | 0x3f607061, 0x3f1fd41d, 0x06024c97, | ||
556 | 0x3f909068, 0x3f2fcc16, 0x05726490, | ||
557 | 0x3fc0b070, 0x3f3fc80f, 0x04f26c8a, | ||
558 | 0x0000d077, 0x3f4fc409, 0x04627484 }, | ||
559 | }, | ||
560 | { 0x3400, { | ||
561 | 0x3f202040, 0x3f202040, 0x07a1e898, | ||
562 | 0x3f303449, 0x3f100c38, 0x0741fc98, | ||
563 | 0x3f504c50, 0x3f10002f, 0x06e21495, | ||
564 | 0x3f706459, 0x3f1ff028, 0x06722492, | ||
565 | 0x3fa08060, 0x3f1fe421, 0x05f2348f, | ||
566 | 0x3fd09c67, 0x3f1fdc19, 0x05824c89, | ||
567 | 0x0000bc6e, 0x3f2fd014, 0x04f25086, | ||
568 | 0x0040dc74, 0x3f3fcc0d, 0x04825c7f }, | ||
569 | }, | ||
570 | { 0x3600, { | ||
571 | 0x3f403042, 0x3f403042, 0x0761d890, | ||
572 | 0x3f504848, 0x3f301c3b, 0x0701f090, | ||
573 | 0x3f805c50, 0x3f200c33, 0x06a2008f, | ||
574 | 0x3fa07458, 0x3f10002b, 0x06520c8d, | ||
575 | 0x3fd0905e, 0x3f1ff424, 0x05e22089, | ||
576 | 0x0000ac65, 0x3f1fe81d, 0x05823483, | ||
577 | 0x0030cc6a, 0x3f2fdc18, 0x04f23c81, | ||
578 | 0x0080e871, 0x3f2fd412, 0x0482407c }, | ||
579 | }, | ||
580 | { 0x3800, { | ||
581 | 0x3f604043, 0x3f604043, 0x0721c88a, | ||
582 | 0x3f80544a, 0x3f502c3c, 0x06d1d88a, | ||
583 | 0x3fb06851, 0x3f301c35, 0x0681e889, | ||
584 | 0x3fd08456, 0x3f30082f, 0x0611fc88, | ||
585 | 0x00009c5d, 0x3f200027, 0x05d20884, | ||
586 | 0x0030b863, 0x3f2ff421, 0x05621880, | ||
587 | 0x0070d468, 0x3f2fe81b, 0x0502247c, | ||
588 | 0x00c0ec6f, 0x3f2fe015, 0x04a22877 }, | ||
589 | }, | ||
590 | { 0x3a00, { | ||
591 | 0x3f904c44, 0x3f904c44, 0x06e1b884, | ||
592 | 0x3fb0604a, 0x3f70383e, 0x0691c885, | ||
593 | 0x3fe07451, 0x3f502c36, 0x0661d483, | ||
594 | 0x00009055, 0x3f401831, 0x0601ec81, | ||
595 | 0x0030a85b, 0x3f300c2a, 0x05b1f480, | ||
596 | 0x0070c061, 0x3f300024, 0x0562047a, | ||
597 | 0x00b0d867, 0x3f3ff41e, 0x05020c77, | ||
598 | 0x00f0f46b, 0x3f2fec19, 0x04a21474 }, | ||
599 | }, | ||
600 | { 0x3c00, { | ||
601 | 0x3fb05c43, 0x3fb05c43, 0x06c1b07e, | ||
602 | 0x3fe06c4b, 0x3f902c3f, 0x0681c081, | ||
603 | 0x0000844f, 0x3f703838, 0x0631cc7d, | ||
604 | 0x00309855, 0x3f602433, 0x05d1d47e, | ||
605 | 0x0060b459, 0x3f50142e, 0x0581e47b, | ||
606 | 0x00a0c85f, 0x3f400828, 0x0531f078, | ||
607 | 0x00e0e064, 0x3f300021, 0x0501fc73, | ||
608 | 0x00b0fc6a, 0x3f3ff41d, 0x04a20873 }, | ||
609 | }, | ||
610 | { 0x3e00, { | ||
611 | 0x3fe06444, 0x3fe06444, 0x0681a07a, | ||
612 | 0x00007849, 0x3fc0503f, 0x0641b07a, | ||
613 | 0x0020904d, 0x3fa0403a, 0x05f1c07a, | ||
614 | 0x0060a453, 0x3f803034, 0x05c1c878, | ||
615 | 0x0090b858, 0x3f70202f, 0x0571d477, | ||
616 | 0x00d0d05d, 0x3f501829, 0x0531e073, | ||
617 | 0x0110e462, 0x3f500825, 0x04e1e471, | ||
618 | 0x01510065, 0x3f40001f, 0x04a1f06d }, | ||
619 | }, | ||
620 | { 0x4000, { | ||
621 | 0x00007044, 0x00007044, 0x06519476, | ||
622 | 0x00208448, 0x3fe05c3f, 0x0621a476, | ||
623 | 0x0050984d, 0x3fc04c3a, 0x05e1b075, | ||
624 | 0x0080ac52, 0x3fa03c35, 0x05a1b875, | ||
625 | 0x00c0c056, 0x3f803030, 0x0561c473, | ||
626 | 0x0100d45b, 0x3f70202b, 0x0521d46f, | ||
627 | 0x0140e860, 0x3f601427, 0x04d1d46e, | ||
628 | 0x01810064, 0x3f500822, 0x0491dc6b }, | ||
629 | }, | ||
630 | { 0x5000, { | ||
631 | 0x0110a442, 0x0110a442, 0x0551545e, | ||
632 | 0x0140b045, 0x00e0983f, 0x0531585f, | ||
633 | 0x0160c047, 0x00c08c3c, 0x0511645e, | ||
634 | 0x0190cc4a, 0x00908039, 0x04f1685f, | ||
635 | 0x01c0dc4c, 0x00707436, 0x04d1705e, | ||
636 | 0x0200e850, 0x00506833, 0x04b1785b, | ||
637 | 0x0230f453, 0x00305c30, 0x0491805a, | ||
638 | 0x02710056, 0x0010542d, 0x04718059 }, | ||
639 | }, | ||
640 | { 0x6000, { | ||
641 | 0x01c0bc40, 0x01c0bc40, 0x04c13052, | ||
642 | 0x01e0c841, 0x01a0b43d, 0x04c13851, | ||
643 | 0x0210cc44, 0x0180a83c, 0x04a13453, | ||
644 | 0x0230d845, 0x0160a03a, 0x04913c52, | ||
645 | 0x0260e047, 0x01409838, 0x04714052, | ||
646 | 0x0280ec49, 0x01208c37, 0x04514c50, | ||
647 | 0x02b0f44b, 0x01008435, 0x04414c50, | ||
648 | 0x02d1004c, 0x00e07c33, 0x0431544f }, | ||
649 | }, | ||
650 | { 0x7000, { | ||
651 | 0x0230c83e, 0x0230c83e, 0x04711c4c, | ||
652 | 0x0250d03f, 0x0210c43c, 0x0471204b, | ||
653 | 0x0270d840, 0x0200b83c, 0x0451244b, | ||
654 | 0x0290dc42, 0x01e0b43a, 0x0441244c, | ||
655 | 0x02b0e443, 0x01c0b038, 0x0441284b, | ||
656 | 0x02d0ec44, 0x01b0a438, 0x0421304a, | ||
657 | 0x02f0f445, 0x0190a036, 0x04213449, | ||
658 | 0x0310f847, 0x01709c34, 0x04213848 }, | ||
659 | }, | ||
660 | { 0x8000, { | ||
661 | 0x0280d03d, 0x0280d03d, 0x04310c48, | ||
662 | 0x02a0d43e, 0x0270c83c, 0x04311047, | ||
663 | 0x02b0dc3e, 0x0250c83a, 0x04311447, | ||
664 | 0x02d0e040, 0x0240c03a, 0x04211446, | ||
665 | 0x02e0e840, 0x0220bc39, 0x04111847, | ||
666 | 0x0300e842, 0x0210b438, 0x04012445, | ||
667 | 0x0310f043, 0x0200b037, 0x04012045, | ||
668 | 0x0330f444, 0x01e0ac36, 0x03f12445 }, | ||
669 | }, | ||
670 | { 0xefff, { | ||
671 | 0x0340dc3a, 0x0340dc3a, 0x03b0ec40, | ||
672 | 0x0340e03a, 0x0330e039, 0x03c0f03e, | ||
673 | 0x0350e03b, 0x0330dc39, 0x03c0ec3e, | ||
674 | 0x0350e43a, 0x0320dc38, 0x03c0f43e, | ||
675 | 0x0360e43b, 0x0320d839, 0x03b0f03e, | ||
676 | 0x0360e83b, 0x0310d838, 0x03c0fc3b, | ||
677 | 0x0370e83b, 0x0310d439, 0x03a0f83d, | ||
678 | 0x0370e83c, 0x0300d438, 0x03b0fc3c }, | ||
679 | } | ||
680 | }; | ||
681 | |||
682 | static void rvin_set_coeff(struct rvin_dev *vin, unsigned short xs) | ||
683 | { | ||
684 | int i; | ||
685 | const struct vin_coeff *p_prev_set = NULL; | ||
686 | const struct vin_coeff *p_set = NULL; | ||
687 | |||
688 | /* Look for suitable coefficient values */ | ||
689 | for (i = 0; i < ARRAY_SIZE(vin_coeff_set); i++) { | ||
690 | p_prev_set = p_set; | ||
691 | p_set = &vin_coeff_set[i]; | ||
692 | |||
693 | if (xs < p_set->xs_value) | ||
694 | break; | ||
695 | } | ||
696 | |||
697 | /* Use previous value if its XS value is closer */ | ||
698 | if (p_prev_set && p_set && | ||
699 | xs - p_prev_set->xs_value < p_set->xs_value - xs) | ||
700 | p_set = p_prev_set; | ||
701 | |||
702 | /* Set coefficient registers */ | ||
703 | rvin_write(vin, p_set->coeff_set[0], VNC1A_REG); | ||
704 | rvin_write(vin, p_set->coeff_set[1], VNC1B_REG); | ||
705 | rvin_write(vin, p_set->coeff_set[2], VNC1C_REG); | ||
706 | |||
707 | rvin_write(vin, p_set->coeff_set[3], VNC2A_REG); | ||
708 | rvin_write(vin, p_set->coeff_set[4], VNC2B_REG); | ||
709 | rvin_write(vin, p_set->coeff_set[5], VNC2C_REG); | ||
710 | |||
711 | rvin_write(vin, p_set->coeff_set[6], VNC3A_REG); | ||
712 | rvin_write(vin, p_set->coeff_set[7], VNC3B_REG); | ||
713 | rvin_write(vin, p_set->coeff_set[8], VNC3C_REG); | ||
714 | |||
715 | rvin_write(vin, p_set->coeff_set[9], VNC4A_REG); | ||
716 | rvin_write(vin, p_set->coeff_set[10], VNC4B_REG); | ||
717 | rvin_write(vin, p_set->coeff_set[11], VNC4C_REG); | ||
718 | |||
719 | rvin_write(vin, p_set->coeff_set[12], VNC5A_REG); | ||
720 | rvin_write(vin, p_set->coeff_set[13], VNC5B_REG); | ||
721 | rvin_write(vin, p_set->coeff_set[14], VNC5C_REG); | ||
722 | |||
723 | rvin_write(vin, p_set->coeff_set[15], VNC6A_REG); | ||
724 | rvin_write(vin, p_set->coeff_set[16], VNC6B_REG); | ||
725 | rvin_write(vin, p_set->coeff_set[17], VNC6C_REG); | ||
726 | |||
727 | rvin_write(vin, p_set->coeff_set[18], VNC7A_REG); | ||
728 | rvin_write(vin, p_set->coeff_set[19], VNC7B_REG); | ||
729 | rvin_write(vin, p_set->coeff_set[20], VNC7C_REG); | ||
730 | |||
731 | rvin_write(vin, p_set->coeff_set[21], VNC8A_REG); | ||
732 | rvin_write(vin, p_set->coeff_set[22], VNC8B_REG); | ||
733 | rvin_write(vin, p_set->coeff_set[23], VNC8C_REG); | ||
734 | } | ||
735 | |||
736 | void rvin_crop_scale_comp(struct rvin_dev *vin) | ||
737 | { | ||
738 | u32 xs, ys; | ||
739 | |||
740 | /* Set Start/End Pixel/Line Pre-Clip */ | ||
741 | rvin_write(vin, vin->crop.left, VNSPPRC_REG); | ||
742 | rvin_write(vin, vin->crop.left + vin->crop.width - 1, VNEPPRC_REG); | ||
743 | switch (vin->format.field) { | ||
744 | case V4L2_FIELD_INTERLACED: | ||
745 | case V4L2_FIELD_INTERLACED_TB: | ||
746 | case V4L2_FIELD_INTERLACED_BT: | ||
747 | rvin_write(vin, vin->crop.top / 2, VNSLPRC_REG); | ||
748 | rvin_write(vin, (vin->crop.top + vin->crop.height) / 2 - 1, | ||
749 | VNELPRC_REG); | ||
750 | break; | ||
751 | default: | ||
752 | rvin_write(vin, vin->crop.top, VNSLPRC_REG); | ||
753 | rvin_write(vin, vin->crop.top + vin->crop.height - 1, | ||
754 | VNELPRC_REG); | ||
755 | break; | ||
756 | } | ||
757 | |||
758 | /* Set scaling coefficient */ | ||
759 | ys = 0; | ||
760 | if (vin->crop.height != vin->compose.height) | ||
761 | ys = (4096 * vin->crop.height) / vin->compose.height; | ||
762 | rvin_write(vin, ys, VNYS_REG); | ||
763 | |||
764 | xs = 0; | ||
765 | if (vin->crop.width != vin->compose.width) | ||
766 | xs = (4096 * vin->crop.width) / vin->compose.width; | ||
767 | |||
768 | /* Horizontal upscaling is up to double size */ | ||
769 | if (xs > 0 && xs < 2048) | ||
770 | xs = 2048; | ||
771 | |||
772 | rvin_write(vin, xs, VNXS_REG); | ||
773 | |||
774 | /* Horizontal upscaling is done out by scaling down from double size */ | ||
775 | if (xs < 4096) | ||
776 | xs *= 2; | ||
777 | |||
778 | rvin_set_coeff(vin, xs); | ||
779 | |||
780 | /* Set Start/End Pixel/Line Post-Clip */ | ||
781 | rvin_write(vin, 0, VNSPPOC_REG); | ||
782 | rvin_write(vin, 0, VNSLPOC_REG); | ||
783 | rvin_write(vin, vin->format.width - 1, VNEPPOC_REG); | ||
784 | switch (vin->format.field) { | ||
785 | case V4L2_FIELD_INTERLACED: | ||
786 | case V4L2_FIELD_INTERLACED_TB: | ||
787 | case V4L2_FIELD_INTERLACED_BT: | ||
788 | rvin_write(vin, vin->format.height / 2 - 1, VNELPOC_REG); | ||
789 | break; | ||
790 | default: | ||
791 | rvin_write(vin, vin->format.height - 1, VNELPOC_REG); | ||
792 | break; | ||
793 | } | ||
794 | |||
795 | if (vin->format.pixelformat == V4L2_PIX_FMT_NV16) | ||
796 | rvin_write(vin, ALIGN(vin->format.width, 0x20), VNIS_REG); | ||
797 | else | ||
798 | rvin_write(vin, ALIGN(vin->format.width, 0x10), VNIS_REG); | ||
799 | |||
800 | vin_dbg(vin, | ||
801 | "Pre-Clip: %ux%u@%u:%u YS: %d XS: %d Post-Clip: %ux%u@%u:%u\n", | ||
802 | vin->crop.width, vin->crop.height, vin->crop.left, | ||
803 | vin->crop.top, ys, xs, vin->format.width, vin->format.height, | ||
804 | 0, 0); | ||
805 | } | ||
806 | |||
807 | void rvin_scale_try(struct rvin_dev *vin, struct v4l2_pix_format *pix, | ||
808 | u32 width, u32 height) | ||
809 | { | ||
810 | /* All VIN channels on Gen2 have scalers */ | ||
811 | pix->width = width; | ||
812 | pix->height = height; | ||
813 | } | ||
814 | |||
815 | /* ----------------------------------------------------------------------------- | ||
816 | * DMA Functions | ||
817 | */ | ||
818 | |||
819 | #define RVIN_TIMEOUT_MS 100 | ||
820 | #define RVIN_RETRIES 10 | ||
821 | |||
822 | struct rvin_buffer { | ||
823 | struct vb2_v4l2_buffer vb; | ||
824 | struct list_head list; | ||
825 | }; | ||
826 | |||
827 | #define to_buf_list(vb2_buffer) (&container_of(vb2_buffer, \ | ||
828 | struct rvin_buffer, \ | ||
829 | vb)->list) | ||
830 | |||
831 | /* Moves a buffer from the queue to the HW slots */ | ||
832 | static bool rvin_fill_hw_slot(struct rvin_dev *vin, int slot) | ||
833 | { | ||
834 | struct rvin_buffer *buf; | ||
835 | struct vb2_v4l2_buffer *vbuf; | ||
836 | dma_addr_t phys_addr_top; | ||
837 | |||
838 | if (vin->queue_buf[slot] != NULL) | ||
839 | return true; | ||
840 | |||
841 | if (list_empty(&vin->buf_list)) | ||
842 | return false; | ||
843 | |||
844 | vin_dbg(vin, "Filling HW slot: %d\n", slot); | ||
845 | |||
846 | /* Keep track of buffer we give to HW */ | ||
847 | buf = list_entry(vin->buf_list.next, struct rvin_buffer, list); | ||
848 | vbuf = &buf->vb; | ||
849 | list_del_init(to_buf_list(vbuf)); | ||
850 | vin->queue_buf[slot] = vbuf; | ||
851 | |||
852 | /* Setup DMA */ | ||
853 | phys_addr_top = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0); | ||
854 | rvin_set_slot_addr(vin, slot, phys_addr_top); | ||
855 | |||
856 | return true; | ||
857 | } | ||
858 | |||
859 | static bool rvin_fill_hw(struct rvin_dev *vin) | ||
860 | { | ||
861 | int slot, limit; | ||
862 | |||
863 | limit = vin->continuous ? HW_BUFFER_NUM : 1; | ||
864 | |||
865 | for (slot = 0; slot < limit; slot++) | ||
866 | if (!rvin_fill_hw_slot(vin, slot)) | ||
867 | return false; | ||
868 | return true; | ||
869 | } | ||
870 | |||
871 | static irqreturn_t rvin_irq(int irq, void *data) | ||
872 | { | ||
873 | struct rvin_dev *vin = data; | ||
874 | u32 int_status; | ||
875 | int slot; | ||
876 | unsigned int sequence, handled = 0; | ||
877 | unsigned long flags; | ||
878 | |||
879 | spin_lock_irqsave(&vin->qlock, flags); | ||
880 | |||
881 | int_status = rvin_get_interrupt_status(vin); | ||
882 | if (!int_status) | ||
883 | goto done; | ||
884 | |||
885 | rvin_ack_interrupt(vin); | ||
886 | handled = 1; | ||
887 | |||
888 | /* Nothing to do if capture status is 'STOPPED' */ | ||
889 | if (vin->state == STOPPED) { | ||
890 | vin_dbg(vin, "IRQ while state stopped\n"); | ||
891 | goto done; | ||
892 | } | ||
893 | |||
894 | /* Nothing to do if capture status is 'STOPPING' */ | ||
895 | if (vin->state == STOPPING) { | ||
896 | vin_dbg(vin, "IRQ while state stopping\n"); | ||
897 | goto done; | ||
898 | } | ||
899 | |||
900 | /* Prepare for capture and update state */ | ||
901 | slot = rvin_get_active_slot(vin); | ||
902 | sequence = vin->sequence++; | ||
903 | |||
904 | vin_dbg(vin, "IRQ %02d: %d\tbuf0: %c buf1: %c buf2: %c\tmore: %d\n", | ||
905 | sequence, slot, | ||
906 | slot == 0 ? 'x' : vin->queue_buf[0] != NULL ? '1' : '0', | ||
907 | slot == 1 ? 'x' : vin->queue_buf[1] != NULL ? '1' : '0', | ||
908 | slot == 2 ? 'x' : vin->queue_buf[2] != NULL ? '1' : '0', | ||
909 | !list_empty(&vin->buf_list)); | ||
910 | |||
911 | /* HW have written to a slot that is not prepared we are in trouble */ | ||
912 | if (WARN_ON((vin->queue_buf[slot] == NULL))) | ||
913 | goto done; | ||
914 | |||
915 | /* Capture frame */ | ||
916 | vin->queue_buf[slot]->field = vin->format.field; | ||
917 | vin->queue_buf[slot]->sequence = sequence; | ||
918 | vin->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns(); | ||
919 | vb2_buffer_done(&vin->queue_buf[slot]->vb2_buf, VB2_BUF_STATE_DONE); | ||
920 | vin->queue_buf[slot] = NULL; | ||
921 | |||
922 | /* Prepare for next frame */ | ||
923 | if (!rvin_fill_hw(vin)) { | ||
924 | |||
925 | /* | ||
926 | * Can't supply HW with new buffers fast enough. Halt | ||
927 | * capture until more buffers are available. | ||
928 | */ | ||
929 | vin->state = STALLED; | ||
930 | |||
931 | /* | ||
932 | * The continuous capturing requires an explicit stop | ||
933 | * operation when there is no buffer to be set into | ||
934 | * the VnMBm registers. | ||
935 | */ | ||
936 | if (vin->continuous) { | ||
937 | rvin_capture_off(vin); | ||
938 | vin_dbg(vin, "IRQ %02d: hw not ready stop\n", sequence); | ||
939 | } | ||
940 | } else { | ||
941 | /* | ||
942 | * The single capturing requires an explicit capture | ||
943 | * operation to fetch the next frame. | ||
944 | */ | ||
945 | if (!vin->continuous) | ||
946 | rvin_capture_on(vin); | ||
947 | } | ||
948 | done: | ||
949 | spin_unlock_irqrestore(&vin->qlock, flags); | ||
950 | |||
951 | return IRQ_RETVAL(handled); | ||
952 | } | ||
953 | |||
954 | /* Need to hold qlock before calling */ | ||
955 | static void return_all_buffers(struct rvin_dev *vin, | ||
956 | enum vb2_buffer_state state) | ||
957 | { | ||
958 | struct rvin_buffer *buf, *node; | ||
959 | int i; | ||
960 | |||
961 | for (i = 0; i < HW_BUFFER_NUM; i++) { | ||
962 | if (vin->queue_buf[i]) { | ||
963 | vb2_buffer_done(&vin->queue_buf[i]->vb2_buf, | ||
964 | state); | ||
965 | vin->queue_buf[i] = NULL; | ||
966 | } | ||
967 | } | ||
968 | |||
969 | list_for_each_entry_safe(buf, node, &vin->buf_list, list) { | ||
970 | vb2_buffer_done(&buf->vb.vb2_buf, state); | ||
971 | list_del(&buf->list); | ||
972 | } | ||
973 | } | ||
974 | |||
975 | static int rvin_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, | ||
976 | unsigned int *nplanes, unsigned int sizes[], | ||
977 | void *alloc_ctxs[]) | ||
978 | |||
979 | { | ||
980 | struct rvin_dev *vin = vb2_get_drv_priv(vq); | ||
981 | |||
982 | alloc_ctxs[0] = vin->alloc_ctx; | ||
983 | /* Make sure the image size is large enough. */ | ||
984 | if (*nplanes) | ||
985 | return sizes[0] < vin->format.sizeimage ? -EINVAL : 0; | ||
986 | |||
987 | *nplanes = 1; | ||
988 | sizes[0] = vin->format.sizeimage; | ||
989 | |||
990 | return 0; | ||
991 | }; | ||
992 | |||
993 | static int rvin_buffer_prepare(struct vb2_buffer *vb) | ||
994 | { | ||
995 | struct rvin_dev *vin = vb2_get_drv_priv(vb->vb2_queue); | ||
996 | unsigned long size = vin->format.sizeimage; | ||
997 | |||
998 | if (vb2_plane_size(vb, 0) < size) { | ||
999 | vin_err(vin, "buffer too small (%lu < %lu)\n", | ||
1000 | vb2_plane_size(vb, 0), size); | ||
1001 | return -EINVAL; | ||
1002 | } | ||
1003 | |||
1004 | vb2_set_plane_payload(vb, 0, size); | ||
1005 | |||
1006 | return 0; | ||
1007 | } | ||
1008 | |||
1009 | static void rvin_buffer_queue(struct vb2_buffer *vb) | ||
1010 | { | ||
1011 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | ||
1012 | struct rvin_dev *vin = vb2_get_drv_priv(vb->vb2_queue); | ||
1013 | unsigned long flags; | ||
1014 | |||
1015 | spin_lock_irqsave(&vin->qlock, flags); | ||
1016 | |||
1017 | list_add_tail(to_buf_list(vbuf), &vin->buf_list); | ||
1018 | |||
1019 | /* | ||
1020 | * If capture is stalled add buffer to HW and restart | ||
1021 | * capturing if HW is ready to continue. | ||
1022 | */ | ||
1023 | if (vin->state == STALLED) | ||
1024 | if (rvin_fill_hw(vin)) | ||
1025 | rvin_capture_on(vin); | ||
1026 | |||
1027 | spin_unlock_irqrestore(&vin->qlock, flags); | ||
1028 | } | ||
1029 | |||
1030 | static int rvin_start_streaming(struct vb2_queue *vq, unsigned int count) | ||
1031 | { | ||
1032 | struct rvin_dev *vin = vb2_get_drv_priv(vq); | ||
1033 | struct v4l2_subdev *sd; | ||
1034 | unsigned long flags; | ||
1035 | int ret; | ||
1036 | |||
1037 | sd = vin_to_source(vin); | ||
1038 | v4l2_subdev_call(sd, video, s_stream, 1); | ||
1039 | |||
1040 | spin_lock_irqsave(&vin->qlock, flags); | ||
1041 | |||
1042 | vin->state = RUNNING; | ||
1043 | vin->sequence = 0; | ||
1044 | |||
1045 | /* Continuous capture requires more buffers then there are HW slots */ | ||
1046 | vin->continuous = count > HW_BUFFER_NUM; | ||
1047 | |||
1048 | /* | ||
1049 | * This should never happen but if we don't have enough | ||
1050 | * buffers for HW bail out | ||
1051 | */ | ||
1052 | if (!rvin_fill_hw(vin)) { | ||
1053 | vin_err(vin, "HW not ready to start, not enough buffers available\n"); | ||
1054 | ret = -EINVAL; | ||
1055 | goto out; | ||
1056 | } | ||
1057 | |||
1058 | ret = rvin_capture_start(vin); | ||
1059 | out: | ||
1060 | /* Return all buffers if something went wrong */ | ||
1061 | if (ret) { | ||
1062 | return_all_buffers(vin, VB2_BUF_STATE_QUEUED); | ||
1063 | v4l2_subdev_call(sd, video, s_stream, 0); | ||
1064 | } | ||
1065 | |||
1066 | spin_unlock_irqrestore(&vin->qlock, flags); | ||
1067 | |||
1068 | return ret; | ||
1069 | } | ||
1070 | |||
1071 | static void rvin_stop_streaming(struct vb2_queue *vq) | ||
1072 | { | ||
1073 | struct rvin_dev *vin = vb2_get_drv_priv(vq); | ||
1074 | struct v4l2_subdev *sd; | ||
1075 | unsigned long flags; | ||
1076 | int retries = 0; | ||
1077 | |||
1078 | spin_lock_irqsave(&vin->qlock, flags); | ||
1079 | |||
1080 | vin->state = STOPPING; | ||
1081 | |||
1082 | /* Wait for streaming to stop */ | ||
1083 | while (retries++ < RVIN_RETRIES) { | ||
1084 | |||
1085 | rvin_capture_stop(vin); | ||
1086 | |||
1087 | /* Check if HW is stopped */ | ||
1088 | if (!rvin_capture_active(vin)) { | ||
1089 | vin->state = STOPPED; | ||
1090 | break; | ||
1091 | } | ||
1092 | |||
1093 | spin_unlock_irqrestore(&vin->qlock, flags); | ||
1094 | msleep(RVIN_TIMEOUT_MS); | ||
1095 | spin_lock_irqsave(&vin->qlock, flags); | ||
1096 | } | ||
1097 | |||
1098 | if (vin->state != STOPPED) { | ||
1099 | /* | ||
1100 | * If this happens something have gone horribly wrong. | ||
1101 | * Set state to stopped to prevent the interrupt handler | ||
1102 | * to make things worse... | ||
1103 | */ | ||
1104 | vin_err(vin, "Failed stop HW, something is seriously broken\n"); | ||
1105 | vin->state = STOPPED; | ||
1106 | } | ||
1107 | |||
1108 | /* Release all active buffers */ | ||
1109 | return_all_buffers(vin, VB2_BUF_STATE_ERROR); | ||
1110 | |||
1111 | spin_unlock_irqrestore(&vin->qlock, flags); | ||
1112 | |||
1113 | sd = vin_to_source(vin); | ||
1114 | v4l2_subdev_call(sd, video, s_stream, 0); | ||
1115 | |||
1116 | /* disable interrupts */ | ||
1117 | rvin_disable_interrupts(vin); | ||
1118 | } | ||
1119 | |||
1120 | static struct vb2_ops rvin_qops = { | ||
1121 | .queue_setup = rvin_queue_setup, | ||
1122 | .buf_prepare = rvin_buffer_prepare, | ||
1123 | .buf_queue = rvin_buffer_queue, | ||
1124 | .start_streaming = rvin_start_streaming, | ||
1125 | .stop_streaming = rvin_stop_streaming, | ||
1126 | .wait_prepare = vb2_ops_wait_prepare, | ||
1127 | .wait_finish = vb2_ops_wait_finish, | ||
1128 | }; | ||
1129 | |||
1130 | void rvin_dma_remove(struct rvin_dev *vin) | ||
1131 | { | ||
1132 | if (!IS_ERR_OR_NULL(vin->alloc_ctx)) | ||
1133 | vb2_dma_contig_cleanup_ctx(vin->alloc_ctx); | ||
1134 | |||
1135 | mutex_destroy(&vin->lock); | ||
1136 | |||
1137 | v4l2_device_unregister(&vin->v4l2_dev); | ||
1138 | } | ||
1139 | |||
1140 | int rvin_dma_probe(struct rvin_dev *vin, int irq) | ||
1141 | { | ||
1142 | struct vb2_queue *q = &vin->queue; | ||
1143 | int i, ret; | ||
1144 | |||
1145 | /* Initialize the top-level structure */ | ||
1146 | ret = v4l2_device_register(vin->dev, &vin->v4l2_dev); | ||
1147 | if (ret) | ||
1148 | return ret; | ||
1149 | |||
1150 | mutex_init(&vin->lock); | ||
1151 | INIT_LIST_HEAD(&vin->buf_list); | ||
1152 | |||
1153 | spin_lock_init(&vin->qlock); | ||
1154 | |||
1155 | vin->state = STOPPED; | ||
1156 | |||
1157 | for (i = 0; i < HW_BUFFER_NUM; i++) | ||
1158 | vin->queue_buf[i] = NULL; | ||
1159 | |||
1160 | /* buffer queue */ | ||
1161 | vin->alloc_ctx = vb2_dma_contig_init_ctx(vin->dev); | ||
1162 | if (IS_ERR(vin->alloc_ctx)) { | ||
1163 | ret = PTR_ERR(vin->alloc_ctx); | ||
1164 | goto error; | ||
1165 | } | ||
1166 | |||
1167 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1168 | q->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF; | ||
1169 | q->lock = &vin->lock; | ||
1170 | q->drv_priv = vin; | ||
1171 | q->buf_struct_size = sizeof(struct rvin_buffer); | ||
1172 | q->ops = &rvin_qops; | ||
1173 | q->mem_ops = &vb2_dma_contig_memops; | ||
1174 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | ||
1175 | q->min_buffers_needed = 2; | ||
1176 | |||
1177 | ret = vb2_queue_init(q); | ||
1178 | if (ret < 0) { | ||
1179 | vin_err(vin, "failed to initialize VB2 queue\n"); | ||
1180 | goto error; | ||
1181 | } | ||
1182 | |||
1183 | /* irq */ | ||
1184 | ret = devm_request_irq(vin->dev, irq, rvin_irq, IRQF_SHARED, | ||
1185 | KBUILD_MODNAME, vin); | ||
1186 | if (ret) { | ||
1187 | vin_err(vin, "failed to request irq\n"); | ||
1188 | goto error; | ||
1189 | } | ||
1190 | |||
1191 | return 0; | ||
1192 | error: | ||
1193 | rvin_dma_remove(vin); | ||
1194 | |||
1195 | return ret; | ||
1196 | } | ||
diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c new file mode 100644 index 000000000000..0bc4487e2482 --- /dev/null +++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c | |||
@@ -0,0 +1,768 @@ | |||
1 | /* | ||
2 | * Driver for Renesas R-Car VIN | ||
3 | * | ||
4 | * Copyright (C) 2016 Renesas Electronics Corp. | ||
5 | * Copyright (C) 2011-2013 Renesas Solutions Corp. | ||
6 | * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com> | ||
7 | * Copyright (C) 2008 Magnus Damm | ||
8 | * | ||
9 | * Based on the soc-camera rcar_vin driver | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | */ | ||
16 | |||
17 | #include <linux/pm_runtime.h> | ||
18 | |||
19 | #include <media/v4l2-event.h> | ||
20 | #include <media/v4l2-ioctl.h> | ||
21 | #include <media/v4l2-rect.h> | ||
22 | |||
23 | #include "rcar-vin.h" | ||
24 | |||
25 | #define RVIN_DEFAULT_FORMAT V4L2_PIX_FMT_YUYV | ||
26 | #define RVIN_MAX_WIDTH 2048 | ||
27 | #define RVIN_MAX_HEIGHT 2048 | ||
28 | |||
29 | /* ----------------------------------------------------------------------------- | ||
30 | * Format Conversions | ||
31 | */ | ||
32 | |||
33 | static const struct rvin_video_format rvin_formats[] = { | ||
34 | { | ||
35 | .fourcc = V4L2_PIX_FMT_NV16, | ||
36 | .bpp = 1, | ||
37 | }, | ||
38 | { | ||
39 | .fourcc = V4L2_PIX_FMT_YUYV, | ||
40 | .bpp = 2, | ||
41 | }, | ||
42 | { | ||
43 | .fourcc = V4L2_PIX_FMT_UYVY, | ||
44 | .bpp = 2, | ||
45 | }, | ||
46 | { | ||
47 | .fourcc = V4L2_PIX_FMT_RGB565, | ||
48 | .bpp = 2, | ||
49 | }, | ||
50 | { | ||
51 | .fourcc = V4L2_PIX_FMT_XRGB555, | ||
52 | .bpp = 2, | ||
53 | }, | ||
54 | { | ||
55 | .fourcc = V4L2_PIX_FMT_XBGR32, | ||
56 | .bpp = 4, | ||
57 | }, | ||
58 | }; | ||
59 | |||
60 | const struct rvin_video_format *rvin_format_from_pixel(u32 pixelformat) | ||
61 | { | ||
62 | int i; | ||
63 | |||
64 | for (i = 0; i < ARRAY_SIZE(rvin_formats); i++) | ||
65 | if (rvin_formats[i].fourcc == pixelformat) | ||
66 | return rvin_formats + i; | ||
67 | |||
68 | return NULL; | ||
69 | } | ||
70 | |||
71 | static u32 rvin_format_bytesperline(struct v4l2_pix_format *pix) | ||
72 | { | ||
73 | const struct rvin_video_format *fmt; | ||
74 | |||
75 | fmt = rvin_format_from_pixel(pix->pixelformat); | ||
76 | |||
77 | if (WARN_ON(!fmt)) | ||
78 | return -EINVAL; | ||
79 | |||
80 | return pix->width * fmt->bpp; | ||
81 | } | ||
82 | |||
83 | static u32 rvin_format_sizeimage(struct v4l2_pix_format *pix) | ||
84 | { | ||
85 | if (pix->pixelformat == V4L2_PIX_FMT_NV16) | ||
86 | return pix->bytesperline * pix->height * 2; | ||
87 | |||
88 | return pix->bytesperline * pix->height; | ||
89 | } | ||
90 | |||
91 | /* ----------------------------------------------------------------------------- | ||
92 | * V4L2 | ||
93 | */ | ||
94 | |||
95 | static int __rvin_try_format_source(struct rvin_dev *vin, | ||
96 | u32 which, | ||
97 | struct v4l2_pix_format *pix, | ||
98 | struct rvin_source_fmt *source) | ||
99 | { | ||
100 | struct v4l2_subdev *sd; | ||
101 | struct v4l2_subdev_pad_config pad_cfg; | ||
102 | struct v4l2_subdev_format format = { | ||
103 | .which = which, | ||
104 | }; | ||
105 | int ret; | ||
106 | |||
107 | sd = vin_to_source(vin); | ||
108 | |||
109 | v4l2_fill_mbus_format(&format.format, pix, vin->source.code); | ||
110 | |||
111 | ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, pad, set_fmt, | ||
112 | &pad_cfg, &format); | ||
113 | if (ret < 0) | ||
114 | return ret; | ||
115 | |||
116 | v4l2_fill_pix_format(pix, &format.format); | ||
117 | |||
118 | source->width = pix->width; | ||
119 | source->height = pix->height; | ||
120 | |||
121 | vin_dbg(vin, "Source resolution: %ux%u\n", source->width, | ||
122 | source->height); | ||
123 | |||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | static int __rvin_try_format(struct rvin_dev *vin, | ||
128 | u32 which, | ||
129 | struct v4l2_pix_format *pix, | ||
130 | struct rvin_source_fmt *source) | ||
131 | { | ||
132 | const struct rvin_video_format *info; | ||
133 | u32 rwidth, rheight, walign; | ||
134 | |||
135 | /* Requested */ | ||
136 | rwidth = pix->width; | ||
137 | rheight = pix->height; | ||
138 | |||
139 | /* | ||
140 | * Retrieve format information and select the current format if the | ||
141 | * requested format isn't supported. | ||
142 | */ | ||
143 | info = rvin_format_from_pixel(pix->pixelformat); | ||
144 | if (!info) { | ||
145 | vin_dbg(vin, "Format %x not found, keeping %x\n", | ||
146 | pix->pixelformat, vin->format.pixelformat); | ||
147 | *pix = vin->format; | ||
148 | pix->width = rwidth; | ||
149 | pix->height = rheight; | ||
150 | } | ||
151 | |||
152 | /* Always recalculate */ | ||
153 | pix->bytesperline = 0; | ||
154 | pix->sizeimage = 0; | ||
155 | |||
156 | /* Limit to source capabilities */ | ||
157 | __rvin_try_format_source(vin, which, pix, source); | ||
158 | |||
159 | /* If source can't match format try if VIN can scale */ | ||
160 | if (source->width != rwidth || source->height != rheight) | ||
161 | rvin_scale_try(vin, pix, rwidth, rheight); | ||
162 | |||
163 | /* HW limit width to a multiple of 32 (2^5) for NV16 else 2 (2^1) */ | ||
164 | walign = vin->format.pixelformat == V4L2_PIX_FMT_NV16 ? 5 : 1; | ||
165 | |||
166 | /* Limit to VIN capabilities */ | ||
167 | v4l_bound_align_image(&pix->width, 2, RVIN_MAX_WIDTH, walign, | ||
168 | &pix->height, 4, RVIN_MAX_HEIGHT, 2, 0); | ||
169 | |||
170 | switch (pix->field) { | ||
171 | case V4L2_FIELD_NONE: | ||
172 | case V4L2_FIELD_TOP: | ||
173 | case V4L2_FIELD_BOTTOM: | ||
174 | case V4L2_FIELD_INTERLACED_TB: | ||
175 | case V4L2_FIELD_INTERLACED_BT: | ||
176 | case V4L2_FIELD_INTERLACED: | ||
177 | break; | ||
178 | default: | ||
179 | pix->field = V4L2_FIELD_NONE; | ||
180 | break; | ||
181 | } | ||
182 | |||
183 | pix->bytesperline = max_t(u32, pix->bytesperline, | ||
184 | rvin_format_bytesperline(pix)); | ||
185 | pix->sizeimage = max_t(u32, pix->sizeimage, | ||
186 | rvin_format_sizeimage(pix)); | ||
187 | |||
188 | vin_dbg(vin, "Requested %ux%u Got %ux%u bpl: %d size: %d\n", | ||
189 | rwidth, rheight, pix->width, pix->height, | ||
190 | pix->bytesperline, pix->sizeimage); | ||
191 | |||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | static int rvin_querycap(struct file *file, void *priv, | ||
196 | struct v4l2_capability *cap) | ||
197 | { | ||
198 | struct rvin_dev *vin = video_drvdata(file); | ||
199 | |||
200 | strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); | ||
201 | strlcpy(cap->card, "R_Car_VIN", sizeof(cap->card)); | ||
202 | snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", | ||
203 | dev_name(vin->dev)); | ||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | static int rvin_try_fmt_vid_cap(struct file *file, void *priv, | ||
208 | struct v4l2_format *f) | ||
209 | { | ||
210 | struct rvin_dev *vin = video_drvdata(file); | ||
211 | struct rvin_source_fmt source; | ||
212 | |||
213 | return __rvin_try_format(vin, V4L2_SUBDEV_FORMAT_TRY, &f->fmt.pix, | ||
214 | &source); | ||
215 | } | ||
216 | |||
217 | static int rvin_s_fmt_vid_cap(struct file *file, void *priv, | ||
218 | struct v4l2_format *f) | ||
219 | { | ||
220 | struct rvin_dev *vin = video_drvdata(file); | ||
221 | struct rvin_source_fmt source; | ||
222 | int ret; | ||
223 | |||
224 | if (vb2_is_busy(&vin->queue)) | ||
225 | return -EBUSY; | ||
226 | |||
227 | ret = __rvin_try_format(vin, V4L2_SUBDEV_FORMAT_ACTIVE, &f->fmt.pix, | ||
228 | &source); | ||
229 | if (ret) | ||
230 | return ret; | ||
231 | |||
232 | vin->source.width = source.width; | ||
233 | vin->source.height = source.height; | ||
234 | |||
235 | vin->format = f->fmt.pix; | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static int rvin_g_fmt_vid_cap(struct file *file, void *priv, | ||
241 | struct v4l2_format *f) | ||
242 | { | ||
243 | struct rvin_dev *vin = video_drvdata(file); | ||
244 | |||
245 | f->fmt.pix = vin->format; | ||
246 | |||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | static int rvin_enum_fmt_vid_cap(struct file *file, void *priv, | ||
251 | struct v4l2_fmtdesc *f) | ||
252 | { | ||
253 | if (f->index >= ARRAY_SIZE(rvin_formats)) | ||
254 | return -EINVAL; | ||
255 | |||
256 | f->pixelformat = rvin_formats[f->index].fourcc; | ||
257 | |||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | static int rvin_g_selection(struct file *file, void *fh, | ||
262 | struct v4l2_selection *s) | ||
263 | { | ||
264 | struct rvin_dev *vin = video_drvdata(file); | ||
265 | |||
266 | if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
267 | return -EINVAL; | ||
268 | |||
269 | switch (s->target) { | ||
270 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
271 | case V4L2_SEL_TGT_CROP_DEFAULT: | ||
272 | s->r.left = s->r.top = 0; | ||
273 | s->r.width = vin->source.width; | ||
274 | s->r.height = vin->source.height; | ||
275 | break; | ||
276 | case V4L2_SEL_TGT_CROP: | ||
277 | s->r = vin->crop; | ||
278 | break; | ||
279 | case V4L2_SEL_TGT_COMPOSE_BOUNDS: | ||
280 | case V4L2_SEL_TGT_COMPOSE_DEFAULT: | ||
281 | s->r.left = s->r.top = 0; | ||
282 | s->r.width = vin->format.width; | ||
283 | s->r.height = vin->format.height; | ||
284 | break; | ||
285 | case V4L2_SEL_TGT_COMPOSE: | ||
286 | s->r = vin->compose; | ||
287 | break; | ||
288 | default: | ||
289 | return -EINVAL; | ||
290 | } | ||
291 | |||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | static int rvin_s_selection(struct file *file, void *fh, | ||
296 | struct v4l2_selection *s) | ||
297 | { | ||
298 | struct rvin_dev *vin = video_drvdata(file); | ||
299 | const struct rvin_video_format *fmt; | ||
300 | struct v4l2_rect r = s->r; | ||
301 | struct v4l2_rect max_rect; | ||
302 | struct v4l2_rect min_rect = { | ||
303 | .width = 6, | ||
304 | .height = 2, | ||
305 | }; | ||
306 | |||
307 | if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
308 | return -EINVAL; | ||
309 | |||
310 | v4l2_rect_set_min_size(&r, &min_rect); | ||
311 | |||
312 | switch (s->target) { | ||
313 | case V4L2_SEL_TGT_CROP: | ||
314 | /* Can't crop outside of source input */ | ||
315 | max_rect.top = max_rect.left = 0; | ||
316 | max_rect.width = vin->source.width; | ||
317 | max_rect.height = vin->source.height; | ||
318 | v4l2_rect_map_inside(&r, &max_rect); | ||
319 | |||
320 | v4l_bound_align_image(&r.width, 2, vin->source.width, 1, | ||
321 | &r.height, 4, vin->source.height, 2, 0); | ||
322 | |||
323 | r.top = clamp_t(s32, r.top, 0, vin->source.height - r.height); | ||
324 | r.left = clamp_t(s32, r.left, 0, vin->source.width - r.width); | ||
325 | |||
326 | vin->crop = s->r = r; | ||
327 | |||
328 | vin_dbg(vin, "Cropped %dx%d@%d:%d of %dx%d\n", | ||
329 | r.width, r.height, r.left, r.top, | ||
330 | vin->source.width, vin->source.height); | ||
331 | break; | ||
332 | case V4L2_SEL_TGT_COMPOSE: | ||
333 | /* Make sure compose rect fits inside output format */ | ||
334 | max_rect.top = max_rect.left = 0; | ||
335 | max_rect.width = vin->format.width; | ||
336 | max_rect.height = vin->format.height; | ||
337 | v4l2_rect_map_inside(&r, &max_rect); | ||
338 | |||
339 | /* | ||
340 | * Composing is done by adding a offset to the buffer address, | ||
341 | * the HW wants this address to be aligned to HW_BUFFER_MASK. | ||
342 | * Make sure the top and left values meets this requirement. | ||
343 | */ | ||
344 | while ((r.top * vin->format.bytesperline) & HW_BUFFER_MASK) | ||
345 | r.top--; | ||
346 | |||
347 | fmt = rvin_format_from_pixel(vin->format.pixelformat); | ||
348 | while ((r.left * fmt->bpp) & HW_BUFFER_MASK) | ||
349 | r.left--; | ||
350 | |||
351 | vin->compose = s->r = r; | ||
352 | |||
353 | vin_dbg(vin, "Compose %dx%d@%d:%d in %dx%d\n", | ||
354 | r.width, r.height, r.left, r.top, | ||
355 | vin->format.width, vin->format.height); | ||
356 | break; | ||
357 | default: | ||
358 | return -EINVAL; | ||
359 | } | ||
360 | |||
361 | /* HW supports modifying configuration while running */ | ||
362 | rvin_crop_scale_comp(vin); | ||
363 | |||
364 | return 0; | ||
365 | } | ||
366 | |||
367 | static int rvin_cropcap(struct file *file, void *priv, | ||
368 | struct v4l2_cropcap *crop) | ||
369 | { | ||
370 | struct rvin_dev *vin = video_drvdata(file); | ||
371 | struct v4l2_subdev *sd = vin_to_source(vin); | ||
372 | |||
373 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
374 | return -EINVAL; | ||
375 | |||
376 | return v4l2_subdev_call(sd, video, cropcap, crop); | ||
377 | } | ||
378 | |||
379 | static int rvin_enum_input(struct file *file, void *priv, | ||
380 | struct v4l2_input *i) | ||
381 | { | ||
382 | struct rvin_dev *vin = video_drvdata(file); | ||
383 | struct v4l2_subdev *sd = vin_to_source(vin); | ||
384 | int ret; | ||
385 | |||
386 | if (i->index != 0) | ||
387 | return -EINVAL; | ||
388 | |||
389 | ret = v4l2_subdev_call(sd, video, g_input_status, &i->status); | ||
390 | if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) | ||
391 | return ret; | ||
392 | |||
393 | i->type = V4L2_INPUT_TYPE_CAMERA; | ||
394 | i->std = vin->vdev.tvnorms; | ||
395 | strlcpy(i->name, "Camera", sizeof(i->name)); | ||
396 | |||
397 | return 0; | ||
398 | } | ||
399 | |||
400 | static int rvin_g_input(struct file *file, void *priv, unsigned int *i) | ||
401 | { | ||
402 | *i = 0; | ||
403 | return 0; | ||
404 | } | ||
405 | |||
406 | static int rvin_s_input(struct file *file, void *priv, unsigned int i) | ||
407 | { | ||
408 | if (i > 0) | ||
409 | return -EINVAL; | ||
410 | return 0; | ||
411 | } | ||
412 | |||
413 | static int rvin_querystd(struct file *file, void *priv, v4l2_std_id *a) | ||
414 | { | ||
415 | struct rvin_dev *vin = video_drvdata(file); | ||
416 | struct v4l2_subdev *sd = vin_to_source(vin); | ||
417 | |||
418 | return v4l2_subdev_call(sd, video, querystd, a); | ||
419 | } | ||
420 | |||
421 | static int rvin_s_std(struct file *file, void *priv, v4l2_std_id a) | ||
422 | { | ||
423 | struct rvin_dev *vin = video_drvdata(file); | ||
424 | struct v4l2_subdev *sd = vin_to_source(vin); | ||
425 | struct v4l2_subdev_format fmt = { | ||
426 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
427 | }; | ||
428 | struct v4l2_mbus_framefmt *mf = &fmt.format; | ||
429 | int ret = v4l2_subdev_call(sd, video, s_std, a); | ||
430 | |||
431 | if (ret < 0) | ||
432 | return ret; | ||
433 | |||
434 | /* Changing the standard will change the width/height */ | ||
435 | ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); | ||
436 | if (ret) { | ||
437 | vin_err(vin, "Failed to get initial format\n"); | ||
438 | return ret; | ||
439 | } | ||
440 | |||
441 | vin->format.width = mf->width; | ||
442 | vin->format.height = mf->height; | ||
443 | |||
444 | vin->crop.top = vin->crop.left = 0; | ||
445 | vin->crop.width = mf->width; | ||
446 | vin->crop.height = mf->height; | ||
447 | |||
448 | vin->compose.top = vin->compose.left = 0; | ||
449 | vin->compose.width = mf->width; | ||
450 | vin->compose.height = mf->height; | ||
451 | |||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | static int rvin_g_std(struct file *file, void *priv, v4l2_std_id *a) | ||
456 | { | ||
457 | struct rvin_dev *vin = video_drvdata(file); | ||
458 | struct v4l2_subdev *sd = vin_to_source(vin); | ||
459 | |||
460 | return v4l2_subdev_call(sd, video, g_std, a); | ||
461 | } | ||
462 | |||
463 | static int rvin_subscribe_event(struct v4l2_fh *fh, | ||
464 | const struct v4l2_event_subscription *sub) | ||
465 | { | ||
466 | switch (sub->type) { | ||
467 | case V4L2_EVENT_SOURCE_CHANGE: | ||
468 | return v4l2_event_subscribe(fh, sub, 4, NULL); | ||
469 | } | ||
470 | return v4l2_ctrl_subscribe_event(fh, sub); | ||
471 | } | ||
472 | |||
473 | static const struct v4l2_ioctl_ops rvin_ioctl_ops = { | ||
474 | .vidioc_querycap = rvin_querycap, | ||
475 | .vidioc_try_fmt_vid_cap = rvin_try_fmt_vid_cap, | ||
476 | .vidioc_g_fmt_vid_cap = rvin_g_fmt_vid_cap, | ||
477 | .vidioc_s_fmt_vid_cap = rvin_s_fmt_vid_cap, | ||
478 | .vidioc_enum_fmt_vid_cap = rvin_enum_fmt_vid_cap, | ||
479 | |||
480 | .vidioc_g_selection = rvin_g_selection, | ||
481 | .vidioc_s_selection = rvin_s_selection, | ||
482 | |||
483 | .vidioc_cropcap = rvin_cropcap, | ||
484 | |||
485 | .vidioc_enum_input = rvin_enum_input, | ||
486 | .vidioc_g_input = rvin_g_input, | ||
487 | .vidioc_s_input = rvin_s_input, | ||
488 | |||
489 | .vidioc_querystd = rvin_querystd, | ||
490 | .vidioc_g_std = rvin_g_std, | ||
491 | .vidioc_s_std = rvin_s_std, | ||
492 | |||
493 | .vidioc_reqbufs = vb2_ioctl_reqbufs, | ||
494 | .vidioc_create_bufs = vb2_ioctl_create_bufs, | ||
495 | .vidioc_querybuf = vb2_ioctl_querybuf, | ||
496 | .vidioc_qbuf = vb2_ioctl_qbuf, | ||
497 | .vidioc_dqbuf = vb2_ioctl_dqbuf, | ||
498 | .vidioc_expbuf = vb2_ioctl_expbuf, | ||
499 | .vidioc_prepare_buf = vb2_ioctl_prepare_buf, | ||
500 | .vidioc_streamon = vb2_ioctl_streamon, | ||
501 | .vidioc_streamoff = vb2_ioctl_streamoff, | ||
502 | |||
503 | .vidioc_log_status = v4l2_ctrl_log_status, | ||
504 | .vidioc_subscribe_event = rvin_subscribe_event, | ||
505 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | ||
506 | }; | ||
507 | |||
508 | /* ----------------------------------------------------------------------------- | ||
509 | * File Operations | ||
510 | */ | ||
511 | |||
512 | static int rvin_power_on(struct rvin_dev *vin) | ||
513 | { | ||
514 | int ret; | ||
515 | struct v4l2_subdev *sd = vin_to_source(vin); | ||
516 | |||
517 | pm_runtime_get_sync(vin->v4l2_dev.dev); | ||
518 | |||
519 | ret = v4l2_subdev_call(sd, core, s_power, 1); | ||
520 | if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) | ||
521 | return ret; | ||
522 | return 0; | ||
523 | } | ||
524 | |||
525 | static int rvin_power_off(struct rvin_dev *vin) | ||
526 | { | ||
527 | int ret; | ||
528 | struct v4l2_subdev *sd = vin_to_source(vin); | ||
529 | |||
530 | ret = v4l2_subdev_call(sd, core, s_power, 0); | ||
531 | |||
532 | pm_runtime_put(vin->v4l2_dev.dev); | ||
533 | |||
534 | if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) | ||
535 | return ret; | ||
536 | |||
537 | return 0; | ||
538 | } | ||
539 | |||
540 | static int rvin_initialize_device(struct file *file) | ||
541 | { | ||
542 | struct rvin_dev *vin = video_drvdata(file); | ||
543 | int ret; | ||
544 | |||
545 | struct v4l2_format f = { | ||
546 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
547 | .fmt.pix = { | ||
548 | .width = vin->format.width, | ||
549 | .height = vin->format.height, | ||
550 | .field = vin->format.field, | ||
551 | .colorspace = vin->format.colorspace, | ||
552 | .pixelformat = vin->format.pixelformat, | ||
553 | }, | ||
554 | }; | ||
555 | |||
556 | ret = rvin_power_on(vin); | ||
557 | if (ret < 0) | ||
558 | return ret; | ||
559 | |||
560 | pm_runtime_enable(&vin->vdev.dev); | ||
561 | ret = pm_runtime_resume(&vin->vdev.dev); | ||
562 | if (ret < 0 && ret != -ENOSYS) | ||
563 | goto eresume; | ||
564 | |||
565 | /* | ||
566 | * Try to configure with default parameters. Notice: this is the | ||
567 | * very first open, so, we cannot race against other calls, | ||
568 | * apart from someone else calling open() simultaneously, but | ||
569 | * .host_lock is protecting us against it. | ||
570 | */ | ||
571 | ret = rvin_s_fmt_vid_cap(file, NULL, &f); | ||
572 | if (ret < 0) | ||
573 | goto esfmt; | ||
574 | |||
575 | v4l2_ctrl_handler_setup(&vin->ctrl_handler); | ||
576 | |||
577 | return 0; | ||
578 | esfmt: | ||
579 | pm_runtime_disable(&vin->vdev.dev); | ||
580 | eresume: | ||
581 | rvin_power_off(vin); | ||
582 | |||
583 | return ret; | ||
584 | } | ||
585 | |||
586 | static int rvin_open(struct file *file) | ||
587 | { | ||
588 | struct rvin_dev *vin = video_drvdata(file); | ||
589 | int ret; | ||
590 | |||
591 | mutex_lock(&vin->lock); | ||
592 | |||
593 | file->private_data = vin; | ||
594 | |||
595 | ret = v4l2_fh_open(file); | ||
596 | if (ret) | ||
597 | goto unlock; | ||
598 | |||
599 | if (!v4l2_fh_is_singular_file(file)) | ||
600 | goto unlock; | ||
601 | |||
602 | if (rvin_initialize_device(file)) { | ||
603 | v4l2_fh_release(file); | ||
604 | ret = -ENODEV; | ||
605 | } | ||
606 | |||
607 | unlock: | ||
608 | mutex_unlock(&vin->lock); | ||
609 | return ret; | ||
610 | } | ||
611 | |||
612 | static int rvin_release(struct file *file) | ||
613 | { | ||
614 | struct rvin_dev *vin = video_drvdata(file); | ||
615 | bool fh_singular; | ||
616 | int ret; | ||
617 | |||
618 | mutex_lock(&vin->lock); | ||
619 | |||
620 | /* Save the singular status before we call the clean-up helper */ | ||
621 | fh_singular = v4l2_fh_is_singular_file(file); | ||
622 | |||
623 | /* the release helper will cleanup any on-going streaming */ | ||
624 | ret = _vb2_fop_release(file, NULL); | ||
625 | |||
626 | /* | ||
627 | * If this was the last open file. | ||
628 | * Then de-initialize hw module. | ||
629 | */ | ||
630 | if (fh_singular) { | ||
631 | pm_runtime_suspend(&vin->vdev.dev); | ||
632 | pm_runtime_disable(&vin->vdev.dev); | ||
633 | rvin_power_off(vin); | ||
634 | } | ||
635 | |||
636 | mutex_unlock(&vin->lock); | ||
637 | |||
638 | return ret; | ||
639 | } | ||
640 | |||
641 | static const struct v4l2_file_operations rvin_fops = { | ||
642 | .owner = THIS_MODULE, | ||
643 | .unlocked_ioctl = video_ioctl2, | ||
644 | .open = rvin_open, | ||
645 | .release = rvin_release, | ||
646 | .poll = vb2_fop_poll, | ||
647 | .mmap = vb2_fop_mmap, | ||
648 | .read = vb2_fop_read, | ||
649 | }; | ||
650 | |||
651 | void rvin_v4l2_remove(struct rvin_dev *vin) | ||
652 | { | ||
653 | v4l2_info(&vin->v4l2_dev, "Removing %s\n", | ||
654 | video_device_node_name(&vin->vdev)); | ||
655 | |||
656 | /* Checks internaly if handlers have been init or not */ | ||
657 | v4l2_ctrl_handler_free(&vin->ctrl_handler); | ||
658 | |||
659 | /* Checks internaly if vdev have been init or not */ | ||
660 | video_unregister_device(&vin->vdev); | ||
661 | } | ||
662 | |||
663 | static void rvin_notify(struct v4l2_subdev *sd, | ||
664 | unsigned int notification, void *arg) | ||
665 | { | ||
666 | struct rvin_dev *vin = | ||
667 | container_of(sd->v4l2_dev, struct rvin_dev, v4l2_dev); | ||
668 | |||
669 | switch (notification) { | ||
670 | case V4L2_DEVICE_NOTIFY_EVENT: | ||
671 | v4l2_event_queue(&vin->vdev, arg); | ||
672 | break; | ||
673 | default: | ||
674 | break; | ||
675 | } | ||
676 | } | ||
677 | |||
678 | int rvin_v4l2_probe(struct rvin_dev *vin) | ||
679 | { | ||
680 | struct v4l2_subdev_format fmt = { | ||
681 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
682 | }; | ||
683 | struct v4l2_mbus_framefmt *mf = &fmt.format; | ||
684 | struct video_device *vdev = &vin->vdev; | ||
685 | struct v4l2_subdev *sd = vin_to_source(vin); | ||
686 | int ret; | ||
687 | |||
688 | v4l2_set_subdev_hostdata(sd, vin); | ||
689 | |||
690 | vin->v4l2_dev.notify = rvin_notify; | ||
691 | |||
692 | ret = v4l2_subdev_call(sd, video, g_tvnorms, &vin->vdev.tvnorms); | ||
693 | if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) | ||
694 | return ret; | ||
695 | |||
696 | if (vin->vdev.tvnorms == 0) { | ||
697 | /* Disable the STD API if there are no tvnorms defined */ | ||
698 | v4l2_disable_ioctl(&vin->vdev, VIDIOC_G_STD); | ||
699 | v4l2_disable_ioctl(&vin->vdev, VIDIOC_S_STD); | ||
700 | v4l2_disable_ioctl(&vin->vdev, VIDIOC_QUERYSTD); | ||
701 | v4l2_disable_ioctl(&vin->vdev, VIDIOC_ENUMSTD); | ||
702 | } | ||
703 | |||
704 | /* Add the controls */ | ||
705 | /* | ||
706 | * Currently the subdev with the largest number of controls (13) is | ||
707 | * ov6550. So let's pick 16 as a hint for the control handler. Note | ||
708 | * that this is a hint only: too large and you waste some memory, too | ||
709 | * small and there is a (very) small performance hit when looking up | ||
710 | * controls in the internal hash. | ||
711 | */ | ||
712 | ret = v4l2_ctrl_handler_init(&vin->ctrl_handler, 16); | ||
713 | if (ret < 0) | ||
714 | return ret; | ||
715 | |||
716 | ret = v4l2_ctrl_add_handler(&vin->ctrl_handler, sd->ctrl_handler, NULL); | ||
717 | if (ret < 0) | ||
718 | return ret; | ||
719 | |||
720 | /* video node */ | ||
721 | vdev->fops = &rvin_fops; | ||
722 | vdev->v4l2_dev = &vin->v4l2_dev; | ||
723 | vdev->queue = &vin->queue; | ||
724 | strlcpy(vdev->name, KBUILD_MODNAME, sizeof(vdev->name)); | ||
725 | vdev->release = video_device_release_empty; | ||
726 | vdev->ioctl_ops = &rvin_ioctl_ops; | ||
727 | vdev->lock = &vin->lock; | ||
728 | vdev->ctrl_handler = &vin->ctrl_handler; | ||
729 | vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | | ||
730 | V4L2_CAP_READWRITE; | ||
731 | |||
732 | /* Try to improve our guess of a reasonable window format */ | ||
733 | ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); | ||
734 | if (ret) { | ||
735 | vin_err(vin, "Failed to get initial format\n"); | ||
736 | return ret; | ||
737 | } | ||
738 | |||
739 | /* Set default format */ | ||
740 | vin->format.width = mf->width; | ||
741 | vin->format.height = mf->height; | ||
742 | vin->format.colorspace = mf->colorspace; | ||
743 | vin->format.field = mf->field; | ||
744 | vin->format.pixelformat = RVIN_DEFAULT_FORMAT; | ||
745 | |||
746 | |||
747 | /* Set initial crop and compose */ | ||
748 | vin->crop.top = vin->crop.left = 0; | ||
749 | vin->crop.width = mf->width; | ||
750 | vin->crop.height = mf->height; | ||
751 | |||
752 | vin->compose.top = vin->compose.left = 0; | ||
753 | vin->compose.width = mf->width; | ||
754 | vin->compose.height = mf->height; | ||
755 | |||
756 | ret = video_register_device(&vin->vdev, VFL_TYPE_GRABBER, -1); | ||
757 | if (ret) { | ||
758 | vin_err(vin, "Failed to register video device\n"); | ||
759 | return ret; | ||
760 | } | ||
761 | |||
762 | video_set_drvdata(&vin->vdev, vin); | ||
763 | |||
764 | v4l2_info(&vin->v4l2_dev, "Device registered as %s\n", | ||
765 | video_device_node_name(&vin->vdev)); | ||
766 | |||
767 | return ret; | ||
768 | } | ||
diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h new file mode 100644 index 000000000000..544a3b362808 --- /dev/null +++ b/drivers/media/platform/rcar-vin/rcar-vin.h | |||
@@ -0,0 +1,163 @@ | |||
1 | /* | ||
2 | * Driver for Renesas R-Car VIN | ||
3 | * | ||
4 | * Copyright (C) 2016 Renesas Electronics Corp. | ||
5 | * Copyright (C) 2011-2013 Renesas Solutions Corp. | ||
6 | * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com> | ||
7 | * Copyright (C) 2008 Magnus Damm | ||
8 | * | ||
9 | * Based on the soc-camera rcar_vin driver | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | */ | ||
16 | |||
17 | #ifndef __RCAR_VIN__ | ||
18 | #define __RCAR_VIN__ | ||
19 | |||
20 | #include <media/v4l2-async.h> | ||
21 | #include <media/v4l2-ctrls.h> | ||
22 | #include <media/v4l2-dev.h> | ||
23 | #include <media/v4l2-device.h> | ||
24 | #include <media/videobuf2-v4l2.h> | ||
25 | |||
26 | /* Number of HW buffers */ | ||
27 | #define HW_BUFFER_NUM 3 | ||
28 | |||
29 | /* Address alignment mask for HW buffers */ | ||
30 | #define HW_BUFFER_MASK 0x7f | ||
31 | |||
32 | enum chip_id { | ||
33 | RCAR_GEN2, | ||
34 | RCAR_H1, | ||
35 | RCAR_M1, | ||
36 | }; | ||
37 | |||
38 | /** | ||
39 | * STOPPED - No operation in progress | ||
40 | * RUNNING - Operation in progress have buffers | ||
41 | * STALLED - No operation in progress have no buffers | ||
42 | * STOPPING - Stopping operation | ||
43 | */ | ||
44 | enum rvin_dma_state { | ||
45 | STOPPED = 0, | ||
46 | RUNNING, | ||
47 | STALLED, | ||
48 | STOPPING, | ||
49 | }; | ||
50 | |||
51 | /** | ||
52 | * struct rvin_source_fmt - Source information | ||
53 | * @code: Media bus format from source | ||
54 | * @width: Width from source | ||
55 | * @height: Height from source | ||
56 | */ | ||
57 | struct rvin_source_fmt { | ||
58 | u32 code; | ||
59 | u32 width; | ||
60 | u32 height; | ||
61 | }; | ||
62 | |||
63 | /** | ||
64 | * struct rvin_video_format - Data format stored in memory | ||
65 | * @fourcc: Pixelformat | ||
66 | * @bpp: Bytes per pixel | ||
67 | */ | ||
68 | struct rvin_video_format { | ||
69 | u32 fourcc; | ||
70 | u8 bpp; | ||
71 | }; | ||
72 | |||
73 | struct rvin_graph_entity { | ||
74 | struct device_node *node; | ||
75 | struct media_entity *entity; | ||
76 | |||
77 | struct v4l2_async_subdev asd; | ||
78 | struct v4l2_subdev *subdev; | ||
79 | }; | ||
80 | |||
81 | /** | ||
82 | * struct rvin_dev - Renesas VIN device structure | ||
83 | * @dev: (OF) device | ||
84 | * @base: device I/O register space remapped to virtual memory | ||
85 | * @chip: type of VIN chip | ||
86 | * @mbus_cfg media bus configuration | ||
87 | * | ||
88 | * @vdev: V4L2 video device associated with VIN | ||
89 | * @v4l2_dev: V4L2 device | ||
90 | * @ctrl_handler: V4L2 control handler | ||
91 | * @notifier: V4L2 asynchronous subdevs notifier | ||
92 | * @entity: entity in the DT for subdevice | ||
93 | * | ||
94 | * @lock: protects @queue | ||
95 | * @queue: vb2 buffers queue | ||
96 | * @alloc_ctx: allocation context for the vb2 @queue | ||
97 | * | ||
98 | * @qlock: protects @queue_buf, @buf_list, @continuous, @sequence | ||
99 | * @state | ||
100 | * @queue_buf: Keeps track of buffers given to HW slot | ||
101 | * @buf_list: list of queued buffers | ||
102 | * @continuous: tracks if active operation is continuous or single mode | ||
103 | * @sequence: V4L2 buffers sequence number | ||
104 | * @state: keeps track of operation state | ||
105 | * | ||
106 | * @source: active format from the video source | ||
107 | * @format: active V4L2 pixel format | ||
108 | * | ||
109 | * @crop: active cropping | ||
110 | * @compose: active composing | ||
111 | */ | ||
112 | struct rvin_dev { | ||
113 | struct device *dev; | ||
114 | void __iomem *base; | ||
115 | enum chip_id chip; | ||
116 | struct v4l2_mbus_config mbus_cfg; | ||
117 | |||
118 | struct video_device vdev; | ||
119 | struct v4l2_device v4l2_dev; | ||
120 | struct v4l2_ctrl_handler ctrl_handler; | ||
121 | struct v4l2_async_notifier notifier; | ||
122 | struct rvin_graph_entity entity; | ||
123 | |||
124 | struct mutex lock; | ||
125 | struct vb2_queue queue; | ||
126 | struct vb2_alloc_ctx *alloc_ctx; | ||
127 | |||
128 | spinlock_t qlock; | ||
129 | struct vb2_v4l2_buffer *queue_buf[HW_BUFFER_NUM]; | ||
130 | struct list_head buf_list; | ||
131 | bool continuous; | ||
132 | unsigned int sequence; | ||
133 | enum rvin_dma_state state; | ||
134 | |||
135 | struct rvin_source_fmt source; | ||
136 | struct v4l2_pix_format format; | ||
137 | |||
138 | struct v4l2_rect crop; | ||
139 | struct v4l2_rect compose; | ||
140 | }; | ||
141 | |||
142 | #define vin_to_source(vin) vin->entity.subdev | ||
143 | |||
144 | /* Debug */ | ||
145 | #define vin_dbg(d, fmt, arg...) dev_dbg(d->dev, fmt, ##arg) | ||
146 | #define vin_info(d, fmt, arg...) dev_info(d->dev, fmt, ##arg) | ||
147 | #define vin_warn(d, fmt, arg...) dev_warn(d->dev, fmt, ##arg) | ||
148 | #define vin_err(d, fmt, arg...) dev_err(d->dev, fmt, ##arg) | ||
149 | |||
150 | int rvin_dma_probe(struct rvin_dev *vin, int irq); | ||
151 | void rvin_dma_remove(struct rvin_dev *vin); | ||
152 | |||
153 | int rvin_v4l2_probe(struct rvin_dev *vin); | ||
154 | void rvin_v4l2_remove(struct rvin_dev *vin); | ||
155 | |||
156 | const struct rvin_video_format *rvin_format_from_pixel(u32 pixelformat); | ||
157 | |||
158 | /* Cropping, composing and scaling */ | ||
159 | void rvin_scale_try(struct rvin_dev *vin, struct v4l2_pix_format *pix, | ||
160 | u32 width, u32 height); | ||
161 | void rvin_crop_scale_comp(struct rvin_dev *vin); | ||
162 | |||
163 | #endif | ||
diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c index 612d1ea514f1..d3e3469db8de 100644 --- a/drivers/media/platform/s5p-g2d/g2d.c +++ b/drivers/media/platform/s5p-g2d/g2d.c | |||
@@ -681,6 +681,7 @@ static int g2d_probe(struct platform_device *pdev) | |||
681 | goto put_clk_gate; | 681 | goto put_clk_gate; |
682 | } | 682 | } |
683 | 683 | ||
684 | vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); | ||
684 | dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); | 685 | dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); |
685 | if (IS_ERR(dev->alloc_ctx)) { | 686 | if (IS_ERR(dev->alloc_ctx)) { |
686 | ret = PTR_ERR(dev->alloc_ctx); | 687 | ret = PTR_ERR(dev->alloc_ctx); |
@@ -757,6 +758,7 @@ static int g2d_remove(struct platform_device *pdev) | |||
757 | video_unregister_device(dev->vfd); | 758 | video_unregister_device(dev->vfd); |
758 | v4l2_device_unregister(&dev->v4l2_dev); | 759 | v4l2_device_unregister(&dev->v4l2_dev); |
759 | vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); | 760 | vb2_dma_contig_cleanup_ctx(dev->alloc_ctx); |
761 | vb2_dma_contig_clear_max_seg_size(&pdev->dev); | ||
760 | clk_unprepare(dev->gate); | 762 | clk_unprepare(dev->gate); |
761 | clk_put(dev->gate); | 763 | clk_put(dev->gate); |
762 | clk_unprepare(dev->clk); | 764 | clk_unprepare(dev->clk); |
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index caa19b408551..17bc94092864 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c | |||
@@ -2843,6 +2843,7 @@ static int s5p_jpeg_probe(struct platform_device *pdev) | |||
2843 | goto device_register_rollback; | 2843 | goto device_register_rollback; |
2844 | } | 2844 | } |
2845 | 2845 | ||
2846 | vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); | ||
2846 | jpeg->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); | 2847 | jpeg->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); |
2847 | if (IS_ERR(jpeg->alloc_ctx)) { | 2848 | if (IS_ERR(jpeg->alloc_ctx)) { |
2848 | v4l2_err(&jpeg->v4l2_dev, "Failed to init memory allocator\n"); | 2849 | v4l2_err(&jpeg->v4l2_dev, "Failed to init memory allocator\n"); |
@@ -2942,6 +2943,7 @@ static int s5p_jpeg_remove(struct platform_device *pdev) | |||
2942 | video_unregister_device(jpeg->vfd_decoder); | 2943 | video_unregister_device(jpeg->vfd_decoder); |
2943 | video_unregister_device(jpeg->vfd_encoder); | 2944 | video_unregister_device(jpeg->vfd_encoder); |
2944 | vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx); | 2945 | vb2_dma_contig_cleanup_ctx(jpeg->alloc_ctx); |
2946 | vb2_dma_contig_clear_max_seg_size(&pdev->dev); | ||
2945 | v4l2_m2m_release(jpeg->m2m_dev); | 2947 | v4l2_m2m_release(jpeg->m2m_dev); |
2946 | v4l2_device_unregister(&jpeg->v4l2_dev); | 2948 | v4l2_device_unregister(&jpeg->v4l2_dev); |
2947 | 2949 | ||
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index b16466fe35ee..6ee620ee8cd5 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <media/v4l2-event.h> | 22 | #include <media/v4l2-event.h> |
23 | #include <linux/workqueue.h> | 23 | #include <linux/workqueue.h> |
24 | #include <linux/of.h> | 24 | #include <linux/of.h> |
25 | #include <linux/of_reserved_mem.h> | ||
25 | #include <media/videobuf2-v4l2.h> | 26 | #include <media/videobuf2-v4l2.h> |
26 | #include "s5p_mfc_common.h" | 27 | #include "s5p_mfc_common.h" |
27 | #include "s5p_mfc_ctrl.h" | 28 | #include "s5p_mfc_ctrl.h" |
@@ -29,6 +30,7 @@ | |||
29 | #include "s5p_mfc_dec.h" | 30 | #include "s5p_mfc_dec.h" |
30 | #include "s5p_mfc_enc.h" | 31 | #include "s5p_mfc_enc.h" |
31 | #include "s5p_mfc_intr.h" | 32 | #include "s5p_mfc_intr.h" |
33 | #include "s5p_mfc_iommu.h" | ||
32 | #include "s5p_mfc_opr.h" | 34 | #include "s5p_mfc_opr.h" |
33 | #include "s5p_mfc_cmd.h" | 35 | #include "s5p_mfc_cmd.h" |
34 | #include "s5p_mfc_pm.h" | 36 | #include "s5p_mfc_pm.h" |
@@ -1043,55 +1045,94 @@ static const struct v4l2_file_operations s5p_mfc_fops = { | |||
1043 | .mmap = s5p_mfc_mmap, | 1045 | .mmap = s5p_mfc_mmap, |
1044 | }; | 1046 | }; |
1045 | 1047 | ||
1046 | static int match_child(struct device *dev, void *data) | 1048 | /* DMA memory related helper functions */ |
1049 | static void s5p_mfc_memdev_release(struct device *dev) | ||
1047 | { | 1050 | { |
1048 | if (!dev_name(dev)) | 1051 | of_reserved_mem_device_release(dev); |
1049 | return 0; | ||
1050 | return !strcmp(dev_name(dev), (char *)data); | ||
1051 | } | 1052 | } |
1052 | 1053 | ||
1053 | static void *mfc_get_drv_data(struct platform_device *pdev); | 1054 | static struct device *s5p_mfc_alloc_memdev(struct device *dev, |
1054 | 1055 | const char *name, unsigned int idx) | |
1055 | static int s5p_mfc_alloc_memdevs(struct s5p_mfc_dev *dev) | ||
1056 | { | 1056 | { |
1057 | unsigned int mem_info[2] = { }; | 1057 | struct device *child; |
1058 | int ret; | ||
1058 | 1059 | ||
1059 | dev->mem_dev_l = devm_kzalloc(&dev->plat_dev->dev, | 1060 | child = devm_kzalloc(dev, sizeof(struct device), GFP_KERNEL); |
1060 | sizeof(struct device), GFP_KERNEL); | 1061 | if (!child) |
1061 | if (!dev->mem_dev_l) { | 1062 | return NULL; |
1062 | mfc_err("Not enough memory\n"); | 1063 | |
1063 | return -ENOMEM; | 1064 | device_initialize(child); |
1064 | } | 1065 | dev_set_name(child, "%s:%s", dev_name(dev), name); |
1065 | device_initialize(dev->mem_dev_l); | 1066 | child->parent = dev; |
1066 | of_property_read_u32_array(dev->plat_dev->dev.of_node, | 1067 | child->bus = dev->bus; |
1067 | "samsung,mfc-l", mem_info, 2); | 1068 | child->coherent_dma_mask = dev->coherent_dma_mask; |
1068 | if (dma_declare_coherent_memory(dev->mem_dev_l, mem_info[0], | 1069 | child->dma_mask = dev->dma_mask; |
1069 | mem_info[0], mem_info[1], | 1070 | child->release = s5p_mfc_memdev_release; |
1070 | DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE) == 0) { | 1071 | |
1071 | mfc_err("Failed to declare coherent memory for\n" | 1072 | if (device_add(child) == 0) { |
1072 | "MFC device\n"); | 1073 | ret = of_reserved_mem_device_init_by_idx(child, dev->of_node, |
1073 | return -ENOMEM; | 1074 | idx); |
1075 | if (ret == 0) | ||
1076 | return child; | ||
1074 | } | 1077 | } |
1075 | 1078 | ||
1076 | dev->mem_dev_r = devm_kzalloc(&dev->plat_dev->dev, | 1079 | put_device(child); |
1077 | sizeof(struct device), GFP_KERNEL); | 1080 | return NULL; |
1078 | if (!dev->mem_dev_r) { | 1081 | } |
1079 | mfc_err("Not enough memory\n"); | 1082 | |
1080 | return -ENOMEM; | 1083 | static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) |
1084 | { | ||
1085 | struct device *dev = &mfc_dev->plat_dev->dev; | ||
1086 | |||
1087 | /* | ||
1088 | * When IOMMU is available, we cannot use the default configuration, | ||
1089 | * because of MFC firmware requirements: address space limited to | ||
1090 | * 256M and non-zero default start address. | ||
1091 | * This is still simplified, not optimal configuration, but for now | ||
1092 | * IOMMU core doesn't allow to configure device's IOMMUs channel | ||
1093 | * separately. | ||
1094 | */ | ||
1095 | if (exynos_is_iommu_available(dev)) { | ||
1096 | int ret = exynos_configure_iommu(dev, S5P_MFC_IOMMU_DMA_BASE, | ||
1097 | S5P_MFC_IOMMU_DMA_SIZE); | ||
1098 | if (ret == 0) | ||
1099 | mfc_dev->mem_dev_l = mfc_dev->mem_dev_r = dev; | ||
1100 | return ret; | ||
1081 | } | 1101 | } |
1082 | device_initialize(dev->mem_dev_r); | 1102 | |
1083 | of_property_read_u32_array(dev->plat_dev->dev.of_node, | 1103 | /* |
1084 | "samsung,mfc-r", mem_info, 2); | 1104 | * Create and initialize virtual devices for accessing |
1085 | if (dma_declare_coherent_memory(dev->mem_dev_r, mem_info[0], | 1105 | * reserved memory regions. |
1086 | mem_info[0], mem_info[1], | 1106 | */ |
1087 | DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE) == 0) { | 1107 | mfc_dev->mem_dev_l = s5p_mfc_alloc_memdev(dev, "left", |
1088 | pr_err("Failed to declare coherent memory for\n" | 1108 | MFC_BANK1_ALLOC_CTX); |
1089 | "MFC device\n"); | 1109 | if (!mfc_dev->mem_dev_l) |
1090 | return -ENOMEM; | 1110 | return -ENODEV; |
1111 | mfc_dev->mem_dev_r = s5p_mfc_alloc_memdev(dev, "right", | ||
1112 | MFC_BANK2_ALLOC_CTX); | ||
1113 | if (!mfc_dev->mem_dev_r) { | ||
1114 | device_unregister(mfc_dev->mem_dev_l); | ||
1115 | return -ENODEV; | ||
1091 | } | 1116 | } |
1117 | |||
1092 | return 0; | 1118 | return 0; |
1093 | } | 1119 | } |
1094 | 1120 | ||
1121 | static void s5p_mfc_unconfigure_dma_memory(struct s5p_mfc_dev *mfc_dev) | ||
1122 | { | ||
1123 | struct device *dev = &mfc_dev->plat_dev->dev; | ||
1124 | |||
1125 | if (exynos_is_iommu_available(dev)) { | ||
1126 | exynos_unconfigure_iommu(dev); | ||
1127 | return; | ||
1128 | } | ||
1129 | |||
1130 | device_unregister(mfc_dev->mem_dev_l); | ||
1131 | device_unregister(mfc_dev->mem_dev_r); | ||
1132 | } | ||
1133 | |||
1134 | static void *mfc_get_drv_data(struct platform_device *pdev); | ||
1135 | |||
1095 | /* MFC probe function */ | 1136 | /* MFC probe function */ |
1096 | static int s5p_mfc_probe(struct platform_device *pdev) | 1137 | static int s5p_mfc_probe(struct platform_device *pdev) |
1097 | { | 1138 | { |
@@ -1117,12 +1158,6 @@ static int s5p_mfc_probe(struct platform_device *pdev) | |||
1117 | 1158 | ||
1118 | dev->variant = mfc_get_drv_data(pdev); | 1159 | dev->variant = mfc_get_drv_data(pdev); |
1119 | 1160 | ||
1120 | ret = s5p_mfc_init_pm(dev); | ||
1121 | if (ret < 0) { | ||
1122 | dev_err(&pdev->dev, "failed to get mfc clock source\n"); | ||
1123 | return ret; | ||
1124 | } | ||
1125 | |||
1126 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1161 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1127 | 1162 | ||
1128 | dev->regs_base = devm_ioremap_resource(&pdev->dev, res); | 1163 | dev->regs_base = devm_ioremap_resource(&pdev->dev, res); |
@@ -1143,32 +1178,25 @@ static int s5p_mfc_probe(struct platform_device *pdev) | |||
1143 | goto err_res; | 1178 | goto err_res; |
1144 | } | 1179 | } |
1145 | 1180 | ||
1146 | if (pdev->dev.of_node) { | 1181 | ret = s5p_mfc_configure_dma_memory(dev); |
1147 | ret = s5p_mfc_alloc_memdevs(dev); | 1182 | if (ret < 0) { |
1148 | if (ret < 0) | 1183 | dev_err(&pdev->dev, "failed to configure DMA memory\n"); |
1149 | goto err_res; | 1184 | return ret; |
1150 | } else { | ||
1151 | dev->mem_dev_l = device_find_child(&dev->plat_dev->dev, | ||
1152 | "s5p-mfc-l", match_child); | ||
1153 | if (!dev->mem_dev_l) { | ||
1154 | mfc_err("Mem child (L) device get failed\n"); | ||
1155 | ret = -ENODEV; | ||
1156 | goto err_res; | ||
1157 | } | ||
1158 | dev->mem_dev_r = device_find_child(&dev->plat_dev->dev, | ||
1159 | "s5p-mfc-r", match_child); | ||
1160 | if (!dev->mem_dev_r) { | ||
1161 | mfc_err("Mem child (R) device get failed\n"); | ||
1162 | ret = -ENODEV; | ||
1163 | goto err_res; | ||
1164 | } | ||
1165 | } | 1185 | } |
1166 | 1186 | ||
1187 | ret = s5p_mfc_init_pm(dev); | ||
1188 | if (ret < 0) { | ||
1189 | dev_err(&pdev->dev, "failed to get mfc clock source\n"); | ||
1190 | return ret; | ||
1191 | } | ||
1192 | |||
1193 | vb2_dma_contig_set_max_seg_size(dev->mem_dev_l, DMA_BIT_MASK(32)); | ||
1167 | dev->alloc_ctx[0] = vb2_dma_contig_init_ctx(dev->mem_dev_l); | 1194 | dev->alloc_ctx[0] = vb2_dma_contig_init_ctx(dev->mem_dev_l); |
1168 | if (IS_ERR(dev->alloc_ctx[0])) { | 1195 | if (IS_ERR(dev->alloc_ctx[0])) { |
1169 | ret = PTR_ERR(dev->alloc_ctx[0]); | 1196 | ret = PTR_ERR(dev->alloc_ctx[0]); |
1170 | goto err_res; | 1197 | goto err_res; |
1171 | } | 1198 | } |
1199 | vb2_dma_contig_set_max_seg_size(dev->mem_dev_r, DMA_BIT_MASK(32)); | ||
1172 | dev->alloc_ctx[1] = vb2_dma_contig_init_ctx(dev->mem_dev_r); | 1200 | dev->alloc_ctx[1] = vb2_dma_contig_init_ctx(dev->mem_dev_r); |
1173 | if (IS_ERR(dev->alloc_ctx[1])) { | 1201 | if (IS_ERR(dev->alloc_ctx[1])) { |
1174 | ret = PTR_ERR(dev->alloc_ctx[1]); | 1202 | ret = PTR_ERR(dev->alloc_ctx[1]); |
@@ -1201,14 +1229,6 @@ static int s5p_mfc_probe(struct platform_device *pdev) | |||
1201 | vfd->vfl_dir = VFL_DIR_M2M; | 1229 | vfd->vfl_dir = VFL_DIR_M2M; |
1202 | snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_DEC_NAME); | 1230 | snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_DEC_NAME); |
1203 | dev->vfd_dec = vfd; | 1231 | dev->vfd_dec = vfd; |
1204 | ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); | ||
1205 | if (ret) { | ||
1206 | v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); | ||
1207 | video_device_release(vfd); | ||
1208 | goto err_dec_reg; | ||
1209 | } | ||
1210 | v4l2_info(&dev->v4l2_dev, | ||
1211 | "decoder registered as /dev/video%d\n", vfd->num); | ||
1212 | video_set_drvdata(vfd, dev); | 1232 | video_set_drvdata(vfd, dev); |
1213 | 1233 | ||
1214 | /* encoder */ | 1234 | /* encoder */ |
@@ -1226,14 +1246,6 @@ static int s5p_mfc_probe(struct platform_device *pdev) | |||
1226 | vfd->vfl_dir = VFL_DIR_M2M; | 1246 | vfd->vfl_dir = VFL_DIR_M2M; |
1227 | snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_ENC_NAME); | 1247 | snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_ENC_NAME); |
1228 | dev->vfd_enc = vfd; | 1248 | dev->vfd_enc = vfd; |
1229 | ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); | ||
1230 | if (ret) { | ||
1231 | v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); | ||
1232 | video_device_release(vfd); | ||
1233 | goto err_enc_reg; | ||
1234 | } | ||
1235 | v4l2_info(&dev->v4l2_dev, | ||
1236 | "encoder registered as /dev/video%d\n", vfd->num); | ||
1237 | video_set_drvdata(vfd, dev); | 1249 | video_set_drvdata(vfd, dev); |
1238 | platform_set_drvdata(pdev, dev); | 1250 | platform_set_drvdata(pdev, dev); |
1239 | 1251 | ||
@@ -1250,15 +1262,34 @@ static int s5p_mfc_probe(struct platform_device *pdev) | |||
1250 | s5p_mfc_init_hw_cmds(dev); | 1262 | s5p_mfc_init_hw_cmds(dev); |
1251 | s5p_mfc_init_regs(dev); | 1263 | s5p_mfc_init_regs(dev); |
1252 | 1264 | ||
1265 | /* Register decoder and encoder */ | ||
1266 | ret = video_register_device(dev->vfd_dec, VFL_TYPE_GRABBER, 0); | ||
1267 | if (ret) { | ||
1268 | v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); | ||
1269 | video_device_release(dev->vfd_dec); | ||
1270 | goto err_dec_reg; | ||
1271 | } | ||
1272 | v4l2_info(&dev->v4l2_dev, | ||
1273 | "decoder registered as /dev/video%d\n", dev->vfd_dec->num); | ||
1274 | |||
1275 | ret = video_register_device(dev->vfd_enc, VFL_TYPE_GRABBER, 0); | ||
1276 | if (ret) { | ||
1277 | v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); | ||
1278 | video_device_release(dev->vfd_enc); | ||
1279 | goto err_enc_reg; | ||
1280 | } | ||
1281 | v4l2_info(&dev->v4l2_dev, | ||
1282 | "encoder registered as /dev/video%d\n", dev->vfd_enc->num); | ||
1283 | |||
1253 | pr_debug("%s--\n", __func__); | 1284 | pr_debug("%s--\n", __func__); |
1254 | return 0; | 1285 | return 0; |
1255 | 1286 | ||
1256 | /* Deinit MFC if probe had failed */ | 1287 | /* Deinit MFC if probe had failed */ |
1257 | err_enc_reg: | 1288 | err_enc_reg: |
1258 | video_device_release(dev->vfd_enc); | ||
1259 | err_enc_alloc: | ||
1260 | video_unregister_device(dev->vfd_dec); | 1289 | video_unregister_device(dev->vfd_dec); |
1261 | err_dec_reg: | 1290 | err_dec_reg: |
1291 | video_device_release(dev->vfd_enc); | ||
1292 | err_enc_alloc: | ||
1262 | video_device_release(dev->vfd_dec); | 1293 | video_device_release(dev->vfd_dec); |
1263 | err_dec_alloc: | 1294 | err_dec_alloc: |
1264 | v4l2_device_unregister(&dev->v4l2_dev); | 1295 | v4l2_device_unregister(&dev->v4l2_dev); |
@@ -1293,10 +1324,9 @@ static int s5p_mfc_remove(struct platform_device *pdev) | |||
1293 | s5p_mfc_release_firmware(dev); | 1324 | s5p_mfc_release_firmware(dev); |
1294 | vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[0]); | 1325 | vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[0]); |
1295 | vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[1]); | 1326 | vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[1]); |
1296 | if (pdev->dev.of_node) { | 1327 | s5p_mfc_unconfigure_dma_memory(dev); |
1297 | put_device(dev->mem_dev_l); | 1328 | vb2_dma_contig_clear_max_seg_size(dev->mem_dev_l); |
1298 | put_device(dev->mem_dev_r); | 1329 | vb2_dma_contig_clear_max_seg_size(dev->mem_dev_r); |
1299 | } | ||
1300 | 1330 | ||
1301 | s5p_mfc_final_pm(dev); | 1331 | s5p_mfc_final_pm(dev); |
1302 | return 0; | 1332 | return 0; |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index f2d6376ce618..a01a373a4c4f 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c | |||
@@ -474,7 +474,6 @@ static int reqbufs_output(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx, | |||
474 | ret = vb2_reqbufs(&ctx->vq_src, reqbufs); | 474 | ret = vb2_reqbufs(&ctx->vq_src, reqbufs); |
475 | if (ret) | 475 | if (ret) |
476 | goto out; | 476 | goto out; |
477 | s5p_mfc_close_mfc_inst(dev, ctx); | ||
478 | ctx->src_bufs_cnt = 0; | 477 | ctx->src_bufs_cnt = 0; |
479 | ctx->output_state = QUEUE_FREE; | 478 | ctx->output_state = QUEUE_FREE; |
480 | } else if (ctx->output_state == QUEUE_FREE) { | 479 | } else if (ctx->output_state == QUEUE_FREE) { |
@@ -573,7 +572,7 @@ static int vidioc_reqbufs(struct file *file, void *priv, | |||
573 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | 572 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); |
574 | 573 | ||
575 | if (reqbufs->memory != V4L2_MEMORY_MMAP) { | 574 | if (reqbufs->memory != V4L2_MEMORY_MMAP) { |
576 | mfc_err("Only V4L2_MEMORY_MAP is supported\n"); | 575 | mfc_err("Only V4L2_MEMORY_MMAP is supported\n"); |
577 | return -EINVAL; | 576 | return -EINVAL; |
578 | } | 577 | } |
579 | 578 | ||
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index 034b5c1d35a1..2f76aba4cc78 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | |||
@@ -1043,10 +1043,6 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) | |||
1043 | mfc_err("failed to try output format\n"); | 1043 | mfc_err("failed to try output format\n"); |
1044 | return -EINVAL; | 1044 | return -EINVAL; |
1045 | } | 1045 | } |
1046 | if (pix_fmt_mp->plane_fmt[0].sizeimage == 0) { | ||
1047 | mfc_err("must be set encoding output size\n"); | ||
1048 | return -EINVAL; | ||
1049 | } | ||
1050 | if ((dev->variant->version_bit & fmt->versions) == 0) { | 1046 | if ((dev->variant->version_bit & fmt->versions) == 0) { |
1051 | mfc_err("Unsupported format by this MFC version.\n"); | 1047 | mfc_err("Unsupported format by this MFC version.\n"); |
1052 | return -EINVAL; | 1048 | return -EINVAL; |
@@ -1060,11 +1056,6 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) | |||
1060 | mfc_err("failed to try output format\n"); | 1056 | mfc_err("failed to try output format\n"); |
1061 | return -EINVAL; | 1057 | return -EINVAL; |
1062 | } | 1058 | } |
1063 | |||
1064 | if (fmt->num_planes != pix_fmt_mp->num_planes) { | ||
1065 | mfc_err("failed to try output format\n"); | ||
1066 | return -EINVAL; | ||
1067 | } | ||
1068 | if ((dev->variant->version_bit & fmt->versions) == 0) { | 1059 | if ((dev->variant->version_bit & fmt->versions) == 0) { |
1069 | mfc_err("Unsupported format by this MFC version.\n"); | 1060 | mfc_err("Unsupported format by this MFC version.\n"); |
1070 | return -EINVAL; | 1061 | return -EINVAL; |
@@ -1144,7 +1135,10 @@ static int vidioc_reqbufs(struct file *file, void *priv, | |||
1144 | return -EINVAL; | 1135 | return -EINVAL; |
1145 | if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | 1136 | if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { |
1146 | if (reqbufs->count == 0) { | 1137 | if (reqbufs->count == 0) { |
1138 | mfc_debug(2, "Freeing buffers\n"); | ||
1147 | ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); | 1139 | ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); |
1140 | s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, | ||
1141 | ctx); | ||
1148 | ctx->capture_state = QUEUE_FREE; | 1142 | ctx->capture_state = QUEUE_FREE; |
1149 | return ret; | 1143 | return ret; |
1150 | } | 1144 | } |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h b/drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h new file mode 100644 index 000000000000..6962132ae8fa --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h | |||
@@ -0,0 +1,79 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 Samsung Electronics Co.Ltd | ||
3 | * Authors: Marek Szyprowski <m.szyprowski@samsung.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2 of the License, or (at your | ||
8 | * option) any later version. | ||
9 | */ | ||
10 | |||
11 | #ifndef S5P_MFC_IOMMU_H_ | ||
12 | #define S5P_MFC_IOMMU_H_ | ||
13 | |||
14 | #define S5P_MFC_IOMMU_DMA_BASE 0x20000000lu | ||
15 | #define S5P_MFC_IOMMU_DMA_SIZE SZ_256M | ||
16 | |||
17 | #if defined(CONFIG_EXYNOS_IOMMU) && defined(CONFIG_ARM_DMA_USE_IOMMU) | ||
18 | |||
19 | #include <asm/dma-iommu.h> | ||
20 | |||
21 | static inline bool exynos_is_iommu_available(struct device *dev) | ||
22 | { | ||
23 | return dev->archdata.iommu != NULL; | ||
24 | } | ||
25 | |||
26 | static inline void exynos_unconfigure_iommu(struct device *dev) | ||
27 | { | ||
28 | struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev); | ||
29 | |||
30 | arm_iommu_detach_device(dev); | ||
31 | arm_iommu_release_mapping(mapping); | ||
32 | } | ||
33 | |||
34 | static inline int exynos_configure_iommu(struct device *dev, | ||
35 | unsigned int base, unsigned int size) | ||
36 | { | ||
37 | struct dma_iommu_mapping *mapping = NULL; | ||
38 | int ret; | ||
39 | |||
40 | /* Disable the default mapping created by device core */ | ||
41 | if (to_dma_iommu_mapping(dev)) | ||
42 | exynos_unconfigure_iommu(dev); | ||
43 | |||
44 | mapping = arm_iommu_create_mapping(dev->bus, base, size); | ||
45 | if (IS_ERR(mapping)) { | ||
46 | pr_warn("Failed to create IOMMU mapping for device %s\n", | ||
47 | dev_name(dev)); | ||
48 | return PTR_ERR(mapping); | ||
49 | } | ||
50 | |||
51 | ret = arm_iommu_attach_device(dev, mapping); | ||
52 | if (ret) { | ||
53 | pr_warn("Failed to attached device %s to IOMMU_mapping\n", | ||
54 | dev_name(dev)); | ||
55 | arm_iommu_release_mapping(mapping); | ||
56 | return ret; | ||
57 | } | ||
58 | |||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | #else | ||
63 | |||
64 | static inline bool exynos_is_iommu_available(struct device *dev) | ||
65 | { | ||
66 | return false; | ||
67 | } | ||
68 | |||
69 | static inline int exynos_configure_iommu(struct device *dev, | ||
70 | unsigned int base, unsigned int size) | ||
71 | { | ||
72 | return -ENOSYS; | ||
73 | } | ||
74 | |||
75 | static inline void exynos_unconfigure_iommu(struct device *dev) { } | ||
76 | |||
77 | #endif | ||
78 | |||
79 | #endif /* S5P_MFC_IOMMU_H_ */ | ||
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c index 5f97a3398c11..9f7522104333 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c | |||
@@ -54,6 +54,7 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev) | |||
54 | pm->clock = clk_get(&dev->plat_dev->dev, MFC_SCLK_NAME); | 54 | pm->clock = clk_get(&dev->plat_dev->dev, MFC_SCLK_NAME); |
55 | if (IS_ERR(pm->clock)) { | 55 | if (IS_ERR(pm->clock)) { |
56 | mfc_info("Failed to get MFC special clock control\n"); | 56 | mfc_info("Failed to get MFC special clock control\n"); |
57 | pm->clock = NULL; | ||
57 | } else { | 58 | } else { |
58 | clk_set_rate(pm->clock, MFC_SCLK_RATE); | 59 | clk_set_rate(pm->clock, MFC_SCLK_RATE); |
59 | ret = clk_prepare_enable(pm->clock); | 60 | ret = clk_prepare_enable(pm->clock); |
diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c index 7ab5578a0405..123d27107f60 100644 --- a/drivers/media/platform/s5p-tv/mixer_video.c +++ b/drivers/media/platform/s5p-tv/mixer_video.c | |||
@@ -80,6 +80,7 @@ int mxr_acquire_video(struct mxr_device *mdev, | |||
80 | goto fail; | 80 | goto fail; |
81 | } | 81 | } |
82 | 82 | ||
83 | vb2_dma_contig_set_max_seg_size(mdev->dev, DMA_BIT_MASK(32)); | ||
83 | mdev->alloc_ctx = vb2_dma_contig_init_ctx(mdev->dev); | 84 | mdev->alloc_ctx = vb2_dma_contig_init_ctx(mdev->dev); |
84 | if (IS_ERR(mdev->alloc_ctx)) { | 85 | if (IS_ERR(mdev->alloc_ctx)) { |
85 | mxr_err(mdev, "could not acquire vb2 allocator\n"); | 86 | mxr_err(mdev, "could not acquire vb2 allocator\n"); |
@@ -152,6 +153,7 @@ void mxr_release_video(struct mxr_device *mdev) | |||
152 | kfree(mdev->output[i]); | 153 | kfree(mdev->output[i]); |
153 | 154 | ||
154 | vb2_dma_contig_cleanup_ctx(mdev->alloc_ctx); | 155 | vb2_dma_contig_cleanup_ctx(mdev->alloc_ctx); |
156 | vb2_dma_contig_clear_max_seg_size(mdev->dev); | ||
155 | v4l2_device_unregister(&mdev->v4l2_dev); | 157 | v4l2_device_unregister(&mdev->v4l2_dev); |
156 | } | 158 | } |
157 | 159 | ||
diff --git a/drivers/media/platform/soc_camera/Kconfig b/drivers/media/platform/soc_camera/Kconfig index 83029a4854ae..39f66414f621 100644 --- a/drivers/media/platform/soc_camera/Kconfig +++ b/drivers/media/platform/soc_camera/Kconfig | |||
@@ -25,8 +25,8 @@ config VIDEO_PXA27x | |||
25 | ---help--- | 25 | ---help--- |
26 | This is a v4l2 driver for the PXA27x Quick Capture Interface | 26 | This is a v4l2 driver for the PXA27x Quick Capture Interface |
27 | 27 | ||
28 | config VIDEO_RCAR_VIN | 28 | config VIDEO_RCAR_VIN_OLD |
29 | tristate "R-Car Video Input (VIN) support" | 29 | tristate "R-Car Video Input (VIN) support (DEPRECATED)" |
30 | depends on VIDEO_DEV && SOC_CAMERA | 30 | depends on VIDEO_DEV && SOC_CAMERA |
31 | depends on ARCH_RENESAS || COMPILE_TEST | 31 | depends on ARCH_RENESAS || COMPILE_TEST |
32 | depends on HAS_DMA | 32 | depends on HAS_DMA |
diff --git a/drivers/media/platform/soc_camera/Makefile b/drivers/media/platform/soc_camera/Makefile index 7ee71ae231c7..7703cb7ce456 100644 --- a/drivers/media/platform/soc_camera/Makefile +++ b/drivers/media/platform/soc_camera/Makefile | |||
@@ -10,4 +10,4 @@ obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o | |||
10 | obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o | 10 | obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o |
11 | obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o | 11 | obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o |
12 | obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2) += sh_mobile_csi2.o | 12 | obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2) += sh_mobile_csi2.o |
13 | obj-$(CONFIG_VIDEO_RCAR_VIN) += rcar_vin.o | 13 | obj-$(CONFIG_VIDEO_RCAR_VIN_OLD) += rcar_vin.o |
diff --git a/drivers/media/platform/vsp1/Makefile b/drivers/media/platform/vsp1/Makefile index 95b3ac2ea7ef..1328e1bd2143 100644 --- a/drivers/media/platform/vsp1/Makefile +++ b/drivers/media/platform/vsp1/Makefile | |||
@@ -1,7 +1,8 @@ | |||
1 | vsp1-y := vsp1_drv.o vsp1_entity.o vsp1_pipe.o | 1 | vsp1-y := vsp1_drv.o vsp1_entity.o vsp1_pipe.o |
2 | vsp1-y += vsp1_dl.o vsp1_drm.o vsp1_video.o | 2 | vsp1-y += vsp1_dl.o vsp1_drm.o vsp1_video.o |
3 | vsp1-y += vsp1_rpf.o vsp1_rwpf.o vsp1_wpf.o | 3 | vsp1-y += vsp1_rpf.o vsp1_rwpf.o vsp1_wpf.o |
4 | vsp1-y += vsp1_hsit.o vsp1_lif.o vsp1_lut.o | 4 | vsp1-y += vsp1_clu.o vsp1_hsit.o vsp1_lut.o |
5 | vsp1-y += vsp1_bru.o vsp1_sru.o vsp1_uds.o | 5 | vsp1-y += vsp1_bru.o vsp1_sru.o vsp1_uds.o |
6 | vsp1-y += vsp1_lif.o | ||
6 | 7 | ||
7 | obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1.o | 8 | obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1.o |
diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h index 46738b6c5f72..06a2ec7e5ad4 100644 --- a/drivers/media/platform/vsp1/vsp1.h +++ b/drivers/media/platform/vsp1/vsp1.h | |||
@@ -25,11 +25,13 @@ | |||
25 | 25 | ||
26 | struct clk; | 26 | struct clk; |
27 | struct device; | 27 | struct device; |
28 | struct rcar_fcp_device; | ||
28 | 29 | ||
29 | struct vsp1_drm; | 30 | struct vsp1_drm; |
30 | struct vsp1_entity; | 31 | struct vsp1_entity; |
31 | struct vsp1_platform_data; | 32 | struct vsp1_platform_data; |
32 | struct vsp1_bru; | 33 | struct vsp1_bru; |
34 | struct vsp1_clu; | ||
33 | struct vsp1_hsit; | 35 | struct vsp1_hsit; |
34 | struct vsp1_lif; | 36 | struct vsp1_lif; |
35 | struct vsp1_lut; | 37 | struct vsp1_lut; |
@@ -45,6 +47,9 @@ struct vsp1_uds; | |||
45 | #define VSP1_HAS_LUT (1 << 1) | 47 | #define VSP1_HAS_LUT (1 << 1) |
46 | #define VSP1_HAS_SRU (1 << 2) | 48 | #define VSP1_HAS_SRU (1 << 2) |
47 | #define VSP1_HAS_BRU (1 << 3) | 49 | #define VSP1_HAS_BRU (1 << 3) |
50 | #define VSP1_HAS_CLU (1 << 4) | ||
51 | #define VSP1_HAS_WPF_VFLIP (1 << 5) | ||
52 | #define VSP1_HAS_WPF_HFLIP (1 << 6) | ||
48 | 53 | ||
49 | struct vsp1_device_info { | 54 | struct vsp1_device_info { |
50 | u32 version; | 55 | u32 version; |
@@ -62,12 +67,10 @@ struct vsp1_device { | |||
62 | const struct vsp1_device_info *info; | 67 | const struct vsp1_device_info *info; |
63 | 68 | ||
64 | void __iomem *mmio; | 69 | void __iomem *mmio; |
65 | struct clk *clock; | 70 | struct rcar_fcp_device *fcp; |
66 | |||
67 | struct mutex lock; | ||
68 | int ref_count; | ||
69 | 71 | ||
70 | struct vsp1_bru *bru; | 72 | struct vsp1_bru *bru; |
73 | struct vsp1_clu *clu; | ||
71 | struct vsp1_hsit *hsi; | 74 | struct vsp1_hsit *hsi; |
72 | struct vsp1_hsit *hst; | 75 | struct vsp1_hsit *hst; |
73 | struct vsp1_lif *lif; | 76 | struct vsp1_lif *lif; |
diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c index b1068c018011..8268b87727a7 100644 --- a/drivers/media/platform/vsp1/vsp1_bru.c +++ b/drivers/media/platform/vsp1/vsp1_bru.c | |||
@@ -249,7 +249,7 @@ static int bru_set_selection(struct v4l2_subdev *subdev, | |||
249 | return 0; | 249 | return 0; |
250 | } | 250 | } |
251 | 251 | ||
252 | static struct v4l2_subdev_pad_ops bru_pad_ops = { | 252 | static const struct v4l2_subdev_pad_ops bru_pad_ops = { |
253 | .init_cfg = vsp1_entity_init_cfg, | 253 | .init_cfg = vsp1_entity_init_cfg, |
254 | .enum_mbus_code = bru_enum_mbus_code, | 254 | .enum_mbus_code = bru_enum_mbus_code, |
255 | .enum_frame_size = bru_enum_frame_size, | 255 | .enum_frame_size = bru_enum_frame_size, |
@@ -259,7 +259,7 @@ static struct v4l2_subdev_pad_ops bru_pad_ops = { | |||
259 | .set_selection = bru_set_selection, | 259 | .set_selection = bru_set_selection, |
260 | }; | 260 | }; |
261 | 261 | ||
262 | static struct v4l2_subdev_ops bru_ops = { | 262 | static const struct v4l2_subdev_ops bru_ops = { |
263 | .pad = &bru_pad_ops, | 263 | .pad = &bru_pad_ops, |
264 | }; | 264 | }; |
265 | 265 | ||
@@ -269,13 +269,16 @@ static struct v4l2_subdev_ops bru_ops = { | |||
269 | 269 | ||
270 | static void bru_configure(struct vsp1_entity *entity, | 270 | static void bru_configure(struct vsp1_entity *entity, |
271 | struct vsp1_pipeline *pipe, | 271 | struct vsp1_pipeline *pipe, |
272 | struct vsp1_dl_list *dl) | 272 | struct vsp1_dl_list *dl, bool full) |
273 | { | 273 | { |
274 | struct vsp1_bru *bru = to_bru(&entity->subdev); | 274 | struct vsp1_bru *bru = to_bru(&entity->subdev); |
275 | struct v4l2_mbus_framefmt *format; | 275 | struct v4l2_mbus_framefmt *format; |
276 | unsigned int flags; | 276 | unsigned int flags; |
277 | unsigned int i; | 277 | unsigned int i; |
278 | 278 | ||
279 | if (!full) | ||
280 | return; | ||
281 | |||
279 | format = vsp1_entity_get_pad_format(&bru->entity, bru->entity.config, | 282 | format = vsp1_entity_get_pad_format(&bru->entity, bru->entity.config, |
280 | bru->entity.source_pad); | 283 | bru->entity.source_pad); |
281 | 284 | ||
@@ -390,7 +393,8 @@ struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1) | |||
390 | bru->entity.type = VSP1_ENTITY_BRU; | 393 | bru->entity.type = VSP1_ENTITY_BRU; |
391 | 394 | ||
392 | ret = vsp1_entity_init(vsp1, &bru->entity, "bru", | 395 | ret = vsp1_entity_init(vsp1, &bru->entity, "bru", |
393 | vsp1->info->num_bru_inputs + 1, &bru_ops); | 396 | vsp1->info->num_bru_inputs + 1, &bru_ops, |
397 | MEDIA_ENT_F_PROC_VIDEO_COMPOSER); | ||
394 | if (ret < 0) | 398 | if (ret < 0) |
395 | return ERR_PTR(ret); | 399 | return ERR_PTR(ret); |
396 | 400 | ||
diff --git a/drivers/media/platform/vsp1/vsp1_clu.c b/drivers/media/platform/vsp1/vsp1_clu.c new file mode 100644 index 000000000000..b63d2dbe5ea3 --- /dev/null +++ b/drivers/media/platform/vsp1/vsp1_clu.c | |||
@@ -0,0 +1,292 @@ | |||
1 | /* | ||
2 | * vsp1_clu.c -- R-Car VSP1 Cubic Look-Up Table | ||
3 | * | ||
4 | * Copyright (C) 2015-2016 Renesas Electronics Corporation | ||
5 | * | ||
6 | * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/device.h> | ||
15 | #include <linux/slab.h> | ||
16 | |||
17 | #include <media/v4l2-subdev.h> | ||
18 | |||
19 | #include "vsp1.h" | ||
20 | #include "vsp1_clu.h" | ||
21 | #include "vsp1_dl.h" | ||
22 | |||
23 | #define CLU_MIN_SIZE 4U | ||
24 | #define CLU_MAX_SIZE 8190U | ||
25 | |||
26 | /* ----------------------------------------------------------------------------- | ||
27 | * Device Access | ||
28 | */ | ||
29 | |||
30 | static inline void vsp1_clu_write(struct vsp1_clu *clu, struct vsp1_dl_list *dl, | ||
31 | u32 reg, u32 data) | ||
32 | { | ||
33 | vsp1_dl_list_write(dl, reg, data); | ||
34 | } | ||
35 | |||
36 | /* ----------------------------------------------------------------------------- | ||
37 | * Controls | ||
38 | */ | ||
39 | |||
40 | #define V4L2_CID_VSP1_CLU_TABLE (V4L2_CID_USER_BASE | 0x1001) | ||
41 | #define V4L2_CID_VSP1_CLU_MODE (V4L2_CID_USER_BASE | 0x1002) | ||
42 | #define V4L2_CID_VSP1_CLU_MODE_2D 0 | ||
43 | #define V4L2_CID_VSP1_CLU_MODE_3D 1 | ||
44 | |||
45 | static int clu_set_table(struct vsp1_clu *clu, struct v4l2_ctrl *ctrl) | ||
46 | { | ||
47 | struct vsp1_dl_body *dlb; | ||
48 | unsigned int i; | ||
49 | |||
50 | dlb = vsp1_dl_fragment_alloc(clu->entity.vsp1, 1 + 17 * 17 * 17); | ||
51 | if (!dlb) | ||
52 | return -ENOMEM; | ||
53 | |||
54 | vsp1_dl_fragment_write(dlb, VI6_CLU_ADDR, 0); | ||
55 | for (i = 0; i < 17 * 17 * 17; ++i) | ||
56 | vsp1_dl_fragment_write(dlb, VI6_CLU_DATA, ctrl->p_new.p_u32[i]); | ||
57 | |||
58 | spin_lock_irq(&clu->lock); | ||
59 | swap(clu->clu, dlb); | ||
60 | spin_unlock_irq(&clu->lock); | ||
61 | |||
62 | vsp1_dl_fragment_free(dlb); | ||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | static int clu_s_ctrl(struct v4l2_ctrl *ctrl) | ||
67 | { | ||
68 | struct vsp1_clu *clu = | ||
69 | container_of(ctrl->handler, struct vsp1_clu, ctrls); | ||
70 | |||
71 | switch (ctrl->id) { | ||
72 | case V4L2_CID_VSP1_CLU_TABLE: | ||
73 | clu_set_table(clu, ctrl); | ||
74 | break; | ||
75 | |||
76 | case V4L2_CID_VSP1_CLU_MODE: | ||
77 | clu->mode = ctrl->val; | ||
78 | break; | ||
79 | } | ||
80 | |||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static const struct v4l2_ctrl_ops clu_ctrl_ops = { | ||
85 | .s_ctrl = clu_s_ctrl, | ||
86 | }; | ||
87 | |||
88 | static const struct v4l2_ctrl_config clu_table_control = { | ||
89 | .ops = &clu_ctrl_ops, | ||
90 | .id = V4L2_CID_VSP1_CLU_TABLE, | ||
91 | .name = "Look-Up Table", | ||
92 | .type = V4L2_CTRL_TYPE_U32, | ||
93 | .min = 0x00000000, | ||
94 | .max = 0x00ffffff, | ||
95 | .step = 1, | ||
96 | .def = 0, | ||
97 | .dims = { 17, 17, 17 }, | ||
98 | }; | ||
99 | |||
100 | static const char * const clu_mode_menu[] = { | ||
101 | "2D", | ||
102 | "3D", | ||
103 | NULL, | ||
104 | }; | ||
105 | |||
106 | static const struct v4l2_ctrl_config clu_mode_control = { | ||
107 | .ops = &clu_ctrl_ops, | ||
108 | .id = V4L2_CID_VSP1_CLU_MODE, | ||
109 | .name = "Mode", | ||
110 | .type = V4L2_CTRL_TYPE_MENU, | ||
111 | .min = 0, | ||
112 | .max = 1, | ||
113 | .def = 1, | ||
114 | .qmenu = clu_mode_menu, | ||
115 | }; | ||
116 | |||
117 | /* ----------------------------------------------------------------------------- | ||
118 | * V4L2 Subdevice Pad Operations | ||
119 | */ | ||
120 | |||
121 | static int clu_enum_mbus_code(struct v4l2_subdev *subdev, | ||
122 | struct v4l2_subdev_pad_config *cfg, | ||
123 | struct v4l2_subdev_mbus_code_enum *code) | ||
124 | { | ||
125 | static const unsigned int codes[] = { | ||
126 | MEDIA_BUS_FMT_ARGB8888_1X32, | ||
127 | MEDIA_BUS_FMT_AHSV8888_1X32, | ||
128 | MEDIA_BUS_FMT_AYUV8_1X32, | ||
129 | }; | ||
130 | |||
131 | return vsp1_subdev_enum_mbus_code(subdev, cfg, code, codes, | ||
132 | ARRAY_SIZE(codes)); | ||
133 | } | ||
134 | |||
135 | static int clu_enum_frame_size(struct v4l2_subdev *subdev, | ||
136 | struct v4l2_subdev_pad_config *cfg, | ||
137 | struct v4l2_subdev_frame_size_enum *fse) | ||
138 | { | ||
139 | return vsp1_subdev_enum_frame_size(subdev, cfg, fse, CLU_MIN_SIZE, | ||
140 | CLU_MIN_SIZE, CLU_MAX_SIZE, | ||
141 | CLU_MAX_SIZE); | ||
142 | } | ||
143 | |||
144 | static int clu_set_format(struct v4l2_subdev *subdev, | ||
145 | struct v4l2_subdev_pad_config *cfg, | ||
146 | struct v4l2_subdev_format *fmt) | ||
147 | { | ||
148 | struct vsp1_clu *clu = to_clu(subdev); | ||
149 | struct v4l2_subdev_pad_config *config; | ||
150 | struct v4l2_mbus_framefmt *format; | ||
151 | |||
152 | config = vsp1_entity_get_pad_config(&clu->entity, cfg, fmt->which); | ||
153 | if (!config) | ||
154 | return -EINVAL; | ||
155 | |||
156 | /* Default to YUV if the requested format is not supported. */ | ||
157 | if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 && | ||
158 | fmt->format.code != MEDIA_BUS_FMT_AHSV8888_1X32 && | ||
159 | fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) | ||
160 | fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; | ||
161 | |||
162 | format = vsp1_entity_get_pad_format(&clu->entity, config, fmt->pad); | ||
163 | |||
164 | if (fmt->pad == CLU_PAD_SOURCE) { | ||
165 | /* The CLU output format can't be modified. */ | ||
166 | fmt->format = *format; | ||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | format->code = fmt->format.code; | ||
171 | format->width = clamp_t(unsigned int, fmt->format.width, | ||
172 | CLU_MIN_SIZE, CLU_MAX_SIZE); | ||
173 | format->height = clamp_t(unsigned int, fmt->format.height, | ||
174 | CLU_MIN_SIZE, CLU_MAX_SIZE); | ||
175 | format->field = V4L2_FIELD_NONE; | ||
176 | format->colorspace = V4L2_COLORSPACE_SRGB; | ||
177 | |||
178 | fmt->format = *format; | ||
179 | |||
180 | /* Propagate the format to the source pad. */ | ||
181 | format = vsp1_entity_get_pad_format(&clu->entity, config, | ||
182 | CLU_PAD_SOURCE); | ||
183 | *format = fmt->format; | ||
184 | |||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | /* ----------------------------------------------------------------------------- | ||
189 | * V4L2 Subdevice Operations | ||
190 | */ | ||
191 | |||
192 | static const struct v4l2_subdev_pad_ops clu_pad_ops = { | ||
193 | .init_cfg = vsp1_entity_init_cfg, | ||
194 | .enum_mbus_code = clu_enum_mbus_code, | ||
195 | .enum_frame_size = clu_enum_frame_size, | ||
196 | .get_fmt = vsp1_subdev_get_pad_format, | ||
197 | .set_fmt = clu_set_format, | ||
198 | }; | ||
199 | |||
200 | static const struct v4l2_subdev_ops clu_ops = { | ||
201 | .pad = &clu_pad_ops, | ||
202 | }; | ||
203 | |||
204 | /* ----------------------------------------------------------------------------- | ||
205 | * VSP1 Entity Operations | ||
206 | */ | ||
207 | |||
208 | static void clu_configure(struct vsp1_entity *entity, | ||
209 | struct vsp1_pipeline *pipe, | ||
210 | struct vsp1_dl_list *dl, bool full) | ||
211 | { | ||
212 | struct vsp1_clu *clu = to_clu(&entity->subdev); | ||
213 | struct vsp1_dl_body *dlb; | ||
214 | unsigned long flags; | ||
215 | u32 ctrl = VI6_CLU_CTRL_AAI | VI6_CLU_CTRL_MVS | VI6_CLU_CTRL_EN; | ||
216 | |||
217 | /* The format can't be changed during streaming, only verify it at | ||
218 | * stream start and store the information internally for future partial | ||
219 | * reconfiguration calls. | ||
220 | */ | ||
221 | if (full) { | ||
222 | struct v4l2_mbus_framefmt *format; | ||
223 | |||
224 | format = vsp1_entity_get_pad_format(&clu->entity, | ||
225 | clu->entity.config, | ||
226 | CLU_PAD_SINK); | ||
227 | clu->yuv_mode = format->code == MEDIA_BUS_FMT_AYUV8_1X32; | ||
228 | return; | ||
229 | } | ||
230 | |||
231 | /* 2D mode can only be used with the YCbCr pixel encoding. */ | ||
232 | if (clu->mode == V4L2_CID_VSP1_CLU_MODE_2D && clu->yuv_mode) | ||
233 | ctrl |= VI6_CLU_CTRL_AX1I_2D | VI6_CLU_CTRL_AX2I_2D | ||
234 | | VI6_CLU_CTRL_OS0_2D | VI6_CLU_CTRL_OS1_2D | ||
235 | | VI6_CLU_CTRL_OS2_2D | VI6_CLU_CTRL_M2D; | ||
236 | |||
237 | vsp1_clu_write(clu, dl, VI6_CLU_CTRL, ctrl); | ||
238 | |||
239 | spin_lock_irqsave(&clu->lock, flags); | ||
240 | dlb = clu->clu; | ||
241 | clu->clu = NULL; | ||
242 | spin_unlock_irqrestore(&clu->lock, flags); | ||
243 | |||
244 | if (dlb) | ||
245 | vsp1_dl_list_add_fragment(dl, dlb); | ||
246 | } | ||
247 | |||
248 | static const struct vsp1_entity_operations clu_entity_ops = { | ||
249 | .configure = clu_configure, | ||
250 | }; | ||
251 | |||
252 | /* ----------------------------------------------------------------------------- | ||
253 | * Initialization and Cleanup | ||
254 | */ | ||
255 | |||
256 | struct vsp1_clu *vsp1_clu_create(struct vsp1_device *vsp1) | ||
257 | { | ||
258 | struct vsp1_clu *clu; | ||
259 | int ret; | ||
260 | |||
261 | clu = devm_kzalloc(vsp1->dev, sizeof(*clu), GFP_KERNEL); | ||
262 | if (clu == NULL) | ||
263 | return ERR_PTR(-ENOMEM); | ||
264 | |||
265 | spin_lock_init(&clu->lock); | ||
266 | |||
267 | clu->entity.ops = &clu_entity_ops; | ||
268 | clu->entity.type = VSP1_ENTITY_CLU; | ||
269 | |||
270 | ret = vsp1_entity_init(vsp1, &clu->entity, "clu", 2, &clu_ops, | ||
271 | MEDIA_ENT_F_PROC_VIDEO_LUT); | ||
272 | if (ret < 0) | ||
273 | return ERR_PTR(ret); | ||
274 | |||
275 | /* Initialize the control handler. */ | ||
276 | v4l2_ctrl_handler_init(&clu->ctrls, 2); | ||
277 | v4l2_ctrl_new_custom(&clu->ctrls, &clu_table_control, NULL); | ||
278 | v4l2_ctrl_new_custom(&clu->ctrls, &clu_mode_control, NULL); | ||
279 | |||
280 | clu->entity.subdev.ctrl_handler = &clu->ctrls; | ||
281 | |||
282 | if (clu->ctrls.error) { | ||
283 | dev_err(vsp1->dev, "clu: failed to initialize controls\n"); | ||
284 | ret = clu->ctrls.error; | ||
285 | vsp1_entity_destroy(&clu->entity); | ||
286 | return ERR_PTR(ret); | ||
287 | } | ||
288 | |||
289 | v4l2_ctrl_handler_setup(&clu->ctrls); | ||
290 | |||
291 | return clu; | ||
292 | } | ||
diff --git a/drivers/media/platform/vsp1/vsp1_clu.h b/drivers/media/platform/vsp1/vsp1_clu.h new file mode 100644 index 000000000000..036e0a2f1a42 --- /dev/null +++ b/drivers/media/platform/vsp1/vsp1_clu.h | |||
@@ -0,0 +1,48 @@ | |||
1 | /* | ||
2 | * vsp1_clu.h -- R-Car VSP1 Cubic Look-Up Table | ||
3 | * | ||
4 | * Copyright (C) 2015 Renesas Corporation | ||
5 | * | ||
6 | * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | */ | ||
13 | #ifndef __VSP1_CLU_H__ | ||
14 | #define __VSP1_CLU_H__ | ||
15 | |||
16 | #include <linux/spinlock.h> | ||
17 | |||
18 | #include <media/media-entity.h> | ||
19 | #include <media/v4l2-ctrls.h> | ||
20 | #include <media/v4l2-subdev.h> | ||
21 | |||
22 | #include "vsp1_entity.h" | ||
23 | |||
24 | struct vsp1_device; | ||
25 | struct vsp1_dl_body; | ||
26 | |||
27 | #define CLU_PAD_SINK 0 | ||
28 | #define CLU_PAD_SOURCE 1 | ||
29 | |||
30 | struct vsp1_clu { | ||
31 | struct vsp1_entity entity; | ||
32 | |||
33 | struct v4l2_ctrl_handler ctrls; | ||
34 | |||
35 | bool yuv_mode; | ||
36 | spinlock_t lock; | ||
37 | unsigned int mode; | ||
38 | struct vsp1_dl_body *clu; | ||
39 | }; | ||
40 | |||
41 | static inline struct vsp1_clu *to_clu(struct v4l2_subdev *subdev) | ||
42 | { | ||
43 | return container_of(subdev, struct vsp1_clu, entity.subdev); | ||
44 | } | ||
45 | |||
46 | struct vsp1_clu *vsp1_clu_create(struct vsp1_device *vsp1); | ||
47 | |||
48 | #endif /* __VSP1_CLU_H__ */ | ||
diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c index e238d9b9376b..37c3518aa2a8 100644 --- a/drivers/media/platform/vsp1/vsp1_dl.c +++ b/drivers/media/platform/vsp1/vsp1_dl.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/dma-mapping.h> | 15 | #include <linux/dma-mapping.h> |
16 | #include <linux/gfp.h> | 16 | #include <linux/gfp.h> |
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/workqueue.h> | ||
18 | 19 | ||
19 | #include "vsp1.h" | 20 | #include "vsp1.h" |
20 | #include "vsp1_dl.h" | 21 | #include "vsp1_dl.h" |
@@ -92,11 +93,13 @@ enum vsp1_dl_mode { | |||
92 | * @index: index of the related WPF | 93 | * @index: index of the related WPF |
93 | * @mode: display list operation mode (header or headerless) | 94 | * @mode: display list operation mode (header or headerless) |
94 | * @vsp1: the VSP1 device | 95 | * @vsp1: the VSP1 device |
95 | * @lock: protects the active, queued and pending lists | 96 | * @lock: protects the free, active, queued, pending and gc_fragments lists |
96 | * @free: array of all free display lists | 97 | * @free: array of all free display lists |
97 | * @active: list currently being processed (loaded) by hardware | 98 | * @active: list currently being processed (loaded) by hardware |
98 | * @queued: list queued to the hardware (written to the DL registers) | 99 | * @queued: list queued to the hardware (written to the DL registers) |
99 | * @pending: list waiting to be queued to the hardware | 100 | * @pending: list waiting to be queued to the hardware |
101 | * @gc_work: fragments garbage collector work struct | ||
102 | * @gc_fragments: array of display list fragments waiting to be freed | ||
100 | */ | 103 | */ |
101 | struct vsp1_dl_manager { | 104 | struct vsp1_dl_manager { |
102 | unsigned int index; | 105 | unsigned int index; |
@@ -108,6 +111,9 @@ struct vsp1_dl_manager { | |||
108 | struct vsp1_dl_list *active; | 111 | struct vsp1_dl_list *active; |
109 | struct vsp1_dl_list *queued; | 112 | struct vsp1_dl_list *queued; |
110 | struct vsp1_dl_list *pending; | 113 | struct vsp1_dl_list *pending; |
114 | |||
115 | struct work_struct gc_work; | ||
116 | struct list_head gc_fragments; | ||
111 | }; | 117 | }; |
112 | 118 | ||
113 | /* ----------------------------------------------------------------------------- | 119 | /* ----------------------------------------------------------------------------- |
@@ -262,21 +268,10 @@ static struct vsp1_dl_list *vsp1_dl_list_alloc(struct vsp1_dl_manager *dlm) | |||
262 | return dl; | 268 | return dl; |
263 | } | 269 | } |
264 | 270 | ||
265 | static void vsp1_dl_list_free_fragments(struct vsp1_dl_list *dl) | ||
266 | { | ||
267 | struct vsp1_dl_body *dlb, *next; | ||
268 | |||
269 | list_for_each_entry_safe(dlb, next, &dl->fragments, list) { | ||
270 | list_del(&dlb->list); | ||
271 | vsp1_dl_body_cleanup(dlb); | ||
272 | kfree(dlb); | ||
273 | } | ||
274 | } | ||
275 | |||
276 | static void vsp1_dl_list_free(struct vsp1_dl_list *dl) | 271 | static void vsp1_dl_list_free(struct vsp1_dl_list *dl) |
277 | { | 272 | { |
278 | vsp1_dl_body_cleanup(&dl->body0); | 273 | vsp1_dl_body_cleanup(&dl->body0); |
279 | vsp1_dl_list_free_fragments(dl); | 274 | list_splice_init(&dl->fragments, &dl->dlm->gc_fragments); |
280 | kfree(dl); | 275 | kfree(dl); |
281 | } | 276 | } |
282 | 277 | ||
@@ -311,7 +306,16 @@ static void __vsp1_dl_list_put(struct vsp1_dl_list *dl) | |||
311 | if (!dl) | 306 | if (!dl) |
312 | return; | 307 | return; |
313 | 308 | ||
314 | vsp1_dl_list_free_fragments(dl); | 309 | /* We can't free fragments here as DMA memory can only be freed in |
310 | * interruptible context. Move all fragments to the display list | ||
311 | * manager's list of fragments to be freed, they will be | ||
312 | * garbage-collected by the work queue. | ||
313 | */ | ||
314 | if (!list_empty(&dl->fragments)) { | ||
315 | list_splice_init(&dl->fragments, &dl->dlm->gc_fragments); | ||
316 | schedule_work(&dl->dlm->gc_work); | ||
317 | } | ||
318 | |||
315 | dl->body0.num_entries = 0; | 319 | dl->body0.num_entries = 0; |
316 | 320 | ||
317 | list_add_tail(&dl->list, &dl->dlm->free); | 321 | list_add_tail(&dl->list, &dl->dlm->free); |
@@ -550,6 +554,40 @@ void vsp1_dlm_reset(struct vsp1_dl_manager *dlm) | |||
550 | dlm->pending = NULL; | 554 | dlm->pending = NULL; |
551 | } | 555 | } |
552 | 556 | ||
557 | /* | ||
558 | * Free all fragments awaiting to be garbage-collected. | ||
559 | * | ||
560 | * This function must be called without the display list manager lock held. | ||
561 | */ | ||
562 | static void vsp1_dlm_fragments_free(struct vsp1_dl_manager *dlm) | ||
563 | { | ||
564 | unsigned long flags; | ||
565 | |||
566 | spin_lock_irqsave(&dlm->lock, flags); | ||
567 | |||
568 | while (!list_empty(&dlm->gc_fragments)) { | ||
569 | struct vsp1_dl_body *dlb; | ||
570 | |||
571 | dlb = list_first_entry(&dlm->gc_fragments, struct vsp1_dl_body, | ||
572 | list); | ||
573 | list_del(&dlb->list); | ||
574 | |||
575 | spin_unlock_irqrestore(&dlm->lock, flags); | ||
576 | vsp1_dl_fragment_free(dlb); | ||
577 | spin_lock_irqsave(&dlm->lock, flags); | ||
578 | } | ||
579 | |||
580 | spin_unlock_irqrestore(&dlm->lock, flags); | ||
581 | } | ||
582 | |||
583 | static void vsp1_dlm_garbage_collect(struct work_struct *work) | ||
584 | { | ||
585 | struct vsp1_dl_manager *dlm = | ||
586 | container_of(work, struct vsp1_dl_manager, gc_work); | ||
587 | |||
588 | vsp1_dlm_fragments_free(dlm); | ||
589 | } | ||
590 | |||
553 | struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1, | 591 | struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1, |
554 | unsigned int index, | 592 | unsigned int index, |
555 | unsigned int prealloc) | 593 | unsigned int prealloc) |
@@ -568,6 +606,8 @@ struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1, | |||
568 | 606 | ||
569 | spin_lock_init(&dlm->lock); | 607 | spin_lock_init(&dlm->lock); |
570 | INIT_LIST_HEAD(&dlm->free); | 608 | INIT_LIST_HEAD(&dlm->free); |
609 | INIT_LIST_HEAD(&dlm->gc_fragments); | ||
610 | INIT_WORK(&dlm->gc_work, vsp1_dlm_garbage_collect); | ||
571 | 611 | ||
572 | for (i = 0; i < prealloc; ++i) { | 612 | for (i = 0; i < prealloc; ++i) { |
573 | struct vsp1_dl_list *dl; | 613 | struct vsp1_dl_list *dl; |
@@ -589,8 +629,12 @@ void vsp1_dlm_destroy(struct vsp1_dl_manager *dlm) | |||
589 | if (!dlm) | 629 | if (!dlm) |
590 | return; | 630 | return; |
591 | 631 | ||
632 | cancel_work_sync(&dlm->gc_work); | ||
633 | |||
592 | list_for_each_entry_safe(dl, next, &dlm->free, list) { | 634 | list_for_each_entry_safe(dl, next, &dlm->free, list) { |
593 | list_del(&dl->list); | 635 | list_del(&dl->list); |
594 | vsp1_dl_list_free(dl); | 636 | vsp1_dl_list_free(dl); |
595 | } | 637 | } |
638 | |||
639 | vsp1_dlm_fragments_free(dlm); | ||
596 | } | 640 | } |
diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c index fc4bbc401e67..fe9665e57b3b 100644 --- a/drivers/media/platform/vsp1/vsp1_drm.c +++ b/drivers/media/platform/vsp1/vsp1_drm.c | |||
@@ -230,42 +230,33 @@ EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin); | |||
230 | * vsp1_du_atomic_update - Setup one RPF input of the VSP pipeline | 230 | * vsp1_du_atomic_update - Setup one RPF input of the VSP pipeline |
231 | * @dev: the VSP device | 231 | * @dev: the VSP device |
232 | * @rpf_index: index of the RPF to setup (0-based) | 232 | * @rpf_index: index of the RPF to setup (0-based) |
233 | * @pixelformat: V4L2 pixel format for the RPF memory input | 233 | * @cfg: the RPF configuration |
234 | * @pitch: number of bytes per line in the image stored in memory | ||
235 | * @mem: DMA addresses of the memory buffers (one per plane) | ||
236 | * @src: the source crop rectangle for the RPF | ||
237 | * @dst: the destination compose rectangle for the BRU input | ||
238 | * @alpha: global alpha value for the input | ||
239 | * @zpos: the Z-order position of the input | ||
240 | * | 234 | * |
241 | * Configure the VSP to perform composition of the image referenced by @mem | 235 | * Configure the VSP to perform image composition through RPF @rpf_index as |
242 | * through RPF @rpf_index, using the @src crop rectangle and the @dst | 236 | * described by the @cfg configuration. The image to compose is referenced by |
237 | * @cfg.mem and composed using the @cfg.src crop rectangle and the @cfg.dst | ||
243 | * composition rectangle. The Z-order is configurable with higher @zpos values | 238 | * composition rectangle. The Z-order is configurable with higher @zpos values |
244 | * displayed on top. | 239 | * displayed on top. |
245 | * | 240 | * |
246 | * Image format as stored in memory is expressed as a V4L2 @pixelformat value. | 241 | * If the @cfg configuration is NULL, the RPF will be disabled. Calling the |
247 | * As a special case, setting the pixel format to 0 will disable the RPF. The | ||
248 | * @pitch, @mem, @src and @dst parameters are ignored in that case. Calling the | ||
249 | * function on a disabled RPF is allowed. | 242 | * function on a disabled RPF is allowed. |
250 | * | 243 | * |
251 | * The memory pitch is configurable to allow for padding at end of lines, or | 244 | * Image format as stored in memory is expressed as a V4L2 @cfg.pixelformat |
252 | * simple for images that extend beyond the crop rectangle boundaries. The | 245 | * value. The memory pitch is configurable to allow for padding at end of lines, |
253 | * @pitch value is expressed in bytes and applies to all planes for multiplanar | 246 | * or simply for images that extend beyond the crop rectangle boundaries. The |
254 | * formats. | 247 | * @cfg.pitch value is expressed in bytes and applies to all planes for |
248 | * multiplanar formats. | ||
255 | * | 249 | * |
256 | * The source memory buffer is referenced by the DMA address of its planes in | 250 | * The source memory buffer is referenced by the DMA address of its planes in |
257 | * the @mem array. Up to two planes are supported. The second plane DMA address | 251 | * the @cfg.mem array. Up to two planes are supported. The second plane DMA |
258 | * is ignored for formats using a single plane. | 252 | * address is ignored for formats using a single plane. |
259 | * | 253 | * |
260 | * This function isn't reentrant, the caller needs to serialize calls. | 254 | * This function isn't reentrant, the caller needs to serialize calls. |
261 | * | 255 | * |
262 | * Return 0 on success or a negative error code on failure. | 256 | * Return 0 on success or a negative error code on failure. |
263 | */ | 257 | */ |
264 | int vsp1_du_atomic_update_ext(struct device *dev, unsigned int rpf_index, | 258 | int vsp1_du_atomic_update(struct device *dev, unsigned int rpf_index, |
265 | u32 pixelformat, unsigned int pitch, | 259 | const struct vsp1_du_atomic_config *cfg) |
266 | dma_addr_t mem[2], const struct v4l2_rect *src, | ||
267 | const struct v4l2_rect *dst, unsigned int alpha, | ||
268 | unsigned int zpos) | ||
269 | { | 260 | { |
270 | struct vsp1_device *vsp1 = dev_get_drvdata(dev); | 261 | struct vsp1_device *vsp1 = dev_get_drvdata(dev); |
271 | const struct vsp1_format_info *fmtinfo; | 262 | const struct vsp1_format_info *fmtinfo; |
@@ -276,7 +267,7 @@ int vsp1_du_atomic_update_ext(struct device *dev, unsigned int rpf_index, | |||
276 | 267 | ||
277 | rpf = vsp1->rpf[rpf_index]; | 268 | rpf = vsp1->rpf[rpf_index]; |
278 | 269 | ||
279 | if (pixelformat == 0) { | 270 | if (!cfg) { |
280 | dev_dbg(vsp1->dev, "%s: RPF%u: disable requested\n", __func__, | 271 | dev_dbg(vsp1->dev, "%s: RPF%u: disable requested\n", __func__, |
281 | rpf_index); | 272 | rpf_index); |
282 | 273 | ||
@@ -287,38 +278,39 @@ int vsp1_du_atomic_update_ext(struct device *dev, unsigned int rpf_index, | |||
287 | dev_dbg(vsp1->dev, | 278 | dev_dbg(vsp1->dev, |
288 | "%s: RPF%u: (%u,%u)/%ux%u -> (%u,%u)/%ux%u (%08x), pitch %u dma { %pad, %pad } zpos %u\n", | 279 | "%s: RPF%u: (%u,%u)/%ux%u -> (%u,%u)/%ux%u (%08x), pitch %u dma { %pad, %pad } zpos %u\n", |
289 | __func__, rpf_index, | 280 | __func__, rpf_index, |
290 | src->left, src->top, src->width, src->height, | 281 | cfg->src.left, cfg->src.top, cfg->src.width, cfg->src.height, |
291 | dst->left, dst->top, dst->width, dst->height, | 282 | cfg->dst.left, cfg->dst.top, cfg->dst.width, cfg->dst.height, |
292 | pixelformat, pitch, &mem[0], &mem[1], zpos); | 283 | cfg->pixelformat, cfg->pitch, &cfg->mem[0], &cfg->mem[1], |
284 | cfg->zpos); | ||
293 | 285 | ||
294 | /* Store the format, stride, memory buffer address, crop and compose | 286 | /* Store the format, stride, memory buffer address, crop and compose |
295 | * rectangles and Z-order position and for the input. | 287 | * rectangles and Z-order position and for the input. |
296 | */ | 288 | */ |
297 | fmtinfo = vsp1_get_format_info(pixelformat); | 289 | fmtinfo = vsp1_get_format_info(cfg->pixelformat); |
298 | if (!fmtinfo) { | 290 | if (!fmtinfo) { |
299 | dev_dbg(vsp1->dev, "Unsupport pixel format %08x for RPF\n", | 291 | dev_dbg(vsp1->dev, "Unsupport pixel format %08x for RPF\n", |
300 | pixelformat); | 292 | cfg->pixelformat); |
301 | return -EINVAL; | 293 | return -EINVAL; |
302 | } | 294 | } |
303 | 295 | ||
304 | rpf->fmtinfo = fmtinfo; | 296 | rpf->fmtinfo = fmtinfo; |
305 | rpf->format.num_planes = fmtinfo->planes; | 297 | rpf->format.num_planes = fmtinfo->planes; |
306 | rpf->format.plane_fmt[0].bytesperline = pitch; | 298 | rpf->format.plane_fmt[0].bytesperline = cfg->pitch; |
307 | rpf->format.plane_fmt[1].bytesperline = pitch; | 299 | rpf->format.plane_fmt[1].bytesperline = cfg->pitch; |
308 | rpf->alpha = alpha; | 300 | rpf->alpha = cfg->alpha; |
309 | 301 | ||
310 | rpf->mem.addr[0] = mem[0]; | 302 | rpf->mem.addr[0] = cfg->mem[0]; |
311 | rpf->mem.addr[1] = mem[1]; | 303 | rpf->mem.addr[1] = cfg->mem[1]; |
312 | rpf->mem.addr[2] = 0; | 304 | rpf->mem.addr[2] = 0; |
313 | 305 | ||
314 | vsp1->drm->inputs[rpf_index].crop = *src; | 306 | vsp1->drm->inputs[rpf_index].crop = cfg->src; |
315 | vsp1->drm->inputs[rpf_index].compose = *dst; | 307 | vsp1->drm->inputs[rpf_index].compose = cfg->dst; |
316 | vsp1->drm->inputs[rpf_index].zpos = zpos; | 308 | vsp1->drm->inputs[rpf_index].zpos = cfg->zpos; |
317 | vsp1->drm->inputs[rpf_index].enabled = true; | 309 | vsp1->drm->inputs[rpf_index].enabled = true; |
318 | 310 | ||
319 | return 0; | 311 | return 0; |
320 | } | 312 | } |
321 | EXPORT_SYMBOL_GPL(vsp1_du_atomic_update_ext); | 313 | EXPORT_SYMBOL_GPL(vsp1_du_atomic_update); |
322 | 314 | ||
323 | static int vsp1_du_setup_rpf_pipe(struct vsp1_device *vsp1, | 315 | static int vsp1_du_setup_rpf_pipe(struct vsp1_device *vsp1, |
324 | struct vsp1_rwpf *rpf, unsigned int bru_input) | 316 | struct vsp1_rwpf *rpf, unsigned int bru_input) |
@@ -499,8 +491,10 @@ void vsp1_du_atomic_flush(struct device *dev) | |||
499 | 491 | ||
500 | vsp1_entity_route_setup(entity, pipe->dl); | 492 | vsp1_entity_route_setup(entity, pipe->dl); |
501 | 493 | ||
502 | if (entity->ops->configure) | 494 | if (entity->ops->configure) { |
503 | entity->ops->configure(entity, pipe, pipe->dl); | 495 | entity->ops->configure(entity, pipe, pipe->dl, true); |
496 | entity->ops->configure(entity, pipe, pipe->dl, false); | ||
497 | } | ||
504 | 498 | ||
505 | /* The memory buffer address must be applied after configuring | 499 | /* The memory buffer address must be applied after configuring |
506 | * the RPF to make sure the crop offset are computed. | 500 | * the RPF to make sure the crop offset are computed. |
diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index e2d779fac0eb..e1377ffe3d68 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c | |||
@@ -19,12 +19,15 @@ | |||
19 | #include <linux/of.h> | 19 | #include <linux/of.h> |
20 | #include <linux/of_device.h> | 20 | #include <linux/of_device.h> |
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <linux/pm_runtime.h> | ||
22 | #include <linux/videodev2.h> | 23 | #include <linux/videodev2.h> |
23 | 24 | ||
25 | #include <media/rcar-fcp.h> | ||
24 | #include <media/v4l2-subdev.h> | 26 | #include <media/v4l2-subdev.h> |
25 | 27 | ||
26 | #include "vsp1.h" | 28 | #include "vsp1.h" |
27 | #include "vsp1_bru.h" | 29 | #include "vsp1_bru.h" |
30 | #include "vsp1_clu.h" | ||
28 | #include "vsp1_dl.h" | 31 | #include "vsp1_dl.h" |
29 | #include "vsp1_drm.h" | 32 | #include "vsp1_drm.h" |
30 | #include "vsp1_hsit.h" | 33 | #include "vsp1_hsit.h" |
@@ -145,7 +148,7 @@ static int vsp1_uapi_create_links(struct vsp1_device *vsp1) | |||
145 | return ret; | 148 | return ret; |
146 | } | 149 | } |
147 | 150 | ||
148 | if (vsp1->info->features & VSP1_HAS_LIF) { | 151 | if (vsp1->lif) { |
149 | ret = media_create_pad_link(&vsp1->wpf[0]->entity.subdev.entity, | 152 | ret = media_create_pad_link(&vsp1->wpf[0]->entity.subdev.entity, |
150 | RWPF_PAD_SOURCE, | 153 | RWPF_PAD_SOURCE, |
151 | &vsp1->lif->entity.subdev.entity, | 154 | &vsp1->lif->entity.subdev.entity, |
@@ -168,19 +171,15 @@ static int vsp1_uapi_create_links(struct vsp1_device *vsp1) | |||
168 | 171 | ||
169 | for (i = 0; i < vsp1->info->wpf_count; ++i) { | 172 | for (i = 0; i < vsp1->info->wpf_count; ++i) { |
170 | /* Connect the video device to the WPF. All connections are | 173 | /* Connect the video device to the WPF. All connections are |
171 | * immutable except for the WPF0 source link if a LIF is | 174 | * immutable. |
172 | * present. | ||
173 | */ | 175 | */ |
174 | struct vsp1_rwpf *wpf = vsp1->wpf[i]; | 176 | struct vsp1_rwpf *wpf = vsp1->wpf[i]; |
175 | unsigned int flags = MEDIA_LNK_FL_ENABLED; | ||
176 | |||
177 | if (!(vsp1->info->features & VSP1_HAS_LIF) || i != 0) | ||
178 | flags |= MEDIA_LNK_FL_IMMUTABLE; | ||
179 | 177 | ||
180 | ret = media_create_pad_link(&wpf->entity.subdev.entity, | 178 | ret = media_create_pad_link(&wpf->entity.subdev.entity, |
181 | RWPF_PAD_SOURCE, | 179 | RWPF_PAD_SOURCE, |
182 | &wpf->video->video.entity, 0, | 180 | &wpf->video->video.entity, 0, |
183 | flags); | 181 | MEDIA_LNK_FL_IMMUTABLE | |
182 | MEDIA_LNK_FL_ENABLED); | ||
184 | if (ret < 0) | 183 | if (ret < 0) |
185 | return ret; | 184 | return ret; |
186 | } | 185 | } |
@@ -204,7 +203,8 @@ static void vsp1_destroy_entities(struct vsp1_device *vsp1) | |||
204 | } | 203 | } |
205 | 204 | ||
206 | v4l2_device_unregister(&vsp1->v4l2_dev); | 205 | v4l2_device_unregister(&vsp1->v4l2_dev); |
207 | media_device_unregister(&vsp1->media_dev); | 206 | if (vsp1->info->uapi) |
207 | media_device_unregister(&vsp1->media_dev); | ||
208 | media_device_cleanup(&vsp1->media_dev); | 208 | media_device_cleanup(&vsp1->media_dev); |
209 | 209 | ||
210 | if (!vsp1->info->uapi) | 210 | if (!vsp1->info->uapi) |
@@ -252,6 +252,16 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) | |||
252 | list_add_tail(&vsp1->bru->entity.list_dev, &vsp1->entities); | 252 | list_add_tail(&vsp1->bru->entity.list_dev, &vsp1->entities); |
253 | } | 253 | } |
254 | 254 | ||
255 | if (vsp1->info->features & VSP1_HAS_CLU) { | ||
256 | vsp1->clu = vsp1_clu_create(vsp1); | ||
257 | if (IS_ERR(vsp1->clu)) { | ||
258 | ret = PTR_ERR(vsp1->clu); | ||
259 | goto done; | ||
260 | } | ||
261 | |||
262 | list_add_tail(&vsp1->clu->entity.list_dev, &vsp1->entities); | ||
263 | } | ||
264 | |||
255 | vsp1->hsi = vsp1_hsit_create(vsp1, true); | 265 | vsp1->hsi = vsp1_hsit_create(vsp1, true); |
256 | if (IS_ERR(vsp1->hsi)) { | 266 | if (IS_ERR(vsp1->hsi)) { |
257 | ret = PTR_ERR(vsp1->hsi); | 267 | ret = PTR_ERR(vsp1->hsi); |
@@ -268,7 +278,11 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) | |||
268 | 278 | ||
269 | list_add_tail(&vsp1->hst->entity.list_dev, &vsp1->entities); | 279 | list_add_tail(&vsp1->hst->entity.list_dev, &vsp1->entities); |
270 | 280 | ||
271 | if (vsp1->info->features & VSP1_HAS_LIF) { | 281 | /* The LIF is only supported when used in conjunction with the DU, in |
282 | * which case the userspace API is disabled. If the userspace API is | ||
283 | * enabled skip the LIF, even when present. | ||
284 | */ | ||
285 | if (vsp1->info->features & VSP1_HAS_LIF && !vsp1->info->uapi) { | ||
272 | vsp1->lif = vsp1_lif_create(vsp1); | 286 | vsp1->lif = vsp1_lif_create(vsp1); |
273 | if (IS_ERR(vsp1->lif)) { | 287 | if (IS_ERR(vsp1->lif)) { |
274 | ret = PTR_ERR(vsp1->lif); | 288 | ret = PTR_ERR(vsp1->lif); |
@@ -379,14 +393,15 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) | |||
379 | /* Register subdev nodes if the userspace API is enabled or initialize | 393 | /* Register subdev nodes if the userspace API is enabled or initialize |
380 | * the DRM pipeline otherwise. | 394 | * the DRM pipeline otherwise. |
381 | */ | 395 | */ |
382 | if (vsp1->info->uapi) | 396 | if (vsp1->info->uapi) { |
383 | ret = v4l2_device_register_subdev_nodes(&vsp1->v4l2_dev); | 397 | ret = v4l2_device_register_subdev_nodes(&vsp1->v4l2_dev); |
384 | else | 398 | if (ret < 0) |
385 | ret = vsp1_drm_init(vsp1); | 399 | goto done; |
386 | if (ret < 0) | ||
387 | goto done; | ||
388 | 400 | ||
389 | ret = media_device_register(mdev); | 401 | ret = media_device_register(mdev); |
402 | } else { | ||
403 | ret = vsp1_drm_init(vsp1); | ||
404 | } | ||
390 | 405 | ||
391 | done: | 406 | done: |
392 | if (ret < 0) | 407 | if (ret < 0) |
@@ -462,35 +477,16 @@ static int vsp1_device_init(struct vsp1_device *vsp1) | |||
462 | /* | 477 | /* |
463 | * vsp1_device_get - Acquire the VSP1 device | 478 | * vsp1_device_get - Acquire the VSP1 device |
464 | * | 479 | * |
465 | * Increment the VSP1 reference count and initialize the device if the first | 480 | * Make sure the device is not suspended and initialize it if needed. |
466 | * reference is taken. | ||
467 | * | 481 | * |
468 | * Return 0 on success or a negative error code otherwise. | 482 | * Return 0 on success or a negative error code otherwise. |
469 | */ | 483 | */ |
470 | int vsp1_device_get(struct vsp1_device *vsp1) | 484 | int vsp1_device_get(struct vsp1_device *vsp1) |
471 | { | 485 | { |
472 | int ret = 0; | 486 | int ret; |
473 | |||
474 | mutex_lock(&vsp1->lock); | ||
475 | if (vsp1->ref_count > 0) | ||
476 | goto done; | ||
477 | |||
478 | ret = clk_prepare_enable(vsp1->clock); | ||
479 | if (ret < 0) | ||
480 | goto done; | ||
481 | |||
482 | ret = vsp1_device_init(vsp1); | ||
483 | if (ret < 0) { | ||
484 | clk_disable_unprepare(vsp1->clock); | ||
485 | goto done; | ||
486 | } | ||
487 | |||
488 | done: | ||
489 | if (!ret) | ||
490 | vsp1->ref_count++; | ||
491 | 487 | ||
492 | mutex_unlock(&vsp1->lock); | 488 | ret = pm_runtime_get_sync(vsp1->dev); |
493 | return ret; | 489 | return ret < 0 ? ret : 0; |
494 | } | 490 | } |
495 | 491 | ||
496 | /* | 492 | /* |
@@ -501,12 +497,7 @@ done: | |||
501 | */ | 497 | */ |
502 | void vsp1_device_put(struct vsp1_device *vsp1) | 498 | void vsp1_device_put(struct vsp1_device *vsp1) |
503 | { | 499 | { |
504 | mutex_lock(&vsp1->lock); | 500 | pm_runtime_put_sync(vsp1->dev); |
505 | |||
506 | if (--vsp1->ref_count == 0) | ||
507 | clk_disable_unprepare(vsp1->clock); | ||
508 | |||
509 | mutex_unlock(&vsp1->lock); | ||
510 | } | 501 | } |
511 | 502 | ||
512 | /* ----------------------------------------------------------------------------- | 503 | /* ----------------------------------------------------------------------------- |
@@ -518,14 +509,8 @@ static int vsp1_pm_suspend(struct device *dev) | |||
518 | { | 509 | { |
519 | struct vsp1_device *vsp1 = dev_get_drvdata(dev); | 510 | struct vsp1_device *vsp1 = dev_get_drvdata(dev); |
520 | 511 | ||
521 | WARN_ON(mutex_is_locked(&vsp1->lock)); | ||
522 | |||
523 | if (vsp1->ref_count == 0) | ||
524 | return 0; | ||
525 | |||
526 | vsp1_pipelines_suspend(vsp1); | 512 | vsp1_pipelines_suspend(vsp1); |
527 | 513 | pm_runtime_force_suspend(vsp1->dev); | |
528 | clk_disable_unprepare(vsp1->clock); | ||
529 | 514 | ||
530 | return 0; | 515 | return 0; |
531 | } | 516 | } |
@@ -534,21 +519,39 @@ static int vsp1_pm_resume(struct device *dev) | |||
534 | { | 519 | { |
535 | struct vsp1_device *vsp1 = dev_get_drvdata(dev); | 520 | struct vsp1_device *vsp1 = dev_get_drvdata(dev); |
536 | 521 | ||
537 | WARN_ON(mutex_is_locked(&vsp1->lock)); | 522 | pm_runtime_force_resume(vsp1->dev); |
523 | vsp1_pipelines_resume(vsp1); | ||
538 | 524 | ||
539 | if (vsp1->ref_count == 0) | 525 | return 0; |
540 | return 0; | 526 | } |
527 | #endif | ||
541 | 528 | ||
542 | clk_prepare_enable(vsp1->clock); | 529 | static int vsp1_pm_runtime_suspend(struct device *dev) |
530 | { | ||
531 | struct vsp1_device *vsp1 = dev_get_drvdata(dev); | ||
543 | 532 | ||
544 | vsp1_pipelines_resume(vsp1); | 533 | rcar_fcp_disable(vsp1->fcp); |
545 | 534 | ||
546 | return 0; | 535 | return 0; |
547 | } | 536 | } |
548 | #endif | 537 | |
538 | static int vsp1_pm_runtime_resume(struct device *dev) | ||
539 | { | ||
540 | struct vsp1_device *vsp1 = dev_get_drvdata(dev); | ||
541 | int ret; | ||
542 | |||
543 | if (vsp1->info) { | ||
544 | ret = vsp1_device_init(vsp1); | ||
545 | if (ret < 0) | ||
546 | return ret; | ||
547 | } | ||
548 | |||
549 | return rcar_fcp_enable(vsp1->fcp); | ||
550 | } | ||
549 | 551 | ||
550 | static const struct dev_pm_ops vsp1_pm_ops = { | 552 | static const struct dev_pm_ops vsp1_pm_ops = { |
551 | SET_SYSTEM_SLEEP_PM_OPS(vsp1_pm_suspend, vsp1_pm_resume) | 553 | SET_SYSTEM_SLEEP_PM_OPS(vsp1_pm_suspend, vsp1_pm_resume) |
554 | SET_RUNTIME_PM_OPS(vsp1_pm_runtime_suspend, vsp1_pm_runtime_resume, NULL) | ||
552 | }; | 555 | }; |
553 | 556 | ||
554 | /* ----------------------------------------------------------------------------- | 557 | /* ----------------------------------------------------------------------------- |
@@ -559,7 +562,8 @@ static const struct vsp1_device_info vsp1_device_infos[] = { | |||
559 | { | 562 | { |
560 | .version = VI6_IP_VERSION_MODEL_VSPS_H2, | 563 | .version = VI6_IP_VERSION_MODEL_VSPS_H2, |
561 | .gen = 2, | 564 | .gen = 2, |
562 | .features = VSP1_HAS_BRU | VSP1_HAS_LUT | VSP1_HAS_SRU, | 565 | .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT |
566 | | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP, | ||
563 | .rpf_count = 5, | 567 | .rpf_count = 5, |
564 | .uds_count = 3, | 568 | .uds_count = 3, |
565 | .wpf_count = 4, | 569 | .wpf_count = 4, |
@@ -568,9 +572,9 @@ static const struct vsp1_device_info vsp1_device_infos[] = { | |||
568 | }, { | 572 | }, { |
569 | .version = VI6_IP_VERSION_MODEL_VSPR_H2, | 573 | .version = VI6_IP_VERSION_MODEL_VSPR_H2, |
570 | .gen = 2, | 574 | .gen = 2, |
571 | .features = VSP1_HAS_BRU | VSP1_HAS_SRU, | 575 | .features = VSP1_HAS_BRU | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP, |
572 | .rpf_count = 5, | 576 | .rpf_count = 5, |
573 | .uds_count = 1, | 577 | .uds_count = 3, |
574 | .wpf_count = 4, | 578 | .wpf_count = 4, |
575 | .num_bru_inputs = 4, | 579 | .num_bru_inputs = 4, |
576 | .uapi = true, | 580 | .uapi = true, |
@@ -580,22 +584,24 @@ static const struct vsp1_device_info vsp1_device_infos[] = { | |||
580 | .features = VSP1_HAS_BRU | VSP1_HAS_LIF | VSP1_HAS_LUT, | 584 | .features = VSP1_HAS_BRU | VSP1_HAS_LIF | VSP1_HAS_LUT, |
581 | .rpf_count = 4, | 585 | .rpf_count = 4, |
582 | .uds_count = 1, | 586 | .uds_count = 1, |
583 | .wpf_count = 4, | 587 | .wpf_count = 1, |
584 | .num_bru_inputs = 4, | 588 | .num_bru_inputs = 4, |
585 | .uapi = true, | 589 | .uapi = true, |
586 | }, { | 590 | }, { |
587 | .version = VI6_IP_VERSION_MODEL_VSPS_M2, | 591 | .version = VI6_IP_VERSION_MODEL_VSPS_M2, |
588 | .gen = 2, | 592 | .gen = 2, |
589 | .features = VSP1_HAS_BRU | VSP1_HAS_LUT | VSP1_HAS_SRU, | 593 | .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT |
594 | | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP, | ||
590 | .rpf_count = 5, | 595 | .rpf_count = 5, |
591 | .uds_count = 3, | 596 | .uds_count = 1, |
592 | .wpf_count = 4, | 597 | .wpf_count = 4, |
593 | .num_bru_inputs = 4, | 598 | .num_bru_inputs = 4, |
594 | .uapi = true, | 599 | .uapi = true, |
595 | }, { | 600 | }, { |
596 | .version = VI6_IP_VERSION_MODEL_VSPI_GEN3, | 601 | .version = VI6_IP_VERSION_MODEL_VSPI_GEN3, |
597 | .gen = 3, | 602 | .gen = 3, |
598 | .features = VSP1_HAS_LUT | VSP1_HAS_SRU, | 603 | .features = VSP1_HAS_CLU | VSP1_HAS_LUT | VSP1_HAS_SRU |
604 | | VSP1_HAS_WPF_HFLIP | VSP1_HAS_WPF_VFLIP, | ||
599 | .rpf_count = 1, | 605 | .rpf_count = 1, |
600 | .uds_count = 1, | 606 | .uds_count = 1, |
601 | .wpf_count = 1, | 607 | .wpf_count = 1, |
@@ -603,7 +609,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = { | |||
603 | }, { | 609 | }, { |
604 | .version = VI6_IP_VERSION_MODEL_VSPBD_GEN3, | 610 | .version = VI6_IP_VERSION_MODEL_VSPBD_GEN3, |
605 | .gen = 3, | 611 | .gen = 3, |
606 | .features = VSP1_HAS_BRU, | 612 | .features = VSP1_HAS_BRU | VSP1_HAS_WPF_VFLIP, |
607 | .rpf_count = 5, | 613 | .rpf_count = 5, |
608 | .wpf_count = 1, | 614 | .wpf_count = 1, |
609 | .num_bru_inputs = 5, | 615 | .num_bru_inputs = 5, |
@@ -611,7 +617,8 @@ static const struct vsp1_device_info vsp1_device_infos[] = { | |||
611 | }, { | 617 | }, { |
612 | .version = VI6_IP_VERSION_MODEL_VSPBC_GEN3, | 618 | .version = VI6_IP_VERSION_MODEL_VSPBC_GEN3, |
613 | .gen = 3, | 619 | .gen = 3, |
614 | .features = VSP1_HAS_BRU | VSP1_HAS_LUT, | 620 | .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT |
621 | | VSP1_HAS_WPF_VFLIP, | ||
615 | .rpf_count = 5, | 622 | .rpf_count = 5, |
616 | .wpf_count = 1, | 623 | .wpf_count = 1, |
617 | .num_bru_inputs = 5, | 624 | .num_bru_inputs = 5, |
@@ -619,7 +626,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = { | |||
619 | }, { | 626 | }, { |
620 | .version = VI6_IP_VERSION_MODEL_VSPD_GEN3, | 627 | .version = VI6_IP_VERSION_MODEL_VSPD_GEN3, |
621 | .gen = 3, | 628 | .gen = 3, |
622 | .features = VSP1_HAS_BRU | VSP1_HAS_LIF, | 629 | .features = VSP1_HAS_BRU | VSP1_HAS_LIF | VSP1_HAS_WPF_VFLIP, |
623 | .rpf_count = 5, | 630 | .rpf_count = 5, |
624 | .wpf_count = 2, | 631 | .wpf_count = 2, |
625 | .num_bru_inputs = 5, | 632 | .num_bru_inputs = 5, |
@@ -629,6 +636,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = { | |||
629 | static int vsp1_probe(struct platform_device *pdev) | 636 | static int vsp1_probe(struct platform_device *pdev) |
630 | { | 637 | { |
631 | struct vsp1_device *vsp1; | 638 | struct vsp1_device *vsp1; |
639 | struct device_node *fcp_node; | ||
632 | struct resource *irq; | 640 | struct resource *irq; |
633 | struct resource *io; | 641 | struct resource *io; |
634 | unsigned int i; | 642 | unsigned int i; |
@@ -640,22 +648,17 @@ static int vsp1_probe(struct platform_device *pdev) | |||
640 | return -ENOMEM; | 648 | return -ENOMEM; |
641 | 649 | ||
642 | vsp1->dev = &pdev->dev; | 650 | vsp1->dev = &pdev->dev; |
643 | mutex_init(&vsp1->lock); | ||
644 | INIT_LIST_HEAD(&vsp1->entities); | 651 | INIT_LIST_HEAD(&vsp1->entities); |
645 | INIT_LIST_HEAD(&vsp1->videos); | 652 | INIT_LIST_HEAD(&vsp1->videos); |
646 | 653 | ||
647 | /* I/O, IRQ and clock resources */ | 654 | platform_set_drvdata(pdev, vsp1); |
655 | |||
656 | /* I/O and IRQ resources (clock managed by the clock PM domain) */ | ||
648 | io = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 657 | io = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
649 | vsp1->mmio = devm_ioremap_resource(&pdev->dev, io); | 658 | vsp1->mmio = devm_ioremap_resource(&pdev->dev, io); |
650 | if (IS_ERR(vsp1->mmio)) | 659 | if (IS_ERR(vsp1->mmio)) |
651 | return PTR_ERR(vsp1->mmio); | 660 | return PTR_ERR(vsp1->mmio); |
652 | 661 | ||
653 | vsp1->clock = devm_clk_get(&pdev->dev, NULL); | ||
654 | if (IS_ERR(vsp1->clock)) { | ||
655 | dev_err(&pdev->dev, "failed to get clock\n"); | ||
656 | return PTR_ERR(vsp1->clock); | ||
657 | } | ||
658 | |||
659 | irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 662 | irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
660 | if (!irq) { | 663 | if (!irq) { |
661 | dev_err(&pdev->dev, "missing IRQ\n"); | 664 | dev_err(&pdev->dev, "missing IRQ\n"); |
@@ -669,13 +672,27 @@ static int vsp1_probe(struct platform_device *pdev) | |||
669 | return ret; | 672 | return ret; |
670 | } | 673 | } |
671 | 674 | ||
675 | /* FCP (optional) */ | ||
676 | fcp_node = of_parse_phandle(pdev->dev.of_node, "renesas,fcp", 0); | ||
677 | if (fcp_node) { | ||
678 | vsp1->fcp = rcar_fcp_get(fcp_node); | ||
679 | of_node_put(fcp_node); | ||
680 | if (IS_ERR(vsp1->fcp)) { | ||
681 | dev_dbg(&pdev->dev, "FCP not found (%ld)\n", | ||
682 | PTR_ERR(vsp1->fcp)); | ||
683 | return PTR_ERR(vsp1->fcp); | ||
684 | } | ||
685 | } | ||
686 | |||
672 | /* Configure device parameters based on the version register. */ | 687 | /* Configure device parameters based on the version register. */ |
673 | ret = clk_prepare_enable(vsp1->clock); | 688 | pm_runtime_enable(&pdev->dev); |
689 | |||
690 | ret = pm_runtime_get_sync(&pdev->dev); | ||
674 | if (ret < 0) | 691 | if (ret < 0) |
675 | return ret; | 692 | goto done; |
676 | 693 | ||
677 | version = vsp1_read(vsp1, VI6_IP_VERSION); | 694 | version = vsp1_read(vsp1, VI6_IP_VERSION); |
678 | clk_disable_unprepare(vsp1->clock); | 695 | pm_runtime_put_sync(&pdev->dev); |
679 | 696 | ||
680 | for (i = 0; i < ARRAY_SIZE(vsp1_device_infos); ++i) { | 697 | for (i = 0; i < ARRAY_SIZE(vsp1_device_infos); ++i) { |
681 | if ((version & VI6_IP_VERSION_MODEL_MASK) == | 698 | if ((version & VI6_IP_VERSION_MODEL_MASK) == |
@@ -687,7 +704,8 @@ static int vsp1_probe(struct platform_device *pdev) | |||
687 | 704 | ||
688 | if (!vsp1->info) { | 705 | if (!vsp1->info) { |
689 | dev_err(&pdev->dev, "unsupported IP version 0x%08x\n", version); | 706 | dev_err(&pdev->dev, "unsupported IP version 0x%08x\n", version); |
690 | return -ENXIO; | 707 | ret = -ENXIO; |
708 | goto done; | ||
691 | } | 709 | } |
692 | 710 | ||
693 | dev_dbg(&pdev->dev, "IP version 0x%08x\n", version); | 711 | dev_dbg(&pdev->dev, "IP version 0x%08x\n", version); |
@@ -696,12 +714,14 @@ static int vsp1_probe(struct platform_device *pdev) | |||
696 | ret = vsp1_create_entities(vsp1); | 714 | ret = vsp1_create_entities(vsp1); |
697 | if (ret < 0) { | 715 | if (ret < 0) { |
698 | dev_err(&pdev->dev, "failed to create entities\n"); | 716 | dev_err(&pdev->dev, "failed to create entities\n"); |
699 | return ret; | 717 | goto done; |
700 | } | 718 | } |
701 | 719 | ||
702 | platform_set_drvdata(pdev, vsp1); | 720 | done: |
721 | if (ret) | ||
722 | pm_runtime_disable(&pdev->dev); | ||
703 | 723 | ||
704 | return 0; | 724 | return ret; |
705 | } | 725 | } |
706 | 726 | ||
707 | static int vsp1_remove(struct platform_device *pdev) | 727 | static int vsp1_remove(struct platform_device *pdev) |
@@ -709,6 +729,9 @@ static int vsp1_remove(struct platform_device *pdev) | |||
709 | struct vsp1_device *vsp1 = platform_get_drvdata(pdev); | 729 | struct vsp1_device *vsp1 = platform_get_drvdata(pdev); |
710 | 730 | ||
711 | vsp1_destroy_entities(vsp1); | 731 | vsp1_destroy_entities(vsp1); |
732 | rcar_fcp_put(vsp1->fcp); | ||
733 | |||
734 | pm_runtime_disable(&pdev->dev); | ||
712 | 735 | ||
713 | return 0; | 736 | return 0; |
714 | } | 737 | } |
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c index 3d070bcc6053..4cf6cc719c00 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.c +++ b/drivers/media/platform/vsp1/vsp1_entity.c | |||
@@ -22,6 +22,12 @@ | |||
22 | #include "vsp1_dl.h" | 22 | #include "vsp1_dl.h" |
23 | #include "vsp1_entity.h" | 23 | #include "vsp1_entity.h" |
24 | 24 | ||
25 | static inline struct vsp1_entity * | ||
26 | media_entity_to_vsp1_entity(struct media_entity *entity) | ||
27 | { | ||
28 | return container_of(entity, struct vsp1_entity, subdev.entity); | ||
29 | } | ||
30 | |||
25 | void vsp1_entity_route_setup(struct vsp1_entity *source, | 31 | void vsp1_entity_route_setup(struct vsp1_entity *source, |
26 | struct vsp1_dl_list *dl) | 32 | struct vsp1_dl_list *dl) |
27 | { | 33 | { |
@@ -30,7 +36,7 @@ void vsp1_entity_route_setup(struct vsp1_entity *source, | |||
30 | if (source->route->reg == 0) | 36 | if (source->route->reg == 0) |
31 | return; | 37 | return; |
32 | 38 | ||
33 | sink = container_of(source->sink, struct vsp1_entity, subdev.entity); | 39 | sink = media_entity_to_vsp1_entity(source->sink); |
34 | vsp1_dl_list_write(dl, source->route->reg, | 40 | vsp1_dl_list_write(dl, source->route->reg, |
35 | sink->route->inputs[source->sink_pad]); | 41 | sink->route->inputs[source->sink_pad]); |
36 | } | 42 | } |
@@ -81,12 +87,30 @@ vsp1_entity_get_pad_format(struct vsp1_entity *entity, | |||
81 | return v4l2_subdev_get_try_format(&entity->subdev, cfg, pad); | 87 | return v4l2_subdev_get_try_format(&entity->subdev, cfg, pad); |
82 | } | 88 | } |
83 | 89 | ||
90 | /** | ||
91 | * vsp1_entity_get_pad_selection - Get a pad selection from storage for entity | ||
92 | * @entity: the entity | ||
93 | * @cfg: the configuration storage | ||
94 | * @pad: the pad number | ||
95 | * @target: the selection target | ||
96 | * | ||
97 | * Return the selection rectangle stored in the given configuration for an | ||
98 | * entity's pad. The configuration can be an ACTIVE or TRY configuration. The | ||
99 | * selection target can be COMPOSE or CROP. | ||
100 | */ | ||
84 | struct v4l2_rect * | 101 | struct v4l2_rect * |
85 | vsp1_entity_get_pad_compose(struct vsp1_entity *entity, | 102 | vsp1_entity_get_pad_selection(struct vsp1_entity *entity, |
86 | struct v4l2_subdev_pad_config *cfg, | 103 | struct v4l2_subdev_pad_config *cfg, |
87 | unsigned int pad) | 104 | unsigned int pad, unsigned int target) |
88 | { | 105 | { |
89 | return v4l2_subdev_get_try_compose(&entity->subdev, cfg, pad); | 106 | switch (target) { |
107 | case V4L2_SEL_TGT_COMPOSE: | ||
108 | return v4l2_subdev_get_try_compose(&entity->subdev, cfg, pad); | ||
109 | case V4L2_SEL_TGT_CROP: | ||
110 | return v4l2_subdev_get_try_crop(&entity->subdev, cfg, pad); | ||
111 | default: | ||
112 | return NULL; | ||
113 | } | ||
90 | } | 114 | } |
91 | 115 | ||
92 | /* | 116 | /* |
@@ -252,7 +276,7 @@ int vsp1_entity_link_setup(struct media_entity *entity, | |||
252 | if (!(local->flags & MEDIA_PAD_FL_SOURCE)) | 276 | if (!(local->flags & MEDIA_PAD_FL_SOURCE)) |
253 | return 0; | 277 | return 0; |
254 | 278 | ||
255 | source = container_of(local->entity, struct vsp1_entity, subdev.entity); | 279 | source = media_entity_to_vsp1_entity(local->entity); |
256 | 280 | ||
257 | if (!source->route) | 281 | if (!source->route) |
258 | return 0; | 282 | return 0; |
@@ -274,33 +298,50 @@ int vsp1_entity_link_setup(struct media_entity *entity, | |||
274 | * Initialization | 298 | * Initialization |
275 | */ | 299 | */ |
276 | 300 | ||
301 | #define VSP1_ENTITY_ROUTE(ent) \ | ||
302 | { VSP1_ENTITY_##ent, 0, VI6_DPR_##ent##_ROUTE, \ | ||
303 | { VI6_DPR_NODE_##ent }, VI6_DPR_NODE_##ent } | ||
304 | |||
305 | #define VSP1_ENTITY_ROUTE_RPF(idx) \ | ||
306 | { VSP1_ENTITY_RPF, idx, VI6_DPR_RPF_ROUTE(idx), \ | ||
307 | { 0, }, VI6_DPR_NODE_RPF(idx) } | ||
308 | |||
309 | #define VSP1_ENTITY_ROUTE_UDS(idx) \ | ||
310 | { VSP1_ENTITY_UDS, idx, VI6_DPR_UDS_ROUTE(idx), \ | ||
311 | { VI6_DPR_NODE_UDS(idx) }, VI6_DPR_NODE_UDS(idx) } | ||
312 | |||
313 | #define VSP1_ENTITY_ROUTE_WPF(idx) \ | ||
314 | { VSP1_ENTITY_WPF, idx, 0, \ | ||
315 | { VI6_DPR_NODE_WPF(idx) }, VI6_DPR_NODE_WPF(idx) } | ||
316 | |||
277 | static const struct vsp1_route vsp1_routes[] = { | 317 | static const struct vsp1_route vsp1_routes[] = { |
278 | { VSP1_ENTITY_BRU, 0, VI6_DPR_BRU_ROUTE, | 318 | { VSP1_ENTITY_BRU, 0, VI6_DPR_BRU_ROUTE, |
279 | { VI6_DPR_NODE_BRU_IN(0), VI6_DPR_NODE_BRU_IN(1), | 319 | { VI6_DPR_NODE_BRU_IN(0), VI6_DPR_NODE_BRU_IN(1), |
280 | VI6_DPR_NODE_BRU_IN(2), VI6_DPR_NODE_BRU_IN(3), | 320 | VI6_DPR_NODE_BRU_IN(2), VI6_DPR_NODE_BRU_IN(3), |
281 | VI6_DPR_NODE_BRU_IN(4) } }, | 321 | VI6_DPR_NODE_BRU_IN(4) }, VI6_DPR_NODE_BRU_OUT }, |
282 | { VSP1_ENTITY_HSI, 0, VI6_DPR_HSI_ROUTE, { VI6_DPR_NODE_HSI, } }, | 322 | VSP1_ENTITY_ROUTE(CLU), |
283 | { VSP1_ENTITY_HST, 0, VI6_DPR_HST_ROUTE, { VI6_DPR_NODE_HST, } }, | 323 | VSP1_ENTITY_ROUTE(HSI), |
284 | { VSP1_ENTITY_LIF, 0, 0, { VI6_DPR_NODE_LIF, } }, | 324 | VSP1_ENTITY_ROUTE(HST), |
285 | { VSP1_ENTITY_LUT, 0, VI6_DPR_LUT_ROUTE, { VI6_DPR_NODE_LUT, } }, | 325 | { VSP1_ENTITY_LIF, 0, 0, { VI6_DPR_NODE_LIF, }, VI6_DPR_NODE_LIF }, |
286 | { VSP1_ENTITY_RPF, 0, VI6_DPR_RPF_ROUTE(0), { 0, } }, | 326 | VSP1_ENTITY_ROUTE(LUT), |
287 | { VSP1_ENTITY_RPF, 1, VI6_DPR_RPF_ROUTE(1), { 0, } }, | 327 | VSP1_ENTITY_ROUTE_RPF(0), |
288 | { VSP1_ENTITY_RPF, 2, VI6_DPR_RPF_ROUTE(2), { 0, } }, | 328 | VSP1_ENTITY_ROUTE_RPF(1), |
289 | { VSP1_ENTITY_RPF, 3, VI6_DPR_RPF_ROUTE(3), { 0, } }, | 329 | VSP1_ENTITY_ROUTE_RPF(2), |
290 | { VSP1_ENTITY_RPF, 4, VI6_DPR_RPF_ROUTE(4), { 0, } }, | 330 | VSP1_ENTITY_ROUTE_RPF(3), |
291 | { VSP1_ENTITY_SRU, 0, VI6_DPR_SRU_ROUTE, { VI6_DPR_NODE_SRU, } }, | 331 | VSP1_ENTITY_ROUTE_RPF(4), |
292 | { VSP1_ENTITY_UDS, 0, VI6_DPR_UDS_ROUTE(0), { VI6_DPR_NODE_UDS(0), } }, | 332 | VSP1_ENTITY_ROUTE(SRU), |
293 | { VSP1_ENTITY_UDS, 1, VI6_DPR_UDS_ROUTE(1), { VI6_DPR_NODE_UDS(1), } }, | 333 | VSP1_ENTITY_ROUTE_UDS(0), |
294 | { VSP1_ENTITY_UDS, 2, VI6_DPR_UDS_ROUTE(2), { VI6_DPR_NODE_UDS(2), } }, | 334 | VSP1_ENTITY_ROUTE_UDS(1), |
295 | { VSP1_ENTITY_WPF, 0, 0, { VI6_DPR_NODE_WPF(0), } }, | 335 | VSP1_ENTITY_ROUTE_UDS(2), |
296 | { VSP1_ENTITY_WPF, 1, 0, { VI6_DPR_NODE_WPF(1), } }, | 336 | VSP1_ENTITY_ROUTE_WPF(0), |
297 | { VSP1_ENTITY_WPF, 2, 0, { VI6_DPR_NODE_WPF(2), } }, | 337 | VSP1_ENTITY_ROUTE_WPF(1), |
298 | { VSP1_ENTITY_WPF, 3, 0, { VI6_DPR_NODE_WPF(3), } }, | 338 | VSP1_ENTITY_ROUTE_WPF(2), |
339 | VSP1_ENTITY_ROUTE_WPF(3), | ||
299 | }; | 340 | }; |
300 | 341 | ||
301 | int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, | 342 | int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, |
302 | const char *name, unsigned int num_pads, | 343 | const char *name, unsigned int num_pads, |
303 | const struct v4l2_subdev_ops *ops) | 344 | const struct v4l2_subdev_ops *ops, u32 function) |
304 | { | 345 | { |
305 | struct v4l2_subdev *subdev; | 346 | struct v4l2_subdev *subdev; |
306 | unsigned int i; | 347 | unsigned int i; |
@@ -341,6 +382,7 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, | |||
341 | subdev = &entity->subdev; | 382 | subdev = &entity->subdev; |
342 | v4l2_subdev_init(subdev, ops); | 383 | v4l2_subdev_init(subdev, ops); |
343 | 384 | ||
385 | subdev->entity.function = function; | ||
344 | subdev->entity.ops = &vsp1->media_ops; | 386 | subdev->entity.ops = &vsp1->media_ops; |
345 | subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | 387 | subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; |
346 | 388 | ||
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h index 69eff4e17350..b43457fd2c43 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.h +++ b/drivers/media/platform/vsp1/vsp1_entity.h | |||
@@ -24,6 +24,7 @@ struct vsp1_pipeline; | |||
24 | 24 | ||
25 | enum vsp1_entity_type { | 25 | enum vsp1_entity_type { |
26 | VSP1_ENTITY_BRU, | 26 | VSP1_ENTITY_BRU, |
27 | VSP1_ENTITY_CLU, | ||
27 | VSP1_ENTITY_HSI, | 28 | VSP1_ENTITY_HSI, |
28 | VSP1_ENTITY_HST, | 29 | VSP1_ENTITY_HST, |
29 | VSP1_ENTITY_LIF, | 30 | VSP1_ENTITY_LIF, |
@@ -42,17 +43,21 @@ enum vsp1_entity_type { | |||
42 | * @index: Entity index this routing entry is associated with | 43 | * @index: Entity index this routing entry is associated with |
43 | * @reg: Output routing configuration register | 44 | * @reg: Output routing configuration register |
44 | * @inputs: Target node value for each input | 45 | * @inputs: Target node value for each input |
46 | * @output: Target node value for entity output | ||
45 | * | 47 | * |
46 | * Each $vsp1_route entry describes routing configuration for the entity | 48 | * Each $vsp1_route entry describes routing configuration for the entity |
47 | * specified by the entry's @type and @index. @reg indicates the register that | 49 | * specified by the entry's @type and @index. @reg indicates the register that |
48 | * holds output routing configuration for the entity, and the @inputs array | 50 | * holds output routing configuration for the entity, and the @inputs array |
49 | * store the target node value for each input of the entity. | 51 | * store the target node value for each input of the entity. The @output field |
52 | * stores the target node value of the entity output when used as a source for | ||
53 | * histogram generation. | ||
50 | */ | 54 | */ |
51 | struct vsp1_route { | 55 | struct vsp1_route { |
52 | enum vsp1_entity_type type; | 56 | enum vsp1_entity_type type; |
53 | unsigned int index; | 57 | unsigned int index; |
54 | unsigned int reg; | 58 | unsigned int reg; |
55 | unsigned int inputs[VSP1_ENTITY_MAX_INPUTS]; | 59 | unsigned int inputs[VSP1_ENTITY_MAX_INPUTS]; |
60 | unsigned int output; | ||
56 | }; | 61 | }; |
57 | 62 | ||
58 | /** | 63 | /** |
@@ -68,7 +73,7 @@ struct vsp1_entity_operations { | |||
68 | void (*destroy)(struct vsp1_entity *); | 73 | void (*destroy)(struct vsp1_entity *); |
69 | void (*set_memory)(struct vsp1_entity *, struct vsp1_dl_list *dl); | 74 | void (*set_memory)(struct vsp1_entity *, struct vsp1_dl_list *dl); |
70 | void (*configure)(struct vsp1_entity *, struct vsp1_pipeline *, | 75 | void (*configure)(struct vsp1_entity *, struct vsp1_pipeline *, |
71 | struct vsp1_dl_list *); | 76 | struct vsp1_dl_list *, bool); |
72 | }; | 77 | }; |
73 | 78 | ||
74 | struct vsp1_entity { | 79 | struct vsp1_entity { |
@@ -100,7 +105,7 @@ static inline struct vsp1_entity *to_vsp1_entity(struct v4l2_subdev *subdev) | |||
100 | 105 | ||
101 | int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, | 106 | int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, |
102 | const char *name, unsigned int num_pads, | 107 | const char *name, unsigned int num_pads, |
103 | const struct v4l2_subdev_ops *ops); | 108 | const struct v4l2_subdev_ops *ops, u32 function); |
104 | void vsp1_entity_destroy(struct vsp1_entity *entity); | 109 | void vsp1_entity_destroy(struct vsp1_entity *entity); |
105 | 110 | ||
106 | extern const struct v4l2_subdev_internal_ops vsp1_subdev_internal_ops; | 111 | extern const struct v4l2_subdev_internal_ops vsp1_subdev_internal_ops; |
@@ -118,9 +123,9 @@ vsp1_entity_get_pad_format(struct vsp1_entity *entity, | |||
118 | struct v4l2_subdev_pad_config *cfg, | 123 | struct v4l2_subdev_pad_config *cfg, |
119 | unsigned int pad); | 124 | unsigned int pad); |
120 | struct v4l2_rect * | 125 | struct v4l2_rect * |
121 | vsp1_entity_get_pad_compose(struct vsp1_entity *entity, | 126 | vsp1_entity_get_pad_selection(struct vsp1_entity *entity, |
122 | struct v4l2_subdev_pad_config *cfg, | 127 | struct v4l2_subdev_pad_config *cfg, |
123 | unsigned int pad); | 128 | unsigned int pad, unsigned int target); |
124 | int vsp1_entity_init_cfg(struct v4l2_subdev *subdev, | 129 | int vsp1_entity_init_cfg(struct v4l2_subdev *subdev, |
125 | struct v4l2_subdev_pad_config *cfg); | 130 | struct v4l2_subdev_pad_config *cfg); |
126 | 131 | ||
diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c index 68b8567b374d..6e5077beb38c 100644 --- a/drivers/media/platform/vsp1/vsp1_hsit.c +++ b/drivers/media/platform/vsp1/vsp1_hsit.c | |||
@@ -107,7 +107,7 @@ static int hsit_set_format(struct v4l2_subdev *subdev, | |||
107 | return 0; | 107 | return 0; |
108 | } | 108 | } |
109 | 109 | ||
110 | static struct v4l2_subdev_pad_ops hsit_pad_ops = { | 110 | static const struct v4l2_subdev_pad_ops hsit_pad_ops = { |
111 | .init_cfg = vsp1_entity_init_cfg, | 111 | .init_cfg = vsp1_entity_init_cfg, |
112 | .enum_mbus_code = hsit_enum_mbus_code, | 112 | .enum_mbus_code = hsit_enum_mbus_code, |
113 | .enum_frame_size = hsit_enum_frame_size, | 113 | .enum_frame_size = hsit_enum_frame_size, |
@@ -115,7 +115,7 @@ static struct v4l2_subdev_pad_ops hsit_pad_ops = { | |||
115 | .set_fmt = hsit_set_format, | 115 | .set_fmt = hsit_set_format, |
116 | }; | 116 | }; |
117 | 117 | ||
118 | static struct v4l2_subdev_ops hsit_ops = { | 118 | static const struct v4l2_subdev_ops hsit_ops = { |
119 | .pad = &hsit_pad_ops, | 119 | .pad = &hsit_pad_ops, |
120 | }; | 120 | }; |
121 | 121 | ||
@@ -125,10 +125,13 @@ static struct v4l2_subdev_ops hsit_ops = { | |||
125 | 125 | ||
126 | static void hsit_configure(struct vsp1_entity *entity, | 126 | static void hsit_configure(struct vsp1_entity *entity, |
127 | struct vsp1_pipeline *pipe, | 127 | struct vsp1_pipeline *pipe, |
128 | struct vsp1_dl_list *dl) | 128 | struct vsp1_dl_list *dl, bool full) |
129 | { | 129 | { |
130 | struct vsp1_hsit *hsit = to_hsit(&entity->subdev); | 130 | struct vsp1_hsit *hsit = to_hsit(&entity->subdev); |
131 | 131 | ||
132 | if (!full) | ||
133 | return; | ||
134 | |||
132 | if (hsit->inverse) | 135 | if (hsit->inverse) |
133 | vsp1_hsit_write(hsit, dl, VI6_HSI_CTRL, VI6_HSI_CTRL_EN); | 136 | vsp1_hsit_write(hsit, dl, VI6_HSI_CTRL, VI6_HSI_CTRL_EN); |
134 | else | 137 | else |
@@ -161,8 +164,9 @@ struct vsp1_hsit *vsp1_hsit_create(struct vsp1_device *vsp1, bool inverse) | |||
161 | else | 164 | else |
162 | hsit->entity.type = VSP1_ENTITY_HST; | 165 | hsit->entity.type = VSP1_ENTITY_HST; |
163 | 166 | ||
164 | ret = vsp1_entity_init(vsp1, &hsit->entity, inverse ? "hsi" : "hst", 2, | 167 | ret = vsp1_entity_init(vsp1, &hsit->entity, inverse ? "hsi" : "hst", |
165 | &hsit_ops); | 168 | 2, &hsit_ops, |
169 | MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV); | ||
166 | if (ret < 0) | 170 | if (ret < 0) |
167 | return ERR_PTR(ret); | 171 | return ERR_PTR(ret); |
168 | 172 | ||
diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c index 0217393f22df..a720063f38c5 100644 --- a/drivers/media/platform/vsp1/vsp1_lif.c +++ b/drivers/media/platform/vsp1/vsp1_lif.c | |||
@@ -104,7 +104,7 @@ static int lif_set_format(struct v4l2_subdev *subdev, | |||
104 | return 0; | 104 | return 0; |
105 | } | 105 | } |
106 | 106 | ||
107 | static struct v4l2_subdev_pad_ops lif_pad_ops = { | 107 | static const struct v4l2_subdev_pad_ops lif_pad_ops = { |
108 | .init_cfg = vsp1_entity_init_cfg, | 108 | .init_cfg = vsp1_entity_init_cfg, |
109 | .enum_mbus_code = lif_enum_mbus_code, | 109 | .enum_mbus_code = lif_enum_mbus_code, |
110 | .enum_frame_size = lif_enum_frame_size, | 110 | .enum_frame_size = lif_enum_frame_size, |
@@ -112,7 +112,7 @@ static struct v4l2_subdev_pad_ops lif_pad_ops = { | |||
112 | .set_fmt = lif_set_format, | 112 | .set_fmt = lif_set_format, |
113 | }; | 113 | }; |
114 | 114 | ||
115 | static struct v4l2_subdev_ops lif_ops = { | 115 | static const struct v4l2_subdev_ops lif_ops = { |
116 | .pad = &lif_pad_ops, | 116 | .pad = &lif_pad_ops, |
117 | }; | 117 | }; |
118 | 118 | ||
@@ -122,7 +122,7 @@ static struct v4l2_subdev_ops lif_ops = { | |||
122 | 122 | ||
123 | static void lif_configure(struct vsp1_entity *entity, | 123 | static void lif_configure(struct vsp1_entity *entity, |
124 | struct vsp1_pipeline *pipe, | 124 | struct vsp1_pipeline *pipe, |
125 | struct vsp1_dl_list *dl) | 125 | struct vsp1_dl_list *dl, bool full) |
126 | { | 126 | { |
127 | const struct v4l2_mbus_framefmt *format; | 127 | const struct v4l2_mbus_framefmt *format; |
128 | struct vsp1_lif *lif = to_lif(&entity->subdev); | 128 | struct vsp1_lif *lif = to_lif(&entity->subdev); |
@@ -130,6 +130,9 @@ static void lif_configure(struct vsp1_entity *entity, | |||
130 | unsigned int obth = 400; | 130 | unsigned int obth = 400; |
131 | unsigned int lbth = 200; | 131 | unsigned int lbth = 200; |
132 | 132 | ||
133 | if (!full) | ||
134 | return; | ||
135 | |||
133 | format = vsp1_entity_get_pad_format(&lif->entity, lif->entity.config, | 136 | format = vsp1_entity_get_pad_format(&lif->entity, lif->entity.config, |
134 | LIF_PAD_SOURCE); | 137 | LIF_PAD_SOURCE); |
135 | 138 | ||
@@ -165,7 +168,12 @@ struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1) | |||
165 | lif->entity.ops = &lif_entity_ops; | 168 | lif->entity.ops = &lif_entity_ops; |
166 | lif->entity.type = VSP1_ENTITY_LIF; | 169 | lif->entity.type = VSP1_ENTITY_LIF; |
167 | 170 | ||
168 | ret = vsp1_entity_init(vsp1, &lif->entity, "lif", 2, &lif_ops); | 171 | /* The LIF is never exposed to userspace, but media entity registration |
172 | * requires a function to be set. Use PROC_VIDEO_PIXEL_FORMATTER just to | ||
173 | * avoid triggering a WARN_ON(), the value won't be seen anywhere. | ||
174 | */ | ||
175 | ret = vsp1_entity_init(vsp1, &lif->entity, "lif", 2, &lif_ops, | ||
176 | MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER); | ||
169 | if (ret < 0) | 177 | if (ret < 0) |
170 | return ERR_PTR(ret); | 178 | return ERR_PTR(ret); |
171 | 179 | ||
diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c index aa09e59f0ab8..dc31de9602ba 100644 --- a/drivers/media/platform/vsp1/vsp1_lut.c +++ b/drivers/media/platform/vsp1/vsp1_lut.c | |||
@@ -13,7 +13,6 @@ | |||
13 | 13 | ||
14 | #include <linux/device.h> | 14 | #include <linux/device.h> |
15 | #include <linux/gfp.h> | 15 | #include <linux/gfp.h> |
16 | #include <linux/vsp1.h> | ||
17 | 16 | ||
18 | #include <media/v4l2-subdev.h> | 17 | #include <media/v4l2-subdev.h> |
19 | 18 | ||
@@ -35,43 +34,62 @@ static inline void vsp1_lut_write(struct vsp1_lut *lut, struct vsp1_dl_list *dl, | |||
35 | } | 34 | } |
36 | 35 | ||
37 | /* ----------------------------------------------------------------------------- | 36 | /* ----------------------------------------------------------------------------- |
38 | * V4L2 Subdevice Core Operations | 37 | * Controls |
39 | */ | 38 | */ |
40 | 39 | ||
41 | static int lut_set_table(struct vsp1_lut *lut, struct vsp1_lut_config *config) | 40 | #define V4L2_CID_VSP1_LUT_TABLE (V4L2_CID_USER_BASE | 0x1001) |
41 | |||
42 | static int lut_set_table(struct vsp1_lut *lut, struct v4l2_ctrl *ctrl) | ||
42 | { | 43 | { |
43 | struct vsp1_dl_body *dlb; | 44 | struct vsp1_dl_body *dlb; |
44 | unsigned int i; | 45 | unsigned int i; |
45 | 46 | ||
46 | dlb = vsp1_dl_fragment_alloc(lut->entity.vsp1, ARRAY_SIZE(config->lut)); | 47 | dlb = vsp1_dl_fragment_alloc(lut->entity.vsp1, 256); |
47 | if (!dlb) | 48 | if (!dlb) |
48 | return -ENOMEM; | 49 | return -ENOMEM; |
49 | 50 | ||
50 | for (i = 0; i < ARRAY_SIZE(config->lut); ++i) | 51 | for (i = 0; i < 256; ++i) |
51 | vsp1_dl_fragment_write(dlb, VI6_LUT_TABLE + 4 * i, | 52 | vsp1_dl_fragment_write(dlb, VI6_LUT_TABLE + 4 * i, |
52 | config->lut[i]); | 53 | ctrl->p_new.p_u32[i]); |
53 | 54 | ||
54 | mutex_lock(&lut->lock); | 55 | spin_lock_irq(&lut->lock); |
55 | swap(lut->lut, dlb); | 56 | swap(lut->lut, dlb); |
56 | mutex_unlock(&lut->lock); | 57 | spin_unlock_irq(&lut->lock); |
57 | 58 | ||
58 | vsp1_dl_fragment_free(dlb); | 59 | vsp1_dl_fragment_free(dlb); |
59 | return 0; | 60 | return 0; |
60 | } | 61 | } |
61 | 62 | ||
62 | static long lut_ioctl(struct v4l2_subdev *subdev, unsigned int cmd, void *arg) | 63 | static int lut_s_ctrl(struct v4l2_ctrl *ctrl) |
63 | { | 64 | { |
64 | struct vsp1_lut *lut = to_lut(subdev); | 65 | struct vsp1_lut *lut = |
65 | 66 | container_of(ctrl->handler, struct vsp1_lut, ctrls); | |
66 | switch (cmd) { | ||
67 | case VIDIOC_VSP1_LUT_CONFIG: | ||
68 | return lut_set_table(lut, arg); | ||
69 | 67 | ||
70 | default: | 68 | switch (ctrl->id) { |
71 | return -ENOIOCTLCMD; | 69 | case V4L2_CID_VSP1_LUT_TABLE: |
70 | lut_set_table(lut, ctrl); | ||
71 | break; | ||
72 | } | 72 | } |
73 | |||
74 | return 0; | ||
73 | } | 75 | } |
74 | 76 | ||
77 | static const struct v4l2_ctrl_ops lut_ctrl_ops = { | ||
78 | .s_ctrl = lut_s_ctrl, | ||
79 | }; | ||
80 | |||
81 | static const struct v4l2_ctrl_config lut_table_control = { | ||
82 | .ops = &lut_ctrl_ops, | ||
83 | .id = V4L2_CID_VSP1_LUT_TABLE, | ||
84 | .name = "Look-Up Table", | ||
85 | .type = V4L2_CTRL_TYPE_U32, | ||
86 | .min = 0x00000000, | ||
87 | .max = 0x00ffffff, | ||
88 | .step = 1, | ||
89 | .def = 0, | ||
90 | .dims = { 256}, | ||
91 | }; | ||
92 | |||
75 | /* ----------------------------------------------------------------------------- | 93 | /* ----------------------------------------------------------------------------- |
76 | * V4L2 Subdevice Pad Operations | 94 | * V4L2 Subdevice Pad Operations |
77 | */ | 95 | */ |
@@ -147,11 +165,7 @@ static int lut_set_format(struct v4l2_subdev *subdev, | |||
147 | * V4L2 Subdevice Operations | 165 | * V4L2 Subdevice Operations |
148 | */ | 166 | */ |
149 | 167 | ||
150 | static struct v4l2_subdev_core_ops lut_core_ops = { | 168 | static const struct v4l2_subdev_pad_ops lut_pad_ops = { |
151 | .ioctl = lut_ioctl, | ||
152 | }; | ||
153 | |||
154 | static struct v4l2_subdev_pad_ops lut_pad_ops = { | ||
155 | .init_cfg = vsp1_entity_init_cfg, | 169 | .init_cfg = vsp1_entity_init_cfg, |
156 | .enum_mbus_code = lut_enum_mbus_code, | 170 | .enum_mbus_code = lut_enum_mbus_code, |
157 | .enum_frame_size = lut_enum_frame_size, | 171 | .enum_frame_size = lut_enum_frame_size, |
@@ -159,8 +173,7 @@ static struct v4l2_subdev_pad_ops lut_pad_ops = { | |||
159 | .set_fmt = lut_set_format, | 173 | .set_fmt = lut_set_format, |
160 | }; | 174 | }; |
161 | 175 | ||
162 | static struct v4l2_subdev_ops lut_ops = { | 176 | static const struct v4l2_subdev_ops lut_ops = { |
163 | .core = &lut_core_ops, | ||
164 | .pad = &lut_pad_ops, | 177 | .pad = &lut_pad_ops, |
165 | }; | 178 | }; |
166 | 179 | ||
@@ -170,18 +183,24 @@ static struct v4l2_subdev_ops lut_ops = { | |||
170 | 183 | ||
171 | static void lut_configure(struct vsp1_entity *entity, | 184 | static void lut_configure(struct vsp1_entity *entity, |
172 | struct vsp1_pipeline *pipe, | 185 | struct vsp1_pipeline *pipe, |
173 | struct vsp1_dl_list *dl) | 186 | struct vsp1_dl_list *dl, bool full) |
174 | { | 187 | { |
175 | struct vsp1_lut *lut = to_lut(&entity->subdev); | 188 | struct vsp1_lut *lut = to_lut(&entity->subdev); |
189 | struct vsp1_dl_body *dlb; | ||
190 | unsigned long flags; | ||
176 | 191 | ||
177 | vsp1_lut_write(lut, dl, VI6_LUT_CTRL, VI6_LUT_CTRL_EN); | 192 | if (full) { |
178 | 193 | vsp1_lut_write(lut, dl, VI6_LUT_CTRL, VI6_LUT_CTRL_EN); | |
179 | mutex_lock(&lut->lock); | 194 | return; |
180 | if (lut->lut) { | ||
181 | vsp1_dl_list_add_fragment(dl, lut->lut); | ||
182 | lut->lut = NULL; | ||
183 | } | 195 | } |
184 | mutex_unlock(&lut->lock); | 196 | |
197 | spin_lock_irqsave(&lut->lock, flags); | ||
198 | dlb = lut->lut; | ||
199 | lut->lut = NULL; | ||
200 | spin_unlock_irqrestore(&lut->lock, flags); | ||
201 | |||
202 | if (dlb) | ||
203 | vsp1_dl_list_add_fragment(dl, dlb); | ||
185 | } | 204 | } |
186 | 205 | ||
187 | static const struct vsp1_entity_operations lut_entity_ops = { | 206 | static const struct vsp1_entity_operations lut_entity_ops = { |
@@ -201,12 +220,30 @@ struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1) | |||
201 | if (lut == NULL) | 220 | if (lut == NULL) |
202 | return ERR_PTR(-ENOMEM); | 221 | return ERR_PTR(-ENOMEM); |
203 | 222 | ||
223 | spin_lock_init(&lut->lock); | ||
224 | |||
204 | lut->entity.ops = &lut_entity_ops; | 225 | lut->entity.ops = &lut_entity_ops; |
205 | lut->entity.type = VSP1_ENTITY_LUT; | 226 | lut->entity.type = VSP1_ENTITY_LUT; |
206 | 227 | ||
207 | ret = vsp1_entity_init(vsp1, &lut->entity, "lut", 2, &lut_ops); | 228 | ret = vsp1_entity_init(vsp1, &lut->entity, "lut", 2, &lut_ops, |
229 | MEDIA_ENT_F_PROC_VIDEO_LUT); | ||
208 | if (ret < 0) | 230 | if (ret < 0) |
209 | return ERR_PTR(ret); | 231 | return ERR_PTR(ret); |
210 | 232 | ||
233 | /* Initialize the control handler. */ | ||
234 | v4l2_ctrl_handler_init(&lut->ctrls, 1); | ||
235 | v4l2_ctrl_new_custom(&lut->ctrls, &lut_table_control, NULL); | ||
236 | |||
237 | lut->entity.subdev.ctrl_handler = &lut->ctrls; | ||
238 | |||
239 | if (lut->ctrls.error) { | ||
240 | dev_err(vsp1->dev, "lut: failed to initialize controls\n"); | ||
241 | ret = lut->ctrls.error; | ||
242 | vsp1_entity_destroy(&lut->entity); | ||
243 | return ERR_PTR(ret); | ||
244 | } | ||
245 | |||
246 | v4l2_ctrl_handler_setup(&lut->ctrls); | ||
247 | |||
211 | return lut; | 248 | return lut; |
212 | } | 249 | } |
diff --git a/drivers/media/platform/vsp1/vsp1_lut.h b/drivers/media/platform/vsp1/vsp1_lut.h index cef874f22b6a..f8c4e8f0a79d 100644 --- a/drivers/media/platform/vsp1/vsp1_lut.h +++ b/drivers/media/platform/vsp1/vsp1_lut.h | |||
@@ -13,9 +13,10 @@ | |||
13 | #ifndef __VSP1_LUT_H__ | 13 | #ifndef __VSP1_LUT_H__ |
14 | #define __VSP1_LUT_H__ | 14 | #define __VSP1_LUT_H__ |
15 | 15 | ||
16 | #include <linux/mutex.h> | 16 | #include <linux/spinlock.h> |
17 | 17 | ||
18 | #include <media/media-entity.h> | 18 | #include <media/media-entity.h> |
19 | #include <media/v4l2-ctrls.h> | ||
19 | #include <media/v4l2-subdev.h> | 20 | #include <media/v4l2-subdev.h> |
20 | 21 | ||
21 | #include "vsp1_entity.h" | 22 | #include "vsp1_entity.h" |
@@ -28,7 +29,9 @@ struct vsp1_device; | |||
28 | struct vsp1_lut { | 29 | struct vsp1_lut { |
29 | struct vsp1_entity entity; | 30 | struct vsp1_entity entity; |
30 | 31 | ||
31 | struct mutex lock; | 32 | struct v4l2_ctrl_handler ctrls; |
33 | |||
34 | spinlock_t lock; | ||
32 | struct vsp1_dl_body *lut; | 35 | struct vsp1_dl_body *lut; |
33 | }; | 36 | }; |
34 | 37 | ||
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c index 4f3b4a1d028a..3e75fb3fcace 100644 --- a/drivers/media/platform/vsp1/vsp1_pipe.c +++ b/drivers/media/platform/vsp1/vsp1_pipe.c | |||
@@ -172,13 +172,17 @@ void vsp1_pipeline_reset(struct vsp1_pipeline *pipe) | |||
172 | bru->inputs[i].rpf = NULL; | 172 | bru->inputs[i].rpf = NULL; |
173 | } | 173 | } |
174 | 174 | ||
175 | for (i = 0; i < pipe->num_inputs; ++i) { | 175 | for (i = 0; i < ARRAY_SIZE(pipe->inputs); ++i) { |
176 | pipe->inputs[i]->pipe = NULL; | 176 | if (pipe->inputs[i]) { |
177 | pipe->inputs[i] = NULL; | 177 | pipe->inputs[i]->pipe = NULL; |
178 | pipe->inputs[i] = NULL; | ||
179 | } | ||
178 | } | 180 | } |
179 | 181 | ||
180 | pipe->output->pipe = NULL; | 182 | if (pipe->output) { |
181 | pipe->output = NULL; | 183 | pipe->output->pipe = NULL; |
184 | pipe->output = NULL; | ||
185 | } | ||
182 | 186 | ||
183 | INIT_LIST_HEAD(&pipe->entities); | 187 | INIT_LIST_HEAD(&pipe->entities); |
184 | pipe->state = VSP1_PIPELINE_STOPPED; | 188 | pipe->state = VSP1_PIPELINE_STOPPED; |
@@ -286,6 +290,8 @@ void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe) | |||
286 | 290 | ||
287 | if (pipe->frame_end) | 291 | if (pipe->frame_end) |
288 | pipe->frame_end(pipe); | 292 | pipe->frame_end(pipe); |
293 | |||
294 | pipe->sequence++; | ||
289 | } | 295 | } |
290 | 296 | ||
291 | /* | 297 | /* |
@@ -295,42 +301,20 @@ void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe) | |||
295 | * to be scaled, we disable alpha scaling when the UDS input has a fixed alpha | 301 | * to be scaled, we disable alpha scaling when the UDS input has a fixed alpha |
296 | * value. The UDS then outputs a fixed alpha value which needs to be programmed | 302 | * value. The UDS then outputs a fixed alpha value which needs to be programmed |
297 | * from the input RPF alpha. | 303 | * from the input RPF alpha. |
298 | * | ||
299 | * This function can only be called from a subdev s_stream handler as it | ||
300 | * requires a valid display list context. | ||
301 | */ | 304 | */ |
302 | void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, | 305 | void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, |
303 | struct vsp1_entity *input, | 306 | struct vsp1_dl_list *dl, unsigned int alpha) |
304 | struct vsp1_dl_list *dl, | ||
305 | unsigned int alpha) | ||
306 | { | 307 | { |
307 | struct vsp1_entity *entity; | 308 | if (!pipe->uds) |
308 | struct media_pad *pad; | 309 | return; |
309 | |||
310 | pad = media_entity_remote_pad(&input->pads[RWPF_PAD_SOURCE]); | ||
311 | |||
312 | while (pad) { | ||
313 | if (!is_media_entity_v4l2_subdev(pad->entity)) | ||
314 | break; | ||
315 | |||
316 | entity = to_vsp1_entity(media_entity_to_v4l2_subdev(pad->entity)); | ||
317 | |||
318 | /* The BRU background color has a fixed alpha value set to 255, | ||
319 | * the output alpha value is thus always equal to 255. | ||
320 | */ | ||
321 | if (entity->type == VSP1_ENTITY_BRU) | ||
322 | alpha = 255; | ||
323 | |||
324 | if (entity->type == VSP1_ENTITY_UDS) { | ||
325 | struct vsp1_uds *uds = to_uds(&entity->subdev); | ||
326 | 310 | ||
327 | vsp1_uds_set_alpha(uds, dl, alpha); | 311 | /* The BRU background color has a fixed alpha value set to 255, the |
328 | break; | 312 | * output alpha value is thus always equal to 255. |
329 | } | 313 | */ |
314 | if (pipe->uds_input->type == VSP1_ENTITY_BRU) | ||
315 | alpha = 255; | ||
330 | 316 | ||
331 | pad = &entity->pads[entity->source_pad]; | 317 | vsp1_uds_set_alpha(pipe->uds, dl, alpha); |
332 | pad = media_entity_remote_pad(pad); | ||
333 | } | ||
334 | } | 318 | } |
335 | 319 | ||
336 | void vsp1_pipelines_suspend(struct vsp1_device *vsp1) | 320 | void vsp1_pipelines_suspend(struct vsp1_device *vsp1) |
@@ -383,7 +367,7 @@ void vsp1_pipelines_resume(struct vsp1_device *vsp1) | |||
383 | { | 367 | { |
384 | unsigned int i; | 368 | unsigned int i; |
385 | 369 | ||
386 | /* Resume pipeline all running pipelines. */ | 370 | /* Resume all running pipelines. */ |
387 | for (i = 0; i < vsp1->info->wpf_count; ++i) { | 371 | for (i = 0; i < vsp1->info->wpf_count; ++i) { |
388 | struct vsp1_rwpf *wpf = vsp1->wpf[i]; | 372 | struct vsp1_rwpf *wpf = vsp1->wpf[i]; |
389 | struct vsp1_pipeline *pipe; | 373 | struct vsp1_pipeline *pipe; |
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h b/drivers/media/platform/vsp1/vsp1_pipe.h index 7b56113511dd..d20d997b1fda 100644 --- a/drivers/media/platform/vsp1/vsp1_pipe.h +++ b/drivers/media/platform/vsp1/vsp1_pipe.h | |||
@@ -61,12 +61,13 @@ enum vsp1_pipeline_state { | |||
61 | * @pipe: the media pipeline | 61 | * @pipe: the media pipeline |
62 | * @irqlock: protects the pipeline state | 62 | * @irqlock: protects the pipeline state |
63 | * @state: current state | 63 | * @state: current state |
64 | * @wq: work queue to wait for state change completion | 64 | * @wq: wait queue to wait for state change completion |
65 | * @frame_end: frame end interrupt handler | 65 | * @frame_end: frame end interrupt handler |
66 | * @lock: protects the pipeline use count and stream count | 66 | * @lock: protects the pipeline use count and stream count |
67 | * @kref: pipeline reference count | 67 | * @kref: pipeline reference count |
68 | * @stream_count: number of streaming video nodes | 68 | * @stream_count: number of streaming video nodes |
69 | * @buffers_ready: bitmask of RPFs and WPFs with at least one buffer available | 69 | * @buffers_ready: bitmask of RPFs and WPFs with at least one buffer available |
70 | * @sequence: frame sequence number | ||
70 | * @num_inputs: number of RPFs | 71 | * @num_inputs: number of RPFs |
71 | * @inputs: array of RPFs in the pipeline (indexed by RPF index) | 72 | * @inputs: array of RPFs in the pipeline (indexed by RPF index) |
72 | * @output: WPF at the output of the pipeline | 73 | * @output: WPF at the output of the pipeline |
@@ -90,6 +91,7 @@ struct vsp1_pipeline { | |||
90 | struct kref kref; | 91 | struct kref kref; |
91 | unsigned int stream_count; | 92 | unsigned int stream_count; |
92 | unsigned int buffers_ready; | 93 | unsigned int buffers_ready; |
94 | unsigned int sequence; | ||
93 | 95 | ||
94 | unsigned int num_inputs; | 96 | unsigned int num_inputs; |
95 | struct vsp1_rwpf *inputs[VSP1_MAX_RPF]; | 97 | struct vsp1_rwpf *inputs[VSP1_MAX_RPF]; |
@@ -115,9 +117,7 @@ bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe); | |||
115 | void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe); | 117 | void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe); |
116 | 118 | ||
117 | void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, | 119 | void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, |
118 | struct vsp1_entity *input, | 120 | struct vsp1_dl_list *dl, unsigned int alpha); |
119 | struct vsp1_dl_list *dl, | ||
120 | unsigned int alpha); | ||
121 | 121 | ||
122 | void vsp1_pipelines_suspend(struct vsp1_device *vsp1); | 122 | void vsp1_pipelines_suspend(struct vsp1_device *vsp1); |
123 | void vsp1_pipelines_resume(struct vsp1_device *vsp1); | 123 | void vsp1_pipelines_resume(struct vsp1_device *vsp1); |
diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h index 927b5fb94c48..3b03007ba625 100644 --- a/drivers/media/platform/vsp1/vsp1_regs.h +++ b/drivers/media/platform/vsp1/vsp1_regs.h | |||
@@ -154,10 +154,10 @@ | |||
154 | #define VI6_RPF_ALPH_SEL_AEXT_EXT (1 << 18) | 154 | #define VI6_RPF_ALPH_SEL_AEXT_EXT (1 << 18) |
155 | #define VI6_RPF_ALPH_SEL_AEXT_ONE (2 << 18) | 155 | #define VI6_RPF_ALPH_SEL_AEXT_ONE (2 << 18) |
156 | #define VI6_RPF_ALPH_SEL_AEXT_MASK (3 << 18) | 156 | #define VI6_RPF_ALPH_SEL_AEXT_MASK (3 << 18) |
157 | #define VI6_RPF_ALPH_SEL_ALPHA0_MASK (0xff << 8) | 157 | #define VI6_RPF_ALPH_SEL_ALPHA1_MASK (0xff << 8) |
158 | #define VI6_RPF_ALPH_SEL_ALPHA0_SHIFT 8 | 158 | #define VI6_RPF_ALPH_SEL_ALPHA1_SHIFT 8 |
159 | #define VI6_RPF_ALPH_SEL_ALPHA1_MASK (0xff << 0) | 159 | #define VI6_RPF_ALPH_SEL_ALPHA0_MASK (0xff << 0) |
160 | #define VI6_RPF_ALPH_SEL_ALPHA1_SHIFT 0 | 160 | #define VI6_RPF_ALPH_SEL_ALPHA0_SHIFT 0 |
161 | 161 | ||
162 | #define VI6_RPF_VRTCOL_SET 0x0318 | 162 | #define VI6_RPF_VRTCOL_SET 0x0318 |
163 | #define VI6_RPF_VRTCOL_SET_LAYA_MASK (0xff << 24) | 163 | #define VI6_RPF_VRTCOL_SET_LAYA_MASK (0xff << 24) |
@@ -255,6 +255,8 @@ | |||
255 | #define VI6_WPF_OUTFMT_PDV_MASK (0xff << 24) | 255 | #define VI6_WPF_OUTFMT_PDV_MASK (0xff << 24) |
256 | #define VI6_WPF_OUTFMT_PDV_SHIFT 24 | 256 | #define VI6_WPF_OUTFMT_PDV_SHIFT 24 |
257 | #define VI6_WPF_OUTFMT_PXA (1 << 23) | 257 | #define VI6_WPF_OUTFMT_PXA (1 << 23) |
258 | #define VI6_WPF_OUTFMT_ROT (1 << 18) | ||
259 | #define VI6_WPF_OUTFMT_HFLP (1 << 17) | ||
258 | #define VI6_WPF_OUTFMT_FLP (1 << 16) | 260 | #define VI6_WPF_OUTFMT_FLP (1 << 16) |
259 | #define VI6_WPF_OUTFMT_SPYCS (1 << 15) | 261 | #define VI6_WPF_OUTFMT_SPYCS (1 << 15) |
260 | #define VI6_WPF_OUTFMT_SPUVS (1 << 14) | 262 | #define VI6_WPF_OUTFMT_SPUVS (1 << 14) |
@@ -289,6 +291,11 @@ | |||
289 | #define VI6_WPF_RNDCTRL_CLMD_EXT (2 << 12) | 291 | #define VI6_WPF_RNDCTRL_CLMD_EXT (2 << 12) |
290 | #define VI6_WPF_RNDCTRL_CLMD_MASK (3 << 12) | 292 | #define VI6_WPF_RNDCTRL_CLMD_MASK (3 << 12) |
291 | 293 | ||
294 | #define VI6_WPF_ROT_CTRL 0x1018 | ||
295 | #define VI6_WPF_ROT_CTRL_LN16 (1 << 17) | ||
296 | #define VI6_WPF_ROT_CTRL_LMEM_WD_MASK (0x1fff << 0) | ||
297 | #define VI6_WPF_ROT_CTRL_LMEM_WD_SHIFT 0 | ||
298 | |||
292 | #define VI6_WPF_DSTM_STRIDE_Y 0x101c | 299 | #define VI6_WPF_DSTM_STRIDE_Y 0x101c |
293 | #define VI6_WPF_DSTM_STRIDE_C 0x1020 | 300 | #define VI6_WPF_DSTM_STRIDE_C 0x1020 |
294 | #define VI6_WPF_DSTM_ADDR_Y 0x1024 | 301 | #define VI6_WPF_DSTM_ADDR_Y 0x1024 |
@@ -444,6 +451,15 @@ | |||
444 | */ | 451 | */ |
445 | 452 | ||
446 | #define VI6_CLU_CTRL 0x2900 | 453 | #define VI6_CLU_CTRL 0x2900 |
454 | #define VI6_CLU_CTRL_AAI (1 << 28) | ||
455 | #define VI6_CLU_CTRL_MVS (1 << 24) | ||
456 | #define VI6_CLU_CTRL_AX1I_2D (3 << 14) | ||
457 | #define VI6_CLU_CTRL_AX2I_2D (1 << 12) | ||
458 | #define VI6_CLU_CTRL_OS0_2D (3 << 8) | ||
459 | #define VI6_CLU_CTRL_OS1_2D (1 << 6) | ||
460 | #define VI6_CLU_CTRL_OS2_2D (3 << 4) | ||
461 | #define VI6_CLU_CTRL_M2D (1 << 1) | ||
462 | #define VI6_CLU_CTRL_EN (1 << 0) | ||
447 | 463 | ||
448 | /* ----------------------------------------------------------------------------- | 464 | /* ----------------------------------------------------------------------------- |
449 | * HST Control Registers | 465 | * HST Control Registers |
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c index 49168db3f529..388838913205 100644 --- a/drivers/media/platform/vsp1/vsp1_rpf.c +++ b/drivers/media/platform/vsp1/vsp1_rpf.c | |||
@@ -38,7 +38,7 @@ static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf, | |||
38 | * V4L2 Subdevice Operations | 38 | * V4L2 Subdevice Operations |
39 | */ | 39 | */ |
40 | 40 | ||
41 | static struct v4l2_subdev_ops rpf_ops = { | 41 | static const struct v4l2_subdev_ops rpf_ops = { |
42 | .pad = &vsp1_rwpf_pad_ops, | 42 | .pad = &vsp1_rwpf_pad_ops, |
43 | }; | 43 | }; |
44 | 44 | ||
@@ -60,7 +60,7 @@ static void rpf_set_memory(struct vsp1_entity *entity, struct vsp1_dl_list *dl) | |||
60 | 60 | ||
61 | static void rpf_configure(struct vsp1_entity *entity, | 61 | static void rpf_configure(struct vsp1_entity *entity, |
62 | struct vsp1_pipeline *pipe, | 62 | struct vsp1_pipeline *pipe, |
63 | struct vsp1_dl_list *dl) | 63 | struct vsp1_dl_list *dl, bool full) |
64 | { | 64 | { |
65 | struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev); | 65 | struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev); |
66 | const struct vsp1_format_info *fmtinfo = rpf->fmtinfo; | 66 | const struct vsp1_format_info *fmtinfo = rpf->fmtinfo; |
@@ -73,6 +73,16 @@ static void rpf_configure(struct vsp1_entity *entity, | |||
73 | u32 pstride; | 73 | u32 pstride; |
74 | u32 infmt; | 74 | u32 infmt; |
75 | 75 | ||
76 | if (!full) { | ||
77 | vsp1_rpf_write(rpf, dl, VI6_RPF_VRTCOL_SET, | ||
78 | rpf->alpha << VI6_RPF_VRTCOL_SET_LAYA_SHIFT); | ||
79 | vsp1_rpf_write(rpf, dl, VI6_RPF_MULT_ALPHA, rpf->mult_alpha | | ||
80 | (rpf->alpha << VI6_RPF_MULT_ALPHA_RATIO_SHIFT)); | ||
81 | |||
82 | vsp1_pipeline_propagate_alpha(pipe, dl, rpf->alpha); | ||
83 | return; | ||
84 | } | ||
85 | |||
76 | /* Source size, stride and crop offsets. | 86 | /* Source size, stride and crop offsets. |
77 | * | 87 | * |
78 | * The crop offsets correspond to the location of the crop rectangle top | 88 | * The crop offsets correspond to the location of the crop rectangle top |
@@ -130,9 +140,10 @@ static void rpf_configure(struct vsp1_entity *entity, | |||
130 | if (pipe->bru) { | 140 | if (pipe->bru) { |
131 | const struct v4l2_rect *compose; | 141 | const struct v4l2_rect *compose; |
132 | 142 | ||
133 | compose = vsp1_entity_get_pad_compose(pipe->bru, | 143 | compose = vsp1_entity_get_pad_selection(pipe->bru, |
134 | pipe->bru->config, | 144 | pipe->bru->config, |
135 | rpf->bru_input); | 145 | rpf->bru_input, |
146 | V4L2_SEL_TGT_COMPOSE); | ||
136 | left = compose->left; | 147 | left = compose->left; |
137 | top = compose->top; | 148 | top = compose->top; |
138 | } | 149 | } |
@@ -167,9 +178,6 @@ static void rpf_configure(struct vsp1_entity *entity, | |||
167 | (fmtinfo->alpha ? VI6_RPF_ALPH_SEL_ASEL_PACKED | 178 | (fmtinfo->alpha ? VI6_RPF_ALPH_SEL_ASEL_PACKED |
168 | : VI6_RPF_ALPH_SEL_ASEL_FIXED)); | 179 | : VI6_RPF_ALPH_SEL_ASEL_FIXED)); |
169 | 180 | ||
170 | vsp1_rpf_write(rpf, dl, VI6_RPF_VRTCOL_SET, | ||
171 | rpf->alpha << VI6_RPF_VRTCOL_SET_LAYA_SHIFT); | ||
172 | |||
173 | if (entity->vsp1->info->gen == 3) { | 181 | if (entity->vsp1->info->gen == 3) { |
174 | u32 mult; | 182 | u32 mult; |
175 | 183 | ||
@@ -187,8 +195,7 @@ static void rpf_configure(struct vsp1_entity *entity, | |||
187 | mult = VI6_RPF_MULT_ALPHA_A_MMD_RATIO | 195 | mult = VI6_RPF_MULT_ALPHA_A_MMD_RATIO |
188 | | (premultiplied ? | 196 | | (premultiplied ? |
189 | VI6_RPF_MULT_ALPHA_P_MMD_RATIO : | 197 | VI6_RPF_MULT_ALPHA_P_MMD_RATIO : |
190 | VI6_RPF_MULT_ALPHA_P_MMD_NONE) | 198 | VI6_RPF_MULT_ALPHA_P_MMD_NONE); |
191 | | (rpf->alpha << VI6_RPF_MULT_ALPHA_RATIO_SHIFT); | ||
192 | } else { | 199 | } else { |
193 | /* When the input doesn't contain an alpha channel the | 200 | /* When the input doesn't contain an alpha channel the |
194 | * global alpha value is applied in the unpacking unit, | 201 | * global alpha value is applied in the unpacking unit, |
@@ -199,11 +206,9 @@ static void rpf_configure(struct vsp1_entity *entity, | |||
199 | | VI6_RPF_MULT_ALPHA_P_MMD_NONE; | 206 | | VI6_RPF_MULT_ALPHA_P_MMD_NONE; |
200 | } | 207 | } |
201 | 208 | ||
202 | vsp1_rpf_write(rpf, dl, VI6_RPF_MULT_ALPHA, mult); | 209 | rpf->mult_alpha = mult; |
203 | } | 210 | } |
204 | 211 | ||
205 | vsp1_pipeline_propagate_alpha(pipe, &rpf->entity, dl, rpf->alpha); | ||
206 | |||
207 | vsp1_rpf_write(rpf, dl, VI6_RPF_MSK_CTRL, 0); | 212 | vsp1_rpf_write(rpf, dl, VI6_RPF_MSK_CTRL, 0); |
208 | vsp1_rpf_write(rpf, dl, VI6_RPF_CKEY_CTRL, 0); | 213 | vsp1_rpf_write(rpf, dl, VI6_RPF_CKEY_CTRL, 0); |
209 | 214 | ||
@@ -236,18 +241,21 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index) | |||
236 | rpf->entity.index = index; | 241 | rpf->entity.index = index; |
237 | 242 | ||
238 | sprintf(name, "rpf.%u", index); | 243 | sprintf(name, "rpf.%u", index); |
239 | ret = vsp1_entity_init(vsp1, &rpf->entity, name, 2, &rpf_ops); | 244 | ret = vsp1_entity_init(vsp1, &rpf->entity, name, 2, &rpf_ops, |
245 | MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER); | ||
240 | if (ret < 0) | 246 | if (ret < 0) |
241 | return ERR_PTR(ret); | 247 | return ERR_PTR(ret); |
242 | 248 | ||
243 | /* Initialize the control handler. */ | 249 | /* Initialize the control handler. */ |
244 | ret = vsp1_rwpf_init_ctrls(rpf); | 250 | ret = vsp1_rwpf_init_ctrls(rpf, 0); |
245 | if (ret < 0) { | 251 | if (ret < 0) { |
246 | dev_err(vsp1->dev, "rpf%u: failed to initialize controls\n", | 252 | dev_err(vsp1->dev, "rpf%u: failed to initialize controls\n", |
247 | index); | 253 | index); |
248 | goto error; | 254 | goto error; |
249 | } | 255 | } |
250 | 256 | ||
257 | v4l2_ctrl_handler_setup(&rpf->ctrls); | ||
258 | |||
251 | return rpf; | 259 | return rpf; |
252 | 260 | ||
253 | error: | 261 | error: |
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c index 3b6e032e7806..8d461b375e91 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.c +++ b/drivers/media/platform/vsp1/vsp1_rwpf.c | |||
@@ -241,11 +241,9 @@ static const struct v4l2_ctrl_ops vsp1_rwpf_ctrl_ops = { | |||
241 | .s_ctrl = vsp1_rwpf_s_ctrl, | 241 | .s_ctrl = vsp1_rwpf_s_ctrl, |
242 | }; | 242 | }; |
243 | 243 | ||
244 | int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf) | 244 | int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf, unsigned int ncontrols) |
245 | { | 245 | { |
246 | rwpf->alpha = 255; | 246 | v4l2_ctrl_handler_init(&rwpf->ctrls, ncontrols + 1); |
247 | |||
248 | v4l2_ctrl_handler_init(&rwpf->ctrls, 1); | ||
249 | v4l2_ctrl_new_std(&rwpf->ctrls, &vsp1_rwpf_ctrl_ops, | 247 | v4l2_ctrl_new_std(&rwpf->ctrls, &vsp1_rwpf_ctrl_ops, |
250 | V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 255); | 248 | V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 255); |
251 | 249 | ||
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h index 9ff7c78f239e..cb20484e80da 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.h +++ b/drivers/media/platform/vsp1/vsp1_rwpf.h | |||
@@ -13,6 +13,8 @@ | |||
13 | #ifndef __VSP1_RWPF_H__ | 13 | #ifndef __VSP1_RWPF_H__ |
14 | #define __VSP1_RWPF_H__ | 14 | #define __VSP1_RWPF_H__ |
15 | 15 | ||
16 | #include <linux/spinlock.h> | ||
17 | |||
16 | #include <media/media-entity.h> | 18 | #include <media/media-entity.h> |
17 | #include <media/v4l2-ctrls.h> | 19 | #include <media/v4l2-ctrls.h> |
18 | #include <media/v4l2-subdev.h> | 20 | #include <media/v4l2-subdev.h> |
@@ -49,6 +51,16 @@ struct vsp1_rwpf { | |||
49 | 51 | ||
50 | unsigned int alpha; | 52 | unsigned int alpha; |
51 | 53 | ||
54 | u32 mult_alpha; | ||
55 | u32 outfmt; | ||
56 | |||
57 | struct { | ||
58 | spinlock_t lock; | ||
59 | struct v4l2_ctrl *ctrls[2]; | ||
60 | unsigned int pending; | ||
61 | unsigned int active; | ||
62 | } flip; | ||
63 | |||
52 | unsigned int offsets[2]; | 64 | unsigned int offsets[2]; |
53 | struct vsp1_rwpf_memory mem; | 65 | struct vsp1_rwpf_memory mem; |
54 | 66 | ||
@@ -68,7 +80,7 @@ static inline struct vsp1_rwpf *entity_to_rwpf(struct vsp1_entity *entity) | |||
68 | struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index); | 80 | struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index); |
69 | struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index); | 81 | struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index); |
70 | 82 | ||
71 | int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf); | 83 | int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf, unsigned int ncontrols); |
72 | 84 | ||
73 | extern const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops; | 85 | extern const struct v4l2_subdev_pad_ops vsp1_rwpf_pad_ops; |
74 | 86 | ||
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c index 97ef997ae735..47f5e0cea2ce 100644 --- a/drivers/media/platform/vsp1/vsp1_sru.c +++ b/drivers/media/platform/vsp1/vsp1_sru.c | |||
@@ -37,7 +37,7 @@ static inline void vsp1_sru_write(struct vsp1_sru *sru, struct vsp1_dl_list *dl, | |||
37 | * Controls | 37 | * Controls |
38 | */ | 38 | */ |
39 | 39 | ||
40 | #define V4L2_CID_VSP1_SRU_INTENSITY (V4L2_CID_USER_BASE + 1) | 40 | #define V4L2_CID_VSP1_SRU_INTENSITY (V4L2_CID_USER_BASE | 0x1001) |
41 | 41 | ||
42 | struct vsp1_sru_param { | 42 | struct vsp1_sru_param { |
43 | u32 ctrl0; | 43 | u32 ctrl0; |
@@ -239,7 +239,7 @@ static int sru_set_format(struct v4l2_subdev *subdev, | |||
239 | return 0; | 239 | return 0; |
240 | } | 240 | } |
241 | 241 | ||
242 | static struct v4l2_subdev_pad_ops sru_pad_ops = { | 242 | static const struct v4l2_subdev_pad_ops sru_pad_ops = { |
243 | .init_cfg = vsp1_entity_init_cfg, | 243 | .init_cfg = vsp1_entity_init_cfg, |
244 | .enum_mbus_code = sru_enum_mbus_code, | 244 | .enum_mbus_code = sru_enum_mbus_code, |
245 | .enum_frame_size = sru_enum_frame_size, | 245 | .enum_frame_size = sru_enum_frame_size, |
@@ -247,7 +247,7 @@ static struct v4l2_subdev_pad_ops sru_pad_ops = { | |||
247 | .set_fmt = sru_set_format, | 247 | .set_fmt = sru_set_format, |
248 | }; | 248 | }; |
249 | 249 | ||
250 | static struct v4l2_subdev_ops sru_ops = { | 250 | static const struct v4l2_subdev_ops sru_ops = { |
251 | .pad = &sru_pad_ops, | 251 | .pad = &sru_pad_ops, |
252 | }; | 252 | }; |
253 | 253 | ||
@@ -257,7 +257,7 @@ static struct v4l2_subdev_ops sru_ops = { | |||
257 | 257 | ||
258 | static void sru_configure(struct vsp1_entity *entity, | 258 | static void sru_configure(struct vsp1_entity *entity, |
259 | struct vsp1_pipeline *pipe, | 259 | struct vsp1_pipeline *pipe, |
260 | struct vsp1_dl_list *dl) | 260 | struct vsp1_dl_list *dl, bool full) |
261 | { | 261 | { |
262 | const struct vsp1_sru_param *param; | 262 | const struct vsp1_sru_param *param; |
263 | struct vsp1_sru *sru = to_sru(&entity->subdev); | 263 | struct vsp1_sru *sru = to_sru(&entity->subdev); |
@@ -265,6 +265,9 @@ static void sru_configure(struct vsp1_entity *entity, | |||
265 | struct v4l2_mbus_framefmt *output; | 265 | struct v4l2_mbus_framefmt *output; |
266 | u32 ctrl0; | 266 | u32 ctrl0; |
267 | 267 | ||
268 | if (!full) | ||
269 | return; | ||
270 | |||
268 | input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config, | 271 | input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config, |
269 | SRU_PAD_SINK); | 272 | SRU_PAD_SINK); |
270 | output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config, | 273 | output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.config, |
@@ -308,7 +311,8 @@ struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1) | |||
308 | sru->entity.ops = &sru_entity_ops; | 311 | sru->entity.ops = &sru_entity_ops; |
309 | sru->entity.type = VSP1_ENTITY_SRU; | 312 | sru->entity.type = VSP1_ENTITY_SRU; |
310 | 313 | ||
311 | ret = vsp1_entity_init(vsp1, &sru->entity, "sru", 2, &sru_ops); | 314 | ret = vsp1_entity_init(vsp1, &sru->entity, "sru", 2, &sru_ops, |
315 | MEDIA_ENT_F_PROC_VIDEO_SCALER); | ||
312 | if (ret < 0) | 316 | if (ret < 0) |
313 | return ERR_PTR(ret); | 317 | return ERR_PTR(ret); |
314 | 318 | ||
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c index 1875e29da184..652dcd895022 100644 --- a/drivers/media/platform/vsp1/vsp1_uds.c +++ b/drivers/media/platform/vsp1/vsp1_uds.c | |||
@@ -40,9 +40,11 @@ static inline void vsp1_uds_write(struct vsp1_uds *uds, struct vsp1_dl_list *dl, | |||
40 | * Scaling Computation | 40 | * Scaling Computation |
41 | */ | 41 | */ |
42 | 42 | ||
43 | void vsp1_uds_set_alpha(struct vsp1_uds *uds, struct vsp1_dl_list *dl, | 43 | void vsp1_uds_set_alpha(struct vsp1_entity *entity, struct vsp1_dl_list *dl, |
44 | unsigned int alpha) | 44 | unsigned int alpha) |
45 | { | 45 | { |
46 | struct vsp1_uds *uds = to_uds(&entity->subdev); | ||
47 | |||
46 | vsp1_uds_write(uds, dl, VI6_UDS_ALPVAL, | 48 | vsp1_uds_write(uds, dl, VI6_UDS_ALPVAL, |
47 | alpha << VI6_UDS_ALPVAL_VAL0_SHIFT); | 49 | alpha << VI6_UDS_ALPVAL_VAL0_SHIFT); |
48 | } | 50 | } |
@@ -226,7 +228,7 @@ static int uds_set_format(struct v4l2_subdev *subdev, | |||
226 | * V4L2 Subdevice Operations | 228 | * V4L2 Subdevice Operations |
227 | */ | 229 | */ |
228 | 230 | ||
229 | static struct v4l2_subdev_pad_ops uds_pad_ops = { | 231 | static const struct v4l2_subdev_pad_ops uds_pad_ops = { |
230 | .init_cfg = vsp1_entity_init_cfg, | 232 | .init_cfg = vsp1_entity_init_cfg, |
231 | .enum_mbus_code = uds_enum_mbus_code, | 233 | .enum_mbus_code = uds_enum_mbus_code, |
232 | .enum_frame_size = uds_enum_frame_size, | 234 | .enum_frame_size = uds_enum_frame_size, |
@@ -234,7 +236,7 @@ static struct v4l2_subdev_pad_ops uds_pad_ops = { | |||
234 | .set_fmt = uds_set_format, | 236 | .set_fmt = uds_set_format, |
235 | }; | 237 | }; |
236 | 238 | ||
237 | static struct v4l2_subdev_ops uds_ops = { | 239 | static const struct v4l2_subdev_ops uds_ops = { |
238 | .pad = &uds_pad_ops, | 240 | .pad = &uds_pad_ops, |
239 | }; | 241 | }; |
240 | 242 | ||
@@ -244,7 +246,7 @@ static struct v4l2_subdev_ops uds_ops = { | |||
244 | 246 | ||
245 | static void uds_configure(struct vsp1_entity *entity, | 247 | static void uds_configure(struct vsp1_entity *entity, |
246 | struct vsp1_pipeline *pipe, | 248 | struct vsp1_pipeline *pipe, |
247 | struct vsp1_dl_list *dl) | 249 | struct vsp1_dl_list *dl, bool full) |
248 | { | 250 | { |
249 | struct vsp1_uds *uds = to_uds(&entity->subdev); | 251 | struct vsp1_uds *uds = to_uds(&entity->subdev); |
250 | const struct v4l2_mbus_framefmt *output; | 252 | const struct v4l2_mbus_framefmt *output; |
@@ -253,6 +255,9 @@ static void uds_configure(struct vsp1_entity *entity, | |||
253 | unsigned int vscale; | 255 | unsigned int vscale; |
254 | bool multitap; | 256 | bool multitap; |
255 | 257 | ||
258 | if (!full) | ||
259 | return; | ||
260 | |||
256 | input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, | 261 | input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, |
257 | UDS_PAD_SINK); | 262 | UDS_PAD_SINK); |
258 | output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, | 263 | output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.config, |
@@ -314,7 +319,8 @@ struct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index) | |||
314 | uds->entity.index = index; | 319 | uds->entity.index = index; |
315 | 320 | ||
316 | sprintf(name, "uds.%u", index); | 321 | sprintf(name, "uds.%u", index); |
317 | ret = vsp1_entity_init(vsp1, &uds->entity, name, 2, &uds_ops); | 322 | ret = vsp1_entity_init(vsp1, &uds->entity, name, 2, &uds_ops, |
323 | MEDIA_ENT_F_PROC_VIDEO_SCALER); | ||
318 | if (ret < 0) | 324 | if (ret < 0) |
319 | return ERR_PTR(ret); | 325 | return ERR_PTR(ret); |
320 | 326 | ||
diff --git a/drivers/media/platform/vsp1/vsp1_uds.h b/drivers/media/platform/vsp1/vsp1_uds.h index 5c8cbfcad4cc..7bf3cdcffc65 100644 --- a/drivers/media/platform/vsp1/vsp1_uds.h +++ b/drivers/media/platform/vsp1/vsp1_uds.h | |||
@@ -35,7 +35,7 @@ static inline struct vsp1_uds *to_uds(struct v4l2_subdev *subdev) | |||
35 | 35 | ||
36 | struct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index); | 36 | struct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index); |
37 | 37 | ||
38 | void vsp1_uds_set_alpha(struct vsp1_uds *uds, struct vsp1_dl_list *dl, | 38 | void vsp1_uds_set_alpha(struct vsp1_entity *uds, struct vsp1_dl_list *dl, |
39 | unsigned int alpha); | 39 | unsigned int alpha); |
40 | 40 | ||
41 | #endif /* __VSP1_UDS_H__ */ | 41 | #endif /* __VSP1_UDS_H__ */ |
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index a9aec5c0bec6..01654232b695 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c | |||
@@ -219,7 +219,7 @@ vsp1_video_complete_buffer(struct vsp1_video *video) | |||
219 | 219 | ||
220 | spin_unlock_irqrestore(&video->irqlock, flags); | 220 | spin_unlock_irqrestore(&video->irqlock, flags); |
221 | 221 | ||
222 | done->buf.sequence = video->sequence++; | 222 | done->buf.sequence = pipe->sequence; |
223 | done->buf.vb2_buf.timestamp = ktime_get_ns(); | 223 | done->buf.vb2_buf.timestamp = ktime_get_ns(); |
224 | for (i = 0; i < done->buf.vb2_buf.num_planes; ++i) | 224 | for (i = 0; i < done->buf.vb2_buf.num_planes; ++i) |
225 | vb2_set_plane_payload(&done->buf.vb2_buf, i, | 225 | vb2_set_plane_payload(&done->buf.vb2_buf, i, |
@@ -251,11 +251,17 @@ static void vsp1_video_frame_end(struct vsp1_pipeline *pipe, | |||
251 | static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe) | 251 | static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe) |
252 | { | 252 | { |
253 | struct vsp1_device *vsp1 = pipe->output->entity.vsp1; | 253 | struct vsp1_device *vsp1 = pipe->output->entity.vsp1; |
254 | struct vsp1_entity *entity; | ||
254 | unsigned int i; | 255 | unsigned int i; |
255 | 256 | ||
256 | if (!pipe->dl) | 257 | if (!pipe->dl) |
257 | pipe->dl = vsp1_dl_list_get(pipe->output->dlm); | 258 | pipe->dl = vsp1_dl_list_get(pipe->output->dlm); |
258 | 259 | ||
260 | list_for_each_entry(entity, &pipe->entities, list_pipe) { | ||
261 | if (entity->ops->configure) | ||
262 | entity->ops->configure(entity, pipe, pipe->dl, false); | ||
263 | } | ||
264 | |||
259 | for (i = 0; i < vsp1->info->rpf_count; ++i) { | 265 | for (i = 0; i < vsp1->info->rpf_count; ++i) { |
260 | struct vsp1_rwpf *rwpf = pipe->inputs[i]; | 266 | struct vsp1_rwpf *rwpf = pipe->inputs[i]; |
261 | 267 | ||
@@ -632,7 +638,7 @@ static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe) | |||
632 | vsp1_entity_route_setup(entity, pipe->dl); | 638 | vsp1_entity_route_setup(entity, pipe->dl); |
633 | 639 | ||
634 | if (entity->ops->configure) | 640 | if (entity->ops->configure) |
635 | entity->ops->configure(entity, pipe, pipe->dl); | 641 | entity->ops->configure(entity, pipe, pipe->dl, true); |
636 | } | 642 | } |
637 | 643 | ||
638 | return 0; | 644 | return 0; |
@@ -674,7 +680,7 @@ static void vsp1_video_stop_streaming(struct vb2_queue *vq) | |||
674 | int ret; | 680 | int ret; |
675 | 681 | ||
676 | mutex_lock(&pipe->lock); | 682 | mutex_lock(&pipe->lock); |
677 | if (--pipe->stream_count == 0) { | 683 | if (--pipe->stream_count == pipe->num_inputs) { |
678 | /* Stop the pipeline. */ | 684 | /* Stop the pipeline. */ |
679 | ret = vsp1_pipeline_stop(pipe); | 685 | ret = vsp1_pipeline_stop(pipe); |
680 | if (ret == -ETIMEDOUT) | 686 | if (ret == -ETIMEDOUT) |
@@ -696,7 +702,7 @@ static void vsp1_video_stop_streaming(struct vb2_queue *vq) | |||
696 | spin_unlock_irqrestore(&video->irqlock, flags); | 702 | spin_unlock_irqrestore(&video->irqlock, flags); |
697 | } | 703 | } |
698 | 704 | ||
699 | static struct vb2_ops vsp1_video_queue_qops = { | 705 | static const struct vb2_ops vsp1_video_queue_qops = { |
700 | .queue_setup = vsp1_video_queue_setup, | 706 | .queue_setup = vsp1_video_queue_setup, |
701 | .buf_prepare = vsp1_video_buffer_prepare, | 707 | .buf_prepare = vsp1_video_buffer_prepare, |
702 | .buf_queue = vsp1_video_buffer_queue, | 708 | .buf_queue = vsp1_video_buffer_queue, |
@@ -805,8 +811,6 @@ vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) | |||
805 | if (video->queue.owner && video->queue.owner != file->private_data) | 811 | if (video->queue.owner && video->queue.owner != file->private_data) |
806 | return -EBUSY; | 812 | return -EBUSY; |
807 | 813 | ||
808 | video->sequence = 0; | ||
809 | |||
810 | /* Get a pipeline for the video node and start streaming on it. No link | 814 | /* Get a pipeline for the video node and start streaming on it. No link |
811 | * touching an entity in the pipeline can be activated or deactivated | 815 | * touching an entity in the pipeline can be activated or deactivated |
812 | * once streaming is started. | 816 | * once streaming is started. |
@@ -915,7 +919,7 @@ static int vsp1_video_release(struct file *file) | |||
915 | return 0; | 919 | return 0; |
916 | } | 920 | } |
917 | 921 | ||
918 | static struct v4l2_file_operations vsp1_video_fops = { | 922 | static const struct v4l2_file_operations vsp1_video_fops = { |
919 | .owner = THIS_MODULE, | 923 | .owner = THIS_MODULE, |
920 | .unlocked_ioctl = video_ioctl2, | 924 | .unlocked_ioctl = video_ioctl2, |
921 | .open = vsp1_video_open, | 925 | .open = vsp1_video_open, |
diff --git a/drivers/media/platform/vsp1/vsp1_video.h b/drivers/media/platform/vsp1/vsp1_video.h index 867b00807c46..1595fd587fbc 100644 --- a/drivers/media/platform/vsp1/vsp1_video.h +++ b/drivers/media/platform/vsp1/vsp1_video.h | |||
@@ -49,7 +49,6 @@ struct vsp1_video { | |||
49 | void *alloc_ctx; | 49 | void *alloc_ctx; |
50 | spinlock_t irqlock; | 50 | spinlock_t irqlock; |
51 | struct list_head irqqueue; | 51 | struct list_head irqqueue; |
52 | unsigned int sequence; | ||
53 | }; | 52 | }; |
54 | 53 | ||
55 | static inline struct vsp1_video *to_vsp1_video(struct video_device *vdev) | 54 | static inline struct vsp1_video *to_vsp1_video(struct video_device *vdev) |
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c index 6c91eaa35e75..31983169c24a 100644 --- a/drivers/media/platform/vsp1/vsp1_wpf.c +++ b/drivers/media/platform/vsp1/vsp1_wpf.c | |||
@@ -37,6 +37,97 @@ static inline void vsp1_wpf_write(struct vsp1_rwpf *wpf, | |||
37 | } | 37 | } |
38 | 38 | ||
39 | /* ----------------------------------------------------------------------------- | 39 | /* ----------------------------------------------------------------------------- |
40 | * Controls | ||
41 | */ | ||
42 | |||
43 | enum wpf_flip_ctrl { | ||
44 | WPF_CTRL_VFLIP = 0, | ||
45 | WPF_CTRL_HFLIP = 1, | ||
46 | WPF_CTRL_MAX, | ||
47 | }; | ||
48 | |||
49 | static int vsp1_wpf_s_ctrl(struct v4l2_ctrl *ctrl) | ||
50 | { | ||
51 | struct vsp1_rwpf *wpf = | ||
52 | container_of(ctrl->handler, struct vsp1_rwpf, ctrls); | ||
53 | unsigned int i; | ||
54 | u32 flip = 0; | ||
55 | |||
56 | switch (ctrl->id) { | ||
57 | case V4L2_CID_HFLIP: | ||
58 | case V4L2_CID_VFLIP: | ||
59 | for (i = 0; i < WPF_CTRL_MAX; ++i) { | ||
60 | if (wpf->flip.ctrls[i]) | ||
61 | flip |= wpf->flip.ctrls[i]->val ? BIT(i) : 0; | ||
62 | } | ||
63 | |||
64 | spin_lock_irq(&wpf->flip.lock); | ||
65 | wpf->flip.pending = flip; | ||
66 | spin_unlock_irq(&wpf->flip.lock); | ||
67 | break; | ||
68 | |||
69 | default: | ||
70 | return -EINVAL; | ||
71 | } | ||
72 | |||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | static const struct v4l2_ctrl_ops vsp1_wpf_ctrl_ops = { | ||
77 | .s_ctrl = vsp1_wpf_s_ctrl, | ||
78 | }; | ||
79 | |||
80 | static int wpf_init_controls(struct vsp1_rwpf *wpf) | ||
81 | { | ||
82 | struct vsp1_device *vsp1 = wpf->entity.vsp1; | ||
83 | unsigned int num_flip_ctrls; | ||
84 | |||
85 | spin_lock_init(&wpf->flip.lock); | ||
86 | |||
87 | if (wpf->entity.index != 0) { | ||
88 | /* Only WPF0 supports flipping. */ | ||
89 | num_flip_ctrls = 0; | ||
90 | } else if (vsp1->info->features & VSP1_HAS_WPF_HFLIP) { | ||
91 | /* When horizontal flip is supported the WPF implements two | ||
92 | * controls (horizontal flip and vertical flip). | ||
93 | */ | ||
94 | num_flip_ctrls = 2; | ||
95 | } else if (vsp1->info->features & VSP1_HAS_WPF_VFLIP) { | ||
96 | /* When only vertical flip is supported the WPF implements a | ||
97 | * single control (vertical flip). | ||
98 | */ | ||
99 | num_flip_ctrls = 1; | ||
100 | } else { | ||
101 | /* Otherwise flipping is not supported. */ | ||
102 | num_flip_ctrls = 0; | ||
103 | } | ||
104 | |||
105 | vsp1_rwpf_init_ctrls(wpf, num_flip_ctrls); | ||
106 | |||
107 | if (num_flip_ctrls >= 1) { | ||
108 | wpf->flip.ctrls[WPF_CTRL_VFLIP] = | ||
109 | v4l2_ctrl_new_std(&wpf->ctrls, &vsp1_wpf_ctrl_ops, | ||
110 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
111 | } | ||
112 | |||
113 | if (num_flip_ctrls == 2) { | ||
114 | wpf->flip.ctrls[WPF_CTRL_HFLIP] = | ||
115 | v4l2_ctrl_new_std(&wpf->ctrls, &vsp1_wpf_ctrl_ops, | ||
116 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
117 | |||
118 | v4l2_ctrl_cluster(2, wpf->flip.ctrls); | ||
119 | } | ||
120 | |||
121 | if (wpf->ctrls.error) { | ||
122 | dev_err(vsp1->dev, "wpf%u: failed to initialize controls\n", | ||
123 | wpf->entity.index); | ||
124 | return wpf->ctrls.error; | ||
125 | } | ||
126 | |||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | /* ----------------------------------------------------------------------------- | ||
40 | * V4L2 Subdevice Core Operations | 131 | * V4L2 Subdevice Core Operations |
41 | */ | 132 | */ |
42 | 133 | ||
@@ -62,11 +153,11 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable) | |||
62 | * V4L2 Subdevice Operations | 153 | * V4L2 Subdevice Operations |
63 | */ | 154 | */ |
64 | 155 | ||
65 | static struct v4l2_subdev_video_ops wpf_video_ops = { | 156 | static const struct v4l2_subdev_video_ops wpf_video_ops = { |
66 | .s_stream = wpf_s_stream, | 157 | .s_stream = wpf_s_stream, |
67 | }; | 158 | }; |
68 | 159 | ||
69 | static struct v4l2_subdev_ops wpf_ops = { | 160 | static const struct v4l2_subdev_ops wpf_ops = { |
70 | .video = &wpf_video_ops, | 161 | .video = &wpf_video_ops, |
71 | .pad = &vsp1_rwpf_pad_ops, | 162 | .pad = &vsp1_rwpf_pad_ops, |
72 | }; | 163 | }; |
@@ -85,15 +176,37 @@ static void vsp1_wpf_destroy(struct vsp1_entity *entity) | |||
85 | static void wpf_set_memory(struct vsp1_entity *entity, struct vsp1_dl_list *dl) | 176 | static void wpf_set_memory(struct vsp1_entity *entity, struct vsp1_dl_list *dl) |
86 | { | 177 | { |
87 | struct vsp1_rwpf *wpf = entity_to_rwpf(entity); | 178 | struct vsp1_rwpf *wpf = entity_to_rwpf(entity); |
179 | const struct v4l2_pix_format_mplane *format = &wpf->format; | ||
180 | struct vsp1_rwpf_memory mem = wpf->mem; | ||
181 | unsigned int flip = wpf->flip.active; | ||
182 | unsigned int offset; | ||
183 | |||
184 | /* Update the memory offsets based on flipping configuration. The | ||
185 | * destination addresses point to the locations where the VSP starts | ||
186 | * writing to memory, which can be different corners of the image | ||
187 | * depending on vertical flipping. Horizontal flipping is handled | ||
188 | * through a line buffer and doesn't modify the start address. | ||
189 | */ | ||
190 | if (flip & BIT(WPF_CTRL_VFLIP)) { | ||
191 | mem.addr[0] += (format->height - 1) | ||
192 | * format->plane_fmt[0].bytesperline; | ||
193 | |||
194 | if (format->num_planes > 1) { | ||
195 | offset = (format->height / wpf->fmtinfo->vsub - 1) | ||
196 | * format->plane_fmt[1].bytesperline; | ||
197 | mem.addr[1] += offset; | ||
198 | mem.addr[2] += offset; | ||
199 | } | ||
200 | } | ||
88 | 201 | ||
89 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_Y, wpf->mem.addr[0]); | 202 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_Y, mem.addr[0]); |
90 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C0, wpf->mem.addr[1]); | 203 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C0, mem.addr[1]); |
91 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C1, wpf->mem.addr[2]); | 204 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C1, mem.addr[2]); |
92 | } | 205 | } |
93 | 206 | ||
94 | static void wpf_configure(struct vsp1_entity *entity, | 207 | static void wpf_configure(struct vsp1_entity *entity, |
95 | struct vsp1_pipeline *pipe, | 208 | struct vsp1_pipeline *pipe, |
96 | struct vsp1_dl_list *dl) | 209 | struct vsp1_dl_list *dl, bool full) |
97 | { | 210 | { |
98 | struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev); | 211 | struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev); |
99 | struct vsp1_device *vsp1 = wpf->entity.vsp1; | 212 | struct vsp1_device *vsp1 = wpf->entity.vsp1; |
@@ -104,6 +217,26 @@ static void wpf_configure(struct vsp1_entity *entity, | |||
104 | u32 outfmt = 0; | 217 | u32 outfmt = 0; |
105 | u32 srcrpf = 0; | 218 | u32 srcrpf = 0; |
106 | 219 | ||
220 | if (!full) { | ||
221 | const unsigned int mask = BIT(WPF_CTRL_VFLIP) | ||
222 | | BIT(WPF_CTRL_HFLIP); | ||
223 | |||
224 | spin_lock(&wpf->flip.lock); | ||
225 | wpf->flip.active = (wpf->flip.active & ~mask) | ||
226 | | (wpf->flip.pending & mask); | ||
227 | spin_unlock(&wpf->flip.lock); | ||
228 | |||
229 | outfmt = (wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT) | wpf->outfmt; | ||
230 | |||
231 | if (wpf->flip.active & BIT(WPF_CTRL_VFLIP)) | ||
232 | outfmt |= VI6_WPF_OUTFMT_FLP; | ||
233 | if (wpf->flip.active & BIT(WPF_CTRL_HFLIP)) | ||
234 | outfmt |= VI6_WPF_OUTFMT_HFLP; | ||
235 | |||
236 | vsp1_wpf_write(wpf, dl, VI6_WPF_OUTFMT, outfmt); | ||
237 | return; | ||
238 | } | ||
239 | |||
107 | /* Cropping */ | 240 | /* Cropping */ |
108 | crop = vsp1_rwpf_get_crop(wpf, wpf->entity.config); | 241 | crop = vsp1_rwpf_get_crop(wpf, wpf->entity.config); |
109 | 242 | ||
@@ -143,13 +276,18 @@ static void wpf_configure(struct vsp1_entity *entity, | |||
143 | format->plane_fmt[1].bytesperline); | 276 | format->plane_fmt[1].bytesperline); |
144 | 277 | ||
145 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSWAP, fmtinfo->swap); | 278 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSWAP, fmtinfo->swap); |
279 | |||
280 | if (vsp1->info->features & VSP1_HAS_WPF_HFLIP && | ||
281 | wpf->entity.index == 0) | ||
282 | vsp1_wpf_write(wpf, dl, VI6_WPF_ROT_CTRL, | ||
283 | VI6_WPF_ROT_CTRL_LN16 | | ||
284 | (256 << VI6_WPF_ROT_CTRL_LMEM_WD_SHIFT)); | ||
146 | } | 285 | } |
147 | 286 | ||
148 | if (sink_format->code != source_format->code) | 287 | if (sink_format->code != source_format->code) |
149 | outfmt |= VI6_WPF_OUTFMT_CSC; | 288 | outfmt |= VI6_WPF_OUTFMT_CSC; |
150 | 289 | ||
151 | outfmt |= wpf->alpha << VI6_WPF_OUTFMT_PDV_SHIFT; | 290 | wpf->outfmt = outfmt; |
152 | vsp1_wpf_write(wpf, dl, VI6_WPF_OUTFMT, outfmt); | ||
153 | 291 | ||
154 | vsp1_dl_list_write(dl, VI6_DPR_WPF_FPORCH(wpf->entity.index), | 292 | vsp1_dl_list_write(dl, VI6_DPR_WPF_FPORCH(wpf->entity.index), |
155 | VI6_DPR_WPF_FPORCH_FP_WPFN); | 293 | VI6_DPR_WPF_FPORCH_FP_WPFN); |
@@ -216,7 +354,8 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index) | |||
216 | wpf->entity.index = index; | 354 | wpf->entity.index = index; |
217 | 355 | ||
218 | sprintf(name, "wpf.%u", index); | 356 | sprintf(name, "wpf.%u", index); |
219 | ret = vsp1_entity_init(vsp1, &wpf->entity, name, 2, &wpf_ops); | 357 | ret = vsp1_entity_init(vsp1, &wpf->entity, name, 2, &wpf_ops, |
358 | MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER); | ||
220 | if (ret < 0) | 359 | if (ret < 0) |
221 | return ERR_PTR(ret); | 360 | return ERR_PTR(ret); |
222 | 361 | ||
@@ -228,13 +367,15 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index) | |||
228 | } | 367 | } |
229 | 368 | ||
230 | /* Initialize the control handler. */ | 369 | /* Initialize the control handler. */ |
231 | ret = vsp1_rwpf_init_ctrls(wpf); | 370 | ret = wpf_init_controls(wpf); |
232 | if (ret < 0) { | 371 | if (ret < 0) { |
233 | dev_err(vsp1->dev, "wpf%u: failed to initialize controls\n", | 372 | dev_err(vsp1->dev, "wpf%u: failed to initialize controls\n", |
234 | index); | 373 | index); |
235 | goto error; | 374 | goto error; |
236 | } | 375 | } |
237 | 376 | ||
377 | v4l2_ctrl_handler_setup(&wpf->ctrls); | ||
378 | |||
238 | return wpf; | 379 | return wpf; |
239 | 380 | ||
240 | error: | 381 | error: |
diff --git a/drivers/media/tuners/mt2063.c b/drivers/media/tuners/mt2063.c index 6457ac91ef09..7f0b9d5940db 100644 --- a/drivers/media/tuners/mt2063.c +++ b/drivers/media/tuners/mt2063.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/string.h> | 25 | #include <linux/string.h> |
26 | #include <linux/videodev2.h> | 26 | #include <linux/videodev2.h> |
27 | #include <linux/gcd.h> | ||
27 | 28 | ||
28 | #include "mt2063.h" | 29 | #include "mt2063.h" |
29 | 30 | ||
@@ -665,27 +666,6 @@ static u32 MT2063_ChooseFirstIF(struct MT2063_AvoidSpursData_t *pAS_Info) | |||
665 | } | 666 | } |
666 | 667 | ||
667 | /** | 668 | /** |
668 | * gcd() - Uses Euclid's algorithm | ||
669 | * | ||
670 | * @u, @v: Unsigned values whose GCD is desired. | ||
671 | * | ||
672 | * Returns THE greatest common divisor of u and v, if either value is 0, | ||
673 | * the other value is returned as the result. | ||
674 | */ | ||
675 | static u32 MT2063_gcd(u32 u, u32 v) | ||
676 | { | ||
677 | u32 r; | ||
678 | |||
679 | while (v != 0) { | ||
680 | r = u % v; | ||
681 | u = v; | ||
682 | v = r; | ||
683 | } | ||
684 | |||
685 | return u; | ||
686 | } | ||
687 | |||
688 | /** | ||
689 | * IsSpurInBand() - Checks to see if a spur will be present within the IF's | 669 | * IsSpurInBand() - Checks to see if a spur will be present within the IF's |
690 | * bandwidth. (fIFOut +/- fIFBW, -fIFOut +/- fIFBW) | 670 | * bandwidth. (fIFOut +/- fIFBW, -fIFOut +/- fIFBW) |
691 | * | 671 | * |
@@ -731,12 +711,12 @@ static u32 IsSpurInBand(struct MT2063_AvoidSpursData_t *pAS_Info, | |||
731 | ** of f_LO1, f_LO2 and the edge value. Use the larger of this | 711 | ** of f_LO1, f_LO2 and the edge value. Use the larger of this |
732 | ** gcd-based scale factor or f_Scale. | 712 | ** gcd-based scale factor or f_Scale. |
733 | */ | 713 | */ |
734 | lo_gcd = MT2063_gcd(f_LO1, f_LO2); | 714 | lo_gcd = gcd(f_LO1, f_LO2); |
735 | gd_Scale = max((u32) MT2063_gcd(lo_gcd, d), f_Scale); | 715 | gd_Scale = max((u32) gcd(lo_gcd, d), f_Scale); |
736 | hgds = gd_Scale / 2; | 716 | hgds = gd_Scale / 2; |
737 | gc_Scale = max((u32) MT2063_gcd(lo_gcd, c), f_Scale); | 717 | gc_Scale = max((u32) gcd(lo_gcd, c), f_Scale); |
738 | hgcs = gc_Scale / 2; | 718 | hgcs = gc_Scale / 2; |
739 | gf_Scale = max((u32) MT2063_gcd(lo_gcd, f), f_Scale); | 719 | gf_Scale = max((u32) gcd(lo_gcd, f), f_Scale); |
740 | hgfs = gf_Scale / 2; | 720 | hgfs = gf_Scale / 2; |
741 | 721 | ||
742 | n0 = DIV_ROUND_UP(f_LO2 - d, f_LO1 - f_LO2); | 722 | n0 = DIV_ROUND_UP(f_LO2 - d, f_LO1 - f_LO2); |
diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index 321ea5cf1329..bf53553d2624 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c | |||
@@ -142,7 +142,7 @@ static void au0828_unregister_media_device(struct au0828_dev *dev) | |||
142 | struct media_device *mdev = dev->media_dev; | 142 | struct media_device *mdev = dev->media_dev; |
143 | struct media_entity_notify *notify, *nextp; | 143 | struct media_entity_notify *notify, *nextp; |
144 | 144 | ||
145 | if (!mdev || !media_devnode_is_registered(&mdev->devnode)) | 145 | if (!mdev || !media_devnode_is_registered(mdev->devnode)) |
146 | return; | 146 | return; |
147 | 147 | ||
148 | /* Remove au0828 entity_notify callbacks */ | 148 | /* Remove au0828 entity_notify callbacks */ |
@@ -482,7 +482,7 @@ static int au0828_media_device_register(struct au0828_dev *dev, | |||
482 | if (!dev->media_dev) | 482 | if (!dev->media_dev) |
483 | return 0; | 483 | return 0; |
484 | 484 | ||
485 | if (!media_devnode_is_registered(&dev->media_dev->devnode)) { | 485 | if (!media_devnode_is_registered(dev->media_dev->devnode)) { |
486 | 486 | ||
487 | /* register media device */ | 487 | /* register media device */ |
488 | ret = media_device_register(dev->media_dev); | 488 | ret = media_device_register(dev->media_dev); |
diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig index 3dc8ef004f8b..524533d3eb29 100644 --- a/drivers/media/usb/dvb-usb-v2/Kconfig +++ b/drivers/media/usb/dvb-usb-v2/Kconfig | |||
@@ -127,17 +127,22 @@ config DVB_USB_MXL111SF | |||
127 | config DVB_USB_RTL28XXU | 127 | config DVB_USB_RTL28XXU |
128 | tristate "Realtek RTL28xxU DVB USB support" | 128 | tristate "Realtek RTL28xxU DVB USB support" |
129 | depends on DVB_USB_V2 && I2C_MUX | 129 | depends on DVB_USB_V2 && I2C_MUX |
130 | select DVB_MN88472 if MEDIA_SUBDRV_AUTOSELECT | ||
131 | select DVB_MN88473 if MEDIA_SUBDRV_AUTOSELECT | ||
130 | select DVB_RTL2830 | 132 | select DVB_RTL2830 |
131 | select DVB_RTL2832 | 133 | select DVB_RTL2832 |
132 | select DVB_RTL2832_SDR if (MEDIA_SUBDRV_AUTOSELECT && MEDIA_SDR_SUPPORT) | 134 | select DVB_RTL2832_SDR if (MEDIA_SUBDRV_AUTOSELECT && MEDIA_SDR_SUPPORT) |
133 | select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT | 135 | select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT |
134 | select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT | 136 | select MEDIA_TUNER_E4000 if MEDIA_SUBDRV_AUTOSELECT |
135 | select MEDIA_TUNER_MXL5005S if MEDIA_SUBDRV_AUTOSELECT | ||
136 | select MEDIA_TUNER_FC0012 if MEDIA_SUBDRV_AUTOSELECT | 137 | select MEDIA_TUNER_FC0012 if MEDIA_SUBDRV_AUTOSELECT |
137 | select MEDIA_TUNER_FC0013 if MEDIA_SUBDRV_AUTOSELECT | 138 | select MEDIA_TUNER_FC0013 if MEDIA_SUBDRV_AUTOSELECT |
138 | select MEDIA_TUNER_E4000 if MEDIA_SUBDRV_AUTOSELECT | ||
139 | select MEDIA_TUNER_FC2580 if MEDIA_SUBDRV_AUTOSELECT | 139 | select MEDIA_TUNER_FC2580 if MEDIA_SUBDRV_AUTOSELECT |
140 | select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT | ||
141 | select MEDIA_TUNER_MXL5005S if MEDIA_SUBDRV_AUTOSELECT | ||
142 | select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT | ||
140 | select MEDIA_TUNER_R820T if MEDIA_SUBDRV_AUTOSELECT | 143 | select MEDIA_TUNER_R820T if MEDIA_SUBDRV_AUTOSELECT |
144 | select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT | ||
145 | select MEDIA_TUNER_TUA9001 if MEDIA_SUBDRV_AUTOSELECT | ||
141 | help | 146 | help |
142 | Say Y here to support the Realtek RTL28xxU DVB USB receiver. | 147 | Say Y here to support the Realtek RTL28xxU DVB USB receiver. |
143 | 148 | ||
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 2638e3251f2a..eabede44ad88 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c | |||
@@ -49,6 +49,7 @@ static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req) | |||
49 | #define CHECKSUM_LEN 2 | 49 | #define CHECKSUM_LEN 2 |
50 | #define USB_TIMEOUT 2000 | 50 | #define USB_TIMEOUT 2000 |
51 | struct state *state = d_to_priv(d); | 51 | struct state *state = d_to_priv(d); |
52 | struct usb_interface *intf = d->intf; | ||
52 | int ret, wlen, rlen; | 53 | int ret, wlen, rlen; |
53 | u16 checksum, tmp_checksum; | 54 | u16 checksum, tmp_checksum; |
54 | 55 | ||
@@ -57,8 +58,8 @@ static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req) | |||
57 | /* buffer overflow check */ | 58 | /* buffer overflow check */ |
58 | if (req->wlen > (BUF_LEN - REQ_HDR_LEN - CHECKSUM_LEN) || | 59 | if (req->wlen > (BUF_LEN - REQ_HDR_LEN - CHECKSUM_LEN) || |
59 | req->rlen > (BUF_LEN - ACK_HDR_LEN - CHECKSUM_LEN)) { | 60 | req->rlen > (BUF_LEN - ACK_HDR_LEN - CHECKSUM_LEN)) { |
60 | dev_err(&d->udev->dev, "%s: too much data wlen=%d rlen=%d\n", | 61 | dev_err(&intf->dev, "too much data wlen=%d rlen=%d\n", |
61 | KBUILD_MODNAME, req->wlen, req->rlen); | 62 | req->wlen, req->rlen); |
62 | ret = -EINVAL; | 63 | ret = -EINVAL; |
63 | goto exit; | 64 | goto exit; |
64 | } | 65 | } |
@@ -94,10 +95,8 @@ static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req) | |||
94 | checksum = af9035_checksum(state->buf, rlen - 2); | 95 | checksum = af9035_checksum(state->buf, rlen - 2); |
95 | tmp_checksum = (state->buf[rlen - 2] << 8) | state->buf[rlen - 1]; | 96 | tmp_checksum = (state->buf[rlen - 2] << 8) | state->buf[rlen - 1]; |
96 | if (tmp_checksum != checksum) { | 97 | if (tmp_checksum != checksum) { |
97 | dev_err(&d->udev->dev, | 98 | dev_err(&intf->dev, "command=%02x checksum mismatch (%04x != %04x)\n", |
98 | "%s: command=%02x checksum mismatch (%04x != %04x)\n", | 99 | req->cmd, tmp_checksum, checksum); |
99 | KBUILD_MODNAME, req->cmd, tmp_checksum, | ||
100 | checksum); | ||
101 | ret = -EIO; | 100 | ret = -EIO; |
102 | goto exit; | 101 | goto exit; |
103 | } | 102 | } |
@@ -110,8 +109,8 @@ static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req) | |||
110 | goto exit; | 109 | goto exit; |
111 | } | 110 | } |
112 | 111 | ||
113 | dev_dbg(&d->udev->dev, "%s: command=%02x failed fw error=%d\n", | 112 | dev_dbg(&intf->dev, "command=%02x failed fw error=%d\n", |
114 | __func__, req->cmd, state->buf[2]); | 113 | req->cmd, state->buf[2]); |
115 | ret = -EIO; | 114 | ret = -EIO; |
116 | goto exit; | 115 | goto exit; |
117 | } | 116 | } |
@@ -122,20 +121,20 @@ static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req) | |||
122 | exit: | 121 | exit: |
123 | mutex_unlock(&d->usb_mutex); | 122 | mutex_unlock(&d->usb_mutex); |
124 | if (ret < 0) | 123 | if (ret < 0) |
125 | dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); | 124 | dev_dbg(&intf->dev, "failed=%d\n", ret); |
126 | return ret; | 125 | return ret; |
127 | } | 126 | } |
128 | 127 | ||
129 | /* write multiple registers */ | 128 | /* write multiple registers */ |
130 | static int af9035_wr_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len) | 129 | static int af9035_wr_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len) |
131 | { | 130 | { |
131 | struct usb_interface *intf = d->intf; | ||
132 | u8 wbuf[MAX_XFER_SIZE]; | 132 | u8 wbuf[MAX_XFER_SIZE]; |
133 | u8 mbox = (reg >> 16) & 0xff; | 133 | u8 mbox = (reg >> 16) & 0xff; |
134 | struct usb_req req = { CMD_MEM_WR, mbox, 6 + len, wbuf, 0, NULL }; | 134 | struct usb_req req = { CMD_MEM_WR, mbox, 6 + len, wbuf, 0, NULL }; |
135 | 135 | ||
136 | if (6 + len > sizeof(wbuf)) { | 136 | if (6 + len > sizeof(wbuf)) { |
137 | dev_warn(&d->udev->dev, "%s: i2c wr: len=%d is too big!\n", | 137 | dev_warn(&intf->dev, "i2c wr: len=%d is too big!\n", len); |
138 | KBUILD_MODNAME, len); | ||
139 | return -EOPNOTSUPP; | 138 | return -EOPNOTSUPP; |
140 | } | 139 | } |
141 | 140 | ||
@@ -198,6 +197,7 @@ static int af9035_add_i2c_dev(struct dvb_usb_device *d, const char *type, | |||
198 | { | 197 | { |
199 | int ret, num; | 198 | int ret, num; |
200 | struct state *state = d_to_priv(d); | 199 | struct state *state = d_to_priv(d); |
200 | struct usb_interface *intf = d->intf; | ||
201 | struct i2c_client *client; | 201 | struct i2c_client *client; |
202 | struct i2c_board_info board_info = { | 202 | struct i2c_board_info board_info = { |
203 | .addr = addr, | 203 | .addr = addr, |
@@ -212,11 +212,10 @@ static int af9035_add_i2c_dev(struct dvb_usb_device *d, const char *type, | |||
212 | break; | 212 | break; |
213 | } | 213 | } |
214 | 214 | ||
215 | dev_dbg(&d->udev->dev, "%s: num=%d\n", __func__, num); | 215 | dev_dbg(&intf->dev, "num=%d\n", num); |
216 | 216 | ||
217 | if (num == AF9035_I2C_CLIENT_MAX) { | 217 | if (num == AF9035_I2C_CLIENT_MAX) { |
218 | dev_err(&d->udev->dev, "%s: I2C client out of index\n", | 218 | dev_err(&intf->dev, "I2C client out of index\n"); |
219 | KBUILD_MODNAME); | ||
220 | ret = -ENODEV; | 219 | ret = -ENODEV; |
221 | goto err; | 220 | goto err; |
222 | } | 221 | } |
@@ -240,7 +239,7 @@ static int af9035_add_i2c_dev(struct dvb_usb_device *d, const char *type, | |||
240 | state->i2c_client[num] = client; | 239 | state->i2c_client[num] = client; |
241 | return 0; | 240 | return 0; |
242 | err: | 241 | err: |
243 | dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); | 242 | dev_dbg(&intf->dev, "failed=%d\n", ret); |
244 | return ret; | 243 | return ret; |
245 | } | 244 | } |
246 | 245 | ||
@@ -248,6 +247,7 @@ static void af9035_del_i2c_dev(struct dvb_usb_device *d) | |||
248 | { | 247 | { |
249 | int num; | 248 | int num; |
250 | struct state *state = d_to_priv(d); | 249 | struct state *state = d_to_priv(d); |
250 | struct usb_interface *intf = d->intf; | ||
251 | struct i2c_client *client; | 251 | struct i2c_client *client; |
252 | 252 | ||
253 | /* find last used client */ | 253 | /* find last used client */ |
@@ -257,11 +257,10 @@ static void af9035_del_i2c_dev(struct dvb_usb_device *d) | |||
257 | break; | 257 | break; |
258 | } | 258 | } |
259 | 259 | ||
260 | dev_dbg(&d->udev->dev, "%s: num=%d\n", __func__, num); | 260 | dev_dbg(&intf->dev, "num=%d\n", num); |
261 | 261 | ||
262 | if (num == -1) { | 262 | if (num == -1) { |
263 | dev_err(&d->udev->dev, "%s: I2C client out of index\n", | 263 | dev_err(&intf->dev, "I2C client out of index\n"); |
264 | KBUILD_MODNAME); | ||
265 | goto err; | 264 | goto err; |
266 | } | 265 | } |
267 | 266 | ||
@@ -276,7 +275,7 @@ static void af9035_del_i2c_dev(struct dvb_usb_device *d) | |||
276 | state->i2c_client[num] = NULL; | 275 | state->i2c_client[num] = NULL; |
277 | return; | 276 | return; |
278 | err: | 277 | err: |
279 | dev_dbg(&d->udev->dev, "%s: failed\n", __func__); | 278 | dev_dbg(&intf->dev, "failed\n"); |
280 | } | 279 | } |
281 | 280 | ||
282 | static int af9035_i2c_master_xfer(struct i2c_adapter *adap, | 281 | static int af9035_i2c_master_xfer(struct i2c_adapter *adap, |
@@ -348,6 +347,9 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, | |||
348 | 347 | ||
349 | ret = af9035_rd_regs(d, reg, &msg[1].buf[0], | 348 | ret = af9035_rd_regs(d, reg, &msg[1].buf[0], |
350 | msg[1].len); | 349 | msg[1].len); |
350 | } else if (state->no_read) { | ||
351 | memset(msg[1].buf, 0, msg[1].len); | ||
352 | ret = 0; | ||
351 | } else { | 353 | } else { |
352 | /* I2C write + read */ | 354 | /* I2C write + read */ |
353 | u8 buf[MAX_XFER_SIZE]; | 355 | u8 buf[MAX_XFER_SIZE]; |
@@ -367,10 +369,25 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, | |||
367 | memcpy(&buf[3], msg[0].buf, msg[0].len); | 369 | memcpy(&buf[3], msg[0].buf, msg[0].len); |
368 | } else { | 370 | } else { |
369 | buf[1] = msg[0].addr << 1; | 371 | buf[1] = msg[0].addr << 1; |
370 | buf[2] = 0x00; /* reg addr len */ | ||
371 | buf[3] = 0x00; /* reg addr MSB */ | 372 | buf[3] = 0x00; /* reg addr MSB */ |
372 | buf[4] = 0x00; /* reg addr LSB */ | 373 | buf[4] = 0x00; /* reg addr LSB */ |
373 | memcpy(&buf[5], msg[0].buf, msg[0].len); | 374 | |
375 | /* Keep prev behavior for write req len > 2*/ | ||
376 | if (msg[0].len > 2) { | ||
377 | buf[2] = 0x00; /* reg addr len */ | ||
378 | memcpy(&buf[5], msg[0].buf, msg[0].len); | ||
379 | |||
380 | /* Use reg addr fields if write req len <= 2 */ | ||
381 | } else { | ||
382 | req.wlen = 5; | ||
383 | buf[2] = msg[0].len; | ||
384 | if (msg[0].len == 2) { | ||
385 | buf[3] = msg[0].buf[0]; | ||
386 | buf[4] = msg[0].buf[1]; | ||
387 | } else if (msg[0].len == 1) { | ||
388 | buf[4] = msg[0].buf[0]; | ||
389 | } | ||
390 | } | ||
374 | } | 391 | } |
375 | ret = af9035_ctrl_msg(d, &req); | 392 | ret = af9035_ctrl_msg(d, &req); |
376 | } | 393 | } |
@@ -421,6 +438,9 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap, | |||
421 | if (msg[0].len > 40) { | 438 | if (msg[0].len > 40) { |
422 | /* TODO: correct limits > 40 */ | 439 | /* TODO: correct limits > 40 */ |
423 | ret = -EOPNOTSUPP; | 440 | ret = -EOPNOTSUPP; |
441 | } else if (state->no_read) { | ||
442 | memset(msg[0].buf, 0, msg[0].len); | ||
443 | ret = 0; | ||
424 | } else { | 444 | } else { |
425 | /* I2C read */ | 445 | /* I2C read */ |
426 | u8 buf[5]; | 446 | u8 buf[5]; |
@@ -475,6 +495,7 @@ static struct i2c_algorithm af9035_i2c_algo = { | |||
475 | static int af9035_identify_state(struct dvb_usb_device *d, const char **name) | 495 | static int af9035_identify_state(struct dvb_usb_device *d, const char **name) |
476 | { | 496 | { |
477 | struct state *state = d_to_priv(d); | 497 | struct state *state = d_to_priv(d); |
498 | struct usb_interface *intf = d->intf; | ||
478 | int ret; | 499 | int ret; |
479 | u8 wbuf[1] = { 1 }; | 500 | u8 wbuf[1] = { 1 }; |
480 | u8 rbuf[4]; | 501 | u8 rbuf[4]; |
@@ -492,10 +513,8 @@ static int af9035_identify_state(struct dvb_usb_device *d, const char **name) | |||
492 | if (ret < 0) | 513 | if (ret < 0) |
493 | goto err; | 514 | goto err; |
494 | 515 | ||
495 | dev_info(&d->udev->dev, | 516 | dev_info(&intf->dev, "prechip_version=%02x chip_version=%02x chip_type=%04x\n", |
496 | "%s: prechip_version=%02x chip_version=%02x chip_type=%04x\n", | 517 | state->prechip_version, state->chip_version, state->chip_type); |
497 | KBUILD_MODNAME, state->prechip_version, | ||
498 | state->chip_version, state->chip_type); | ||
499 | 518 | ||
500 | if (state->chip_type == 0x9135) { | 519 | if (state->chip_type == 0x9135) { |
501 | if (state->chip_version == 0x02) | 520 | if (state->chip_version == 0x02) |
@@ -515,7 +534,7 @@ static int af9035_identify_state(struct dvb_usb_device *d, const char **name) | |||
515 | if (ret < 0) | 534 | if (ret < 0) |
516 | goto err; | 535 | goto err; |
517 | 536 | ||
518 | dev_dbg(&d->udev->dev, "%s: reply=%*ph\n", __func__, 4, rbuf); | 537 | dev_dbg(&intf->dev, "reply=%*ph\n", 4, rbuf); |
519 | if (rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3]) | 538 | if (rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3]) |
520 | ret = WARM; | 539 | ret = WARM; |
521 | else | 540 | else |
@@ -524,7 +543,7 @@ static int af9035_identify_state(struct dvb_usb_device *d, const char **name) | |||
524 | return ret; | 543 | return ret; |
525 | 544 | ||
526 | err: | 545 | err: |
527 | dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); | 546 | dev_dbg(&intf->dev, "failed=%d\n", ret); |
528 | 547 | ||
529 | return ret; | 548 | return ret; |
530 | } | 549 | } |
@@ -532,6 +551,7 @@ err: | |||
532 | static int af9035_download_firmware_old(struct dvb_usb_device *d, | 551 | static int af9035_download_firmware_old(struct dvb_usb_device *d, |
533 | const struct firmware *fw) | 552 | const struct firmware *fw) |
534 | { | 553 | { |
554 | struct usb_interface *intf = d->intf; | ||
535 | int ret, i, j, len; | 555 | int ret, i, j, len; |
536 | u8 wbuf[1]; | 556 | u8 wbuf[1]; |
537 | struct usb_req req = { 0, 0, 0, NULL, 0, NULL }; | 557 | struct usb_req req = { 0, 0, 0, NULL, 0, NULL }; |
@@ -562,14 +582,12 @@ static int af9035_download_firmware_old(struct dvb_usb_device *d, | |||
562 | hdr_checksum = fw->data[fw->size - i + 5] << 8; | 582 | hdr_checksum = fw->data[fw->size - i + 5] << 8; |
563 | hdr_checksum |= fw->data[fw->size - i + 6] << 0; | 583 | hdr_checksum |= fw->data[fw->size - i + 6] << 0; |
564 | 584 | ||
565 | dev_dbg(&d->udev->dev, | 585 | dev_dbg(&intf->dev, "core=%d addr=%04x data_len=%d checksum=%04x\n", |
566 | "%s: core=%d addr=%04x data_len=%d checksum=%04x\n", | 586 | hdr_core, hdr_addr, hdr_data_len, hdr_checksum); |
567 | __func__, hdr_core, hdr_addr, hdr_data_len, | ||
568 | hdr_checksum); | ||
569 | 587 | ||
570 | if (((hdr_core != 1) && (hdr_core != 2)) || | 588 | if (((hdr_core != 1) && (hdr_core != 2)) || |
571 | (hdr_data_len > i)) { | 589 | (hdr_data_len > i)) { |
572 | dev_dbg(&d->udev->dev, "%s: bad firmware\n", __func__); | 590 | dev_dbg(&intf->dev, "bad firmware\n"); |
573 | break; | 591 | break; |
574 | } | 592 | } |
575 | 593 | ||
@@ -600,18 +618,17 @@ static int af9035_download_firmware_old(struct dvb_usb_device *d, | |||
600 | 618 | ||
601 | i -= hdr_data_len + HDR_SIZE; | 619 | i -= hdr_data_len + HDR_SIZE; |
602 | 620 | ||
603 | dev_dbg(&d->udev->dev, "%s: data uploaded=%zu\n", | 621 | dev_dbg(&intf->dev, "data uploaded=%zu\n", fw->size - i); |
604 | __func__, fw->size - i); | ||
605 | } | 622 | } |
606 | 623 | ||
607 | /* print warn if firmware is bad, continue and see what happens */ | 624 | /* print warn if firmware is bad, continue and see what happens */ |
608 | if (i) | 625 | if (i) |
609 | dev_warn(&d->udev->dev, "%s: bad firmware\n", KBUILD_MODNAME); | 626 | dev_warn(&intf->dev, "bad firmware\n"); |
610 | 627 | ||
611 | return 0; | 628 | return 0; |
612 | 629 | ||
613 | err: | 630 | err: |
614 | dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); | 631 | dev_dbg(&intf->dev, "failed=%d\n", ret); |
615 | 632 | ||
616 | return ret; | 633 | return ret; |
617 | } | 634 | } |
@@ -619,6 +636,7 @@ err: | |||
619 | static int af9035_download_firmware_new(struct dvb_usb_device *d, | 636 | static int af9035_download_firmware_new(struct dvb_usb_device *d, |
620 | const struct firmware *fw) | 637 | const struct firmware *fw) |
621 | { | 638 | { |
639 | struct usb_interface *intf = d->intf; | ||
622 | int ret, i, i_prev; | 640 | int ret, i, i_prev; |
623 | struct usb_req req_fw_dl = { CMD_FW_SCATTER_WR, 0, 0, NULL, 0, NULL }; | 641 | struct usb_req req_fw_dl = { CMD_FW_SCATTER_WR, 0, 0, NULL, 0, NULL }; |
624 | #define HDR_SIZE 7 | 642 | #define HDR_SIZE 7 |
@@ -648,15 +666,14 @@ static int af9035_download_firmware_new(struct dvb_usb_device *d, | |||
648 | if (ret < 0) | 666 | if (ret < 0) |
649 | goto err; | 667 | goto err; |
650 | 668 | ||
651 | dev_dbg(&d->udev->dev, "%s: data uploaded=%d\n", | 669 | dev_dbg(&intf->dev, "data uploaded=%d\n", i); |
652 | __func__, i); | ||
653 | } | 670 | } |
654 | } | 671 | } |
655 | 672 | ||
656 | return 0; | 673 | return 0; |
657 | 674 | ||
658 | err: | 675 | err: |
659 | dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); | 676 | dev_dbg(&intf->dev, "failed=%d\n", ret); |
660 | 677 | ||
661 | return ret; | 678 | return ret; |
662 | } | 679 | } |
@@ -664,6 +681,7 @@ err: | |||
664 | static int af9035_download_firmware(struct dvb_usb_device *d, | 681 | static int af9035_download_firmware(struct dvb_usb_device *d, |
665 | const struct firmware *fw) | 682 | const struct firmware *fw) |
666 | { | 683 | { |
684 | struct usb_interface *intf = d->intf; | ||
667 | struct state *state = d_to_priv(d); | 685 | struct state *state = d_to_priv(d); |
668 | int ret; | 686 | int ret; |
669 | u8 wbuf[1]; | 687 | u8 wbuf[1]; |
@@ -672,7 +690,7 @@ static int af9035_download_firmware(struct dvb_usb_device *d, | |||
672 | struct usb_req req = { 0, 0, 0, NULL, 0, NULL }; | 690 | struct usb_req req = { 0, 0, 0, NULL, 0, NULL }; |
673 | struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf }; | 691 | struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf }; |
674 | 692 | ||
675 | dev_dbg(&d->udev->dev, "%s:\n", __func__); | 693 | dev_dbg(&intf->dev, "\n"); |
676 | 694 | ||
677 | /* | 695 | /* |
678 | * In case of dual tuner configuration we need to do some extra | 696 | * In case of dual tuner configuration we need to do some extra |
@@ -752,25 +770,25 @@ static int af9035_download_firmware(struct dvb_usb_device *d, | |||
752 | goto err; | 770 | goto err; |
753 | 771 | ||
754 | if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) { | 772 | if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) { |
755 | dev_err(&d->udev->dev, "%s: firmware did not run\n", | 773 | dev_err(&intf->dev, "firmware did not run\n"); |
756 | KBUILD_MODNAME); | ||
757 | ret = -ENODEV; | 774 | ret = -ENODEV; |
758 | goto err; | 775 | goto err; |
759 | } | 776 | } |
760 | 777 | ||
761 | dev_info(&d->udev->dev, "%s: firmware version=%d.%d.%d.%d", | 778 | dev_info(&intf->dev, "firmware version=%d.%d.%d.%d", |
762 | KBUILD_MODNAME, rbuf[0], rbuf[1], rbuf[2], rbuf[3]); | 779 | rbuf[0], rbuf[1], rbuf[2], rbuf[3]); |
763 | 780 | ||
764 | return 0; | 781 | return 0; |
765 | 782 | ||
766 | err: | 783 | err: |
767 | dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); | 784 | dev_dbg(&intf->dev, "failed=%d\n", ret); |
768 | 785 | ||
769 | return ret; | 786 | return ret; |
770 | } | 787 | } |
771 | 788 | ||
772 | static int af9035_read_config(struct dvb_usb_device *d) | 789 | static int af9035_read_config(struct dvb_usb_device *d) |
773 | { | 790 | { |
791 | struct usb_interface *intf = d->intf; | ||
774 | struct state *state = d_to_priv(d); | 792 | struct state *state = d_to_priv(d); |
775 | int ret, i; | 793 | int ret, i; |
776 | u8 tmp; | 794 | u8 tmp; |
@@ -805,7 +823,7 @@ static int af9035_read_config(struct dvb_usb_device *d) | |||
805 | goto err; | 823 | goto err; |
806 | 824 | ||
807 | if (tmp == 0x00) { | 825 | if (tmp == 0x00) { |
808 | dev_dbg(&d->udev->dev, "%s: no eeprom\n", __func__); | 826 | dev_dbg(&intf->dev, "no eeprom\n"); |
809 | goto skip_eeprom; | 827 | goto skip_eeprom; |
810 | } | 828 | } |
811 | } else if (state->chip_type == 0x9306) { | 829 | } else if (state->chip_type == 0x9306) { |
@@ -826,8 +844,7 @@ static int af9035_read_config(struct dvb_usb_device *d) | |||
826 | if (tmp == 1 || tmp == 3 || tmp == 5) | 844 | if (tmp == 1 || tmp == 3 || tmp == 5) |
827 | state->dual_mode = true; | 845 | state->dual_mode = true; |
828 | 846 | ||
829 | dev_dbg(&d->udev->dev, "%s: ts mode=%d dual mode=%d\n", __func__, | 847 | dev_dbg(&intf->dev, "ts mode=%d dual mode=%d\n", tmp, state->dual_mode); |
830 | tmp, state->dual_mode); | ||
831 | 848 | ||
832 | if (state->dual_mode) { | 849 | if (state->dual_mode) { |
833 | /* read 2nd demodulator I2C address */ | 850 | /* read 2nd demodulator I2C address */ |
@@ -840,8 +857,7 @@ static int af9035_read_config(struct dvb_usb_device *d) | |||
840 | if (tmp) | 857 | if (tmp) |
841 | state->af9033_i2c_addr[1] = tmp; | 858 | state->af9033_i2c_addr[1] = tmp; |
842 | 859 | ||
843 | dev_dbg(&d->udev->dev, "%s: 2nd demod I2C addr=%02x\n", | 860 | dev_dbg(&intf->dev, "2nd demod I2C addr=%02x\n", tmp); |
844 | __func__, tmp); | ||
845 | } | 861 | } |
846 | 862 | ||
847 | addr = state->eeprom_addr; | 863 | addr = state->eeprom_addr; |
@@ -852,8 +868,7 @@ static int af9035_read_config(struct dvb_usb_device *d) | |||
852 | if (ret < 0) | 868 | if (ret < 0) |
853 | goto err; | 869 | goto err; |
854 | 870 | ||
855 | dev_dbg(&d->udev->dev, "%s: [%d]tuner=%02x\n", | 871 | dev_dbg(&intf->dev, "[%d]tuner=%02x\n", i, tmp); |
856 | __func__, i, tmp); | ||
857 | 872 | ||
858 | /* tuner sanity check */ | 873 | /* tuner sanity check */ |
859 | if (state->chip_type == 0x9135) { | 874 | if (state->chip_type == 0x9135) { |
@@ -882,10 +897,8 @@ static int af9035_read_config(struct dvb_usb_device *d) | |||
882 | } | 897 | } |
883 | 898 | ||
884 | if (state->af9033_config[i].tuner != tmp) { | 899 | if (state->af9033_config[i].tuner != tmp) { |
885 | dev_info(&d->udev->dev, | 900 | dev_info(&intf->dev, "[%d] overriding tuner from %02x to %02x\n", |
886 | "%s: [%d] overriding tuner from %02x to %02x\n", | 901 | i, tmp, state->af9033_config[i].tuner); |
887 | KBUILD_MODNAME, i, tmp, | ||
888 | state->af9033_config[i].tuner); | ||
889 | } | 902 | } |
890 | 903 | ||
891 | switch (state->af9033_config[i].tuner) { | 904 | switch (state->af9033_config[i].tuner) { |
@@ -905,9 +918,8 @@ static int af9035_read_config(struct dvb_usb_device *d) | |||
905 | case AF9033_TUNER_IT9135_62: | 918 | case AF9033_TUNER_IT9135_62: |
906 | break; | 919 | break; |
907 | default: | 920 | default: |
908 | dev_warn(&d->udev->dev, | 921 | dev_warn(&intf->dev, "tuner id=%02x not supported, please report!", |
909 | "%s: tuner id=%02x not supported, please report!", | 922 | tmp); |
910 | KBUILD_MODNAME, tmp); | ||
911 | } | 923 | } |
912 | 924 | ||
913 | /* disable dual mode if driver does not support it */ | 925 | /* disable dual mode if driver does not support it */ |
@@ -924,9 +936,7 @@ static int af9035_read_config(struct dvb_usb_device *d) | |||
924 | break; | 936 | break; |
925 | default: | 937 | default: |
926 | state->dual_mode = false; | 938 | state->dual_mode = false; |
927 | dev_info(&d->udev->dev, | 939 | dev_info(&intf->dev, "driver does not support 2nd tuner and will disable it"); |
928 | "%s: driver does not support 2nd tuner and will disable it", | ||
929 | KBUILD_MODNAME); | ||
930 | } | 940 | } |
931 | 941 | ||
932 | /* tuner IF frequency */ | 942 | /* tuner IF frequency */ |
@@ -942,7 +952,7 @@ static int af9035_read_config(struct dvb_usb_device *d) | |||
942 | 952 | ||
943 | tmp16 |= tmp << 8; | 953 | tmp16 |= tmp << 8; |
944 | 954 | ||
945 | dev_dbg(&d->udev->dev, "%s: [%d]IF=%d\n", __func__, i, tmp16); | 955 | dev_dbg(&intf->dev, "[%d]IF=%d\n", i, tmp16); |
946 | 956 | ||
947 | addr += 0x10; /* shift for the 2nd tuner params */ | 957 | addr += 0x10; /* shift for the 2nd tuner params */ |
948 | } | 958 | } |
@@ -962,10 +972,24 @@ skip_eeprom: | |||
962 | state->af9033_config[i].clock = clock_lut_af9035[tmp]; | 972 | state->af9033_config[i].clock = clock_lut_af9035[tmp]; |
963 | } | 973 | } |
964 | 974 | ||
975 | state->no_read = false; | ||
976 | /* Some MXL5007T devices cannot properly handle tuner I2C read ops. */ | ||
977 | if (state->af9033_config[0].tuner == AF9033_TUNER_MXL5007T && | ||
978 | le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_AVERMEDIA) | ||
979 | |||
980 | switch (le16_to_cpu(d->udev->descriptor.idProduct)) { | ||
981 | case USB_PID_AVERMEDIA_A867: | ||
982 | case USB_PID_AVERMEDIA_TWINSTAR: | ||
983 | dev_info(&intf->dev, | ||
984 | "Device may have issues with I2C read operations. Enabling fix.\n"); | ||
985 | state->no_read = true; | ||
986 | break; | ||
987 | } | ||
988 | |||
965 | return 0; | 989 | return 0; |
966 | 990 | ||
967 | err: | 991 | err: |
968 | dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); | 992 | dev_dbg(&intf->dev, "failed=%d\n", ret); |
969 | 993 | ||
970 | return ret; | 994 | return ret; |
971 | } | 995 | } |
@@ -973,10 +997,11 @@ err: | |||
973 | static int af9035_tua9001_tuner_callback(struct dvb_usb_device *d, | 997 | static int af9035_tua9001_tuner_callback(struct dvb_usb_device *d, |
974 | int cmd, int arg) | 998 | int cmd, int arg) |
975 | { | 999 | { |
1000 | struct usb_interface *intf = d->intf; | ||
976 | int ret; | 1001 | int ret; |
977 | u8 val; | 1002 | u8 val; |
978 | 1003 | ||
979 | dev_dbg(&d->udev->dev, "%s: cmd=%d arg=%d\n", __func__, cmd, arg); | 1004 | dev_dbg(&intf->dev, "cmd=%d arg=%d\n", cmd, arg); |
980 | 1005 | ||
981 | /* | 1006 | /* |
982 | * CEN always enabled by hardware wiring | 1007 | * CEN always enabled by hardware wiring |
@@ -1010,7 +1035,7 @@ static int af9035_tua9001_tuner_callback(struct dvb_usb_device *d, | |||
1010 | return 0; | 1035 | return 0; |
1011 | 1036 | ||
1012 | err: | 1037 | err: |
1013 | dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); | 1038 | dev_dbg(&intf->dev, "failed=%d\n", ret); |
1014 | 1039 | ||
1015 | return ret; | 1040 | return ret; |
1016 | } | 1041 | } |
@@ -1019,6 +1044,7 @@ err: | |||
1019 | static int af9035_fc0011_tuner_callback(struct dvb_usb_device *d, | 1044 | static int af9035_fc0011_tuner_callback(struct dvb_usb_device *d, |
1020 | int cmd, int arg) | 1045 | int cmd, int arg) |
1021 | { | 1046 | { |
1047 | struct usb_interface *intf = d->intf; | ||
1022 | int ret; | 1048 | int ret; |
1023 | 1049 | ||
1024 | switch (cmd) { | 1050 | switch (cmd) { |
@@ -1076,7 +1102,7 @@ static int af9035_fc0011_tuner_callback(struct dvb_usb_device *d, | |||
1076 | return 0; | 1102 | return 0; |
1077 | 1103 | ||
1078 | err: | 1104 | err: |
1079 | dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); | 1105 | dev_dbg(&intf->dev, "failed=%d\n", ret); |
1080 | 1106 | ||
1081 | return ret; | 1107 | return ret; |
1082 | } | 1108 | } |
@@ -1102,9 +1128,10 @@ static int af9035_frontend_callback(void *adapter_priv, int component, | |||
1102 | { | 1128 | { |
1103 | struct i2c_adapter *adap = adapter_priv; | 1129 | struct i2c_adapter *adap = adapter_priv; |
1104 | struct dvb_usb_device *d = i2c_get_adapdata(adap); | 1130 | struct dvb_usb_device *d = i2c_get_adapdata(adap); |
1131 | struct usb_interface *intf = d->intf; | ||
1105 | 1132 | ||
1106 | dev_dbg(&d->udev->dev, "%s: component=%d cmd=%d arg=%d\n", | 1133 | dev_dbg(&intf->dev, "component=%d cmd=%d arg=%d\n", |
1107 | __func__, component, cmd, arg); | 1134 | component, cmd, arg); |
1108 | 1135 | ||
1109 | switch (component) { | 1136 | switch (component) { |
1110 | case DVB_FRONTEND_COMPONENT_TUNER: | 1137 | case DVB_FRONTEND_COMPONENT_TUNER: |
@@ -1127,9 +1154,10 @@ static int af9035_frontend_attach(struct dvb_usb_adapter *adap) | |||
1127 | { | 1154 | { |
1128 | struct state *state = adap_to_priv(adap); | 1155 | struct state *state = adap_to_priv(adap); |
1129 | struct dvb_usb_device *d = adap_to_d(adap); | 1156 | struct dvb_usb_device *d = adap_to_d(adap); |
1157 | struct usb_interface *intf = d->intf; | ||
1130 | int ret; | 1158 | int ret; |
1131 | 1159 | ||
1132 | dev_dbg(&d->udev->dev, "%s: adap->id=%d\n", __func__, adap->id); | 1160 | dev_dbg(&intf->dev, "adap->id=%d\n", adap->id); |
1133 | 1161 | ||
1134 | if (!state->af9033_config[adap->id].tuner) { | 1162 | if (!state->af9033_config[adap->id].tuner) { |
1135 | /* unsupported tuner */ | 1163 | /* unsupported tuner */ |
@@ -1156,7 +1184,7 @@ static int af9035_frontend_attach(struct dvb_usb_adapter *adap) | |||
1156 | return 0; | 1184 | return 0; |
1157 | 1185 | ||
1158 | err: | 1186 | err: |
1159 | dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); | 1187 | dev_dbg(&intf->dev, "failed=%d\n", ret); |
1160 | 1188 | ||
1161 | return ret; | 1189 | return ret; |
1162 | } | 1190 | } |
@@ -1165,11 +1193,12 @@ static int it930x_frontend_attach(struct dvb_usb_adapter *adap) | |||
1165 | { | 1193 | { |
1166 | struct state *state = adap_to_priv(adap); | 1194 | struct state *state = adap_to_priv(adap); |
1167 | struct dvb_usb_device *d = adap_to_d(adap); | 1195 | struct dvb_usb_device *d = adap_to_d(adap); |
1196 | struct usb_interface *intf = d->intf; | ||
1168 | int ret; | 1197 | int ret; |
1169 | struct si2168_config si2168_config; | 1198 | struct si2168_config si2168_config; |
1170 | struct i2c_adapter *adapter; | 1199 | struct i2c_adapter *adapter; |
1171 | 1200 | ||
1172 | dev_dbg(&d->udev->dev, "adap->id=%d\n", adap->id); | 1201 | dev_dbg(&intf->dev, "adap->id=%d\n", adap->id); |
1173 | 1202 | ||
1174 | memset(&si2168_config, 0, sizeof(si2168_config)); | 1203 | memset(&si2168_config, 0, sizeof(si2168_config)); |
1175 | si2168_config.i2c_adapter = &adapter; | 1204 | si2168_config.i2c_adapter = &adapter; |
@@ -1192,7 +1221,7 @@ static int it930x_frontend_attach(struct dvb_usb_adapter *adap) | |||
1192 | return 0; | 1221 | return 0; |
1193 | 1222 | ||
1194 | err: | 1223 | err: |
1195 | dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); | 1224 | dev_dbg(&intf->dev, "failed=%d\n", ret); |
1196 | 1225 | ||
1197 | return ret; | 1226 | return ret; |
1198 | } | 1227 | } |
@@ -1201,9 +1230,10 @@ static int af9035_frontend_detach(struct dvb_usb_adapter *adap) | |||
1201 | { | 1230 | { |
1202 | struct state *state = adap_to_priv(adap); | 1231 | struct state *state = adap_to_priv(adap); |
1203 | struct dvb_usb_device *d = adap_to_d(adap); | 1232 | struct dvb_usb_device *d = adap_to_d(adap); |
1233 | struct usb_interface *intf = d->intf; | ||
1204 | int demod2; | 1234 | int demod2; |
1205 | 1235 | ||
1206 | dev_dbg(&d->udev->dev, "%s: adap->id=%d\n", __func__, adap->id); | 1236 | dev_dbg(&intf->dev, "adap->id=%d\n", adap->id); |
1207 | 1237 | ||
1208 | /* | 1238 | /* |
1209 | * For dual tuner devices we have to resolve 2nd demod client, as there | 1239 | * For dual tuner devices we have to resolve 2nd demod client, as there |
@@ -1279,12 +1309,13 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap) | |||
1279 | { | 1309 | { |
1280 | struct state *state = adap_to_priv(adap); | 1310 | struct state *state = adap_to_priv(adap); |
1281 | struct dvb_usb_device *d = adap_to_d(adap); | 1311 | struct dvb_usb_device *d = adap_to_d(adap); |
1312 | struct usb_interface *intf = d->intf; | ||
1282 | int ret; | 1313 | int ret; |
1283 | struct dvb_frontend *fe; | 1314 | struct dvb_frontend *fe; |
1284 | struct i2c_msg msg[1]; | 1315 | struct i2c_msg msg[1]; |
1285 | u8 tuner_addr; | 1316 | u8 tuner_addr; |
1286 | 1317 | ||
1287 | dev_dbg(&d->udev->dev, "%s: adap->id=%d\n", __func__, adap->id); | 1318 | dev_dbg(&intf->dev, "adap->id=%d\n", adap->id); |
1288 | 1319 | ||
1289 | /* | 1320 | /* |
1290 | * XXX: Hack used in that function: we abuse unused I2C address bit [7] | 1321 | * XXX: Hack used in that function: we abuse unused I2C address bit [7] |
@@ -1522,7 +1553,7 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap) | |||
1522 | return 0; | 1553 | return 0; |
1523 | 1554 | ||
1524 | err: | 1555 | err: |
1525 | dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); | 1556 | dev_dbg(&intf->dev, "failed=%d\n", ret); |
1526 | 1557 | ||
1527 | return ret; | 1558 | return ret; |
1528 | } | 1559 | } |
@@ -1531,10 +1562,11 @@ static int it930x_tuner_attach(struct dvb_usb_adapter *adap) | |||
1531 | { | 1562 | { |
1532 | struct state *state = adap_to_priv(adap); | 1563 | struct state *state = adap_to_priv(adap); |
1533 | struct dvb_usb_device *d = adap_to_d(adap); | 1564 | struct dvb_usb_device *d = adap_to_d(adap); |
1565 | struct usb_interface *intf = d->intf; | ||
1534 | int ret; | 1566 | int ret; |
1535 | struct si2157_config si2157_config; | 1567 | struct si2157_config si2157_config; |
1536 | 1568 | ||
1537 | dev_dbg(&d->udev->dev, "%s: adap->id=%d\n", __func__, adap->id); | 1569 | dev_dbg(&intf->dev, "adap->id=%d\n", adap->id); |
1538 | 1570 | ||
1539 | /* I2C master bus 2 clock speed 300k */ | 1571 | /* I2C master bus 2 clock speed 300k */ |
1540 | ret = af9035_wr_reg(d, 0x00f6a7, 0x07); | 1572 | ret = af9035_wr_reg(d, 0x00f6a7, 0x07); |
@@ -1590,7 +1622,7 @@ static int it930x_tuner_attach(struct dvb_usb_adapter *adap) | |||
1590 | return 0; | 1622 | return 0; |
1591 | 1623 | ||
1592 | err: | 1624 | err: |
1593 | dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); | 1625 | dev_dbg(&intf->dev, "failed=%d\n", ret); |
1594 | 1626 | ||
1595 | return ret; | 1627 | return ret; |
1596 | } | 1628 | } |
@@ -1600,8 +1632,9 @@ static int it930x_tuner_detach(struct dvb_usb_adapter *adap) | |||
1600 | { | 1632 | { |
1601 | struct state *state = adap_to_priv(adap); | 1633 | struct state *state = adap_to_priv(adap); |
1602 | struct dvb_usb_device *d = adap_to_d(adap); | 1634 | struct dvb_usb_device *d = adap_to_d(adap); |
1635 | struct usb_interface *intf = d->intf; | ||
1603 | 1636 | ||
1604 | dev_dbg(&d->udev->dev, "adap->id=%d\n", adap->id); | 1637 | dev_dbg(&intf->dev, "adap->id=%d\n", adap->id); |
1605 | 1638 | ||
1606 | if (adap->id == 1) { | 1639 | if (adap->id == 1) { |
1607 | if (state->i2c_client[3]) | 1640 | if (state->i2c_client[3]) |
@@ -1619,8 +1652,9 @@ static int af9035_tuner_detach(struct dvb_usb_adapter *adap) | |||
1619 | { | 1652 | { |
1620 | struct state *state = adap_to_priv(adap); | 1653 | struct state *state = adap_to_priv(adap); |
1621 | struct dvb_usb_device *d = adap_to_d(adap); | 1654 | struct dvb_usb_device *d = adap_to_d(adap); |
1655 | struct usb_interface *intf = d->intf; | ||
1622 | 1656 | ||
1623 | dev_dbg(&d->udev->dev, "%s: adap->id=%d\n", __func__, adap->id); | 1657 | dev_dbg(&intf->dev, "adap->id=%d\n", adap->id); |
1624 | 1658 | ||
1625 | switch (state->af9033_config[adap->id].tuner) { | 1659 | switch (state->af9033_config[adap->id].tuner) { |
1626 | case AF9033_TUNER_TUA9001: | 1660 | case AF9033_TUNER_TUA9001: |
@@ -1646,6 +1680,7 @@ static int af9035_tuner_detach(struct dvb_usb_adapter *adap) | |||
1646 | static int af9035_init(struct dvb_usb_device *d) | 1680 | static int af9035_init(struct dvb_usb_device *d) |
1647 | { | 1681 | { |
1648 | struct state *state = d_to_priv(d); | 1682 | struct state *state = d_to_priv(d); |
1683 | struct usb_interface *intf = d->intf; | ||
1649 | int ret, i; | 1684 | int ret, i; |
1650 | u16 frame_size = (d->udev->speed == USB_SPEED_FULL ? 5 : 87) * 188 / 4; | 1685 | u16 frame_size = (d->udev->speed == USB_SPEED_FULL ? 5 : 87) * 188 / 4; |
1651 | u8 packet_size = (d->udev->speed == USB_SPEED_FULL ? 64 : 512) / 4; | 1686 | u8 packet_size = (d->udev->speed == USB_SPEED_FULL ? 64 : 512) / 4; |
@@ -1670,9 +1705,8 @@ static int af9035_init(struct dvb_usb_device *d) | |||
1670 | { 0x80f9a4, 0x00, 0x01 }, | 1705 | { 0x80f9a4, 0x00, 0x01 }, |
1671 | }; | 1706 | }; |
1672 | 1707 | ||
1673 | dev_dbg(&d->udev->dev, | 1708 | dev_dbg(&intf->dev, "USB speed=%d frame_size=%04x packet_size=%02x\n", |
1674 | "%s: USB speed=%d frame_size=%04x packet_size=%02x\n", | 1709 | d->udev->speed, frame_size, packet_size); |
1675 | __func__, d->udev->speed, frame_size, packet_size); | ||
1676 | 1710 | ||
1677 | /* init endpoints */ | 1711 | /* init endpoints */ |
1678 | for (i = 0; i < ARRAY_SIZE(tab); i++) { | 1712 | for (i = 0; i < ARRAY_SIZE(tab); i++) { |
@@ -1685,7 +1719,7 @@ static int af9035_init(struct dvb_usb_device *d) | |||
1685 | return 0; | 1719 | return 0; |
1686 | 1720 | ||
1687 | err: | 1721 | err: |
1688 | dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); | 1722 | dev_dbg(&intf->dev, "failed=%d\n", ret); |
1689 | 1723 | ||
1690 | return ret; | 1724 | return ret; |
1691 | } | 1725 | } |
@@ -1693,6 +1727,7 @@ err: | |||
1693 | static int it930x_init(struct dvb_usb_device *d) | 1727 | static int it930x_init(struct dvb_usb_device *d) |
1694 | { | 1728 | { |
1695 | struct state *state = d_to_priv(d); | 1729 | struct state *state = d_to_priv(d); |
1730 | struct usb_interface *intf = d->intf; | ||
1696 | int ret, i; | 1731 | int ret, i; |
1697 | u16 frame_size = (d->udev->speed == USB_SPEED_FULL ? 5 : 816) * 188 / 4; | 1732 | u16 frame_size = (d->udev->speed == USB_SPEED_FULL ? 5 : 816) * 188 / 4; |
1698 | u8 packet_size = (d->udev->speed == USB_SPEED_FULL ? 64 : 512) / 4; | 1733 | u8 packet_size = (d->udev->speed == USB_SPEED_FULL ? 64 : 512) / 4; |
@@ -1752,9 +1787,8 @@ static int it930x_init(struct dvb_usb_device *d) | |||
1752 | { 0x00da5a, 0x1f, 0xff }, /* ts_fail_ignore */ | 1787 | { 0x00da5a, 0x1f, 0xff }, /* ts_fail_ignore */ |
1753 | }; | 1788 | }; |
1754 | 1789 | ||
1755 | dev_dbg(&d->udev->dev, | 1790 | dev_dbg(&intf->dev, "USB speed=%d frame_size=%04x packet_size=%02x\n", |
1756 | "%s: USB speed=%d frame_size=%04x packet_size=%02x\n", | 1791 | d->udev->speed, frame_size, packet_size); |
1757 | __func__, d->udev->speed, frame_size, packet_size); | ||
1758 | 1792 | ||
1759 | /* init endpoints */ | 1793 | /* init endpoints */ |
1760 | for (i = 0; i < ARRAY_SIZE(tab); i++) { | 1794 | for (i = 0; i < ARRAY_SIZE(tab); i++) { |
@@ -1767,7 +1801,7 @@ static int it930x_init(struct dvb_usb_device *d) | |||
1767 | 1801 | ||
1768 | return 0; | 1802 | return 0; |
1769 | err: | 1803 | err: |
1770 | dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); | 1804 | dev_dbg(&intf->dev, "failed=%d\n", ret); |
1771 | 1805 | ||
1772 | return ret; | 1806 | return ret; |
1773 | } | 1807 | } |
@@ -1776,6 +1810,7 @@ err: | |||
1776 | #if IS_ENABLED(CONFIG_RC_CORE) | 1810 | #if IS_ENABLED(CONFIG_RC_CORE) |
1777 | static int af9035_rc_query(struct dvb_usb_device *d) | 1811 | static int af9035_rc_query(struct dvb_usb_device *d) |
1778 | { | 1812 | { |
1813 | struct usb_interface *intf = d->intf; | ||
1779 | int ret; | 1814 | int ret; |
1780 | u32 key; | 1815 | u32 key; |
1781 | u8 buf[4]; | 1816 | u8 buf[4]; |
@@ -1801,14 +1836,14 @@ static int af9035_rc_query(struct dvb_usb_device *d) | |||
1801 | buf[2] << 8 | buf[3]); | 1836 | buf[2] << 8 | buf[3]); |
1802 | } | 1837 | } |
1803 | 1838 | ||
1804 | dev_dbg(&d->udev->dev, "%s: %*ph\n", __func__, 4, buf); | 1839 | dev_dbg(&intf->dev, "%*ph\n", 4, buf); |
1805 | 1840 | ||
1806 | rc_keydown(d->rc_dev, RC_TYPE_NEC, key, 0); | 1841 | rc_keydown(d->rc_dev, RC_TYPE_NEC, key, 0); |
1807 | 1842 | ||
1808 | return 0; | 1843 | return 0; |
1809 | 1844 | ||
1810 | err: | 1845 | err: |
1811 | dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); | 1846 | dev_dbg(&intf->dev, "failed=%d\n", ret); |
1812 | 1847 | ||
1813 | return ret; | 1848 | return ret; |
1814 | } | 1849 | } |
@@ -1816,6 +1851,7 @@ err: | |||
1816 | static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) | 1851 | static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) |
1817 | { | 1852 | { |
1818 | struct state *state = d_to_priv(d); | 1853 | struct state *state = d_to_priv(d); |
1854 | struct usb_interface *intf = d->intf; | ||
1819 | int ret; | 1855 | int ret; |
1820 | u8 tmp; | 1856 | u8 tmp; |
1821 | 1857 | ||
@@ -1823,7 +1859,7 @@ static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) | |||
1823 | if (ret < 0) | 1859 | if (ret < 0) |
1824 | goto err; | 1860 | goto err; |
1825 | 1861 | ||
1826 | dev_dbg(&d->udev->dev, "%s: ir_mode=%02x\n", __func__, tmp); | 1862 | dev_dbg(&intf->dev, "ir_mode=%02x\n", tmp); |
1827 | 1863 | ||
1828 | /* don't activate rc if in HID mode or if not available */ | 1864 | /* don't activate rc if in HID mode or if not available */ |
1829 | if (tmp == 5) { | 1865 | if (tmp == 5) { |
@@ -1832,7 +1868,7 @@ static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) | |||
1832 | if (ret < 0) | 1868 | if (ret < 0) |
1833 | goto err; | 1869 | goto err; |
1834 | 1870 | ||
1835 | dev_dbg(&d->udev->dev, "%s: ir_type=%02x\n", __func__, tmp); | 1871 | dev_dbg(&intf->dev, "ir_type=%02x\n", tmp); |
1836 | 1872 | ||
1837 | switch (tmp) { | 1873 | switch (tmp) { |
1838 | case 0: /* NEC */ | 1874 | case 0: /* NEC */ |
@@ -1855,7 +1891,7 @@ static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) | |||
1855 | return 0; | 1891 | return 0; |
1856 | 1892 | ||
1857 | err: | 1893 | err: |
1858 | dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); | 1894 | dev_dbg(&intf->dev, "failed=%d\n", ret); |
1859 | 1895 | ||
1860 | return ret; | 1896 | return ret; |
1861 | } | 1897 | } |
@@ -1867,8 +1903,9 @@ static int af9035_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, | |||
1867 | struct usb_data_stream_properties *stream) | 1903 | struct usb_data_stream_properties *stream) |
1868 | { | 1904 | { |
1869 | struct dvb_usb_device *d = fe_to_d(fe); | 1905 | struct dvb_usb_device *d = fe_to_d(fe); |
1906 | struct usb_interface *intf = d->intf; | ||
1870 | 1907 | ||
1871 | dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, fe_to_adap(fe)->id); | 1908 | dev_dbg(&intf->dev, "adap=%d\n", fe_to_adap(fe)->id); |
1872 | 1909 | ||
1873 | if (d->udev->speed == USB_SPEED_FULL) | 1910 | if (d->udev->speed == USB_SPEED_FULL) |
1874 | stream->u.bulk.buffersize = 5 * 188; | 1911 | stream->u.bulk.buffersize = 5 * 188; |
@@ -1920,7 +1957,7 @@ static int af9035_probe(struct usb_interface *intf, | |||
1920 | if ((le16_to_cpu(udev->descriptor.idVendor) == USB_VID_TERRATEC) && | 1957 | if ((le16_to_cpu(udev->descriptor.idVendor) == USB_VID_TERRATEC) && |
1921 | (le16_to_cpu(udev->descriptor.idProduct) == 0x0099)) { | 1958 | (le16_to_cpu(udev->descriptor.idProduct) == 0x0099)) { |
1922 | if (!strcmp("Afatech", manufacturer)) { | 1959 | if (!strcmp("Afatech", manufacturer)) { |
1923 | dev_dbg(&udev->dev, "%s: rejecting device\n", __func__); | 1960 | dev_dbg(&udev->dev, "rejecting device\n"); |
1924 | return -ENODEV; | 1961 | return -ENODEV; |
1925 | } | 1962 | } |
1926 | } | 1963 | } |
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h index 89e629a24aec..c91d1a3789e6 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.h +++ b/drivers/media/usb/dvb-usb-v2/af9035.h | |||
@@ -62,6 +62,7 @@ struct state { | |||
62 | u8 chip_version; | 62 | u8 chip_version; |
63 | u16 chip_type; | 63 | u16 chip_type; |
64 | u8 dual_mode:1; | 64 | u8 dual_mode:1; |
65 | u8 no_read:1; | ||
65 | u16 eeprom_addr; | 66 | u16 eeprom_addr; |
66 | u8 af9033_i2c_addr[2]; | 67 | u8 af9033_i2c_addr[2]; |
67 | struct af9033_config af9033_config[2]; | 68 | struct af9033_config af9033_config[2]; |
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index eb7af8cb8aca..6643762a9ff7 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c | |||
@@ -624,7 +624,7 @@ static int rtl28xxu_identify_state(struct dvb_usb_device *d, const char **name) | |||
624 | dev_dbg(&d->intf->dev, "chip_id=%u\n", dev->chip_id); | 624 | dev_dbg(&d->intf->dev, "chip_id=%u\n", dev->chip_id); |
625 | 625 | ||
626 | /* Retry failed I2C messages */ | 626 | /* Retry failed I2C messages */ |
627 | d->i2c_adap.retries = 1; | 627 | d->i2c_adap.retries = 3; |
628 | d->i2c_adap.timeout = msecs_to_jiffies(10); | 628 | d->i2c_adap.timeout = msecs_to_jiffies(10); |
629 | 629 | ||
630 | return WARM; | 630 | return WARM; |
diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index a19b5c8b56ff..1a9e1e556706 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c | |||
@@ -507,9 +507,8 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, | |||
507 | if (dev->disconnected) | 507 | if (dev->disconnected) |
508 | return -ENODEV; | 508 | return -ENODEV; |
509 | 509 | ||
510 | rc = rt_mutex_trylock(&dev->i2c_bus_lock); | 510 | if (!rt_mutex_trylock(&dev->i2c_bus_lock)) |
511 | if (rc < 0) | 511 | return -EAGAIN; |
512 | return rc; | ||
513 | 512 | ||
514 | /* Switch I2C bus if needed */ | 513 | /* Switch I2C bus if needed */ |
515 | if (bus != dev->cur_i2c_bus && | 514 | if (bus != dev->cur_i2c_bus && |
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 451e84e962e2..302e284a95eb 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c | |||
@@ -1674,7 +1674,7 @@ static void uvc_delete(struct uvc_device *dev) | |||
1674 | if (dev->vdev.dev) | 1674 | if (dev->vdev.dev) |
1675 | v4l2_device_unregister(&dev->vdev); | 1675 | v4l2_device_unregister(&dev->vdev); |
1676 | #ifdef CONFIG_MEDIA_CONTROLLER | 1676 | #ifdef CONFIG_MEDIA_CONTROLLER |
1677 | if (media_devnode_is_registered(&dev->mdev.devnode)) | 1677 | if (media_devnode_is_registered(dev->mdev.devnode)) |
1678 | media_device_unregister(&dev->mdev); | 1678 | media_device_unregister(&dev->mdev); |
1679 | media_device_cleanup(&dev->mdev); | 1679 | media_device_cleanup(&dev->mdev); |
1680 | #endif | 1680 | #endif |
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index c04bc6afb965..05eed4be25df 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c | |||
@@ -142,6 +142,21 @@ static __u32 uvc_try_frame_interval(struct uvc_frame *frame, __u32 interval) | |||
142 | return interval; | 142 | return interval; |
143 | } | 143 | } |
144 | 144 | ||
145 | static __u32 uvc_v4l2_get_bytesperline(const struct uvc_format *format, | ||
146 | const struct uvc_frame *frame) | ||
147 | { | ||
148 | switch (format->fcc) { | ||
149 | case V4L2_PIX_FMT_NV12: | ||
150 | case V4L2_PIX_FMT_YVU420: | ||
151 | case V4L2_PIX_FMT_YUV420: | ||
152 | case V4L2_PIX_FMT_M420: | ||
153 | return frame->wWidth; | ||
154 | |||
155 | default: | ||
156 | return format->bpp * frame->wWidth / 8; | ||
157 | } | ||
158 | } | ||
159 | |||
145 | static int uvc_v4l2_try_format(struct uvc_streaming *stream, | 160 | static int uvc_v4l2_try_format(struct uvc_streaming *stream, |
146 | struct v4l2_format *fmt, struct uvc_streaming_control *probe, | 161 | struct v4l2_format *fmt, struct uvc_streaming_control *probe, |
147 | struct uvc_format **uvc_format, struct uvc_frame **uvc_frame) | 162 | struct uvc_format **uvc_format, struct uvc_frame **uvc_frame) |
@@ -245,7 +260,7 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, | |||
245 | fmt->fmt.pix.width = frame->wWidth; | 260 | fmt->fmt.pix.width = frame->wWidth; |
246 | fmt->fmt.pix.height = frame->wHeight; | 261 | fmt->fmt.pix.height = frame->wHeight; |
247 | fmt->fmt.pix.field = V4L2_FIELD_NONE; | 262 | fmt->fmt.pix.field = V4L2_FIELD_NONE; |
248 | fmt->fmt.pix.bytesperline = format->bpp * frame->wWidth / 8; | 263 | fmt->fmt.pix.bytesperline = uvc_v4l2_get_bytesperline(format, frame); |
249 | fmt->fmt.pix.sizeimage = probe->dwMaxVideoFrameSize; | 264 | fmt->fmt.pix.sizeimage = probe->dwMaxVideoFrameSize; |
250 | fmt->fmt.pix.colorspace = format->colorspace; | 265 | fmt->fmt.pix.colorspace = format->colorspace; |
251 | fmt->fmt.pix.priv = 0; | 266 | fmt->fmt.pix.priv = 0; |
@@ -282,7 +297,7 @@ static int uvc_v4l2_get_format(struct uvc_streaming *stream, | |||
282 | fmt->fmt.pix.width = frame->wWidth; | 297 | fmt->fmt.pix.width = frame->wWidth; |
283 | fmt->fmt.pix.height = frame->wHeight; | 298 | fmt->fmt.pix.height = frame->wHeight; |
284 | fmt->fmt.pix.field = V4L2_FIELD_NONE; | 299 | fmt->fmt.pix.field = V4L2_FIELD_NONE; |
285 | fmt->fmt.pix.bytesperline = format->bpp * frame->wWidth / 8; | 300 | fmt->fmt.pix.bytesperline = uvc_v4l2_get_bytesperline(format, frame); |
286 | fmt->fmt.pix.sizeimage = stream->ctrl.dwMaxVideoFrameSize; | 301 | fmt->fmt.pix.sizeimage = stream->ctrl.dwMaxVideoFrameSize; |
287 | fmt->fmt.pix.colorspace = format->colorspace; | 302 | fmt->fmt.pix.colorspace = format->colorspace; |
288 | fmt->fmt.pix.priv = 0; | 303 | fmt->fmt.pix.priv = 0; |
diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 075a0fe77485..b5589d5f5da4 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c | |||
@@ -1470,6 +1470,7 @@ static unsigned int uvc_endpoint_max_bpi(struct usb_device *dev, | |||
1470 | 1470 | ||
1471 | switch (dev->speed) { | 1471 | switch (dev->speed) { |
1472 | case USB_SPEED_SUPER: | 1472 | case USB_SPEED_SUPER: |
1473 | case USB_SPEED_SUPER_PLUS: | ||
1473 | return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval); | 1474 | return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval); |
1474 | case USB_SPEED_HIGH: | 1475 | case USB_SPEED_HIGH: |
1475 | psize = usb_endpoint_maxp(&ep->desc); | 1476 | psize = usb_endpoint_maxp(&ep->desc); |
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 9fbcb67a9ee6..633fc1ab1d7a 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c | |||
@@ -1648,7 +1648,7 @@ static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb, | |||
1648 | void *pb, int nonblocking) | 1648 | void *pb, int nonblocking) |
1649 | { | 1649 | { |
1650 | unsigned long flags; | 1650 | unsigned long flags; |
1651 | int ret; | 1651 | int ret = 0; |
1652 | 1652 | ||
1653 | /* | 1653 | /* |
1654 | * Wait for at least one buffer to become available on the done_list. | 1654 | * Wait for at least one buffer to become available on the done_list. |
@@ -1664,10 +1664,12 @@ static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb, | |||
1664 | spin_lock_irqsave(&q->done_lock, flags); | 1664 | spin_lock_irqsave(&q->done_lock, flags); |
1665 | *vb = list_first_entry(&q->done_list, struct vb2_buffer, done_entry); | 1665 | *vb = list_first_entry(&q->done_list, struct vb2_buffer, done_entry); |
1666 | /* | 1666 | /* |
1667 | * Only remove the buffer from done_list if v4l2_buffer can handle all | 1667 | * Only remove the buffer from done_list if all planes can be |
1668 | * the planes. | 1668 | * handled. Some cases such as V4L2 file I/O and DVB have pb |
1669 | * == NULL; skip the check then as there's nothing to verify. | ||
1669 | */ | 1670 | */ |
1670 | ret = call_bufop(q, verify_planes_array, *vb, pb); | 1671 | if (pb) |
1672 | ret = call_bufop(q, verify_planes_array, *vb, pb); | ||
1671 | if (!ret) | 1673 | if (!ret) |
1672 | list_del(&(*vb)->done_entry); | 1674 | list_del(&(*vb)->done_entry); |
1673 | spin_unlock_irqrestore(&q->done_lock, flags); | 1675 | spin_unlock_irqrestore(&q->done_lock, flags); |
diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c index 5361197f3e57..e3e47ace7daf 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c | |||
@@ -753,6 +753,59 @@ void vb2_dma_contig_cleanup_ctx(void *alloc_ctx) | |||
753 | } | 753 | } |
754 | EXPORT_SYMBOL_GPL(vb2_dma_contig_cleanup_ctx); | 754 | EXPORT_SYMBOL_GPL(vb2_dma_contig_cleanup_ctx); |
755 | 755 | ||
756 | /** | ||
757 | * vb2_dma_contig_set_max_seg_size() - configure DMA max segment size | ||
758 | * @dev: device for configuring DMA parameters | ||
759 | * @size: size of DMA max segment size to set | ||
760 | * | ||
761 | * To allow mapping the scatter-list into a single chunk in the DMA | ||
762 | * address space, the device is required to have the DMA max segment | ||
763 | * size parameter set to a value larger than the buffer size. Otherwise, | ||
764 | * the DMA-mapping subsystem will split the mapping into max segment | ||
765 | * size chunks. This function sets the DMA max segment size | ||
766 | * parameter to let DMA-mapping map a buffer as a single chunk in DMA | ||
767 | * address space. | ||
768 | * This code assumes that the DMA-mapping subsystem will merge all | ||
769 | * scatterlist segments if this is really possible (for example when | ||
770 | * an IOMMU is available and enabled). | ||
771 | * Ideally, this parameter should be set by the generic bus code, but it | ||
772 | * is left with the default 64KiB value due to historical litmiations in | ||
773 | * other subsystems (like limited USB host drivers) and there no good | ||
774 | * place to set it to the proper value. | ||
775 | * This function should be called from the drivers, which are known to | ||
776 | * operate on platforms with IOMMU and provide access to shared buffers | ||
777 | * (either USERPTR or DMABUF). This should be done before initializing | ||
778 | * videobuf2 queue. | ||
779 | */ | ||
780 | int vb2_dma_contig_set_max_seg_size(struct device *dev, unsigned int size) | ||
781 | { | ||
782 | if (!dev->dma_parms) { | ||
783 | dev->dma_parms = kzalloc(sizeof(dev->dma_parms), GFP_KERNEL); | ||
784 | if (!dev->dma_parms) | ||
785 | return -ENOMEM; | ||
786 | } | ||
787 | if (dma_get_max_seg_size(dev) < size) | ||
788 | return dma_set_max_seg_size(dev, size); | ||
789 | |||
790 | return 0; | ||
791 | } | ||
792 | EXPORT_SYMBOL_GPL(vb2_dma_contig_set_max_seg_size); | ||
793 | |||
794 | /* | ||
795 | * vb2_dma_contig_clear_max_seg_size() - release resources for DMA parameters | ||
796 | * @dev: device for configuring DMA parameters | ||
797 | * | ||
798 | * This function releases resources allocated to configure DMA parameters | ||
799 | * (see vb2_dma_contig_set_max_seg_size() function). It should be called from | ||
800 | * device drivers on driver remove. | ||
801 | */ | ||
802 | void vb2_dma_contig_clear_max_seg_size(struct device *dev) | ||
803 | { | ||
804 | kfree(dev->dma_parms); | ||
805 | dev->dma_parms = NULL; | ||
806 | } | ||
807 | EXPORT_SYMBOL_GPL(vb2_dma_contig_clear_max_seg_size); | ||
808 | |||
756 | MODULE_DESCRIPTION("DMA-contig memory handling routines for videobuf2"); | 809 | MODULE_DESCRIPTION("DMA-contig memory handling routines for videobuf2"); |
757 | MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>"); | 810 | MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>"); |
758 | MODULE_LICENSE("GPL"); | 811 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/media/v4l2-core/videobuf2-v4l2.c b/drivers/media/v4l2-core/videobuf2-v4l2.c index 0b1b8c7b6ce5..7f366f1b0377 100644 --- a/drivers/media/v4l2-core/videobuf2-v4l2.c +++ b/drivers/media/v4l2-core/videobuf2-v4l2.c | |||
@@ -74,6 +74,11 @@ static int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_buffer | |||
74 | return 0; | 74 | return 0; |
75 | } | 75 | } |
76 | 76 | ||
77 | static int __verify_planes_array_core(struct vb2_buffer *vb, const void *pb) | ||
78 | { | ||
79 | return __verify_planes_array(vb, pb); | ||
80 | } | ||
81 | |||
77 | /** | 82 | /** |
78 | * __verify_length() - Verify that the bytesused value for each plane fits in | 83 | * __verify_length() - Verify that the bytesused value for each plane fits in |
79 | * the plane length and that the data offset doesn't exceed the bytesused value. | 84 | * the plane length and that the data offset doesn't exceed the bytesused value. |
@@ -437,6 +442,7 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, | |||
437 | } | 442 | } |
438 | 443 | ||
439 | static const struct vb2_buf_ops v4l2_buf_ops = { | 444 | static const struct vb2_buf_ops v4l2_buf_ops = { |
445 | .verify_planes_array = __verify_planes_array_core, | ||
440 | .fill_user_buffer = __fill_v4l2_buffer, | 446 | .fill_user_buffer = __fill_v4l2_buffer, |
441 | .fill_vb2_buffer = __fill_vb2_buffer, | 447 | .fill_vb2_buffer = __fill_vb2_buffer, |
442 | .copy_timestamp = __copy_timestamp, | 448 | .copy_timestamp = __copy_timestamp, |
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index 216648233874..06af99f64ad8 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/sizes.h> | 21 | #include <linux/sizes.h> |
22 | #include <linux/of_reserved_mem.h> | 22 | #include <linux/of_reserved_mem.h> |
23 | #include <linux/sort.h> | 23 | #include <linux/sort.h> |
24 | #include <linux/slab.h> | ||
24 | 25 | ||
25 | #define MAX_RESERVED_REGIONS 16 | 26 | #define MAX_RESERVED_REGIONS 16 |
26 | static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS]; | 27 | static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS]; |
@@ -296,53 +297,95 @@ static inline struct reserved_mem *__find_rmem(struct device_node *node) | |||
296 | return NULL; | 297 | return NULL; |
297 | } | 298 | } |
298 | 299 | ||
300 | struct rmem_assigned_device { | ||
301 | struct device *dev; | ||
302 | struct reserved_mem *rmem; | ||
303 | struct list_head list; | ||
304 | }; | ||
305 | |||
306 | static LIST_HEAD(of_rmem_assigned_device_list); | ||
307 | static DEFINE_MUTEX(of_rmem_assigned_device_mutex); | ||
308 | |||
299 | /** | 309 | /** |
300 | * of_reserved_mem_device_init() - assign reserved memory region to given device | 310 | * of_reserved_mem_device_init_by_idx() - assign reserved memory region to |
311 | * given device | ||
312 | * @dev: Pointer to the device to configure | ||
313 | * @np: Pointer to the device_node with 'reserved-memory' property | ||
314 | * @idx: Index of selected region | ||
301 | * | 315 | * |
302 | * This function assign memory region pointed by "memory-region" device tree | 316 | * This function assigns respective DMA-mapping operations based on reserved |
303 | * property to the given device. | 317 | * memory region specified by 'memory-region' property in @np node to the @dev |
318 | * device. When driver needs to use more than one reserved memory region, it | ||
319 | * should allocate child devices and initialize regions by name for each of | ||
320 | * child device. | ||
321 | * | ||
322 | * Returns error code or zero on success. | ||
304 | */ | 323 | */ |
305 | int of_reserved_mem_device_init(struct device *dev) | 324 | int of_reserved_mem_device_init_by_idx(struct device *dev, |
325 | struct device_node *np, int idx) | ||
306 | { | 326 | { |
327 | struct rmem_assigned_device *rd; | ||
328 | struct device_node *target; | ||
307 | struct reserved_mem *rmem; | 329 | struct reserved_mem *rmem; |
308 | struct device_node *np; | ||
309 | int ret; | 330 | int ret; |
310 | 331 | ||
311 | np = of_parse_phandle(dev->of_node, "memory-region", 0); | 332 | if (!np || !dev) |
312 | if (!np) | 333 | return -EINVAL; |
334 | |||
335 | target = of_parse_phandle(np, "memory-region", idx); | ||
336 | if (!target) | ||
313 | return -ENODEV; | 337 | return -ENODEV; |
314 | 338 | ||
315 | rmem = __find_rmem(np); | 339 | rmem = __find_rmem(target); |
316 | of_node_put(np); | 340 | of_node_put(target); |
317 | 341 | ||
318 | if (!rmem || !rmem->ops || !rmem->ops->device_init) | 342 | if (!rmem || !rmem->ops || !rmem->ops->device_init) |
319 | return -EINVAL; | 343 | return -EINVAL; |
320 | 344 | ||
345 | rd = kmalloc(sizeof(struct rmem_assigned_device), GFP_KERNEL); | ||
346 | if (!rd) | ||
347 | return -ENOMEM; | ||
348 | |||
321 | ret = rmem->ops->device_init(rmem, dev); | 349 | ret = rmem->ops->device_init(rmem, dev); |
322 | if (ret == 0) | 350 | if (ret == 0) { |
351 | rd->dev = dev; | ||
352 | rd->rmem = rmem; | ||
353 | |||
354 | mutex_lock(&of_rmem_assigned_device_mutex); | ||
355 | list_add(&rd->list, &of_rmem_assigned_device_list); | ||
356 | mutex_unlock(&of_rmem_assigned_device_mutex); | ||
357 | |||
323 | dev_info(dev, "assigned reserved memory node %s\n", rmem->name); | 358 | dev_info(dev, "assigned reserved memory node %s\n", rmem->name); |
359 | } else { | ||
360 | kfree(rd); | ||
361 | } | ||
324 | 362 | ||
325 | return ret; | 363 | return ret; |
326 | } | 364 | } |
327 | EXPORT_SYMBOL_GPL(of_reserved_mem_device_init); | 365 | EXPORT_SYMBOL_GPL(of_reserved_mem_device_init_by_idx); |
328 | 366 | ||
329 | /** | 367 | /** |
330 | * of_reserved_mem_device_release() - release reserved memory device structures | 368 | * of_reserved_mem_device_release() - release reserved memory device structures |
369 | * @dev: Pointer to the device to deconfigure | ||
331 | * | 370 | * |
332 | * This function releases structures allocated for memory region handling for | 371 | * This function releases structures allocated for memory region handling for |
333 | * the given device. | 372 | * the given device. |
334 | */ | 373 | */ |
335 | void of_reserved_mem_device_release(struct device *dev) | 374 | void of_reserved_mem_device_release(struct device *dev) |
336 | { | 375 | { |
337 | struct reserved_mem *rmem; | 376 | struct rmem_assigned_device *rd; |
338 | struct device_node *np; | 377 | struct reserved_mem *rmem = NULL; |
339 | 378 | ||
340 | np = of_parse_phandle(dev->of_node, "memory-region", 0); | 379 | mutex_lock(&of_rmem_assigned_device_mutex); |
341 | if (!np) | 380 | list_for_each_entry(rd, &of_rmem_assigned_device_list, list) { |
342 | return; | 381 | if (rd->dev == dev) { |
343 | 382 | rmem = rd->rmem; | |
344 | rmem = __find_rmem(np); | 383 | list_del(&rd->list); |
345 | of_node_put(np); | 384 | kfree(rd); |
385 | break; | ||
386 | } | ||
387 | } | ||
388 | mutex_unlock(&of_rmem_assigned_device_mutex); | ||
346 | 389 | ||
347 | if (!rmem || !rmem->ops || !rmem->ops->device_release) | 390 | if (!rmem || !rmem->ops || !rmem->ops->device_release) |
348 | return; | 391 | return; |
diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index de7e9f52e7eb..ee9186843371 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig | |||
@@ -25,18 +25,8 @@ source "drivers/staging/media/cxd2099/Kconfig" | |||
25 | 25 | ||
26 | source "drivers/staging/media/davinci_vpfe/Kconfig" | 26 | source "drivers/staging/media/davinci_vpfe/Kconfig" |
27 | 27 | ||
28 | source "drivers/staging/media/mn88472/Kconfig" | ||
29 | |||
30 | source "drivers/staging/media/mx2/Kconfig" | ||
31 | |||
32 | source "drivers/staging/media/mx3/Kconfig" | ||
33 | |||
34 | source "drivers/staging/media/omap1/Kconfig" | ||
35 | |||
36 | source "drivers/staging/media/omap4iss/Kconfig" | 28 | source "drivers/staging/media/omap4iss/Kconfig" |
37 | 29 | ||
38 | source "drivers/staging/media/timb/Kconfig" | ||
39 | |||
40 | source "drivers/staging/media/tw686x-kh/Kconfig" | 30 | source "drivers/staging/media/tw686x-kh/Kconfig" |
41 | 31 | ||
42 | # Keep LIRC at the end, as it has sub-menus | 32 | # Keep LIRC at the end, as it has sub-menus |
diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index 60a35b3a47e7..8c05d0ace0fb 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile | |||
@@ -2,10 +2,5 @@ obj-$(CONFIG_I2C_BCM2048) += bcm2048/ | |||
2 | obj-$(CONFIG_DVB_CXD2099) += cxd2099/ | 2 | obj-$(CONFIG_DVB_CXD2099) += cxd2099/ |
3 | obj-$(CONFIG_LIRC_STAGING) += lirc/ | 3 | obj-$(CONFIG_LIRC_STAGING) += lirc/ |
4 | obj-$(CONFIG_VIDEO_DM365_VPFE) += davinci_vpfe/ | 4 | obj-$(CONFIG_VIDEO_DM365_VPFE) += davinci_vpfe/ |
5 | obj-$(CONFIG_VIDEO_MX2) += mx2/ | ||
6 | obj-$(CONFIG_VIDEO_MX3) += mx3/ | ||
7 | obj-$(CONFIG_VIDEO_OMAP1) += omap1/ | ||
8 | obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/ | 5 | obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/ |
9 | obj-$(CONFIG_DVB_MN88472) += mn88472/ | ||
10 | obj-$(CONFIG_VIDEO_TIMBERDALE) += timb/ | ||
11 | obj-$(CONFIG_VIDEO_TW686X_KH) += tw686x-kh/ | 6 | obj-$(CONFIG_VIDEO_TW686X_KH) += tw686x-kh/ |
diff --git a/drivers/staging/media/mn88472/Kconfig b/drivers/staging/media/mn88472/Kconfig deleted file mode 100644 index a85c90a60bce..000000000000 --- a/drivers/staging/media/mn88472/Kconfig +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | config DVB_MN88472 | ||
2 | tristate "Panasonic MN88472" | ||
3 | depends on DVB_CORE && I2C | ||
4 | select REGMAP_I2C | ||
5 | default m if !MEDIA_SUBDRV_AUTOSELECT | ||
6 | help | ||
7 | Say Y when you want to support this frontend. | ||
diff --git a/drivers/staging/media/mn88472/Makefile b/drivers/staging/media/mn88472/Makefile deleted file mode 100644 index 5987b7e6d82a..000000000000 --- a/drivers/staging/media/mn88472/Makefile +++ /dev/null | |||
@@ -1,5 +0,0 @@ | |||
1 | obj-$(CONFIG_DVB_MN88472) += mn88472.o | ||
2 | |||
3 | ccflags-y += -Idrivers/media/dvb-core/ | ||
4 | ccflags-y += -Idrivers/media/dvb-frontends/ | ||
5 | ccflags-y += -Idrivers/media/tuners/ | ||
diff --git a/drivers/staging/media/mn88472/TODO b/drivers/staging/media/mn88472/TODO deleted file mode 100644 index b90a14be3beb..000000000000 --- a/drivers/staging/media/mn88472/TODO +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | Driver general quality is not good enough for mainline. Also, other | ||
2 | device drivers (USB-bridge, tuner) needed for Astrometa receiver in | ||
3 | question could need some changes. However, if that driver is mainlined | ||
4 | due to some other device than Astrometa, unrelated TODOs could be | ||
5 | skipped. In that case rtl28xxu driver needs module parameter to prevent | ||
6 | driver loading. | ||
7 | |||
8 | Required TODOs: | ||
9 | * missing lock flags | ||
10 | * I2C errors | ||
11 | * tuner sensitivity | ||
12 | |||
13 | *Do not* send any patch fixing checkpatch.pl issues. Currently it passes | ||
14 | checkpatch.pl tests. I don't want waste my time to review this kind of | ||
15 | trivial stuff. *Do not* add missing register I/O error checks. Those are | ||
16 | missing for the reason it is much easier to compare I2C data sniffs when | ||
17 | there is less lines. Those error checks are about the last thing to be added. | ||
18 | |||
19 | Patches should be submitted to: | ||
20 | linux-media@vger.kernel.org and Antti Palosaari <crope@iki.fi> | ||
21 | |||
diff --git a/drivers/staging/media/mx2/Kconfig b/drivers/staging/media/mx2/Kconfig deleted file mode 100644 index beaa885cf104..000000000000 --- a/drivers/staging/media/mx2/Kconfig +++ /dev/null | |||
@@ -1,15 +0,0 @@ | |||
1 | config VIDEO_MX2 | ||
2 | tristate "i.MX27 Camera Sensor Interface driver" | ||
3 | depends on VIDEO_DEV && SOC_CAMERA | ||
4 | depends on SOC_IMX27 || COMPILE_TEST | ||
5 | depends on HAS_DMA | ||
6 | select VIDEOBUF2_DMA_CONTIG | ||
7 | ---help--- | ||
8 | This is a v4l2 driver for the i.MX27 Camera Sensor Interface | ||
9 | |||
10 | This driver is deprecated: it should become a stand-alone driver | ||
11 | instead of using the soc-camera framework. | ||
12 | |||
13 | Unless someone is willing to take this on (unlikely with such | ||
14 | ancient hardware) it is going to be removed from the kernel | ||
15 | soon. | ||
diff --git a/drivers/staging/media/mx2/Makefile b/drivers/staging/media/mx2/Makefile deleted file mode 100644 index fc5b2826a558..000000000000 --- a/drivers/staging/media/mx2/Makefile +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | # Makefile for i.MX27 Camera Sensor driver | ||
2 | |||
3 | obj-$(CONFIG_VIDEO_MX2) += mx2_camera.o | ||
diff --git a/drivers/staging/media/mx2/TODO b/drivers/staging/media/mx2/TODO deleted file mode 100644 index bc68fa443a3e..000000000000 --- a/drivers/staging/media/mx2/TODO +++ /dev/null | |||
@@ -1,10 +0,0 @@ | |||
1 | This driver is deprecated: it should become a stand-alone driver instead of | ||
2 | using the soc-camera framework. | ||
3 | |||
4 | Unless someone is willing to take this on (unlikely with such ancient | ||
5 | hardware) it is going to be removed from the kernel soon. | ||
6 | |||
7 | Note that trivial patches will not be accepted anymore, only a full conversion. | ||
8 | |||
9 | If you want to convert this driver, please contact the linux-media mailinglist | ||
10 | (see http://linuxtv.org/lists.php). | ||
diff --git a/drivers/staging/media/mx2/mx2_camera.c b/drivers/staging/media/mx2/mx2_camera.c deleted file mode 100644 index 48dd5b7851b5..000000000000 --- a/drivers/staging/media/mx2/mx2_camera.c +++ /dev/null | |||
@@ -1,1636 +0,0 @@ | |||
1 | /* | ||
2 | * V4L2 Driver for i.MX27 camera host | ||
3 | * | ||
4 | * Copyright (C) 2008, Sascha Hauer, Pengutronix | ||
5 | * Copyright (C) 2010, Baruch Siach, Orex Computed Radiography | ||
6 | * Copyright (C) 2012, Javier Martin, Vista Silicon S.L. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/init.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/dma-mapping.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/fs.h> | ||
22 | #include <linux/gcd.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/math64.h> | ||
26 | #include <linux/mm.h> | ||
27 | #include <linux/moduleparam.h> | ||
28 | #include <linux/time.h> | ||
29 | #include <linux/device.h> | ||
30 | #include <linux/platform_device.h> | ||
31 | #include <linux/clk.h> | ||
32 | |||
33 | #include <media/v4l2-common.h> | ||
34 | #include <media/v4l2-dev.h> | ||
35 | #include <media/videobuf2-v4l2.h> | ||
36 | #include <media/videobuf2-dma-contig.h> | ||
37 | #include <media/soc_camera.h> | ||
38 | #include <media/drv-intf/soc_mediabus.h> | ||
39 | |||
40 | #include <linux/videodev2.h> | ||
41 | |||
42 | #include <linux/platform_data/media/camera-mx2.h> | ||
43 | |||
44 | #include <asm/dma.h> | ||
45 | |||
46 | #define MX2_CAM_DRV_NAME "mx2-camera" | ||
47 | #define MX2_CAM_VERSION "0.0.6" | ||
48 | #define MX2_CAM_DRIVER_DESCRIPTION "i.MX2x_Camera" | ||
49 | |||
50 | /* reset values */ | ||
51 | #define CSICR1_RESET_VAL 0x40000800 | ||
52 | #define CSICR2_RESET_VAL 0x0 | ||
53 | #define CSICR3_RESET_VAL 0x0 | ||
54 | |||
55 | /* csi control reg 1 */ | ||
56 | #define CSICR1_SWAP16_EN (1 << 31) | ||
57 | #define CSICR1_EXT_VSYNC (1 << 30) | ||
58 | #define CSICR1_EOF_INTEN (1 << 29) | ||
59 | #define CSICR1_PRP_IF_EN (1 << 28) | ||
60 | #define CSICR1_CCIR_MODE (1 << 27) | ||
61 | #define CSICR1_COF_INTEN (1 << 26) | ||
62 | #define CSICR1_SF_OR_INTEN (1 << 25) | ||
63 | #define CSICR1_RF_OR_INTEN (1 << 24) | ||
64 | #define CSICR1_STATFF_LEVEL (3 << 22) | ||
65 | #define CSICR1_STATFF_INTEN (1 << 21) | ||
66 | #define CSICR1_RXFF_LEVEL(l) (((l) & 3) << 19) | ||
67 | #define CSICR1_RXFF_INTEN (1 << 18) | ||
68 | #define CSICR1_SOF_POL (1 << 17) | ||
69 | #define CSICR1_SOF_INTEN (1 << 16) | ||
70 | #define CSICR1_MCLKDIV(d) (((d) & 0xF) << 12) | ||
71 | #define CSICR1_HSYNC_POL (1 << 11) | ||
72 | #define CSICR1_CCIR_EN (1 << 10) | ||
73 | #define CSICR1_MCLKEN (1 << 9) | ||
74 | #define CSICR1_FCC (1 << 8) | ||
75 | #define CSICR1_PACK_DIR (1 << 7) | ||
76 | #define CSICR1_CLR_STATFIFO (1 << 6) | ||
77 | #define CSICR1_CLR_RXFIFO (1 << 5) | ||
78 | #define CSICR1_GCLK_MODE (1 << 4) | ||
79 | #define CSICR1_INV_DATA (1 << 3) | ||
80 | #define CSICR1_INV_PCLK (1 << 2) | ||
81 | #define CSICR1_REDGE (1 << 1) | ||
82 | #define CSICR1_FMT_MASK (CSICR1_PACK_DIR | CSICR1_SWAP16_EN) | ||
83 | |||
84 | #define SHIFT_STATFF_LEVEL 22 | ||
85 | #define SHIFT_RXFF_LEVEL 19 | ||
86 | #define SHIFT_MCLKDIV 12 | ||
87 | |||
88 | #define SHIFT_FRMCNT 16 | ||
89 | |||
90 | #define CSICR1 0x00 | ||
91 | #define CSICR2 0x04 | ||
92 | #define CSISR 0x08 | ||
93 | #define CSISTATFIFO 0x0c | ||
94 | #define CSIRFIFO 0x10 | ||
95 | #define CSIRXCNT 0x14 | ||
96 | #define CSICR3 0x1c | ||
97 | #define CSIDMASA_STATFIFO 0x20 | ||
98 | #define CSIDMATA_STATFIFO 0x24 | ||
99 | #define CSIDMASA_FB1 0x28 | ||
100 | #define CSIDMASA_FB2 0x2c | ||
101 | #define CSIFBUF_PARA 0x30 | ||
102 | #define CSIIMAG_PARA 0x34 | ||
103 | |||
104 | /* EMMA PrP */ | ||
105 | #define PRP_CNTL 0x00 | ||
106 | #define PRP_INTR_CNTL 0x04 | ||
107 | #define PRP_INTRSTATUS 0x08 | ||
108 | #define PRP_SOURCE_Y_PTR 0x0c | ||
109 | #define PRP_SOURCE_CB_PTR 0x10 | ||
110 | #define PRP_SOURCE_CR_PTR 0x14 | ||
111 | #define PRP_DEST_RGB1_PTR 0x18 | ||
112 | #define PRP_DEST_RGB2_PTR 0x1c | ||
113 | #define PRP_DEST_Y_PTR 0x20 | ||
114 | #define PRP_DEST_CB_PTR 0x24 | ||
115 | #define PRP_DEST_CR_PTR 0x28 | ||
116 | #define PRP_SRC_FRAME_SIZE 0x2c | ||
117 | #define PRP_DEST_CH1_LINE_STRIDE 0x30 | ||
118 | #define PRP_SRC_PIXEL_FORMAT_CNTL 0x34 | ||
119 | #define PRP_CH1_PIXEL_FORMAT_CNTL 0x38 | ||
120 | #define PRP_CH1_OUT_IMAGE_SIZE 0x3c | ||
121 | #define PRP_CH2_OUT_IMAGE_SIZE 0x40 | ||
122 | #define PRP_SRC_LINE_STRIDE 0x44 | ||
123 | #define PRP_CSC_COEF_012 0x48 | ||
124 | #define PRP_CSC_COEF_345 0x4c | ||
125 | #define PRP_CSC_COEF_678 0x50 | ||
126 | #define PRP_CH1_RZ_HORI_COEF1 0x54 | ||
127 | #define PRP_CH1_RZ_HORI_COEF2 0x58 | ||
128 | #define PRP_CH1_RZ_HORI_VALID 0x5c | ||
129 | #define PRP_CH1_RZ_VERT_COEF1 0x60 | ||
130 | #define PRP_CH1_RZ_VERT_COEF2 0x64 | ||
131 | #define PRP_CH1_RZ_VERT_VALID 0x68 | ||
132 | #define PRP_CH2_RZ_HORI_COEF1 0x6c | ||
133 | #define PRP_CH2_RZ_HORI_COEF2 0x70 | ||
134 | #define PRP_CH2_RZ_HORI_VALID 0x74 | ||
135 | #define PRP_CH2_RZ_VERT_COEF1 0x78 | ||
136 | #define PRP_CH2_RZ_VERT_COEF2 0x7c | ||
137 | #define PRP_CH2_RZ_VERT_VALID 0x80 | ||
138 | |||
139 | #define PRP_CNTL_CH1EN (1 << 0) | ||
140 | #define PRP_CNTL_CH2EN (1 << 1) | ||
141 | #define PRP_CNTL_CSIEN (1 << 2) | ||
142 | #define PRP_CNTL_DATA_IN_YUV420 (0 << 3) | ||
143 | #define PRP_CNTL_DATA_IN_YUV422 (1 << 3) | ||
144 | #define PRP_CNTL_DATA_IN_RGB16 (2 << 3) | ||
145 | #define PRP_CNTL_DATA_IN_RGB32 (3 << 3) | ||
146 | #define PRP_CNTL_CH1_OUT_RGB8 (0 << 5) | ||
147 | #define PRP_CNTL_CH1_OUT_RGB16 (1 << 5) | ||
148 | #define PRP_CNTL_CH1_OUT_RGB32 (2 << 5) | ||
149 | #define PRP_CNTL_CH1_OUT_YUV422 (3 << 5) | ||
150 | #define PRP_CNTL_CH2_OUT_YUV420 (0 << 7) | ||
151 | #define PRP_CNTL_CH2_OUT_YUV422 (1 << 7) | ||
152 | #define PRP_CNTL_CH2_OUT_YUV444 (2 << 7) | ||
153 | #define PRP_CNTL_CH1_LEN (1 << 9) | ||
154 | #define PRP_CNTL_CH2_LEN (1 << 10) | ||
155 | #define PRP_CNTL_SKIP_FRAME (1 << 11) | ||
156 | #define PRP_CNTL_SWRST (1 << 12) | ||
157 | #define PRP_CNTL_CLKEN (1 << 13) | ||
158 | #define PRP_CNTL_WEN (1 << 14) | ||
159 | #define PRP_CNTL_CH1BYP (1 << 15) | ||
160 | #define PRP_CNTL_IN_TSKIP(x) ((x) << 16) | ||
161 | #define PRP_CNTL_CH1_TSKIP(x) ((x) << 19) | ||
162 | #define PRP_CNTL_CH2_TSKIP(x) ((x) << 22) | ||
163 | #define PRP_CNTL_INPUT_FIFO_LEVEL(x) ((x) << 25) | ||
164 | #define PRP_CNTL_RZ_FIFO_LEVEL(x) ((x) << 27) | ||
165 | #define PRP_CNTL_CH2B1EN (1 << 29) | ||
166 | #define PRP_CNTL_CH2B2EN (1 << 30) | ||
167 | #define PRP_CNTL_CH2FEN (1 << 31) | ||
168 | |||
169 | /* IRQ Enable and status register */ | ||
170 | #define PRP_INTR_RDERR (1 << 0) | ||
171 | #define PRP_INTR_CH1WERR (1 << 1) | ||
172 | #define PRP_INTR_CH2WERR (1 << 2) | ||
173 | #define PRP_INTR_CH1FC (1 << 3) | ||
174 | #define PRP_INTR_CH2FC (1 << 5) | ||
175 | #define PRP_INTR_LBOVF (1 << 7) | ||
176 | #define PRP_INTR_CH2OVF (1 << 8) | ||
177 | |||
178 | /* Resizing registers */ | ||
179 | #define PRP_RZ_VALID_TBL_LEN(x) ((x) << 24) | ||
180 | #define PRP_RZ_VALID_BILINEAR (1 << 31) | ||
181 | |||
182 | #define MAX_VIDEO_MEM 16 | ||
183 | |||
184 | #define RESIZE_NUM_MIN 1 | ||
185 | #define RESIZE_NUM_MAX 20 | ||
186 | #define BC_COEF 3 | ||
187 | #define SZ_COEF (1 << BC_COEF) | ||
188 | |||
189 | #define RESIZE_DIR_H 0 | ||
190 | #define RESIZE_DIR_V 1 | ||
191 | |||
192 | #define RESIZE_ALGO_BILINEAR 0 | ||
193 | #define RESIZE_ALGO_AVERAGING 1 | ||
194 | |||
195 | struct mx2_prp_cfg { | ||
196 | int channel; | ||
197 | u32 in_fmt; | ||
198 | u32 out_fmt; | ||
199 | u32 src_pixel; | ||
200 | u32 ch1_pixel; | ||
201 | u32 irq_flags; | ||
202 | u32 csicr1; | ||
203 | }; | ||
204 | |||
205 | /* prp resizing parameters */ | ||
206 | struct emma_prp_resize { | ||
207 | int algo; /* type of algorithm used */ | ||
208 | int len; /* number of coefficients */ | ||
209 | unsigned char s[RESIZE_NUM_MAX]; /* table of coefficients */ | ||
210 | }; | ||
211 | |||
212 | /* prp configuration for a client-host fmt pair */ | ||
213 | struct mx2_fmt_cfg { | ||
214 | u32 in_fmt; | ||
215 | u32 out_fmt; | ||
216 | struct mx2_prp_cfg cfg; | ||
217 | }; | ||
218 | |||
219 | struct mx2_buf_internal { | ||
220 | struct list_head queue; | ||
221 | int bufnum; | ||
222 | bool discard; | ||
223 | }; | ||
224 | |||
225 | /* buffer for one video frame */ | ||
226 | struct mx2_buffer { | ||
227 | /* common v4l buffer stuff -- must be first */ | ||
228 | struct vb2_v4l2_buffer vb; | ||
229 | struct mx2_buf_internal internal; | ||
230 | }; | ||
231 | |||
232 | enum mx2_camera_type { | ||
233 | IMX27_CAMERA, | ||
234 | }; | ||
235 | |||
236 | struct mx2_camera_dev { | ||
237 | struct device *dev; | ||
238 | struct soc_camera_host soc_host; | ||
239 | struct clk *clk_emma_ahb, *clk_emma_ipg; | ||
240 | struct clk *clk_csi_ahb, *clk_csi_per; | ||
241 | |||
242 | void __iomem *base_csi, *base_emma; | ||
243 | |||
244 | struct mx2_camera_platform_data *pdata; | ||
245 | unsigned long platform_flags; | ||
246 | |||
247 | struct list_head capture; | ||
248 | struct list_head active_bufs; | ||
249 | struct list_head discard; | ||
250 | |||
251 | spinlock_t lock; | ||
252 | |||
253 | int dma; | ||
254 | struct mx2_buffer *active; | ||
255 | struct mx2_buffer *fb1_active; | ||
256 | struct mx2_buffer *fb2_active; | ||
257 | |||
258 | u32 csicr1; | ||
259 | enum mx2_camera_type devtype; | ||
260 | |||
261 | struct mx2_buf_internal buf_discard[2]; | ||
262 | void *discard_buffer; | ||
263 | dma_addr_t discard_buffer_dma; | ||
264 | size_t discard_size; | ||
265 | struct mx2_fmt_cfg *emma_prp; | ||
266 | struct emma_prp_resize resizing[2]; | ||
267 | unsigned int s_width, s_height; | ||
268 | u32 frame_count; | ||
269 | struct vb2_alloc_ctx *alloc_ctx; | ||
270 | }; | ||
271 | |||
272 | static struct platform_device_id mx2_camera_devtype[] = { | ||
273 | { | ||
274 | .name = "imx27-camera", | ||
275 | .driver_data = IMX27_CAMERA, | ||
276 | }, { | ||
277 | /* sentinel */ | ||
278 | } | ||
279 | }; | ||
280 | MODULE_DEVICE_TABLE(platform, mx2_camera_devtype); | ||
281 | |||
282 | static struct mx2_buffer *mx2_ibuf_to_buf(struct mx2_buf_internal *int_buf) | ||
283 | { | ||
284 | return container_of(int_buf, struct mx2_buffer, internal); | ||
285 | } | ||
286 | |||
287 | static struct mx2_fmt_cfg mx27_emma_prp_table[] = { | ||
288 | /* | ||
289 | * This is a generic configuration which is valid for most | ||
290 | * prp input-output format combinations. | ||
291 | * We set the incoming and outgoing pixelformat to a | ||
292 | * 16 Bit wide format and adjust the bytesperline | ||
293 | * accordingly. With this configuration the inputdata | ||
294 | * will not be changed by the emma and could be any type | ||
295 | * of 16 Bit Pixelformat. | ||
296 | */ | ||
297 | { | ||
298 | .in_fmt = 0, | ||
299 | .out_fmt = 0, | ||
300 | .cfg = { | ||
301 | .channel = 1, | ||
302 | .in_fmt = PRP_CNTL_DATA_IN_RGB16, | ||
303 | .out_fmt = PRP_CNTL_CH1_OUT_RGB16, | ||
304 | .src_pixel = 0x2ca00565, /* RGB565 */ | ||
305 | .ch1_pixel = 0x2ca00565, /* RGB565 */ | ||
306 | .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH1WERR | | ||
307 | PRP_INTR_CH1FC | PRP_INTR_LBOVF, | ||
308 | .csicr1 = 0, | ||
309 | } | ||
310 | }, | ||
311 | { | ||
312 | .in_fmt = MEDIA_BUS_FMT_UYVY8_2X8, | ||
313 | .out_fmt = V4L2_PIX_FMT_YUYV, | ||
314 | .cfg = { | ||
315 | .channel = 1, | ||
316 | .in_fmt = PRP_CNTL_DATA_IN_YUV422, | ||
317 | .out_fmt = PRP_CNTL_CH1_OUT_YUV422, | ||
318 | .src_pixel = 0x22000888, /* YUV422 (YUYV) */ | ||
319 | .ch1_pixel = 0x62000888, /* YUV422 (YUYV) */ | ||
320 | .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH1WERR | | ||
321 | PRP_INTR_CH1FC | PRP_INTR_LBOVF, | ||
322 | .csicr1 = CSICR1_SWAP16_EN, | ||
323 | } | ||
324 | }, | ||
325 | { | ||
326 | .in_fmt = MEDIA_BUS_FMT_YUYV8_2X8, | ||
327 | .out_fmt = V4L2_PIX_FMT_YUYV, | ||
328 | .cfg = { | ||
329 | .channel = 1, | ||
330 | .in_fmt = PRP_CNTL_DATA_IN_YUV422, | ||
331 | .out_fmt = PRP_CNTL_CH1_OUT_YUV422, | ||
332 | .src_pixel = 0x22000888, /* YUV422 (YUYV) */ | ||
333 | .ch1_pixel = 0x62000888, /* YUV422 (YUYV) */ | ||
334 | .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH1WERR | | ||
335 | PRP_INTR_CH1FC | PRP_INTR_LBOVF, | ||
336 | .csicr1 = CSICR1_PACK_DIR, | ||
337 | } | ||
338 | }, | ||
339 | { | ||
340 | .in_fmt = MEDIA_BUS_FMT_YUYV8_2X8, | ||
341 | .out_fmt = V4L2_PIX_FMT_YUV420, | ||
342 | .cfg = { | ||
343 | .channel = 2, | ||
344 | .in_fmt = PRP_CNTL_DATA_IN_YUV422, | ||
345 | .out_fmt = PRP_CNTL_CH2_OUT_YUV420, | ||
346 | .src_pixel = 0x22000888, /* YUV422 (YUYV) */ | ||
347 | .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH2WERR | | ||
348 | PRP_INTR_CH2FC | PRP_INTR_LBOVF | | ||
349 | PRP_INTR_CH2OVF, | ||
350 | .csicr1 = CSICR1_PACK_DIR, | ||
351 | } | ||
352 | }, | ||
353 | { | ||
354 | .in_fmt = MEDIA_BUS_FMT_UYVY8_2X8, | ||
355 | .out_fmt = V4L2_PIX_FMT_YUV420, | ||
356 | .cfg = { | ||
357 | .channel = 2, | ||
358 | .in_fmt = PRP_CNTL_DATA_IN_YUV422, | ||
359 | .out_fmt = PRP_CNTL_CH2_OUT_YUV420, | ||
360 | .src_pixel = 0x22000888, /* YUV422 (YUYV) */ | ||
361 | .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH2WERR | | ||
362 | PRP_INTR_CH2FC | PRP_INTR_LBOVF | | ||
363 | PRP_INTR_CH2OVF, | ||
364 | .csicr1 = CSICR1_SWAP16_EN, | ||
365 | } | ||
366 | }, | ||
367 | }; | ||
368 | |||
369 | static struct mx2_fmt_cfg *mx27_emma_prp_get_format(u32 in_fmt, u32 out_fmt) | ||
370 | { | ||
371 | int i; | ||
372 | |||
373 | for (i = 1; i < ARRAY_SIZE(mx27_emma_prp_table); i++) | ||
374 | if ((mx27_emma_prp_table[i].in_fmt == in_fmt) && | ||
375 | (mx27_emma_prp_table[i].out_fmt == out_fmt)) { | ||
376 | return &mx27_emma_prp_table[i]; | ||
377 | } | ||
378 | /* If no match return the most generic configuration */ | ||
379 | return &mx27_emma_prp_table[0]; | ||
380 | }; | ||
381 | |||
382 | static void mx27_update_emma_buf(struct mx2_camera_dev *pcdev, | ||
383 | unsigned long phys, int bufnum) | ||
384 | { | ||
385 | struct mx2_fmt_cfg *prp = pcdev->emma_prp; | ||
386 | |||
387 | if (prp->cfg.channel == 1) { | ||
388 | writel(phys, pcdev->base_emma + | ||
389 | PRP_DEST_RGB1_PTR + 4 * bufnum); | ||
390 | } else { | ||
391 | writel(phys, pcdev->base_emma + | ||
392 | PRP_DEST_Y_PTR - 0x14 * bufnum); | ||
393 | if (prp->out_fmt == V4L2_PIX_FMT_YUV420) { | ||
394 | u32 imgsize = pcdev->soc_host.icd->user_height * | ||
395 | pcdev->soc_host.icd->user_width; | ||
396 | |||
397 | writel(phys + imgsize, pcdev->base_emma + | ||
398 | PRP_DEST_CB_PTR - 0x14 * bufnum); | ||
399 | writel(phys + ((5 * imgsize) / 4), pcdev->base_emma + | ||
400 | PRP_DEST_CR_PTR - 0x14 * bufnum); | ||
401 | } | ||
402 | } | ||
403 | } | ||
404 | |||
405 | static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev) | ||
406 | { | ||
407 | clk_disable_unprepare(pcdev->clk_csi_ahb); | ||
408 | clk_disable_unprepare(pcdev->clk_csi_per); | ||
409 | writel(0, pcdev->base_csi + CSICR1); | ||
410 | writel(0, pcdev->base_emma + PRP_CNTL); | ||
411 | } | ||
412 | |||
413 | static int mx2_camera_add_device(struct soc_camera_device *icd) | ||
414 | { | ||
415 | dev_info(icd->parent, "Camera driver attached to camera %d\n", | ||
416 | icd->devnum); | ||
417 | |||
418 | return 0; | ||
419 | } | ||
420 | |||
421 | static void mx2_camera_remove_device(struct soc_camera_device *icd) | ||
422 | { | ||
423 | dev_info(icd->parent, "Camera driver detached from camera %d\n", | ||
424 | icd->devnum); | ||
425 | } | ||
426 | |||
427 | /* | ||
428 | * The following two functions absolutely depend on the fact, that | ||
429 | * there can be only one camera on mx2 camera sensor interface | ||
430 | */ | ||
431 | static int mx2_camera_clock_start(struct soc_camera_host *ici) | ||
432 | { | ||
433 | struct mx2_camera_dev *pcdev = ici->priv; | ||
434 | int ret; | ||
435 | u32 csicr1; | ||
436 | |||
437 | ret = clk_prepare_enable(pcdev->clk_csi_ahb); | ||
438 | if (ret < 0) | ||
439 | return ret; | ||
440 | |||
441 | ret = clk_prepare_enable(pcdev->clk_csi_per); | ||
442 | if (ret < 0) | ||
443 | goto exit_csi_ahb; | ||
444 | |||
445 | csicr1 = CSICR1_MCLKEN | CSICR1_PRP_IF_EN | CSICR1_FCC | | ||
446 | CSICR1_RXFF_LEVEL(0); | ||
447 | |||
448 | pcdev->csicr1 = csicr1; | ||
449 | writel(pcdev->csicr1, pcdev->base_csi + CSICR1); | ||
450 | |||
451 | pcdev->frame_count = 0; | ||
452 | |||
453 | return 0; | ||
454 | |||
455 | exit_csi_ahb: | ||
456 | clk_disable_unprepare(pcdev->clk_csi_ahb); | ||
457 | |||
458 | return ret; | ||
459 | } | ||
460 | |||
461 | static void mx2_camera_clock_stop(struct soc_camera_host *ici) | ||
462 | { | ||
463 | struct mx2_camera_dev *pcdev = ici->priv; | ||
464 | |||
465 | mx2_camera_deactivate(pcdev); | ||
466 | } | ||
467 | |||
468 | /* | ||
469 | * Videobuf operations | ||
470 | */ | ||
471 | static int mx2_videobuf_setup(struct vb2_queue *vq, | ||
472 | unsigned int *count, unsigned int *num_planes, | ||
473 | unsigned int sizes[], void *alloc_ctxs[]) | ||
474 | { | ||
475 | struct soc_camera_device *icd = soc_camera_from_vb2q(vq); | ||
476 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
477 | struct mx2_camera_dev *pcdev = ici->priv; | ||
478 | |||
479 | dev_dbg(icd->parent, "count=%d, size=%d\n", *count, sizes[0]); | ||
480 | |||
481 | alloc_ctxs[0] = pcdev->alloc_ctx; | ||
482 | |||
483 | sizes[0] = icd->sizeimage; | ||
484 | |||
485 | if (0 == *count) | ||
486 | *count = 32; | ||
487 | if (!*num_planes && | ||
488 | sizes[0] * *count > MAX_VIDEO_MEM * 1024 * 1024) | ||
489 | *count = (MAX_VIDEO_MEM * 1024 * 1024) / sizes[0]; | ||
490 | |||
491 | *num_planes = 1; | ||
492 | |||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | static int mx2_videobuf_prepare(struct vb2_buffer *vb) | ||
497 | { | ||
498 | struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); | ||
499 | int ret = 0; | ||
500 | |||
501 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, | ||
502 | vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); | ||
503 | |||
504 | #ifdef DEBUG | ||
505 | /* | ||
506 | * This can be useful if you want to see if we actually fill | ||
507 | * the buffer with something | ||
508 | */ | ||
509 | memset((void *)vb2_plane_vaddr(vb, 0), | ||
510 | 0xaa, vb2_get_plane_payload(vb, 0)); | ||
511 | #endif | ||
512 | |||
513 | vb2_set_plane_payload(vb, 0, icd->sizeimage); | ||
514 | if (vb2_plane_vaddr(vb, 0) && | ||
515 | vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) { | ||
516 | ret = -EINVAL; | ||
517 | goto out; | ||
518 | } | ||
519 | |||
520 | return 0; | ||
521 | |||
522 | out: | ||
523 | return ret; | ||
524 | } | ||
525 | |||
526 | static void mx2_videobuf_queue(struct vb2_buffer *vb) | ||
527 | { | ||
528 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | ||
529 | struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); | ||
530 | struct soc_camera_host *ici = | ||
531 | to_soc_camera_host(icd->parent); | ||
532 | struct mx2_camera_dev *pcdev = ici->priv; | ||
533 | struct mx2_buffer *buf = container_of(vbuf, struct mx2_buffer, vb); | ||
534 | unsigned long flags; | ||
535 | |||
536 | dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, | ||
537 | vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); | ||
538 | |||
539 | spin_lock_irqsave(&pcdev->lock, flags); | ||
540 | |||
541 | list_add_tail(&buf->internal.queue, &pcdev->capture); | ||
542 | |||
543 | spin_unlock_irqrestore(&pcdev->lock, flags); | ||
544 | } | ||
545 | |||
546 | static void mx27_camera_emma_buf_init(struct soc_camera_device *icd, | ||
547 | int bytesperline) | ||
548 | { | ||
549 | struct soc_camera_host *ici = | ||
550 | to_soc_camera_host(icd->parent); | ||
551 | struct mx2_camera_dev *pcdev = ici->priv; | ||
552 | struct mx2_fmt_cfg *prp = pcdev->emma_prp; | ||
553 | |||
554 | writel((pcdev->s_width << 16) | pcdev->s_height, | ||
555 | pcdev->base_emma + PRP_SRC_FRAME_SIZE); | ||
556 | writel(prp->cfg.src_pixel, | ||
557 | pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL); | ||
558 | if (prp->cfg.channel == 1) { | ||
559 | writel((icd->user_width << 16) | icd->user_height, | ||
560 | pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE); | ||
561 | writel(bytesperline, | ||
562 | pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE); | ||
563 | writel(prp->cfg.ch1_pixel, | ||
564 | pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL); | ||
565 | } else { /* channel 2 */ | ||
566 | writel((icd->user_width << 16) | icd->user_height, | ||
567 | pcdev->base_emma + PRP_CH2_OUT_IMAGE_SIZE); | ||
568 | } | ||
569 | |||
570 | /* Enable interrupts */ | ||
571 | writel(prp->cfg.irq_flags, pcdev->base_emma + PRP_INTR_CNTL); | ||
572 | } | ||
573 | |||
574 | static void mx2_prp_resize_commit(struct mx2_camera_dev *pcdev) | ||
575 | { | ||
576 | int dir; | ||
577 | |||
578 | for (dir = RESIZE_DIR_H; dir <= RESIZE_DIR_V; dir++) { | ||
579 | unsigned char *s = pcdev->resizing[dir].s; | ||
580 | int len = pcdev->resizing[dir].len; | ||
581 | unsigned int coeff[2] = {0, 0}; | ||
582 | unsigned int valid = 0; | ||
583 | int i; | ||
584 | |||
585 | if (len == 0) | ||
586 | continue; | ||
587 | |||
588 | for (i = RESIZE_NUM_MAX - 1; i >= 0; i--) { | ||
589 | int j; | ||
590 | |||
591 | j = i > 9 ? 1 : 0; | ||
592 | coeff[j] = (coeff[j] << BC_COEF) | | ||
593 | (s[i] & (SZ_COEF - 1)); | ||
594 | |||
595 | if (i == 5 || i == 15) | ||
596 | coeff[j] <<= 1; | ||
597 | |||
598 | valid = (valid << 1) | (s[i] >> BC_COEF); | ||
599 | } | ||
600 | |||
601 | valid |= PRP_RZ_VALID_TBL_LEN(len); | ||
602 | |||
603 | if (pcdev->resizing[dir].algo == RESIZE_ALGO_BILINEAR) | ||
604 | valid |= PRP_RZ_VALID_BILINEAR; | ||
605 | |||
606 | if (pcdev->emma_prp->cfg.channel == 1) { | ||
607 | if (dir == RESIZE_DIR_H) { | ||
608 | writel(coeff[0], pcdev->base_emma + | ||
609 | PRP_CH1_RZ_HORI_COEF1); | ||
610 | writel(coeff[1], pcdev->base_emma + | ||
611 | PRP_CH1_RZ_HORI_COEF2); | ||
612 | writel(valid, pcdev->base_emma + | ||
613 | PRP_CH1_RZ_HORI_VALID); | ||
614 | } else { | ||
615 | writel(coeff[0], pcdev->base_emma + | ||
616 | PRP_CH1_RZ_VERT_COEF1); | ||
617 | writel(coeff[1], pcdev->base_emma + | ||
618 | PRP_CH1_RZ_VERT_COEF2); | ||
619 | writel(valid, pcdev->base_emma + | ||
620 | PRP_CH1_RZ_VERT_VALID); | ||
621 | } | ||
622 | } else { | ||
623 | if (dir == RESIZE_DIR_H) { | ||
624 | writel(coeff[0], pcdev->base_emma + | ||
625 | PRP_CH2_RZ_HORI_COEF1); | ||
626 | writel(coeff[1], pcdev->base_emma + | ||
627 | PRP_CH2_RZ_HORI_COEF2); | ||
628 | writel(valid, pcdev->base_emma + | ||
629 | PRP_CH2_RZ_HORI_VALID); | ||
630 | } else { | ||
631 | writel(coeff[0], pcdev->base_emma + | ||
632 | PRP_CH2_RZ_VERT_COEF1); | ||
633 | writel(coeff[1], pcdev->base_emma + | ||
634 | PRP_CH2_RZ_VERT_COEF2); | ||
635 | writel(valid, pcdev->base_emma + | ||
636 | PRP_CH2_RZ_VERT_VALID); | ||
637 | } | ||
638 | } | ||
639 | } | ||
640 | } | ||
641 | |||
642 | static int mx2_start_streaming(struct vb2_queue *q, unsigned int count) | ||
643 | { | ||
644 | struct soc_camera_device *icd = soc_camera_from_vb2q(q); | ||
645 | struct soc_camera_host *ici = | ||
646 | to_soc_camera_host(icd->parent); | ||
647 | struct mx2_camera_dev *pcdev = ici->priv; | ||
648 | struct mx2_fmt_cfg *prp = pcdev->emma_prp; | ||
649 | struct vb2_buffer *vb; | ||
650 | struct mx2_buffer *buf; | ||
651 | unsigned long phys; | ||
652 | int bytesperline; | ||
653 | unsigned long flags; | ||
654 | |||
655 | if (count < 2) | ||
656 | return -ENOBUFS; | ||
657 | |||
658 | spin_lock_irqsave(&pcdev->lock, flags); | ||
659 | |||
660 | buf = list_first_entry(&pcdev->capture, struct mx2_buffer, | ||
661 | internal.queue); | ||
662 | buf->internal.bufnum = 0; | ||
663 | vb = &buf->vb.vb2_buf; | ||
664 | |||
665 | phys = vb2_dma_contig_plane_dma_addr(vb, 0); | ||
666 | mx27_update_emma_buf(pcdev, phys, buf->internal.bufnum); | ||
667 | list_move_tail(pcdev->capture.next, &pcdev->active_bufs); | ||
668 | |||
669 | buf = list_first_entry(&pcdev->capture, struct mx2_buffer, | ||
670 | internal.queue); | ||
671 | buf->internal.bufnum = 1; | ||
672 | vb = &buf->vb.vb2_buf; | ||
673 | |||
674 | phys = vb2_dma_contig_plane_dma_addr(vb, 0); | ||
675 | mx27_update_emma_buf(pcdev, phys, buf->internal.bufnum); | ||
676 | list_move_tail(pcdev->capture.next, &pcdev->active_bufs); | ||
677 | |||
678 | bytesperline = soc_mbus_bytes_per_line(icd->user_width, | ||
679 | icd->current_fmt->host_fmt); | ||
680 | if (bytesperline < 0) { | ||
681 | spin_unlock_irqrestore(&pcdev->lock, flags); | ||
682 | return bytesperline; | ||
683 | } | ||
684 | |||
685 | /* | ||
686 | * I didn't manage to properly enable/disable the prp | ||
687 | * on a per frame basis during running transfers, | ||
688 | * thus we allocate a buffer here and use it to | ||
689 | * discard frames when no buffer is available. | ||
690 | * Feel free to work on this ;) | ||
691 | */ | ||
692 | pcdev->discard_size = icd->user_height * bytesperline; | ||
693 | pcdev->discard_buffer = dma_alloc_coherent(ici->v4l2_dev.dev, | ||
694 | pcdev->discard_size, | ||
695 | &pcdev->discard_buffer_dma, GFP_ATOMIC); | ||
696 | if (!pcdev->discard_buffer) { | ||
697 | spin_unlock_irqrestore(&pcdev->lock, flags); | ||
698 | return -ENOMEM; | ||
699 | } | ||
700 | |||
701 | pcdev->buf_discard[0].discard = true; | ||
702 | list_add_tail(&pcdev->buf_discard[0].queue, | ||
703 | &pcdev->discard); | ||
704 | |||
705 | pcdev->buf_discard[1].discard = true; | ||
706 | list_add_tail(&pcdev->buf_discard[1].queue, | ||
707 | &pcdev->discard); | ||
708 | |||
709 | mx2_prp_resize_commit(pcdev); | ||
710 | |||
711 | mx27_camera_emma_buf_init(icd, bytesperline); | ||
712 | |||
713 | if (prp->cfg.channel == 1) { | ||
714 | writel(PRP_CNTL_CH1EN | | ||
715 | PRP_CNTL_CSIEN | | ||
716 | prp->cfg.in_fmt | | ||
717 | prp->cfg.out_fmt | | ||
718 | PRP_CNTL_CH1_LEN | | ||
719 | PRP_CNTL_CH1BYP | | ||
720 | PRP_CNTL_CH1_TSKIP(0) | | ||
721 | PRP_CNTL_IN_TSKIP(0), | ||
722 | pcdev->base_emma + PRP_CNTL); | ||
723 | } else { | ||
724 | writel(PRP_CNTL_CH2EN | | ||
725 | PRP_CNTL_CSIEN | | ||
726 | prp->cfg.in_fmt | | ||
727 | prp->cfg.out_fmt | | ||
728 | PRP_CNTL_CH2_LEN | | ||
729 | PRP_CNTL_CH2_TSKIP(0) | | ||
730 | PRP_CNTL_IN_TSKIP(0), | ||
731 | pcdev->base_emma + PRP_CNTL); | ||
732 | } | ||
733 | spin_unlock_irqrestore(&pcdev->lock, flags); | ||
734 | |||
735 | return 0; | ||
736 | } | ||
737 | |||
738 | static void mx2_stop_streaming(struct vb2_queue *q) | ||
739 | { | ||
740 | struct soc_camera_device *icd = soc_camera_from_vb2q(q); | ||
741 | struct soc_camera_host *ici = | ||
742 | to_soc_camera_host(icd->parent); | ||
743 | struct mx2_camera_dev *pcdev = ici->priv; | ||
744 | struct mx2_fmt_cfg *prp = pcdev->emma_prp; | ||
745 | unsigned long flags; | ||
746 | void *b; | ||
747 | u32 cntl; | ||
748 | |||
749 | spin_lock_irqsave(&pcdev->lock, flags); | ||
750 | |||
751 | cntl = readl(pcdev->base_emma + PRP_CNTL); | ||
752 | if (prp->cfg.channel == 1) { | ||
753 | writel(cntl & ~PRP_CNTL_CH1EN, | ||
754 | pcdev->base_emma + PRP_CNTL); | ||
755 | } else { | ||
756 | writel(cntl & ~PRP_CNTL_CH2EN, | ||
757 | pcdev->base_emma + PRP_CNTL); | ||
758 | } | ||
759 | INIT_LIST_HEAD(&pcdev->capture); | ||
760 | INIT_LIST_HEAD(&pcdev->active_bufs); | ||
761 | INIT_LIST_HEAD(&pcdev->discard); | ||
762 | |||
763 | b = pcdev->discard_buffer; | ||
764 | pcdev->discard_buffer = NULL; | ||
765 | |||
766 | spin_unlock_irqrestore(&pcdev->lock, flags); | ||
767 | |||
768 | dma_free_coherent(ici->v4l2_dev.dev, | ||
769 | pcdev->discard_size, b, pcdev->discard_buffer_dma); | ||
770 | } | ||
771 | |||
772 | static struct vb2_ops mx2_videobuf_ops = { | ||
773 | .queue_setup = mx2_videobuf_setup, | ||
774 | .buf_prepare = mx2_videobuf_prepare, | ||
775 | .buf_queue = mx2_videobuf_queue, | ||
776 | .start_streaming = mx2_start_streaming, | ||
777 | .stop_streaming = mx2_stop_streaming, | ||
778 | }; | ||
779 | |||
780 | static int mx2_camera_init_videobuf(struct vb2_queue *q, | ||
781 | struct soc_camera_device *icd) | ||
782 | { | ||
783 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
784 | q->io_modes = VB2_MMAP | VB2_USERPTR; | ||
785 | q->drv_priv = icd; | ||
786 | q->ops = &mx2_videobuf_ops; | ||
787 | q->mem_ops = &vb2_dma_contig_memops; | ||
788 | q->buf_struct_size = sizeof(struct mx2_buffer); | ||
789 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | ||
790 | |||
791 | return vb2_queue_init(q); | ||
792 | } | ||
793 | |||
794 | #define MX2_BUS_FLAGS (V4L2_MBUS_MASTER | \ | ||
795 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | \ | ||
796 | V4L2_MBUS_VSYNC_ACTIVE_LOW | \ | ||
797 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | \ | ||
798 | V4L2_MBUS_HSYNC_ACTIVE_LOW | \ | ||
799 | V4L2_MBUS_PCLK_SAMPLE_RISING | \ | ||
800 | V4L2_MBUS_PCLK_SAMPLE_FALLING | \ | ||
801 | V4L2_MBUS_DATA_ACTIVE_HIGH | \ | ||
802 | V4L2_MBUS_DATA_ACTIVE_LOW) | ||
803 | |||
804 | static int mx27_camera_emma_prp_reset(struct mx2_camera_dev *pcdev) | ||
805 | { | ||
806 | int count = 0; | ||
807 | |||
808 | readl(pcdev->base_emma + PRP_CNTL); | ||
809 | writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL); | ||
810 | while (count++ < 100) { | ||
811 | if (!(readl(pcdev->base_emma + PRP_CNTL) & PRP_CNTL_SWRST)) | ||
812 | return 0; | ||
813 | barrier(); | ||
814 | udelay(1); | ||
815 | } | ||
816 | |||
817 | return -ETIMEDOUT; | ||
818 | } | ||
819 | |||
820 | static int mx2_camera_set_bus_param(struct soc_camera_device *icd) | ||
821 | { | ||
822 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
823 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
824 | struct mx2_camera_dev *pcdev = ici->priv; | ||
825 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; | ||
826 | unsigned long common_flags; | ||
827 | int ret; | ||
828 | int bytesperline; | ||
829 | u32 csicr1 = pcdev->csicr1; | ||
830 | |||
831 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); | ||
832 | if (!ret) { | ||
833 | common_flags = soc_mbus_config_compatible(&cfg, MX2_BUS_FLAGS); | ||
834 | if (!common_flags) { | ||
835 | dev_warn(icd->parent, | ||
836 | "Flags incompatible: camera 0x%x, host 0x%x\n", | ||
837 | cfg.flags, MX2_BUS_FLAGS); | ||
838 | return -EINVAL; | ||
839 | } | ||
840 | } else if (ret != -ENOIOCTLCMD) { | ||
841 | return ret; | ||
842 | } else { | ||
843 | common_flags = MX2_BUS_FLAGS; | ||
844 | } | ||
845 | |||
846 | if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && | ||
847 | (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { | ||
848 | if (pcdev->platform_flags & MX2_CAMERA_HSYNC_HIGH) | ||
849 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; | ||
850 | else | ||
851 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; | ||
852 | } | ||
853 | |||
854 | if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && | ||
855 | (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { | ||
856 | if (pcdev->platform_flags & MX2_CAMERA_PCLK_SAMPLE_RISING) | ||
857 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; | ||
858 | else | ||
859 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; | ||
860 | } | ||
861 | |||
862 | cfg.flags = common_flags; | ||
863 | ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); | ||
864 | if (ret < 0 && ret != -ENOIOCTLCMD) { | ||
865 | dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n", | ||
866 | common_flags, ret); | ||
867 | return ret; | ||
868 | } | ||
869 | |||
870 | csicr1 = (csicr1 & ~CSICR1_FMT_MASK) | pcdev->emma_prp->cfg.csicr1; | ||
871 | |||
872 | if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) | ||
873 | csicr1 |= CSICR1_REDGE; | ||
874 | if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) | ||
875 | csicr1 |= CSICR1_SOF_POL; | ||
876 | if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) | ||
877 | csicr1 |= CSICR1_HSYNC_POL; | ||
878 | if (pcdev->platform_flags & MX2_CAMERA_EXT_VSYNC) | ||
879 | csicr1 |= CSICR1_EXT_VSYNC; | ||
880 | if (pcdev->platform_flags & MX2_CAMERA_CCIR) | ||
881 | csicr1 |= CSICR1_CCIR_EN; | ||
882 | if (pcdev->platform_flags & MX2_CAMERA_CCIR_INTERLACE) | ||
883 | csicr1 |= CSICR1_CCIR_MODE; | ||
884 | if (pcdev->platform_flags & MX2_CAMERA_GATED_CLOCK) | ||
885 | csicr1 |= CSICR1_GCLK_MODE; | ||
886 | if (pcdev->platform_flags & MX2_CAMERA_INV_DATA) | ||
887 | csicr1 |= CSICR1_INV_DATA; | ||
888 | |||
889 | pcdev->csicr1 = csicr1; | ||
890 | |||
891 | bytesperline = soc_mbus_bytes_per_line(icd->user_width, | ||
892 | icd->current_fmt->host_fmt); | ||
893 | if (bytesperline < 0) | ||
894 | return bytesperline; | ||
895 | |||
896 | ret = mx27_camera_emma_prp_reset(pcdev); | ||
897 | if (ret) | ||
898 | return ret; | ||
899 | |||
900 | writel(pcdev->csicr1, pcdev->base_csi + CSICR1); | ||
901 | |||
902 | return 0; | ||
903 | } | ||
904 | |||
905 | static int mx2_camera_set_crop(struct soc_camera_device *icd, | ||
906 | const struct v4l2_crop *a) | ||
907 | { | ||
908 | struct v4l2_crop a_writable = *a; | ||
909 | struct v4l2_rect *rect = &a_writable.c; | ||
910 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
911 | struct v4l2_subdev_format fmt = { | ||
912 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
913 | }; | ||
914 | struct v4l2_mbus_framefmt *mf = &fmt.format; | ||
915 | int ret; | ||
916 | |||
917 | soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096); | ||
918 | soc_camera_limit_side(&rect->top, &rect->height, 0, 2, 4096); | ||
919 | |||
920 | ret = v4l2_subdev_call(sd, video, s_crop, a); | ||
921 | if (ret < 0) | ||
922 | return ret; | ||
923 | |||
924 | /* The capture device might have changed its output */ | ||
925 | ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); | ||
926 | if (ret < 0) | ||
927 | return ret; | ||
928 | |||
929 | dev_dbg(icd->parent, "Sensor cropped %dx%d\n", | ||
930 | mf->width, mf->height); | ||
931 | |||
932 | icd->user_width = mf->width; | ||
933 | icd->user_height = mf->height; | ||
934 | |||
935 | return ret; | ||
936 | } | ||
937 | |||
938 | static int mx2_camera_get_formats(struct soc_camera_device *icd, | ||
939 | unsigned int idx, | ||
940 | struct soc_camera_format_xlate *xlate) | ||
941 | { | ||
942 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
943 | const struct soc_mbus_pixelfmt *fmt; | ||
944 | struct device *dev = icd->parent; | ||
945 | struct v4l2_subdev_mbus_code_enum code = { | ||
946 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
947 | .index = idx, | ||
948 | }; | ||
949 | int ret, formats = 0; | ||
950 | |||
951 | ret = v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code); | ||
952 | if (ret < 0) | ||
953 | /* no more formats */ | ||
954 | return 0; | ||
955 | |||
956 | fmt = soc_mbus_get_fmtdesc(code.code); | ||
957 | if (!fmt) { | ||
958 | dev_err(dev, "Invalid format code #%u: %d\n", idx, code.code); | ||
959 | return 0; | ||
960 | } | ||
961 | |||
962 | if (code.code == MEDIA_BUS_FMT_YUYV8_2X8 || | ||
963 | code.code == MEDIA_BUS_FMT_UYVY8_2X8) { | ||
964 | formats++; | ||
965 | if (xlate) { | ||
966 | /* | ||
967 | * CH2 can output YUV420 which is a standard format in | ||
968 | * soc_mediabus.c | ||
969 | */ | ||
970 | xlate->host_fmt = | ||
971 | soc_mbus_get_fmtdesc(MEDIA_BUS_FMT_YUYV8_1_5X8); | ||
972 | xlate->code = code.code; | ||
973 | dev_dbg(dev, "Providing host format %s for sensor code %d\n", | ||
974 | xlate->host_fmt->name, code.code); | ||
975 | xlate++; | ||
976 | } | ||
977 | } | ||
978 | |||
979 | if (code.code == MEDIA_BUS_FMT_UYVY8_2X8) { | ||
980 | formats++; | ||
981 | if (xlate) { | ||
982 | xlate->host_fmt = | ||
983 | soc_mbus_get_fmtdesc(MEDIA_BUS_FMT_YUYV8_2X8); | ||
984 | xlate->code = code.code; | ||
985 | dev_dbg(dev, "Providing host format %s for sensor code %d\n", | ||
986 | xlate->host_fmt->name, code.code); | ||
987 | xlate++; | ||
988 | } | ||
989 | } | ||
990 | |||
991 | /* Generic pass-trough */ | ||
992 | formats++; | ||
993 | if (xlate) { | ||
994 | xlate->host_fmt = fmt; | ||
995 | xlate->code = code.code; | ||
996 | xlate++; | ||
997 | } | ||
998 | return formats; | ||
999 | } | ||
1000 | |||
1001 | static int mx2_emmaprp_resize(struct mx2_camera_dev *pcdev, | ||
1002 | struct v4l2_mbus_framefmt *mf_in, | ||
1003 | struct v4l2_pix_format *pix_out, bool apply) | ||
1004 | { | ||
1005 | unsigned int num, den; | ||
1006 | unsigned long m; | ||
1007 | int i, dir; | ||
1008 | |||
1009 | for (dir = RESIZE_DIR_H; dir <= RESIZE_DIR_V; dir++) { | ||
1010 | struct emma_prp_resize tmprsz; | ||
1011 | unsigned char *s = tmprsz.s; | ||
1012 | int len = 0; | ||
1013 | int in, out; | ||
1014 | |||
1015 | if (dir == RESIZE_DIR_H) { | ||
1016 | in = mf_in->width; | ||
1017 | out = pix_out->width; | ||
1018 | } else { | ||
1019 | in = mf_in->height; | ||
1020 | out = pix_out->height; | ||
1021 | } | ||
1022 | |||
1023 | if (in < out) | ||
1024 | return -EINVAL; | ||
1025 | else if (in == out) | ||
1026 | continue; | ||
1027 | |||
1028 | /* Calculate ratio */ | ||
1029 | m = gcd(in, out); | ||
1030 | num = in / m; | ||
1031 | den = out / m; | ||
1032 | if (num > RESIZE_NUM_MAX) | ||
1033 | return -EINVAL; | ||
1034 | |||
1035 | if ((num >= 2 * den) && (den == 1) && | ||
1036 | (num < 9) && (!(num & 0x01))) { | ||
1037 | int sum = 0; | ||
1038 | int j; | ||
1039 | |||
1040 | /* Average scaling for >= 2:1 ratios */ | ||
1041 | /* Support can be added for num >=9 and odd values */ | ||
1042 | |||
1043 | tmprsz.algo = RESIZE_ALGO_AVERAGING; | ||
1044 | len = num; | ||
1045 | |||
1046 | for (i = 0; i < (len / 2); i++) | ||
1047 | s[i] = 8; | ||
1048 | |||
1049 | do { | ||
1050 | for (i = 0; i < (len / 2); i++) { | ||
1051 | s[i] = s[i] >> 1; | ||
1052 | sum = 0; | ||
1053 | for (j = 0; j < (len / 2); j++) | ||
1054 | sum += s[j]; | ||
1055 | if (sum == 4) | ||
1056 | break; | ||
1057 | } | ||
1058 | } while (sum != 4); | ||
1059 | |||
1060 | for (i = (len / 2); i < len; i++) | ||
1061 | s[i] = s[len - i - 1]; | ||
1062 | |||
1063 | s[len - 1] |= SZ_COEF; | ||
1064 | } else { | ||
1065 | /* bilinear scaling for < 2:1 ratios */ | ||
1066 | int v; /* overflow counter */ | ||
1067 | int coeff, nxt; /* table output */ | ||
1068 | int in_pos_inc = 2 * den; | ||
1069 | int out_pos = num; | ||
1070 | int out_pos_inc = 2 * num; | ||
1071 | int init_carry = num - den; | ||
1072 | int carry = init_carry; | ||
1073 | |||
1074 | tmprsz.algo = RESIZE_ALGO_BILINEAR; | ||
1075 | v = den + in_pos_inc; | ||
1076 | do { | ||
1077 | coeff = v - out_pos; | ||
1078 | out_pos += out_pos_inc; | ||
1079 | carry += out_pos_inc; | ||
1080 | for (nxt = 0; v < out_pos; nxt++) { | ||
1081 | v += in_pos_inc; | ||
1082 | carry -= in_pos_inc; | ||
1083 | } | ||
1084 | |||
1085 | if (len > RESIZE_NUM_MAX) | ||
1086 | return -EINVAL; | ||
1087 | |||
1088 | coeff = ((coeff << BC_COEF) + | ||
1089 | (in_pos_inc >> 1)) / in_pos_inc; | ||
1090 | |||
1091 | if (coeff >= (SZ_COEF - 1)) | ||
1092 | coeff--; | ||
1093 | |||
1094 | coeff |= SZ_COEF; | ||
1095 | s[len] = (unsigned char)coeff; | ||
1096 | len++; | ||
1097 | |||
1098 | for (i = 1; i < nxt; i++) { | ||
1099 | if (len >= RESIZE_NUM_MAX) | ||
1100 | return -EINVAL; | ||
1101 | s[len] = 0; | ||
1102 | len++; | ||
1103 | } | ||
1104 | } while (carry != init_carry); | ||
1105 | } | ||
1106 | tmprsz.len = len; | ||
1107 | if (dir == RESIZE_DIR_H) | ||
1108 | mf_in->width = pix_out->width; | ||
1109 | else | ||
1110 | mf_in->height = pix_out->height; | ||
1111 | |||
1112 | if (apply) | ||
1113 | memcpy(&pcdev->resizing[dir], &tmprsz, sizeof(tmprsz)); | ||
1114 | } | ||
1115 | return 0; | ||
1116 | } | ||
1117 | |||
1118 | static int mx2_camera_set_fmt(struct soc_camera_device *icd, | ||
1119 | struct v4l2_format *f) | ||
1120 | { | ||
1121 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1122 | struct mx2_camera_dev *pcdev = ici->priv; | ||
1123 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1124 | const struct soc_camera_format_xlate *xlate; | ||
1125 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
1126 | struct v4l2_subdev_format format = { | ||
1127 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
1128 | }; | ||
1129 | struct v4l2_mbus_framefmt *mf = &format.format; | ||
1130 | int ret; | ||
1131 | |||
1132 | dev_dbg(icd->parent, "%s: requested params: width = %d, height = %d\n", | ||
1133 | __func__, pix->width, pix->height); | ||
1134 | |||
1135 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); | ||
1136 | if (!xlate) { | ||
1137 | dev_warn(icd->parent, "Format %x not found\n", | ||
1138 | pix->pixelformat); | ||
1139 | return -EINVAL; | ||
1140 | } | ||
1141 | |||
1142 | mf->width = pix->width; | ||
1143 | mf->height = pix->height; | ||
1144 | mf->field = pix->field; | ||
1145 | mf->colorspace = pix->colorspace; | ||
1146 | mf->code = xlate->code; | ||
1147 | |||
1148 | ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &format); | ||
1149 | if (ret < 0 && ret != -ENOIOCTLCMD) | ||
1150 | return ret; | ||
1151 | |||
1152 | /* Store width and height returned by the sensor for resizing */ | ||
1153 | pcdev->s_width = mf->width; | ||
1154 | pcdev->s_height = mf->height; | ||
1155 | dev_dbg(icd->parent, "%s: sensor params: width = %d, height = %d\n", | ||
1156 | __func__, pcdev->s_width, pcdev->s_height); | ||
1157 | |||
1158 | pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code, | ||
1159 | xlate->host_fmt->fourcc); | ||
1160 | |||
1161 | memset(pcdev->resizing, 0, sizeof(pcdev->resizing)); | ||
1162 | if ((mf->width != pix->width || mf->height != pix->height) && | ||
1163 | pcdev->emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) { | ||
1164 | if (mx2_emmaprp_resize(pcdev, mf, pix, true) < 0) | ||
1165 | dev_dbg(icd->parent, "%s: can't resize\n", __func__); | ||
1166 | } | ||
1167 | |||
1168 | if (mf->code != xlate->code) | ||
1169 | return -EINVAL; | ||
1170 | |||
1171 | pix->width = mf->width; | ||
1172 | pix->height = mf->height; | ||
1173 | pix->field = mf->field; | ||
1174 | pix->colorspace = mf->colorspace; | ||
1175 | icd->current_fmt = xlate; | ||
1176 | |||
1177 | dev_dbg(icd->parent, "%s: returned params: width = %d, height = %d\n", | ||
1178 | __func__, pix->width, pix->height); | ||
1179 | |||
1180 | return 0; | ||
1181 | } | ||
1182 | |||
1183 | static int mx2_camera_try_fmt(struct soc_camera_device *icd, | ||
1184 | struct v4l2_format *f) | ||
1185 | { | ||
1186 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1187 | const struct soc_camera_format_xlate *xlate; | ||
1188 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
1189 | struct v4l2_subdev_pad_config pad_cfg; | ||
1190 | struct v4l2_subdev_format format = { | ||
1191 | .which = V4L2_SUBDEV_FORMAT_TRY, | ||
1192 | }; | ||
1193 | struct v4l2_mbus_framefmt *mf = &format.format; | ||
1194 | __u32 pixfmt = pix->pixelformat; | ||
1195 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1196 | struct mx2_camera_dev *pcdev = ici->priv; | ||
1197 | struct mx2_fmt_cfg *emma_prp; | ||
1198 | int ret; | ||
1199 | |||
1200 | dev_dbg(icd->parent, "%s: requested params: width = %d, height = %d\n", | ||
1201 | __func__, pix->width, pix->height); | ||
1202 | |||
1203 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | ||
1204 | if (pixfmt && !xlate) { | ||
1205 | dev_warn(icd->parent, "Format %x not found\n", pixfmt); | ||
1206 | return -EINVAL; | ||
1207 | } | ||
1208 | |||
1209 | /* | ||
1210 | * limit to MX27 hardware capabilities: width must be a multiple of 8 as | ||
1211 | * requested by the CSI. (Table 39-2 in the i.MX27 Reference Manual). | ||
1212 | */ | ||
1213 | pix->width &= ~0x7; | ||
1214 | |||
1215 | /* limit to sensor capabilities */ | ||
1216 | mf->width = pix->width; | ||
1217 | mf->height = pix->height; | ||
1218 | mf->field = pix->field; | ||
1219 | mf->colorspace = pix->colorspace; | ||
1220 | mf->code = xlate->code; | ||
1221 | |||
1222 | ret = v4l2_subdev_call(sd, pad, set_fmt, &pad_cfg, &format); | ||
1223 | if (ret < 0) | ||
1224 | return ret; | ||
1225 | |||
1226 | dev_dbg(icd->parent, "%s: sensor params: width = %d, height = %d\n", | ||
1227 | __func__, pcdev->s_width, pcdev->s_height); | ||
1228 | |||
1229 | /* If the sensor does not support image size try PrP resizing */ | ||
1230 | emma_prp = mx27_emma_prp_get_format(xlate->code, | ||
1231 | xlate->host_fmt->fourcc); | ||
1232 | |||
1233 | if ((mf->width != pix->width || mf->height != pix->height) && | ||
1234 | emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) { | ||
1235 | if (mx2_emmaprp_resize(pcdev, mf, pix, false) < 0) | ||
1236 | dev_dbg(icd->parent, "%s: can't resize\n", __func__); | ||
1237 | } | ||
1238 | |||
1239 | if (mf->field == V4L2_FIELD_ANY) | ||
1240 | mf->field = V4L2_FIELD_NONE; | ||
1241 | /* | ||
1242 | * Driver supports interlaced images provided they have | ||
1243 | * both fields so that they can be processed as if they | ||
1244 | * were progressive. | ||
1245 | */ | ||
1246 | if (mf->field != V4L2_FIELD_NONE && !V4L2_FIELD_HAS_BOTH(mf->field)) { | ||
1247 | dev_err(icd->parent, "Field type %d unsupported.\n", | ||
1248 | mf->field); | ||
1249 | return -EINVAL; | ||
1250 | } | ||
1251 | |||
1252 | pix->width = mf->width; | ||
1253 | pix->height = mf->height; | ||
1254 | pix->field = mf->field; | ||
1255 | pix->colorspace = mf->colorspace; | ||
1256 | |||
1257 | dev_dbg(icd->parent, "%s: returned params: width = %d, height = %d\n", | ||
1258 | __func__, pix->width, pix->height); | ||
1259 | |||
1260 | return 0; | ||
1261 | } | ||
1262 | |||
1263 | static int mx2_camera_querycap(struct soc_camera_host *ici, | ||
1264 | struct v4l2_capability *cap) | ||
1265 | { | ||
1266 | /* cap->name is set by the friendly caller:-> */ | ||
1267 | strlcpy(cap->card, MX2_CAM_DRIVER_DESCRIPTION, sizeof(cap->card)); | ||
1268 | cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; | ||
1269 | cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; | ||
1270 | |||
1271 | return 0; | ||
1272 | } | ||
1273 | |||
1274 | static unsigned int mx2_camera_poll(struct file *file, poll_table *pt) | ||
1275 | { | ||
1276 | struct soc_camera_device *icd = file->private_data; | ||
1277 | |||
1278 | return vb2_poll(&icd->vb2_vidq, file, pt); | ||
1279 | } | ||
1280 | |||
1281 | static struct soc_camera_host_ops mx2_soc_camera_host_ops = { | ||
1282 | .owner = THIS_MODULE, | ||
1283 | .add = mx2_camera_add_device, | ||
1284 | .remove = mx2_camera_remove_device, | ||
1285 | .clock_start = mx2_camera_clock_start, | ||
1286 | .clock_stop = mx2_camera_clock_stop, | ||
1287 | .set_fmt = mx2_camera_set_fmt, | ||
1288 | .set_crop = mx2_camera_set_crop, | ||
1289 | .get_formats = mx2_camera_get_formats, | ||
1290 | .try_fmt = mx2_camera_try_fmt, | ||
1291 | .init_videobuf2 = mx2_camera_init_videobuf, | ||
1292 | .poll = mx2_camera_poll, | ||
1293 | .querycap = mx2_camera_querycap, | ||
1294 | .set_bus_param = mx2_camera_set_bus_param, | ||
1295 | }; | ||
1296 | |||
1297 | static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev, | ||
1298 | int bufnum, bool err) | ||
1299 | { | ||
1300 | #ifdef DEBUG | ||
1301 | struct mx2_fmt_cfg *prp = pcdev->emma_prp; | ||
1302 | #endif | ||
1303 | struct mx2_buf_internal *ibuf; | ||
1304 | struct mx2_buffer *buf; | ||
1305 | struct vb2_buffer *vb; | ||
1306 | struct vb2_v4l2_buffer *vbuf; | ||
1307 | unsigned long phys; | ||
1308 | |||
1309 | ibuf = list_first_entry(&pcdev->active_bufs, struct mx2_buf_internal, | ||
1310 | queue); | ||
1311 | |||
1312 | BUG_ON(ibuf->bufnum != bufnum); | ||
1313 | |||
1314 | if (ibuf->discard) { | ||
1315 | /* | ||
1316 | * Discard buffer must not be returned to user space. | ||
1317 | * Just return it to the discard queue. | ||
1318 | */ | ||
1319 | list_move_tail(pcdev->active_bufs.next, &pcdev->discard); | ||
1320 | } else { | ||
1321 | buf = mx2_ibuf_to_buf(ibuf); | ||
1322 | |||
1323 | vb = &buf->vb.vb2_buf; | ||
1324 | vbuf = to_vb2_v4l2_buffer(vb); | ||
1325 | #ifdef DEBUG | ||
1326 | phys = vb2_dma_contig_plane_dma_addr(vb, 0); | ||
1327 | if (prp->cfg.channel == 1) { | ||
1328 | if (readl(pcdev->base_emma + PRP_DEST_RGB1_PTR + | ||
1329 | 4 * bufnum) != phys) { | ||
1330 | dev_err(pcdev->dev, "%lx != %x\n", phys, | ||
1331 | readl(pcdev->base_emma + | ||
1332 | PRP_DEST_RGB1_PTR + 4 * bufnum)); | ||
1333 | } | ||
1334 | } else { | ||
1335 | if (readl(pcdev->base_emma + PRP_DEST_Y_PTR - | ||
1336 | 0x14 * bufnum) != phys) { | ||
1337 | dev_err(pcdev->dev, "%lx != %x\n", phys, | ||
1338 | readl(pcdev->base_emma + | ||
1339 | PRP_DEST_Y_PTR - 0x14 * bufnum)); | ||
1340 | } | ||
1341 | } | ||
1342 | #endif | ||
1343 | dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__, vb, | ||
1344 | vb2_plane_vaddr(vb, 0), | ||
1345 | vb2_get_plane_payload(vb, 0)); | ||
1346 | |||
1347 | list_del_init(&buf->internal.queue); | ||
1348 | vb->timestamp = ktime_get_ns(); | ||
1349 | vbuf->sequence = pcdev->frame_count; | ||
1350 | if (err) | ||
1351 | vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); | ||
1352 | else | ||
1353 | vb2_buffer_done(vb, VB2_BUF_STATE_DONE); | ||
1354 | } | ||
1355 | |||
1356 | pcdev->frame_count++; | ||
1357 | |||
1358 | if (list_empty(&pcdev->capture)) { | ||
1359 | if (list_empty(&pcdev->discard)) { | ||
1360 | dev_warn(pcdev->dev, "%s: trying to access empty discard list\n", | ||
1361 | __func__); | ||
1362 | return; | ||
1363 | } | ||
1364 | |||
1365 | ibuf = list_first_entry(&pcdev->discard, | ||
1366 | struct mx2_buf_internal, queue); | ||
1367 | ibuf->bufnum = bufnum; | ||
1368 | |||
1369 | list_move_tail(pcdev->discard.next, &pcdev->active_bufs); | ||
1370 | mx27_update_emma_buf(pcdev, pcdev->discard_buffer_dma, bufnum); | ||
1371 | return; | ||
1372 | } | ||
1373 | |||
1374 | buf = list_first_entry(&pcdev->capture, struct mx2_buffer, | ||
1375 | internal.queue); | ||
1376 | |||
1377 | buf->internal.bufnum = bufnum; | ||
1378 | |||
1379 | list_move_tail(pcdev->capture.next, &pcdev->active_bufs); | ||
1380 | |||
1381 | vb = &buf->vb.vb2_buf; | ||
1382 | |||
1383 | phys = vb2_dma_contig_plane_dma_addr(vb, 0); | ||
1384 | mx27_update_emma_buf(pcdev, phys, bufnum); | ||
1385 | } | ||
1386 | |||
1387 | static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data) | ||
1388 | { | ||
1389 | struct mx2_camera_dev *pcdev = data; | ||
1390 | unsigned int status = readl(pcdev->base_emma + PRP_INTRSTATUS); | ||
1391 | struct mx2_buf_internal *ibuf; | ||
1392 | |||
1393 | spin_lock(&pcdev->lock); | ||
1394 | |||
1395 | if (list_empty(&pcdev->active_bufs)) { | ||
1396 | dev_warn(pcdev->dev, "%s: called while active list is empty\n", | ||
1397 | __func__); | ||
1398 | |||
1399 | if (!status) { | ||
1400 | spin_unlock(&pcdev->lock); | ||
1401 | return IRQ_NONE; | ||
1402 | } | ||
1403 | } | ||
1404 | |||
1405 | if (status & (1 << 7)) { /* overflow */ | ||
1406 | u32 cntl = readl(pcdev->base_emma + PRP_CNTL); | ||
1407 | writel(cntl & ~(PRP_CNTL_CH1EN | PRP_CNTL_CH2EN), | ||
1408 | pcdev->base_emma + PRP_CNTL); | ||
1409 | writel(cntl, pcdev->base_emma + PRP_CNTL); | ||
1410 | |||
1411 | ibuf = list_first_entry(&pcdev->active_bufs, | ||
1412 | struct mx2_buf_internal, queue); | ||
1413 | mx27_camera_frame_done_emma(pcdev, | ||
1414 | ibuf->bufnum, true); | ||
1415 | |||
1416 | status &= ~(1 << 7); | ||
1417 | } else if (((status & (3 << 5)) == (3 << 5)) || | ||
1418 | ((status & (3 << 3)) == (3 << 3))) { | ||
1419 | /* | ||
1420 | * Both buffers have triggered, process the one we're expecting | ||
1421 | * to first | ||
1422 | */ | ||
1423 | ibuf = list_first_entry(&pcdev->active_bufs, | ||
1424 | struct mx2_buf_internal, queue); | ||
1425 | mx27_camera_frame_done_emma(pcdev, ibuf->bufnum, false); | ||
1426 | status &= ~(1 << (6 - ibuf->bufnum)); /* mark processed */ | ||
1427 | } else if ((status & (1 << 6)) || (status & (1 << 4))) { | ||
1428 | mx27_camera_frame_done_emma(pcdev, 0, false); | ||
1429 | } else if ((status & (1 << 5)) || (status & (1 << 3))) { | ||
1430 | mx27_camera_frame_done_emma(pcdev, 1, false); | ||
1431 | } | ||
1432 | |||
1433 | spin_unlock(&pcdev->lock); | ||
1434 | writel(status, pcdev->base_emma + PRP_INTRSTATUS); | ||
1435 | |||
1436 | return IRQ_HANDLED; | ||
1437 | } | ||
1438 | |||
1439 | static int mx27_camera_emma_init(struct platform_device *pdev) | ||
1440 | { | ||
1441 | struct mx2_camera_dev *pcdev = platform_get_drvdata(pdev); | ||
1442 | struct resource *res_emma; | ||
1443 | int irq_emma; | ||
1444 | int err = 0; | ||
1445 | |||
1446 | res_emma = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
1447 | irq_emma = platform_get_irq(pdev, 1); | ||
1448 | if (!res_emma || !irq_emma) { | ||
1449 | dev_err(pcdev->dev, "no EMMA resources\n"); | ||
1450 | err = -ENODEV; | ||
1451 | goto out; | ||
1452 | } | ||
1453 | |||
1454 | pcdev->base_emma = devm_ioremap_resource(pcdev->dev, res_emma); | ||
1455 | if (IS_ERR(pcdev->base_emma)) { | ||
1456 | err = PTR_ERR(pcdev->base_emma); | ||
1457 | goto out; | ||
1458 | } | ||
1459 | |||
1460 | err = devm_request_irq(pcdev->dev, irq_emma, mx27_camera_emma_irq, 0, | ||
1461 | MX2_CAM_DRV_NAME, pcdev); | ||
1462 | if (err) { | ||
1463 | dev_err(pcdev->dev, "Camera EMMA interrupt register failed\n"); | ||
1464 | goto out; | ||
1465 | } | ||
1466 | |||
1467 | pcdev->clk_emma_ipg = devm_clk_get(pcdev->dev, "emma-ipg"); | ||
1468 | if (IS_ERR(pcdev->clk_emma_ipg)) { | ||
1469 | err = PTR_ERR(pcdev->clk_emma_ipg); | ||
1470 | goto out; | ||
1471 | } | ||
1472 | |||
1473 | clk_prepare_enable(pcdev->clk_emma_ipg); | ||
1474 | |||
1475 | pcdev->clk_emma_ahb = devm_clk_get(pcdev->dev, "emma-ahb"); | ||
1476 | if (IS_ERR(pcdev->clk_emma_ahb)) { | ||
1477 | err = PTR_ERR(pcdev->clk_emma_ahb); | ||
1478 | goto exit_clk_emma_ipg; | ||
1479 | } | ||
1480 | |||
1481 | clk_prepare_enable(pcdev->clk_emma_ahb); | ||
1482 | |||
1483 | err = mx27_camera_emma_prp_reset(pcdev); | ||
1484 | if (err) | ||
1485 | goto exit_clk_emma_ahb; | ||
1486 | |||
1487 | return err; | ||
1488 | |||
1489 | exit_clk_emma_ahb: | ||
1490 | clk_disable_unprepare(pcdev->clk_emma_ahb); | ||
1491 | exit_clk_emma_ipg: | ||
1492 | clk_disable_unprepare(pcdev->clk_emma_ipg); | ||
1493 | out: | ||
1494 | return err; | ||
1495 | } | ||
1496 | |||
1497 | static int mx2_camera_probe(struct platform_device *pdev) | ||
1498 | { | ||
1499 | struct mx2_camera_dev *pcdev; | ||
1500 | struct resource *res_csi; | ||
1501 | int irq_csi; | ||
1502 | int err = 0; | ||
1503 | |||
1504 | dev_dbg(&pdev->dev, "initialising\n"); | ||
1505 | |||
1506 | res_csi = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1507 | irq_csi = platform_get_irq(pdev, 0); | ||
1508 | if (res_csi == NULL || irq_csi < 0) { | ||
1509 | dev_err(&pdev->dev, "Missing platform resources data\n"); | ||
1510 | err = -ENODEV; | ||
1511 | goto exit; | ||
1512 | } | ||
1513 | |||
1514 | pcdev = devm_kzalloc(&pdev->dev, sizeof(*pcdev), GFP_KERNEL); | ||
1515 | if (!pcdev) { | ||
1516 | dev_err(&pdev->dev, "Could not allocate pcdev\n"); | ||
1517 | err = -ENOMEM; | ||
1518 | goto exit; | ||
1519 | } | ||
1520 | |||
1521 | pcdev->clk_csi_ahb = devm_clk_get(&pdev->dev, "ahb"); | ||
1522 | if (IS_ERR(pcdev->clk_csi_ahb)) { | ||
1523 | dev_err(&pdev->dev, "Could not get csi ahb clock\n"); | ||
1524 | err = PTR_ERR(pcdev->clk_csi_ahb); | ||
1525 | goto exit; | ||
1526 | } | ||
1527 | |||
1528 | pcdev->clk_csi_per = devm_clk_get(&pdev->dev, "per"); | ||
1529 | if (IS_ERR(pcdev->clk_csi_per)) { | ||
1530 | dev_err(&pdev->dev, "Could not get csi per clock\n"); | ||
1531 | err = PTR_ERR(pcdev->clk_csi_per); | ||
1532 | goto exit; | ||
1533 | } | ||
1534 | |||
1535 | pcdev->pdata = pdev->dev.platform_data; | ||
1536 | if (pcdev->pdata) { | ||
1537 | long rate; | ||
1538 | |||
1539 | pcdev->platform_flags = pcdev->pdata->flags; | ||
1540 | |||
1541 | rate = clk_round_rate(pcdev->clk_csi_per, | ||
1542 | pcdev->pdata->clk * 2); | ||
1543 | if (rate <= 0) { | ||
1544 | err = -ENODEV; | ||
1545 | goto exit; | ||
1546 | } | ||
1547 | err = clk_set_rate(pcdev->clk_csi_per, rate); | ||
1548 | if (err < 0) | ||
1549 | goto exit; | ||
1550 | } | ||
1551 | |||
1552 | INIT_LIST_HEAD(&pcdev->capture); | ||
1553 | INIT_LIST_HEAD(&pcdev->active_bufs); | ||
1554 | INIT_LIST_HEAD(&pcdev->discard); | ||
1555 | spin_lock_init(&pcdev->lock); | ||
1556 | |||
1557 | pcdev->base_csi = devm_ioremap_resource(&pdev->dev, res_csi); | ||
1558 | if (IS_ERR(pcdev->base_csi)) { | ||
1559 | err = PTR_ERR(pcdev->base_csi); | ||
1560 | goto exit; | ||
1561 | } | ||
1562 | |||
1563 | pcdev->dev = &pdev->dev; | ||
1564 | platform_set_drvdata(pdev, pcdev); | ||
1565 | |||
1566 | err = mx27_camera_emma_init(pdev); | ||
1567 | if (err) | ||
1568 | goto exit; | ||
1569 | |||
1570 | /* | ||
1571 | * We're done with drvdata here. Clear the pointer so that | ||
1572 | * v4l2 core can start using drvdata on its purpose. | ||
1573 | */ | ||
1574 | platform_set_drvdata(pdev, NULL); | ||
1575 | |||
1576 | pcdev->soc_host.drv_name = MX2_CAM_DRV_NAME, | ||
1577 | pcdev->soc_host.ops = &mx2_soc_camera_host_ops, | ||
1578 | pcdev->soc_host.priv = pcdev; | ||
1579 | pcdev->soc_host.v4l2_dev.dev = &pdev->dev; | ||
1580 | pcdev->soc_host.nr = pdev->id; | ||
1581 | |||
1582 | pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); | ||
1583 | if (IS_ERR(pcdev->alloc_ctx)) { | ||
1584 | err = PTR_ERR(pcdev->alloc_ctx); | ||
1585 | goto eallocctx; | ||
1586 | } | ||
1587 | err = soc_camera_host_register(&pcdev->soc_host); | ||
1588 | if (err) | ||
1589 | goto exit_free_emma; | ||
1590 | |||
1591 | dev_info(&pdev->dev, "MX2 Camera (CSI) driver probed, clock frequency: %ld\n", | ||
1592 | clk_get_rate(pcdev->clk_csi_per)); | ||
1593 | |||
1594 | return 0; | ||
1595 | |||
1596 | exit_free_emma: | ||
1597 | vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); | ||
1598 | eallocctx: | ||
1599 | clk_disable_unprepare(pcdev->clk_emma_ipg); | ||
1600 | clk_disable_unprepare(pcdev->clk_emma_ahb); | ||
1601 | exit: | ||
1602 | return err; | ||
1603 | } | ||
1604 | |||
1605 | static int mx2_camera_remove(struct platform_device *pdev) | ||
1606 | { | ||
1607 | struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); | ||
1608 | struct mx2_camera_dev *pcdev = container_of(soc_host, | ||
1609 | struct mx2_camera_dev, soc_host); | ||
1610 | |||
1611 | soc_camera_host_unregister(&pcdev->soc_host); | ||
1612 | |||
1613 | vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); | ||
1614 | |||
1615 | clk_disable_unprepare(pcdev->clk_emma_ipg); | ||
1616 | clk_disable_unprepare(pcdev->clk_emma_ahb); | ||
1617 | |||
1618 | dev_info(&pdev->dev, "MX2 Camera driver unloaded\n"); | ||
1619 | |||
1620 | return 0; | ||
1621 | } | ||
1622 | |||
1623 | static struct platform_driver mx2_camera_driver = { | ||
1624 | .driver = { | ||
1625 | .name = MX2_CAM_DRV_NAME, | ||
1626 | }, | ||
1627 | .id_table = mx2_camera_devtype, | ||
1628 | .remove = mx2_camera_remove, | ||
1629 | }; | ||
1630 | |||
1631 | module_platform_driver_probe(mx2_camera_driver, mx2_camera_probe); | ||
1632 | |||
1633 | MODULE_DESCRIPTION("i.MX27 SoC Camera Host driver"); | ||
1634 | MODULE_AUTHOR("Sascha Hauer <sha@pengutronix.de>"); | ||
1635 | MODULE_LICENSE("GPL"); | ||
1636 | MODULE_VERSION(MX2_CAM_VERSION); | ||
diff --git a/drivers/staging/media/mx3/Kconfig b/drivers/staging/media/mx3/Kconfig deleted file mode 100644 index 595d5fe7cad1..000000000000 --- a/drivers/staging/media/mx3/Kconfig +++ /dev/null | |||
@@ -1,15 +0,0 @@ | |||
1 | config VIDEO_MX3 | ||
2 | tristate "i.MX3x Camera Sensor Interface driver" | ||
3 | depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA | ||
4 | depends on MX3_IPU || COMPILE_TEST | ||
5 | depends on HAS_DMA | ||
6 | select VIDEOBUF2_DMA_CONTIG | ||
7 | ---help--- | ||
8 | This is a v4l2 driver for the i.MX3x Camera Sensor Interface | ||
9 | |||
10 | This driver is deprecated: it should become a stand-alone driver | ||
11 | instead of using the soc-camera framework. | ||
12 | |||
13 | Unless someone is willing to take this on (unlikely with such | ||
14 | ancient hardware) it is going to be removed from the kernel | ||
15 | soon. | ||
diff --git a/drivers/staging/media/mx3/Makefile b/drivers/staging/media/mx3/Makefile deleted file mode 100644 index 6d91dcd80c1d..000000000000 --- a/drivers/staging/media/mx3/Makefile +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | # Makefile for i.MX3x Camera Sensor driver | ||
2 | |||
3 | obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o | ||
diff --git a/drivers/staging/media/mx3/TODO b/drivers/staging/media/mx3/TODO deleted file mode 100644 index bc68fa443a3e..000000000000 --- a/drivers/staging/media/mx3/TODO +++ /dev/null | |||
@@ -1,10 +0,0 @@ | |||
1 | This driver is deprecated: it should become a stand-alone driver instead of | ||
2 | using the soc-camera framework. | ||
3 | |||
4 | Unless someone is willing to take this on (unlikely with such ancient | ||
5 | hardware) it is going to be removed from the kernel soon. | ||
6 | |||
7 | Note that trivial patches will not be accepted anymore, only a full conversion. | ||
8 | |||
9 | If you want to convert this driver, please contact the linux-media mailinglist | ||
10 | (see http://linuxtv.org/lists.php). | ||
diff --git a/drivers/staging/media/mx3/mx3_camera.c b/drivers/staging/media/mx3/mx3_camera.c deleted file mode 100644 index aa39e9569b1a..000000000000 --- a/drivers/staging/media/mx3/mx3_camera.c +++ /dev/null | |||
@@ -1,1264 +0,0 @@ | |||
1 | /* | ||
2 | * V4L2 Driver for i.MX3x camera host | ||
3 | * | ||
4 | * Copyright (C) 2008 | ||
5 | * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/videodev2.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/clk.h> | ||
17 | #include <linux/vmalloc.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/dma/ipu-dma.h> | ||
21 | |||
22 | #include <media/v4l2-common.h> | ||
23 | #include <media/v4l2-dev.h> | ||
24 | #include <media/videobuf2-dma-contig.h> | ||
25 | #include <media/soc_camera.h> | ||
26 | #include <media/drv-intf/soc_mediabus.h> | ||
27 | |||
28 | #include <linux/platform_data/media/camera-mx3.h> | ||
29 | #include <linux/platform_data/dma-imx.h> | ||
30 | |||
31 | #define MX3_CAM_DRV_NAME "mx3-camera" | ||
32 | |||
33 | /* CMOS Sensor Interface Registers */ | ||
34 | #define CSI_REG_START 0x60 | ||
35 | |||
36 | #define CSI_SENS_CONF (0x60 - CSI_REG_START) | ||
37 | #define CSI_SENS_FRM_SIZE (0x64 - CSI_REG_START) | ||
38 | #define CSI_ACT_FRM_SIZE (0x68 - CSI_REG_START) | ||
39 | #define CSI_OUT_FRM_CTRL (0x6C - CSI_REG_START) | ||
40 | #define CSI_TST_CTRL (0x70 - CSI_REG_START) | ||
41 | #define CSI_CCIR_CODE_1 (0x74 - CSI_REG_START) | ||
42 | #define CSI_CCIR_CODE_2 (0x78 - CSI_REG_START) | ||
43 | #define CSI_CCIR_CODE_3 (0x7C - CSI_REG_START) | ||
44 | #define CSI_FLASH_STROBE_1 (0x80 - CSI_REG_START) | ||
45 | #define CSI_FLASH_STROBE_2 (0x84 - CSI_REG_START) | ||
46 | |||
47 | #define CSI_SENS_CONF_VSYNC_POL_SHIFT 0 | ||
48 | #define CSI_SENS_CONF_HSYNC_POL_SHIFT 1 | ||
49 | #define CSI_SENS_CONF_DATA_POL_SHIFT 2 | ||
50 | #define CSI_SENS_CONF_PIX_CLK_POL_SHIFT 3 | ||
51 | #define CSI_SENS_CONF_SENS_PRTCL_SHIFT 4 | ||
52 | #define CSI_SENS_CONF_SENS_CLKSRC_SHIFT 7 | ||
53 | #define CSI_SENS_CONF_DATA_FMT_SHIFT 8 | ||
54 | #define CSI_SENS_CONF_DATA_WIDTH_SHIFT 10 | ||
55 | #define CSI_SENS_CONF_EXT_VSYNC_SHIFT 15 | ||
56 | #define CSI_SENS_CONF_DIVRATIO_SHIFT 16 | ||
57 | |||
58 | #define CSI_SENS_CONF_DATA_FMT_RGB_YUV444 (0UL << CSI_SENS_CONF_DATA_FMT_SHIFT) | ||
59 | #define CSI_SENS_CONF_DATA_FMT_YUV422 (2UL << CSI_SENS_CONF_DATA_FMT_SHIFT) | ||
60 | #define CSI_SENS_CONF_DATA_FMT_BAYER (3UL << CSI_SENS_CONF_DATA_FMT_SHIFT) | ||
61 | |||
62 | #define MAX_VIDEO_MEM 16 | ||
63 | |||
64 | struct mx3_camera_buffer { | ||
65 | /* common v4l buffer stuff -- must be first */ | ||
66 | struct vb2_v4l2_buffer vb; | ||
67 | struct list_head queue; | ||
68 | |||
69 | /* One descriptot per scatterlist (per frame) */ | ||
70 | struct dma_async_tx_descriptor *txd; | ||
71 | |||
72 | /* We have to "build" a scatterlist ourselves - one element per frame */ | ||
73 | struct scatterlist sg; | ||
74 | }; | ||
75 | |||
76 | /** | ||
77 | * struct mx3_camera_dev - i.MX3x camera (CSI) object | ||
78 | * @dev: camera device, to which the coherent buffer is attached | ||
79 | * @icd: currently attached camera sensor | ||
80 | * @clk: pointer to clock | ||
81 | * @base: remapped register base address | ||
82 | * @pdata: platform data | ||
83 | * @platform_flags: platform flags | ||
84 | * @mclk: master clock frequency in Hz | ||
85 | * @capture: list of capture videobuffers | ||
86 | * @lock: protects video buffer lists | ||
87 | * @active: active video buffer | ||
88 | * @idmac_channel: array of pointers to IPU DMAC DMA channels | ||
89 | * @soc_host: embedded soc_host object | ||
90 | */ | ||
91 | struct mx3_camera_dev { | ||
92 | /* | ||
93 | * i.MX3x is only supposed to handle one camera on its Camera Sensor | ||
94 | * Interface. If anyone ever builds hardware to enable more than one | ||
95 | * camera _simultaneously_, they will have to modify this driver too | ||
96 | */ | ||
97 | struct clk *clk; | ||
98 | |||
99 | void __iomem *base; | ||
100 | |||
101 | struct mx3_camera_pdata *pdata; | ||
102 | |||
103 | unsigned long platform_flags; | ||
104 | unsigned long mclk; | ||
105 | u16 width_flags; /* max 15 bits */ | ||
106 | |||
107 | struct list_head capture; | ||
108 | spinlock_t lock; /* Protects video buffer lists */ | ||
109 | struct mx3_camera_buffer *active; | ||
110 | size_t buf_total; | ||
111 | struct vb2_alloc_ctx *alloc_ctx; | ||
112 | enum v4l2_field field; | ||
113 | int sequence; | ||
114 | |||
115 | /* IDMAC / dmaengine interface */ | ||
116 | struct idmac_channel *idmac_channel[1]; /* We need one channel */ | ||
117 | |||
118 | struct soc_camera_host soc_host; | ||
119 | }; | ||
120 | |||
121 | struct dma_chan_request { | ||
122 | struct mx3_camera_dev *mx3_cam; | ||
123 | enum ipu_channel id; | ||
124 | }; | ||
125 | |||
126 | static u32 csi_reg_read(struct mx3_camera_dev *mx3, off_t reg) | ||
127 | { | ||
128 | return __raw_readl(mx3->base + reg); | ||
129 | } | ||
130 | |||
131 | static void csi_reg_write(struct mx3_camera_dev *mx3, u32 value, off_t reg) | ||
132 | { | ||
133 | __raw_writel(value, mx3->base + reg); | ||
134 | } | ||
135 | |||
136 | static struct mx3_camera_buffer *to_mx3_vb(struct vb2_v4l2_buffer *vb) | ||
137 | { | ||
138 | return container_of(vb, struct mx3_camera_buffer, vb); | ||
139 | } | ||
140 | |||
141 | /* Called from the IPU IDMAC ISR */ | ||
142 | static void mx3_cam_dma_done(void *arg) | ||
143 | { | ||
144 | struct idmac_tx_desc *desc = to_tx_desc(arg); | ||
145 | struct dma_chan *chan = desc->txd.chan; | ||
146 | struct idmac_channel *ichannel = to_idmac_chan(chan); | ||
147 | struct mx3_camera_dev *mx3_cam = ichannel->client; | ||
148 | |||
149 | dev_dbg(chan->device->dev, "callback cookie %d, active DMA %pad\n", | ||
150 | desc->txd.cookie, mx3_cam->active ? &sg_dma_address(&mx3_cam->active->sg) : NULL); | ||
151 | |||
152 | spin_lock(&mx3_cam->lock); | ||
153 | if (mx3_cam->active) { | ||
154 | struct vb2_v4l2_buffer *vb = &mx3_cam->active->vb; | ||
155 | struct mx3_camera_buffer *buf = to_mx3_vb(vb); | ||
156 | |||
157 | list_del_init(&buf->queue); | ||
158 | vb->vb2_buf.timestamp = ktime_get_ns(); | ||
159 | vb->field = mx3_cam->field; | ||
160 | vb->sequence = mx3_cam->sequence++; | ||
161 | vb2_buffer_done(&vb->vb2_buf, VB2_BUF_STATE_DONE); | ||
162 | } | ||
163 | |||
164 | if (list_empty(&mx3_cam->capture)) { | ||
165 | mx3_cam->active = NULL; | ||
166 | spin_unlock(&mx3_cam->lock); | ||
167 | |||
168 | /* | ||
169 | * stop capture - without further buffers IPU_CHA_BUF0_RDY will | ||
170 | * not get updated | ||
171 | */ | ||
172 | return; | ||
173 | } | ||
174 | |||
175 | mx3_cam->active = list_entry(mx3_cam->capture.next, | ||
176 | struct mx3_camera_buffer, queue); | ||
177 | spin_unlock(&mx3_cam->lock); | ||
178 | } | ||
179 | |||
180 | /* | ||
181 | * Videobuf operations | ||
182 | */ | ||
183 | |||
184 | /* | ||
185 | * Calculate the __buffer__ (not data) size and number of buffers. | ||
186 | */ | ||
187 | static int mx3_videobuf_setup(struct vb2_queue *vq, | ||
188 | unsigned int *count, unsigned int *num_planes, | ||
189 | unsigned int sizes[], void *alloc_ctxs[]) | ||
190 | { | ||
191 | struct soc_camera_device *icd = soc_camera_from_vb2q(vq); | ||
192 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
193 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
194 | |||
195 | if (!mx3_cam->idmac_channel[0]) | ||
196 | return -EINVAL; | ||
197 | |||
198 | alloc_ctxs[0] = mx3_cam->alloc_ctx; | ||
199 | |||
200 | if (!vq->num_buffers) | ||
201 | mx3_cam->sequence = 0; | ||
202 | |||
203 | if (!*count) | ||
204 | *count = 2; | ||
205 | |||
206 | /* Called from VIDIOC_REQBUFS or in compatibility mode */ | ||
207 | if (!*num_planes) | ||
208 | sizes[0] = icd->sizeimage; | ||
209 | else if (sizes[0] < icd->sizeimage) | ||
210 | return -EINVAL; | ||
211 | |||
212 | /* If *num_planes != 0, we have already verified *count. */ | ||
213 | if (sizes[0] * *count + mx3_cam->buf_total > MAX_VIDEO_MEM * 1024 * 1024) | ||
214 | *count = (MAX_VIDEO_MEM * 1024 * 1024 - mx3_cam->buf_total) / | ||
215 | sizes[0]; | ||
216 | |||
217 | *num_planes = 1; | ||
218 | |||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | static enum pixel_fmt fourcc_to_ipu_pix(__u32 fourcc) | ||
223 | { | ||
224 | /* Add more formats as need arises and test possibilities appear... */ | ||
225 | switch (fourcc) { | ||
226 | case V4L2_PIX_FMT_RGB24: | ||
227 | return IPU_PIX_FMT_RGB24; | ||
228 | case V4L2_PIX_FMT_UYVY: | ||
229 | case V4L2_PIX_FMT_RGB565: | ||
230 | default: | ||
231 | return IPU_PIX_FMT_GENERIC; | ||
232 | } | ||
233 | } | ||
234 | |||
235 | static void mx3_videobuf_queue(struct vb2_buffer *vb) | ||
236 | { | ||
237 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | ||
238 | struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); | ||
239 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
240 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
241 | struct mx3_camera_buffer *buf = to_mx3_vb(vbuf); | ||
242 | struct scatterlist *sg = &buf->sg; | ||
243 | struct dma_async_tx_descriptor *txd; | ||
244 | struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; | ||
245 | struct idmac_video_param *video = &ichan->params.video; | ||
246 | const struct soc_mbus_pixelfmt *host_fmt = icd->current_fmt->host_fmt; | ||
247 | dma_cookie_t cookie; | ||
248 | size_t new_size; | ||
249 | |||
250 | new_size = icd->sizeimage; | ||
251 | |||
252 | if (vb2_plane_size(vb, 0) < new_size) { | ||
253 | dev_err(icd->parent, "Buffer #%d too small (%lu < %zu)\n", | ||
254 | vbuf->vb2_buf.index, vb2_plane_size(vb, 0), new_size); | ||
255 | goto error; | ||
256 | } | ||
257 | |||
258 | if (!buf->txd) { | ||
259 | sg_dma_address(sg) = vb2_dma_contig_plane_dma_addr(vb, 0); | ||
260 | sg_dma_len(sg) = new_size; | ||
261 | |||
262 | txd = dmaengine_prep_slave_sg( | ||
263 | &ichan->dma_chan, sg, 1, DMA_DEV_TO_MEM, | ||
264 | DMA_PREP_INTERRUPT); | ||
265 | if (!txd) | ||
266 | goto error; | ||
267 | |||
268 | txd->callback_param = txd; | ||
269 | txd->callback = mx3_cam_dma_done; | ||
270 | |||
271 | buf->txd = txd; | ||
272 | } else { | ||
273 | txd = buf->txd; | ||
274 | } | ||
275 | |||
276 | vb2_set_plane_payload(vb, 0, new_size); | ||
277 | |||
278 | /* This is the configuration of one sg-element */ | ||
279 | video->out_pixel_fmt = fourcc_to_ipu_pix(host_fmt->fourcc); | ||
280 | |||
281 | if (video->out_pixel_fmt == IPU_PIX_FMT_GENERIC) { | ||
282 | /* | ||
283 | * If the IPU DMA channel is configured to transfer generic | ||
284 | * 8-bit data, we have to set up the geometry parameters | ||
285 | * correctly, according to the current pixel format. The DMA | ||
286 | * horizontal parameters in this case are expressed in bytes, | ||
287 | * not in pixels. | ||
288 | */ | ||
289 | video->out_width = icd->bytesperline; | ||
290 | video->out_height = icd->user_height; | ||
291 | video->out_stride = icd->bytesperline; | ||
292 | } else { | ||
293 | /* | ||
294 | * For IPU known formats the pixel unit will be managed | ||
295 | * successfully by the IPU code | ||
296 | */ | ||
297 | video->out_width = icd->user_width; | ||
298 | video->out_height = icd->user_height; | ||
299 | video->out_stride = icd->user_width; | ||
300 | } | ||
301 | |||
302 | #ifdef DEBUG | ||
303 | /* helps to see what DMA actually has written */ | ||
304 | if (vb2_plane_vaddr(vb, 0)) | ||
305 | memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0)); | ||
306 | #endif | ||
307 | |||
308 | spin_lock_irq(&mx3_cam->lock); | ||
309 | list_add_tail(&buf->queue, &mx3_cam->capture); | ||
310 | |||
311 | if (!mx3_cam->active) | ||
312 | mx3_cam->active = buf; | ||
313 | |||
314 | spin_unlock_irq(&mx3_cam->lock); | ||
315 | |||
316 | cookie = txd->tx_submit(txd); | ||
317 | dev_dbg(icd->parent, "Submitted cookie %d DMA %pad\n", | ||
318 | cookie, &sg_dma_address(&buf->sg)); | ||
319 | |||
320 | if (cookie >= 0) | ||
321 | return; | ||
322 | |||
323 | spin_lock_irq(&mx3_cam->lock); | ||
324 | |||
325 | /* Submit error */ | ||
326 | list_del_init(&buf->queue); | ||
327 | |||
328 | if (mx3_cam->active == buf) | ||
329 | mx3_cam->active = NULL; | ||
330 | |||
331 | spin_unlock_irq(&mx3_cam->lock); | ||
332 | error: | ||
333 | vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); | ||
334 | } | ||
335 | |||
336 | static void mx3_videobuf_release(struct vb2_buffer *vb) | ||
337 | { | ||
338 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | ||
339 | struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); | ||
340 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
341 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
342 | struct mx3_camera_buffer *buf = to_mx3_vb(vbuf); | ||
343 | struct dma_async_tx_descriptor *txd = buf->txd; | ||
344 | unsigned long flags; | ||
345 | |||
346 | dev_dbg(icd->parent, | ||
347 | "Release%s DMA %pad, queue %sempty\n", | ||
348 | mx3_cam->active == buf ? " active" : "", &sg_dma_address(&buf->sg), | ||
349 | list_empty(&buf->queue) ? "" : "not "); | ||
350 | |||
351 | spin_lock_irqsave(&mx3_cam->lock, flags); | ||
352 | |||
353 | if (mx3_cam->active == buf) | ||
354 | mx3_cam->active = NULL; | ||
355 | |||
356 | /* Doesn't hurt also if the list is empty */ | ||
357 | list_del_init(&buf->queue); | ||
358 | |||
359 | if (txd) { | ||
360 | buf->txd = NULL; | ||
361 | if (mx3_cam->idmac_channel[0]) | ||
362 | async_tx_ack(txd); | ||
363 | } | ||
364 | |||
365 | spin_unlock_irqrestore(&mx3_cam->lock, flags); | ||
366 | |||
367 | mx3_cam->buf_total -= vb2_plane_size(vb, 0); | ||
368 | } | ||
369 | |||
370 | static int mx3_videobuf_init(struct vb2_buffer *vb) | ||
371 | { | ||
372 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | ||
373 | struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); | ||
374 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
375 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
376 | struct mx3_camera_buffer *buf = to_mx3_vb(vbuf); | ||
377 | |||
378 | if (!buf->txd) { | ||
379 | /* This is for locking debugging only */ | ||
380 | INIT_LIST_HEAD(&buf->queue); | ||
381 | sg_init_table(&buf->sg, 1); | ||
382 | |||
383 | mx3_cam->buf_total += vb2_plane_size(vb, 0); | ||
384 | } | ||
385 | |||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | static void mx3_stop_streaming(struct vb2_queue *q) | ||
390 | { | ||
391 | struct soc_camera_device *icd = soc_camera_from_vb2q(q); | ||
392 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
393 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
394 | struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; | ||
395 | struct mx3_camera_buffer *buf, *tmp; | ||
396 | unsigned long flags; | ||
397 | |||
398 | if (ichan) | ||
399 | dmaengine_pause(&ichan->dma_chan); | ||
400 | |||
401 | spin_lock_irqsave(&mx3_cam->lock, flags); | ||
402 | |||
403 | mx3_cam->active = NULL; | ||
404 | |||
405 | list_for_each_entry_safe(buf, tmp, &mx3_cam->capture, queue) { | ||
406 | list_del_init(&buf->queue); | ||
407 | vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); | ||
408 | } | ||
409 | |||
410 | spin_unlock_irqrestore(&mx3_cam->lock, flags); | ||
411 | } | ||
412 | |||
413 | static struct vb2_ops mx3_videobuf_ops = { | ||
414 | .queue_setup = mx3_videobuf_setup, | ||
415 | .buf_queue = mx3_videobuf_queue, | ||
416 | .buf_cleanup = mx3_videobuf_release, | ||
417 | .buf_init = mx3_videobuf_init, | ||
418 | .wait_prepare = vb2_ops_wait_prepare, | ||
419 | .wait_finish = vb2_ops_wait_finish, | ||
420 | .stop_streaming = mx3_stop_streaming, | ||
421 | }; | ||
422 | |||
423 | static int mx3_camera_init_videobuf(struct vb2_queue *q, | ||
424 | struct soc_camera_device *icd) | ||
425 | { | ||
426 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
427 | |||
428 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
429 | q->io_modes = VB2_MMAP | VB2_USERPTR; | ||
430 | q->drv_priv = icd; | ||
431 | q->ops = &mx3_videobuf_ops; | ||
432 | q->mem_ops = &vb2_dma_contig_memops; | ||
433 | q->buf_struct_size = sizeof(struct mx3_camera_buffer); | ||
434 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | ||
435 | q->lock = &ici->host_lock; | ||
436 | |||
437 | return vb2_queue_init(q); | ||
438 | } | ||
439 | |||
440 | /* First part of ipu_csi_init_interface() */ | ||
441 | static void mx3_camera_activate(struct mx3_camera_dev *mx3_cam) | ||
442 | { | ||
443 | u32 conf; | ||
444 | long rate; | ||
445 | |||
446 | /* Set default size: ipu_csi_set_window_size() */ | ||
447 | csi_reg_write(mx3_cam, (640 - 1) | ((480 - 1) << 16), CSI_ACT_FRM_SIZE); | ||
448 | /* ...and position to 0:0: ipu_csi_set_window_pos() */ | ||
449 | conf = csi_reg_read(mx3_cam, CSI_OUT_FRM_CTRL) & 0xffff0000; | ||
450 | csi_reg_write(mx3_cam, conf, CSI_OUT_FRM_CTRL); | ||
451 | |||
452 | /* We use only gated clock synchronisation mode so far */ | ||
453 | conf = 0 << CSI_SENS_CONF_SENS_PRTCL_SHIFT; | ||
454 | |||
455 | /* Set generic data, platform-biggest bus-width */ | ||
456 | conf |= CSI_SENS_CONF_DATA_FMT_BAYER; | ||
457 | |||
458 | if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15) | ||
459 | conf |= 3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; | ||
460 | else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10) | ||
461 | conf |= 2 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; | ||
462 | else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8) | ||
463 | conf |= 1 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; | ||
464 | else/* if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4)*/ | ||
465 | conf |= 0 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; | ||
466 | |||
467 | if (mx3_cam->platform_flags & MX3_CAMERA_CLK_SRC) | ||
468 | conf |= 1 << CSI_SENS_CONF_SENS_CLKSRC_SHIFT; | ||
469 | if (mx3_cam->platform_flags & MX3_CAMERA_EXT_VSYNC) | ||
470 | conf |= 1 << CSI_SENS_CONF_EXT_VSYNC_SHIFT; | ||
471 | if (mx3_cam->platform_flags & MX3_CAMERA_DP) | ||
472 | conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT; | ||
473 | if (mx3_cam->platform_flags & MX3_CAMERA_PCP) | ||
474 | conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT; | ||
475 | if (mx3_cam->platform_flags & MX3_CAMERA_HSP) | ||
476 | conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT; | ||
477 | if (mx3_cam->platform_flags & MX3_CAMERA_VSP) | ||
478 | conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT; | ||
479 | |||
480 | /* ipu_csi_init_interface() */ | ||
481 | csi_reg_write(mx3_cam, conf, CSI_SENS_CONF); | ||
482 | |||
483 | clk_prepare_enable(mx3_cam->clk); | ||
484 | rate = clk_round_rate(mx3_cam->clk, mx3_cam->mclk); | ||
485 | dev_dbg(mx3_cam->soc_host.v4l2_dev.dev, "Set SENS_CONF to %x, rate %ld\n", conf, rate); | ||
486 | if (rate) | ||
487 | clk_set_rate(mx3_cam->clk, rate); | ||
488 | } | ||
489 | |||
490 | static int mx3_camera_add_device(struct soc_camera_device *icd) | ||
491 | { | ||
492 | dev_info(icd->parent, "MX3 Camera driver attached to camera %d\n", | ||
493 | icd->devnum); | ||
494 | |||
495 | return 0; | ||
496 | } | ||
497 | |||
498 | static void mx3_camera_remove_device(struct soc_camera_device *icd) | ||
499 | { | ||
500 | dev_info(icd->parent, "MX3 Camera driver detached from camera %d\n", | ||
501 | icd->devnum); | ||
502 | } | ||
503 | |||
504 | /* Called with .host_lock held */ | ||
505 | static int mx3_camera_clock_start(struct soc_camera_host *ici) | ||
506 | { | ||
507 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
508 | |||
509 | mx3_camera_activate(mx3_cam); | ||
510 | |||
511 | mx3_cam->buf_total = 0; | ||
512 | |||
513 | return 0; | ||
514 | } | ||
515 | |||
516 | /* Called with .host_lock held */ | ||
517 | static void mx3_camera_clock_stop(struct soc_camera_host *ici) | ||
518 | { | ||
519 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
520 | struct idmac_channel **ichan = &mx3_cam->idmac_channel[0]; | ||
521 | |||
522 | if (*ichan) { | ||
523 | dma_release_channel(&(*ichan)->dma_chan); | ||
524 | *ichan = NULL; | ||
525 | } | ||
526 | |||
527 | clk_disable_unprepare(mx3_cam->clk); | ||
528 | } | ||
529 | |||
530 | static int test_platform_param(struct mx3_camera_dev *mx3_cam, | ||
531 | unsigned char buswidth, unsigned long *flags) | ||
532 | { | ||
533 | /* | ||
534 | * If requested data width is supported by the platform, use it or any | ||
535 | * possible lower value - i.MX31 is smart enough to shift bits | ||
536 | */ | ||
537 | if (buswidth > fls(mx3_cam->width_flags)) | ||
538 | return -EINVAL; | ||
539 | |||
540 | /* | ||
541 | * Platform specified synchronization and pixel clock polarities are | ||
542 | * only a recommendation and are only used during probing. MX3x | ||
543 | * camera interface only works in master mode, i.e., uses HSYNC and | ||
544 | * VSYNC signals from the sensor | ||
545 | */ | ||
546 | *flags = V4L2_MBUS_MASTER | | ||
547 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | | ||
548 | V4L2_MBUS_HSYNC_ACTIVE_LOW | | ||
549 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | | ||
550 | V4L2_MBUS_VSYNC_ACTIVE_LOW | | ||
551 | V4L2_MBUS_PCLK_SAMPLE_RISING | | ||
552 | V4L2_MBUS_PCLK_SAMPLE_FALLING | | ||
553 | V4L2_MBUS_DATA_ACTIVE_HIGH | | ||
554 | V4L2_MBUS_DATA_ACTIVE_LOW; | ||
555 | |||
556 | return 0; | ||
557 | } | ||
558 | |||
559 | static int mx3_camera_try_bus_param(struct soc_camera_device *icd, | ||
560 | const unsigned int depth) | ||
561 | { | ||
562 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
563 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
564 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
565 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; | ||
566 | unsigned long bus_flags, common_flags; | ||
567 | int ret = test_platform_param(mx3_cam, depth, &bus_flags); | ||
568 | |||
569 | dev_dbg(icd->parent, "request bus width %d bit: %d\n", depth, ret); | ||
570 | |||
571 | if (ret < 0) | ||
572 | return ret; | ||
573 | |||
574 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); | ||
575 | if (!ret) { | ||
576 | common_flags = soc_mbus_config_compatible(&cfg, | ||
577 | bus_flags); | ||
578 | if (!common_flags) { | ||
579 | dev_warn(icd->parent, | ||
580 | "Flags incompatible: camera 0x%x, host 0x%lx\n", | ||
581 | cfg.flags, bus_flags); | ||
582 | return -EINVAL; | ||
583 | } | ||
584 | } else if (ret != -ENOIOCTLCMD) { | ||
585 | return ret; | ||
586 | } | ||
587 | |||
588 | return 0; | ||
589 | } | ||
590 | |||
591 | static bool chan_filter(struct dma_chan *chan, void *arg) | ||
592 | { | ||
593 | struct dma_chan_request *rq = arg; | ||
594 | struct mx3_camera_pdata *pdata; | ||
595 | |||
596 | if (!imx_dma_is_ipu(chan)) | ||
597 | return false; | ||
598 | |||
599 | if (!rq) | ||
600 | return false; | ||
601 | |||
602 | pdata = rq->mx3_cam->soc_host.v4l2_dev.dev->platform_data; | ||
603 | |||
604 | return rq->id == chan->chan_id && | ||
605 | pdata->dma_dev == chan->device->dev; | ||
606 | } | ||
607 | |||
608 | static const struct soc_mbus_pixelfmt mx3_camera_formats[] = { | ||
609 | { | ||
610 | .fourcc = V4L2_PIX_FMT_SBGGR8, | ||
611 | .name = "Bayer BGGR (sRGB) 8 bit", | ||
612 | .bits_per_sample = 8, | ||
613 | .packing = SOC_MBUS_PACKING_NONE, | ||
614 | .order = SOC_MBUS_ORDER_LE, | ||
615 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
616 | }, { | ||
617 | .fourcc = V4L2_PIX_FMT_GREY, | ||
618 | .name = "Monochrome 8 bit", | ||
619 | .bits_per_sample = 8, | ||
620 | .packing = SOC_MBUS_PACKING_NONE, | ||
621 | .order = SOC_MBUS_ORDER_LE, | ||
622 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
623 | }, | ||
624 | }; | ||
625 | |||
626 | /* This will be corrected as we get more formats */ | ||
627 | static bool mx3_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt) | ||
628 | { | ||
629 | return fmt->packing == SOC_MBUS_PACKING_NONE || | ||
630 | (fmt->bits_per_sample == 8 && | ||
631 | fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) || | ||
632 | (fmt->bits_per_sample > 8 && | ||
633 | fmt->packing == SOC_MBUS_PACKING_EXTEND16); | ||
634 | } | ||
635 | |||
636 | static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int idx, | ||
637 | struct soc_camera_format_xlate *xlate) | ||
638 | { | ||
639 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
640 | struct device *dev = icd->parent; | ||
641 | int formats = 0, ret; | ||
642 | struct v4l2_subdev_mbus_code_enum code = { | ||
643 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
644 | .index = idx, | ||
645 | }; | ||
646 | const struct soc_mbus_pixelfmt *fmt; | ||
647 | |||
648 | ret = v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code); | ||
649 | if (ret < 0) | ||
650 | /* No more formats */ | ||
651 | return 0; | ||
652 | |||
653 | fmt = soc_mbus_get_fmtdesc(code.code); | ||
654 | if (!fmt) { | ||
655 | dev_warn(icd->parent, | ||
656 | "Unsupported format code #%u: 0x%x\n", idx, code.code); | ||
657 | return 0; | ||
658 | } | ||
659 | |||
660 | /* This also checks support for the requested bits-per-sample */ | ||
661 | ret = mx3_camera_try_bus_param(icd, fmt->bits_per_sample); | ||
662 | if (ret < 0) | ||
663 | return 0; | ||
664 | |||
665 | switch (code.code) { | ||
666 | case MEDIA_BUS_FMT_SBGGR10_1X10: | ||
667 | formats++; | ||
668 | if (xlate) { | ||
669 | xlate->host_fmt = &mx3_camera_formats[0]; | ||
670 | xlate->code = code.code; | ||
671 | xlate++; | ||
672 | dev_dbg(dev, "Providing format %s using code 0x%x\n", | ||
673 | mx3_camera_formats[0].name, code.code); | ||
674 | } | ||
675 | break; | ||
676 | case MEDIA_BUS_FMT_Y10_1X10: | ||
677 | formats++; | ||
678 | if (xlate) { | ||
679 | xlate->host_fmt = &mx3_camera_formats[1]; | ||
680 | xlate->code = code.code; | ||
681 | xlate++; | ||
682 | dev_dbg(dev, "Providing format %s using code 0x%x\n", | ||
683 | mx3_camera_formats[1].name, code.code); | ||
684 | } | ||
685 | break; | ||
686 | default: | ||
687 | if (!mx3_camera_packing_supported(fmt)) | ||
688 | return 0; | ||
689 | } | ||
690 | |||
691 | /* Generic pass-through */ | ||
692 | formats++; | ||
693 | if (xlate) { | ||
694 | xlate->host_fmt = fmt; | ||
695 | xlate->code = code.code; | ||
696 | dev_dbg(dev, "Providing format %c%c%c%c in pass-through mode\n", | ||
697 | (fmt->fourcc >> (0*8)) & 0xFF, | ||
698 | (fmt->fourcc >> (1*8)) & 0xFF, | ||
699 | (fmt->fourcc >> (2*8)) & 0xFF, | ||
700 | (fmt->fourcc >> (3*8)) & 0xFF); | ||
701 | xlate++; | ||
702 | } | ||
703 | |||
704 | return formats; | ||
705 | } | ||
706 | |||
707 | static void configure_geometry(struct mx3_camera_dev *mx3_cam, | ||
708 | unsigned int width, unsigned int height, | ||
709 | const struct soc_mbus_pixelfmt *fmt) | ||
710 | { | ||
711 | u32 ctrl, width_field, height_field; | ||
712 | |||
713 | if (fourcc_to_ipu_pix(fmt->fourcc) == IPU_PIX_FMT_GENERIC) { | ||
714 | /* | ||
715 | * As the CSI will be configured to output BAYER, here | ||
716 | * the width parameter count the number of samples to | ||
717 | * capture to complete the whole image width. | ||
718 | */ | ||
719 | unsigned int num, den; | ||
720 | int ret = soc_mbus_samples_per_pixel(fmt, &num, &den); | ||
721 | BUG_ON(ret < 0); | ||
722 | width = width * num / den; | ||
723 | } | ||
724 | |||
725 | /* Setup frame size - this cannot be changed on-the-fly... */ | ||
726 | width_field = width - 1; | ||
727 | height_field = height - 1; | ||
728 | csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_SENS_FRM_SIZE); | ||
729 | |||
730 | csi_reg_write(mx3_cam, width_field << 16, CSI_FLASH_STROBE_1); | ||
731 | csi_reg_write(mx3_cam, (height_field << 16) | 0x22, CSI_FLASH_STROBE_2); | ||
732 | |||
733 | csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_ACT_FRM_SIZE); | ||
734 | |||
735 | /* ...and position */ | ||
736 | ctrl = csi_reg_read(mx3_cam, CSI_OUT_FRM_CTRL) & 0xffff0000; | ||
737 | /* Sensor does the cropping */ | ||
738 | csi_reg_write(mx3_cam, ctrl | 0 | (0 << 8), CSI_OUT_FRM_CTRL); | ||
739 | } | ||
740 | |||
741 | static int acquire_dma_channel(struct mx3_camera_dev *mx3_cam) | ||
742 | { | ||
743 | dma_cap_mask_t mask; | ||
744 | struct dma_chan *chan; | ||
745 | struct idmac_channel **ichan = &mx3_cam->idmac_channel[0]; | ||
746 | /* We have to use IDMAC_IC_7 for Bayer / generic data */ | ||
747 | struct dma_chan_request rq = {.mx3_cam = mx3_cam, | ||
748 | .id = IDMAC_IC_7}; | ||
749 | |||
750 | dma_cap_zero(mask); | ||
751 | dma_cap_set(DMA_SLAVE, mask); | ||
752 | dma_cap_set(DMA_PRIVATE, mask); | ||
753 | chan = dma_request_channel(mask, chan_filter, &rq); | ||
754 | if (!chan) | ||
755 | return -EBUSY; | ||
756 | |||
757 | *ichan = to_idmac_chan(chan); | ||
758 | (*ichan)->client = mx3_cam; | ||
759 | |||
760 | return 0; | ||
761 | } | ||
762 | |||
763 | /* | ||
764 | * FIXME: learn to use stride != width, then we can keep stride properly aligned | ||
765 | * and support arbitrary (even) widths. | ||
766 | */ | ||
767 | static inline void stride_align(__u32 *width) | ||
768 | { | ||
769 | if (ALIGN(*width, 8) < 4096) | ||
770 | *width = ALIGN(*width, 8); | ||
771 | else | ||
772 | *width = *width & ~7; | ||
773 | } | ||
774 | |||
775 | /* | ||
776 | * As long as we don't implement host-side cropping and scaling, we can use | ||
777 | * default g_crop and cropcap from soc_camera.c | ||
778 | */ | ||
779 | static int mx3_camera_set_crop(struct soc_camera_device *icd, | ||
780 | const struct v4l2_crop *a) | ||
781 | { | ||
782 | struct v4l2_crop a_writable = *a; | ||
783 | struct v4l2_rect *rect = &a_writable.c; | ||
784 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
785 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
786 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
787 | struct v4l2_subdev_format fmt = { | ||
788 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
789 | }; | ||
790 | struct v4l2_mbus_framefmt *mf = &fmt.format; | ||
791 | int ret; | ||
792 | |||
793 | soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096); | ||
794 | soc_camera_limit_side(&rect->top, &rect->height, 0, 2, 4096); | ||
795 | |||
796 | ret = v4l2_subdev_call(sd, video, s_crop, a); | ||
797 | if (ret < 0) | ||
798 | return ret; | ||
799 | |||
800 | /* The capture device might have changed its output sizes */ | ||
801 | ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); | ||
802 | if (ret < 0) | ||
803 | return ret; | ||
804 | |||
805 | if (mf->code != icd->current_fmt->code) | ||
806 | return -EINVAL; | ||
807 | |||
808 | if (mf->width & 7) { | ||
809 | /* Ouch! We can only handle 8-byte aligned width... */ | ||
810 | stride_align(&mf->width); | ||
811 | ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &fmt); | ||
812 | if (ret < 0) | ||
813 | return ret; | ||
814 | } | ||
815 | |||
816 | if (mf->width != icd->user_width || mf->height != icd->user_height) | ||
817 | configure_geometry(mx3_cam, mf->width, mf->height, | ||
818 | icd->current_fmt->host_fmt); | ||
819 | |||
820 | dev_dbg(icd->parent, "Sensor cropped %dx%d\n", | ||
821 | mf->width, mf->height); | ||
822 | |||
823 | icd->user_width = mf->width; | ||
824 | icd->user_height = mf->height; | ||
825 | |||
826 | return ret; | ||
827 | } | ||
828 | |||
829 | static int mx3_camera_set_fmt(struct soc_camera_device *icd, | ||
830 | struct v4l2_format *f) | ||
831 | { | ||
832 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
833 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
834 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
835 | const struct soc_camera_format_xlate *xlate; | ||
836 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
837 | struct v4l2_subdev_format format = { | ||
838 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
839 | }; | ||
840 | struct v4l2_mbus_framefmt *mf = &format.format; | ||
841 | int ret; | ||
842 | |||
843 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); | ||
844 | if (!xlate) { | ||
845 | dev_warn(icd->parent, "Format %x not found\n", | ||
846 | pix->pixelformat); | ||
847 | return -EINVAL; | ||
848 | } | ||
849 | |||
850 | stride_align(&pix->width); | ||
851 | dev_dbg(icd->parent, "Set format %dx%d\n", pix->width, pix->height); | ||
852 | |||
853 | /* | ||
854 | * Might have to perform a complete interface initialisation like in | ||
855 | * ipu_csi_init_interface() in mxc_v4l2_s_param(). Also consider | ||
856 | * mxc_v4l2_s_fmt() | ||
857 | */ | ||
858 | |||
859 | configure_geometry(mx3_cam, pix->width, pix->height, xlate->host_fmt); | ||
860 | |||
861 | mf->width = pix->width; | ||
862 | mf->height = pix->height; | ||
863 | mf->field = pix->field; | ||
864 | mf->colorspace = pix->colorspace; | ||
865 | mf->code = xlate->code; | ||
866 | |||
867 | ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &format); | ||
868 | if (ret < 0) | ||
869 | return ret; | ||
870 | |||
871 | if (mf->code != xlate->code) | ||
872 | return -EINVAL; | ||
873 | |||
874 | if (!mx3_cam->idmac_channel[0]) { | ||
875 | ret = acquire_dma_channel(mx3_cam); | ||
876 | if (ret < 0) | ||
877 | return ret; | ||
878 | } | ||
879 | |||
880 | pix->width = mf->width; | ||
881 | pix->height = mf->height; | ||
882 | pix->field = mf->field; | ||
883 | mx3_cam->field = mf->field; | ||
884 | pix->colorspace = mf->colorspace; | ||
885 | icd->current_fmt = xlate; | ||
886 | |||
887 | dev_dbg(icd->parent, "Sensor set %dx%d\n", pix->width, pix->height); | ||
888 | |||
889 | return ret; | ||
890 | } | ||
891 | |||
892 | static int mx3_camera_try_fmt(struct soc_camera_device *icd, | ||
893 | struct v4l2_format *f) | ||
894 | { | ||
895 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
896 | const struct soc_camera_format_xlate *xlate; | ||
897 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
898 | struct v4l2_subdev_pad_config pad_cfg; | ||
899 | struct v4l2_subdev_format format = { | ||
900 | .which = V4L2_SUBDEV_FORMAT_TRY, | ||
901 | }; | ||
902 | struct v4l2_mbus_framefmt *mf = &format.format; | ||
903 | __u32 pixfmt = pix->pixelformat; | ||
904 | int ret; | ||
905 | |||
906 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | ||
907 | if (pixfmt && !xlate) { | ||
908 | dev_warn(icd->parent, "Format %x not found\n", pixfmt); | ||
909 | return -EINVAL; | ||
910 | } | ||
911 | |||
912 | /* limit to MX3 hardware capabilities */ | ||
913 | if (pix->height > 4096) | ||
914 | pix->height = 4096; | ||
915 | if (pix->width > 4096) | ||
916 | pix->width = 4096; | ||
917 | |||
918 | /* limit to sensor capabilities */ | ||
919 | mf->width = pix->width; | ||
920 | mf->height = pix->height; | ||
921 | mf->field = pix->field; | ||
922 | mf->colorspace = pix->colorspace; | ||
923 | mf->code = xlate->code; | ||
924 | |||
925 | ret = v4l2_subdev_call(sd, pad, set_fmt, &pad_cfg, &format); | ||
926 | if (ret < 0) | ||
927 | return ret; | ||
928 | |||
929 | pix->width = mf->width; | ||
930 | pix->height = mf->height; | ||
931 | pix->colorspace = mf->colorspace; | ||
932 | |||
933 | switch (mf->field) { | ||
934 | case V4L2_FIELD_ANY: | ||
935 | pix->field = V4L2_FIELD_NONE; | ||
936 | break; | ||
937 | case V4L2_FIELD_NONE: | ||
938 | break; | ||
939 | default: | ||
940 | dev_err(icd->parent, "Field type %d unsupported.\n", | ||
941 | mf->field); | ||
942 | ret = -EINVAL; | ||
943 | } | ||
944 | |||
945 | return ret; | ||
946 | } | ||
947 | |||
948 | static int mx3_camera_reqbufs(struct soc_camera_device *icd, | ||
949 | struct v4l2_requestbuffers *p) | ||
950 | { | ||
951 | return 0; | ||
952 | } | ||
953 | |||
954 | static unsigned int mx3_camera_poll(struct file *file, poll_table *pt) | ||
955 | { | ||
956 | struct soc_camera_device *icd = file->private_data; | ||
957 | |||
958 | return vb2_poll(&icd->vb2_vidq, file, pt); | ||
959 | } | ||
960 | |||
961 | static int mx3_camera_querycap(struct soc_camera_host *ici, | ||
962 | struct v4l2_capability *cap) | ||
963 | { | ||
964 | /* cap->name is set by the firendly caller:-> */ | ||
965 | strlcpy(cap->card, "i.MX3x Camera", sizeof(cap->card)); | ||
966 | cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; | ||
967 | cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; | ||
968 | |||
969 | return 0; | ||
970 | } | ||
971 | |||
972 | static int mx3_camera_set_bus_param(struct soc_camera_device *icd) | ||
973 | { | ||
974 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
975 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
976 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
977 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; | ||
978 | u32 pixfmt = icd->current_fmt->host_fmt->fourcc; | ||
979 | unsigned long bus_flags, common_flags; | ||
980 | u32 dw, sens_conf; | ||
981 | const struct soc_mbus_pixelfmt *fmt; | ||
982 | int buswidth; | ||
983 | int ret; | ||
984 | const struct soc_camera_format_xlate *xlate; | ||
985 | struct device *dev = icd->parent; | ||
986 | |||
987 | fmt = soc_mbus_get_fmtdesc(icd->current_fmt->code); | ||
988 | if (!fmt) | ||
989 | return -EINVAL; | ||
990 | |||
991 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | ||
992 | if (!xlate) { | ||
993 | dev_warn(dev, "Format %x not found\n", pixfmt); | ||
994 | return -EINVAL; | ||
995 | } | ||
996 | |||
997 | buswidth = fmt->bits_per_sample; | ||
998 | ret = test_platform_param(mx3_cam, buswidth, &bus_flags); | ||
999 | |||
1000 | dev_dbg(dev, "requested bus width %d bit: %d\n", buswidth, ret); | ||
1001 | |||
1002 | if (ret < 0) | ||
1003 | return ret; | ||
1004 | |||
1005 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); | ||
1006 | if (!ret) { | ||
1007 | common_flags = soc_mbus_config_compatible(&cfg, | ||
1008 | bus_flags); | ||
1009 | if (!common_flags) { | ||
1010 | dev_warn(icd->parent, | ||
1011 | "Flags incompatible: camera 0x%x, host 0x%lx\n", | ||
1012 | cfg.flags, bus_flags); | ||
1013 | return -EINVAL; | ||
1014 | } | ||
1015 | } else if (ret != -ENOIOCTLCMD) { | ||
1016 | return ret; | ||
1017 | } else { | ||
1018 | common_flags = bus_flags; | ||
1019 | } | ||
1020 | |||
1021 | dev_dbg(dev, "Flags cam: 0x%x host: 0x%lx common: 0x%lx\n", | ||
1022 | cfg.flags, bus_flags, common_flags); | ||
1023 | |||
1024 | /* Make choices, based on platform preferences */ | ||
1025 | if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && | ||
1026 | (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { | ||
1027 | if (mx3_cam->platform_flags & MX3_CAMERA_HSP) | ||
1028 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; | ||
1029 | else | ||
1030 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; | ||
1031 | } | ||
1032 | |||
1033 | if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && | ||
1034 | (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { | ||
1035 | if (mx3_cam->platform_flags & MX3_CAMERA_VSP) | ||
1036 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; | ||
1037 | else | ||
1038 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; | ||
1039 | } | ||
1040 | |||
1041 | if ((common_flags & V4L2_MBUS_DATA_ACTIVE_HIGH) && | ||
1042 | (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW)) { | ||
1043 | if (mx3_cam->platform_flags & MX3_CAMERA_DP) | ||
1044 | common_flags &= ~V4L2_MBUS_DATA_ACTIVE_HIGH; | ||
1045 | else | ||
1046 | common_flags &= ~V4L2_MBUS_DATA_ACTIVE_LOW; | ||
1047 | } | ||
1048 | |||
1049 | if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && | ||
1050 | (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { | ||
1051 | if (mx3_cam->platform_flags & MX3_CAMERA_PCP) | ||
1052 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; | ||
1053 | else | ||
1054 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; | ||
1055 | } | ||
1056 | |||
1057 | cfg.flags = common_flags; | ||
1058 | ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); | ||
1059 | if (ret < 0 && ret != -ENOIOCTLCMD) { | ||
1060 | dev_dbg(dev, "camera s_mbus_config(0x%lx) returned %d\n", | ||
1061 | common_flags, ret); | ||
1062 | return ret; | ||
1063 | } | ||
1064 | |||
1065 | /* | ||
1066 | * So far only gated clock mode is supported. Add a line | ||
1067 | * (3 << CSI_SENS_CONF_SENS_PRTCL_SHIFT) | | ||
1068 | * below and select the required mode when supporting other | ||
1069 | * synchronisation protocols. | ||
1070 | */ | ||
1071 | sens_conf = csi_reg_read(mx3_cam, CSI_SENS_CONF) & | ||
1072 | ~((1 << CSI_SENS_CONF_VSYNC_POL_SHIFT) | | ||
1073 | (1 << CSI_SENS_CONF_HSYNC_POL_SHIFT) | | ||
1074 | (1 << CSI_SENS_CONF_DATA_POL_SHIFT) | | ||
1075 | (1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT) | | ||
1076 | (3 << CSI_SENS_CONF_DATA_FMT_SHIFT) | | ||
1077 | (3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT)); | ||
1078 | |||
1079 | /* TODO: Support RGB and YUV formats */ | ||
1080 | |||
1081 | /* This has been set in mx3_camera_activate(), but we clear it above */ | ||
1082 | sens_conf |= CSI_SENS_CONF_DATA_FMT_BAYER; | ||
1083 | |||
1084 | if (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) | ||
1085 | sens_conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT; | ||
1086 | if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) | ||
1087 | sens_conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT; | ||
1088 | if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) | ||
1089 | sens_conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT; | ||
1090 | if (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW) | ||
1091 | sens_conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT; | ||
1092 | |||
1093 | /* Just do what we're asked to do */ | ||
1094 | switch (xlate->host_fmt->bits_per_sample) { | ||
1095 | case 4: | ||
1096 | dw = 0 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; | ||
1097 | break; | ||
1098 | case 8: | ||
1099 | dw = 1 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; | ||
1100 | break; | ||
1101 | case 10: | ||
1102 | dw = 2 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; | ||
1103 | break; | ||
1104 | default: | ||
1105 | /* | ||
1106 | * Actually it can only be 15 now, default is just to silence | ||
1107 | * compiler warnings | ||
1108 | */ | ||
1109 | case 15: | ||
1110 | dw = 3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; | ||
1111 | } | ||
1112 | |||
1113 | csi_reg_write(mx3_cam, sens_conf | dw, CSI_SENS_CONF); | ||
1114 | |||
1115 | dev_dbg(dev, "Set SENS_CONF to %x\n", sens_conf | dw); | ||
1116 | |||
1117 | return 0; | ||
1118 | } | ||
1119 | |||
1120 | static struct soc_camera_host_ops mx3_soc_camera_host_ops = { | ||
1121 | .owner = THIS_MODULE, | ||
1122 | .add = mx3_camera_add_device, | ||
1123 | .remove = mx3_camera_remove_device, | ||
1124 | .clock_start = mx3_camera_clock_start, | ||
1125 | .clock_stop = mx3_camera_clock_stop, | ||
1126 | .set_crop = mx3_camera_set_crop, | ||
1127 | .set_fmt = mx3_camera_set_fmt, | ||
1128 | .try_fmt = mx3_camera_try_fmt, | ||
1129 | .get_formats = mx3_camera_get_formats, | ||
1130 | .init_videobuf2 = mx3_camera_init_videobuf, | ||
1131 | .reqbufs = mx3_camera_reqbufs, | ||
1132 | .poll = mx3_camera_poll, | ||
1133 | .querycap = mx3_camera_querycap, | ||
1134 | .set_bus_param = mx3_camera_set_bus_param, | ||
1135 | }; | ||
1136 | |||
1137 | static int mx3_camera_probe(struct platform_device *pdev) | ||
1138 | { | ||
1139 | struct mx3_camera_pdata *pdata = pdev->dev.platform_data; | ||
1140 | struct mx3_camera_dev *mx3_cam; | ||
1141 | struct resource *res; | ||
1142 | void __iomem *base; | ||
1143 | int err = 0; | ||
1144 | struct soc_camera_host *soc_host; | ||
1145 | |||
1146 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1147 | base = devm_ioremap_resource(&pdev->dev, res); | ||
1148 | if (IS_ERR(base)) | ||
1149 | return PTR_ERR(base); | ||
1150 | |||
1151 | if (!pdata) | ||
1152 | return -EINVAL; | ||
1153 | |||
1154 | mx3_cam = devm_kzalloc(&pdev->dev, sizeof(*mx3_cam), GFP_KERNEL); | ||
1155 | if (!mx3_cam) { | ||
1156 | dev_err(&pdev->dev, "Could not allocate mx3 camera object\n"); | ||
1157 | return -ENOMEM; | ||
1158 | } | ||
1159 | |||
1160 | mx3_cam->clk = devm_clk_get(&pdev->dev, NULL); | ||
1161 | if (IS_ERR(mx3_cam->clk)) | ||
1162 | return PTR_ERR(mx3_cam->clk); | ||
1163 | |||
1164 | mx3_cam->pdata = pdata; | ||
1165 | mx3_cam->platform_flags = pdata->flags; | ||
1166 | if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_MASK)) { | ||
1167 | /* | ||
1168 | * Platform hasn't set available data widths. This is bad. | ||
1169 | * Warn and use a default. | ||
1170 | */ | ||
1171 | dev_warn(&pdev->dev, "WARNING! Platform hasn't set available " | ||
1172 | "data widths, using default 8 bit\n"); | ||
1173 | mx3_cam->platform_flags |= MX3_CAMERA_DATAWIDTH_8; | ||
1174 | } | ||
1175 | if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4) | ||
1176 | mx3_cam->width_flags = 1 << 3; | ||
1177 | if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8) | ||
1178 | mx3_cam->width_flags |= 1 << 7; | ||
1179 | if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10) | ||
1180 | mx3_cam->width_flags |= 1 << 9; | ||
1181 | if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15) | ||
1182 | mx3_cam->width_flags |= 1 << 14; | ||
1183 | |||
1184 | mx3_cam->mclk = pdata->mclk_10khz * 10000; | ||
1185 | if (!mx3_cam->mclk) { | ||
1186 | dev_warn(&pdev->dev, | ||
1187 | "mclk_10khz == 0! Please, fix your platform data. " | ||
1188 | "Using default 20MHz\n"); | ||
1189 | mx3_cam->mclk = 20000000; | ||
1190 | } | ||
1191 | |||
1192 | /* list of video-buffers */ | ||
1193 | INIT_LIST_HEAD(&mx3_cam->capture); | ||
1194 | spin_lock_init(&mx3_cam->lock); | ||
1195 | |||
1196 | mx3_cam->base = base; | ||
1197 | |||
1198 | soc_host = &mx3_cam->soc_host; | ||
1199 | soc_host->drv_name = MX3_CAM_DRV_NAME; | ||
1200 | soc_host->ops = &mx3_soc_camera_host_ops; | ||
1201 | soc_host->priv = mx3_cam; | ||
1202 | soc_host->v4l2_dev.dev = &pdev->dev; | ||
1203 | soc_host->nr = pdev->id; | ||
1204 | |||
1205 | mx3_cam->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); | ||
1206 | if (IS_ERR(mx3_cam->alloc_ctx)) | ||
1207 | return PTR_ERR(mx3_cam->alloc_ctx); | ||
1208 | |||
1209 | if (pdata->asd_sizes) { | ||
1210 | soc_host->asd = pdata->asd; | ||
1211 | soc_host->asd_sizes = pdata->asd_sizes; | ||
1212 | } | ||
1213 | |||
1214 | err = soc_camera_host_register(soc_host); | ||
1215 | if (err) | ||
1216 | goto ecamhostreg; | ||
1217 | |||
1218 | /* IDMAC interface */ | ||
1219 | dmaengine_get(); | ||
1220 | |||
1221 | return 0; | ||
1222 | |||
1223 | ecamhostreg: | ||
1224 | vb2_dma_contig_cleanup_ctx(mx3_cam->alloc_ctx); | ||
1225 | return err; | ||
1226 | } | ||
1227 | |||
1228 | static int mx3_camera_remove(struct platform_device *pdev) | ||
1229 | { | ||
1230 | struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); | ||
1231 | struct mx3_camera_dev *mx3_cam = container_of(soc_host, | ||
1232 | struct mx3_camera_dev, soc_host); | ||
1233 | |||
1234 | soc_camera_host_unregister(soc_host); | ||
1235 | |||
1236 | /* | ||
1237 | * The channel has either not been allocated, | ||
1238 | * or should have been released | ||
1239 | */ | ||
1240 | if (WARN_ON(mx3_cam->idmac_channel[0])) | ||
1241 | dma_release_channel(&mx3_cam->idmac_channel[0]->dma_chan); | ||
1242 | |||
1243 | vb2_dma_contig_cleanup_ctx(mx3_cam->alloc_ctx); | ||
1244 | |||
1245 | dmaengine_put(); | ||
1246 | |||
1247 | return 0; | ||
1248 | } | ||
1249 | |||
1250 | static struct platform_driver mx3_camera_driver = { | ||
1251 | .driver = { | ||
1252 | .name = MX3_CAM_DRV_NAME, | ||
1253 | }, | ||
1254 | .probe = mx3_camera_probe, | ||
1255 | .remove = mx3_camera_remove, | ||
1256 | }; | ||
1257 | |||
1258 | module_platform_driver(mx3_camera_driver); | ||
1259 | |||
1260 | MODULE_DESCRIPTION("i.MX3x SoC Camera Host driver"); | ||
1261 | MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>"); | ||
1262 | MODULE_LICENSE("GPL v2"); | ||
1263 | MODULE_VERSION("0.2.3"); | ||
1264 | MODULE_ALIAS("platform:" MX3_CAM_DRV_NAME); | ||
diff --git a/drivers/staging/media/omap1/Kconfig b/drivers/staging/media/omap1/Kconfig deleted file mode 100644 index 6cfab3a04ae1..000000000000 --- a/drivers/staging/media/omap1/Kconfig +++ /dev/null | |||
@@ -1,13 +0,0 @@ | |||
1 | config VIDEO_OMAP1 | ||
2 | tristate "OMAP1 Camera Interface driver" | ||
3 | depends on VIDEO_DEV && SOC_CAMERA | ||
4 | depends on ARCH_OMAP1 | ||
5 | depends on HAS_DMA | ||
6 | select VIDEOBUF_DMA_CONTIG | ||
7 | select VIDEOBUF_DMA_SG | ||
8 | ---help--- | ||
9 | This is a v4l2 driver for the TI OMAP1 camera interface | ||
10 | |||
11 | This driver is deprecated and will be removed soon unless someone | ||
12 | will start the work to convert this driver to the vb2 framework | ||
13 | and remove the soc-camera dependency. | ||
diff --git a/drivers/staging/media/omap1/Makefile b/drivers/staging/media/omap1/Makefile deleted file mode 100644 index 2885622600f2..000000000000 --- a/drivers/staging/media/omap1/Makefile +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | # Makefile for OMAP1 driver | ||
2 | |||
3 | obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o | ||
diff --git a/drivers/staging/media/omap1/TODO b/drivers/staging/media/omap1/TODO deleted file mode 100644 index 1025f9f60ff0..000000000000 --- a/drivers/staging/media/omap1/TODO +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | This driver is deprecated and will be removed soon unless someone will start | ||
2 | the work to convert this driver to the vb2 framework and remove the | ||
3 | soc-camera dependency. | ||
4 | |||
5 | Note that trivial patches will not be accepted anymore, only a full conversion. | ||
6 | |||
7 | If you want to convert this driver, please contact the linux-media mailinglist | ||
8 | (see http://linuxtv.org/lists.php). | ||
diff --git a/drivers/staging/media/omap1/omap1_camera.c b/drivers/staging/media/omap1/omap1_camera.c deleted file mode 100644 index 54b8dd2d2bba..000000000000 --- a/drivers/staging/media/omap1/omap1_camera.c +++ /dev/null | |||
@@ -1,1702 +0,0 @@ | |||
1 | /* | ||
2 | * V4L2 SoC Camera driver for OMAP1 Camera Interface | ||
3 | * | ||
4 | * Copyright (C) 2010, Janusz Krzysztofik <jkrzyszt@tis.icnet.pl> | ||
5 | * | ||
6 | * Based on V4L2 Driver for i.MXL/i.MXL camera (CSI) host | ||
7 | * Copyright (C) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt> | ||
8 | * Copyright (C) 2009, Darius Augulis <augulis.darius@gmail.com> | ||
9 | * | ||
10 | * Based on PXA SoC camera driver | ||
11 | * Copyright (C) 2006, Sascha Hauer, Pengutronix | ||
12 | * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> | ||
13 | * | ||
14 | * Hardware specific bits initialy based on former work by Matt Callow | ||
15 | * drivers/media/platform/omap/omap1510cam.c | ||
16 | * Copyright (C) 2006 Matt Callow | ||
17 | * | ||
18 | * This program is free software; you can redistribute it and/or modify | ||
19 | * it under the terms of the GNU General Public License version 2 as | ||
20 | * published by the Free Software Foundation. | ||
21 | */ | ||
22 | |||
23 | |||
24 | #include <linux/clk.h> | ||
25 | #include <linux/dma-mapping.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/platform_device.h> | ||
29 | #include <linux/slab.h> | ||
30 | |||
31 | #include <linux/platform_data/media/omap1_camera.h> | ||
32 | #include <media/soc_camera.h> | ||
33 | #include <media/drv-intf/soc_mediabus.h> | ||
34 | #include <media/videobuf-dma-contig.h> | ||
35 | #include <media/videobuf-dma-sg.h> | ||
36 | |||
37 | #include <linux/omap-dma.h> | ||
38 | |||
39 | |||
40 | #define DRIVER_NAME "omap1-camera" | ||
41 | #define DRIVER_VERSION "0.0.2" | ||
42 | |||
43 | #define OMAP_DMA_CAMERA_IF_RX 20 | ||
44 | |||
45 | /* | ||
46 | * --------------------------------------------------------------------------- | ||
47 | * OMAP1 Camera Interface registers | ||
48 | * --------------------------------------------------------------------------- | ||
49 | */ | ||
50 | |||
51 | #define REG_CTRLCLOCK 0x00 | ||
52 | #define REG_IT_STATUS 0x04 | ||
53 | #define REG_MODE 0x08 | ||
54 | #define REG_STATUS 0x0C | ||
55 | #define REG_CAMDATA 0x10 | ||
56 | #define REG_GPIO 0x14 | ||
57 | #define REG_PEAK_COUNTER 0x18 | ||
58 | |||
59 | /* CTRLCLOCK bit shifts */ | ||
60 | #define LCLK_EN BIT(7) | ||
61 | #define DPLL_EN BIT(6) | ||
62 | #define MCLK_EN BIT(5) | ||
63 | #define CAMEXCLK_EN BIT(4) | ||
64 | #define POLCLK BIT(3) | ||
65 | #define FOSCMOD_SHIFT 0 | ||
66 | #define FOSCMOD_MASK (0x7 << FOSCMOD_SHIFT) | ||
67 | #define FOSCMOD_12MHz 0x0 | ||
68 | #define FOSCMOD_6MHz 0x2 | ||
69 | #define FOSCMOD_9_6MHz 0x4 | ||
70 | #define FOSCMOD_24MHz 0x5 | ||
71 | #define FOSCMOD_8MHz 0x6 | ||
72 | |||
73 | /* IT_STATUS bit shifts */ | ||
74 | #define DATA_TRANSFER BIT(5) | ||
75 | #define FIFO_FULL BIT(4) | ||
76 | #define H_DOWN BIT(3) | ||
77 | #define H_UP BIT(2) | ||
78 | #define V_DOWN BIT(1) | ||
79 | #define V_UP BIT(0) | ||
80 | |||
81 | /* MODE bit shifts */ | ||
82 | #define RAZ_FIFO BIT(18) | ||
83 | #define EN_FIFO_FULL BIT(17) | ||
84 | #define EN_NIRQ BIT(16) | ||
85 | #define THRESHOLD_SHIFT 9 | ||
86 | #define THRESHOLD_MASK (0x7f << THRESHOLD_SHIFT) | ||
87 | #define DMA BIT(8) | ||
88 | #define EN_H_DOWN BIT(7) | ||
89 | #define EN_H_UP BIT(6) | ||
90 | #define EN_V_DOWN BIT(5) | ||
91 | #define EN_V_UP BIT(4) | ||
92 | #define ORDERCAMD BIT(3) | ||
93 | |||
94 | #define IRQ_MASK (EN_V_UP | EN_V_DOWN | EN_H_UP | EN_H_DOWN | \ | ||
95 | EN_NIRQ | EN_FIFO_FULL) | ||
96 | |||
97 | /* STATUS bit shifts */ | ||
98 | #define HSTATUS BIT(1) | ||
99 | #define VSTATUS BIT(0) | ||
100 | |||
101 | /* GPIO bit shifts */ | ||
102 | #define CAM_RST BIT(0) | ||
103 | |||
104 | /* end of OMAP1 Camera Interface registers */ | ||
105 | |||
106 | |||
107 | #define SOCAM_BUS_FLAGS (V4L2_MBUS_MASTER | \ | ||
108 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | \ | ||
109 | V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | \ | ||
110 | V4L2_MBUS_DATA_ACTIVE_HIGH) | ||
111 | |||
112 | |||
113 | #define FIFO_SIZE ((THRESHOLD_MASK >> THRESHOLD_SHIFT) + 1) | ||
114 | #define FIFO_SHIFT __fls(FIFO_SIZE) | ||
115 | |||
116 | #define DMA_BURST_SHIFT (1 + OMAP_DMA_DATA_BURST_4) | ||
117 | #define DMA_BURST_SIZE (1 << DMA_BURST_SHIFT) | ||
118 | |||
119 | #define DMA_ELEMENT_SHIFT OMAP_DMA_DATA_TYPE_S32 | ||
120 | #define DMA_ELEMENT_SIZE (1 << DMA_ELEMENT_SHIFT) | ||
121 | |||
122 | #define DMA_FRAME_SHIFT_CONTIG (FIFO_SHIFT - 1) | ||
123 | #define DMA_FRAME_SHIFT_SG DMA_BURST_SHIFT | ||
124 | |||
125 | #define DMA_FRAME_SHIFT(x) ((x) == OMAP1_CAM_DMA_CONTIG ? \ | ||
126 | DMA_FRAME_SHIFT_CONTIG : \ | ||
127 | DMA_FRAME_SHIFT_SG) | ||
128 | #define DMA_FRAME_SIZE(x) (1 << DMA_FRAME_SHIFT(x)) | ||
129 | #define DMA_SYNC OMAP_DMA_SYNC_FRAME | ||
130 | #define THRESHOLD_LEVEL DMA_FRAME_SIZE | ||
131 | |||
132 | |||
133 | #define MAX_VIDEO_MEM 4 /* arbitrary video memory limit in MB */ | ||
134 | |||
135 | |||
136 | /* | ||
137 | * Structures | ||
138 | */ | ||
139 | |||
140 | /* buffer for one video frame */ | ||
141 | struct omap1_cam_buf { | ||
142 | struct videobuf_buffer vb; | ||
143 | u32 code; | ||
144 | int inwork; | ||
145 | struct scatterlist *sgbuf; | ||
146 | int sgcount; | ||
147 | int bytes_left; | ||
148 | enum videobuf_state result; | ||
149 | }; | ||
150 | |||
151 | struct omap1_cam_dev { | ||
152 | struct soc_camera_host soc_host; | ||
153 | struct clk *clk; | ||
154 | |||
155 | unsigned int irq; | ||
156 | void __iomem *base; | ||
157 | |||
158 | int dma_ch; | ||
159 | |||
160 | struct omap1_cam_platform_data *pdata; | ||
161 | struct resource *res; | ||
162 | unsigned long pflags; | ||
163 | unsigned long camexclk; | ||
164 | |||
165 | struct list_head capture; | ||
166 | |||
167 | /* lock used to protect videobuf */ | ||
168 | spinlock_t lock; | ||
169 | |||
170 | /* Pointers to DMA buffers */ | ||
171 | struct omap1_cam_buf *active; | ||
172 | struct omap1_cam_buf *ready; | ||
173 | |||
174 | enum omap1_cam_vb_mode vb_mode; | ||
175 | int (*mmap_mapper)(struct videobuf_queue *q, | ||
176 | struct videobuf_buffer *buf, | ||
177 | struct vm_area_struct *vma); | ||
178 | |||
179 | u32 reg_cache[0]; | ||
180 | }; | ||
181 | |||
182 | |||
183 | static void cam_write(struct omap1_cam_dev *pcdev, u16 reg, u32 val) | ||
184 | { | ||
185 | pcdev->reg_cache[reg / sizeof(u32)] = val; | ||
186 | __raw_writel(val, pcdev->base + reg); | ||
187 | } | ||
188 | |||
189 | static u32 cam_read(struct omap1_cam_dev *pcdev, u16 reg, bool from_cache) | ||
190 | { | ||
191 | return !from_cache ? __raw_readl(pcdev->base + reg) : | ||
192 | pcdev->reg_cache[reg / sizeof(u32)]; | ||
193 | } | ||
194 | |||
195 | #define CAM_READ(pcdev, reg) \ | ||
196 | cam_read(pcdev, REG_##reg, false) | ||
197 | #define CAM_WRITE(pcdev, reg, val) \ | ||
198 | cam_write(pcdev, REG_##reg, val) | ||
199 | #define CAM_READ_CACHE(pcdev, reg) \ | ||
200 | cam_read(pcdev, REG_##reg, true) | ||
201 | |||
202 | /* | ||
203 | * Videobuf operations | ||
204 | */ | ||
205 | static int omap1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, | ||
206 | unsigned int *size) | ||
207 | { | ||
208 | struct soc_camera_device *icd = vq->priv_data; | ||
209 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
210 | struct omap1_cam_dev *pcdev = ici->priv; | ||
211 | |||
212 | *size = icd->sizeimage; | ||
213 | |||
214 | if (!*count || *count < OMAP1_CAMERA_MIN_BUF_COUNT(pcdev->vb_mode)) | ||
215 | *count = OMAP1_CAMERA_MIN_BUF_COUNT(pcdev->vb_mode); | ||
216 | |||
217 | if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024) | ||
218 | *count = (MAX_VIDEO_MEM * 1024 * 1024) / *size; | ||
219 | |||
220 | dev_dbg(icd->parent, | ||
221 | "%s: count=%d, size=%d\n", __func__, *count, *size); | ||
222 | |||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static void free_buffer(struct videobuf_queue *vq, struct omap1_cam_buf *buf, | ||
227 | enum omap1_cam_vb_mode vb_mode) | ||
228 | { | ||
229 | struct videobuf_buffer *vb = &buf->vb; | ||
230 | |||
231 | BUG_ON(in_interrupt()); | ||
232 | |||
233 | videobuf_waiton(vq, vb, 0, 0); | ||
234 | |||
235 | if (vb_mode == OMAP1_CAM_DMA_CONTIG) { | ||
236 | videobuf_dma_contig_free(vq, vb); | ||
237 | } else { | ||
238 | struct soc_camera_device *icd = vq->priv_data; | ||
239 | struct device *dev = icd->parent; | ||
240 | struct videobuf_dmabuf *dma = videobuf_to_dma(vb); | ||
241 | |||
242 | videobuf_dma_unmap(dev, dma); | ||
243 | videobuf_dma_free(dma); | ||
244 | } | ||
245 | |||
246 | vb->state = VIDEOBUF_NEEDS_INIT; | ||
247 | } | ||
248 | |||
249 | static int omap1_videobuf_prepare(struct videobuf_queue *vq, | ||
250 | struct videobuf_buffer *vb, enum v4l2_field field) | ||
251 | { | ||
252 | struct soc_camera_device *icd = vq->priv_data; | ||
253 | struct omap1_cam_buf *buf = container_of(vb, struct omap1_cam_buf, vb); | ||
254 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
255 | struct omap1_cam_dev *pcdev = ici->priv; | ||
256 | int ret; | ||
257 | |||
258 | WARN_ON(!list_empty(&vb->queue)); | ||
259 | |||
260 | BUG_ON(NULL == icd->current_fmt); | ||
261 | |||
262 | buf->inwork = 1; | ||
263 | |||
264 | if (buf->code != icd->current_fmt->code || vb->field != field || | ||
265 | vb->width != icd->user_width || | ||
266 | vb->height != icd->user_height) { | ||
267 | buf->code = icd->current_fmt->code; | ||
268 | vb->width = icd->user_width; | ||
269 | vb->height = icd->user_height; | ||
270 | vb->field = field; | ||
271 | vb->state = VIDEOBUF_NEEDS_INIT; | ||
272 | } | ||
273 | |||
274 | vb->size = icd->sizeimage; | ||
275 | |||
276 | if (vb->baddr && vb->bsize < vb->size) { | ||
277 | ret = -EINVAL; | ||
278 | goto out; | ||
279 | } | ||
280 | |||
281 | if (vb->state == VIDEOBUF_NEEDS_INIT) { | ||
282 | ret = videobuf_iolock(vq, vb, NULL); | ||
283 | if (ret) | ||
284 | goto fail; | ||
285 | |||
286 | vb->state = VIDEOBUF_PREPARED; | ||
287 | } | ||
288 | buf->inwork = 0; | ||
289 | |||
290 | return 0; | ||
291 | fail: | ||
292 | free_buffer(vq, buf, pcdev->vb_mode); | ||
293 | out: | ||
294 | buf->inwork = 0; | ||
295 | return ret; | ||
296 | } | ||
297 | |||
298 | static void set_dma_dest_params(int dma_ch, struct omap1_cam_buf *buf, | ||
299 | enum omap1_cam_vb_mode vb_mode) | ||
300 | { | ||
301 | dma_addr_t dma_addr; | ||
302 | unsigned int block_size; | ||
303 | |||
304 | if (vb_mode == OMAP1_CAM_DMA_CONTIG) { | ||
305 | dma_addr = videobuf_to_dma_contig(&buf->vb); | ||
306 | block_size = buf->vb.size; | ||
307 | } else { | ||
308 | if (WARN_ON(!buf->sgbuf)) { | ||
309 | buf->result = VIDEOBUF_ERROR; | ||
310 | return; | ||
311 | } | ||
312 | dma_addr = sg_dma_address(buf->sgbuf); | ||
313 | if (WARN_ON(!dma_addr)) { | ||
314 | buf->sgbuf = NULL; | ||
315 | buf->result = VIDEOBUF_ERROR; | ||
316 | return; | ||
317 | } | ||
318 | block_size = sg_dma_len(buf->sgbuf); | ||
319 | if (WARN_ON(!block_size)) { | ||
320 | buf->sgbuf = NULL; | ||
321 | buf->result = VIDEOBUF_ERROR; | ||
322 | return; | ||
323 | } | ||
324 | if (unlikely(buf->bytes_left < block_size)) | ||
325 | block_size = buf->bytes_left; | ||
326 | if (WARN_ON(dma_addr & (DMA_FRAME_SIZE(vb_mode) * | ||
327 | DMA_ELEMENT_SIZE - 1))) { | ||
328 | dma_addr = ALIGN(dma_addr, DMA_FRAME_SIZE(vb_mode) * | ||
329 | DMA_ELEMENT_SIZE); | ||
330 | block_size &= ~(DMA_FRAME_SIZE(vb_mode) * | ||
331 | DMA_ELEMENT_SIZE - 1); | ||
332 | } | ||
333 | buf->bytes_left -= block_size; | ||
334 | buf->sgcount++; | ||
335 | } | ||
336 | |||
337 | omap_set_dma_dest_params(dma_ch, | ||
338 | OMAP_DMA_PORT_EMIFF, OMAP_DMA_AMODE_POST_INC, dma_addr, 0, 0); | ||
339 | omap_set_dma_transfer_params(dma_ch, | ||
340 | OMAP_DMA_DATA_TYPE_S32, DMA_FRAME_SIZE(vb_mode), | ||
341 | block_size >> (DMA_FRAME_SHIFT(vb_mode) + DMA_ELEMENT_SHIFT), | ||
342 | DMA_SYNC, 0, 0); | ||
343 | } | ||
344 | |||
345 | static struct omap1_cam_buf *prepare_next_vb(struct omap1_cam_dev *pcdev) | ||
346 | { | ||
347 | struct omap1_cam_buf *buf; | ||
348 | |||
349 | /* | ||
350 | * If there is already a buffer pointed out by the pcdev->ready, | ||
351 | * (re)use it, otherwise try to fetch and configure a new one. | ||
352 | */ | ||
353 | buf = pcdev->ready; | ||
354 | if (!buf) { | ||
355 | if (list_empty(&pcdev->capture)) | ||
356 | return buf; | ||
357 | buf = list_entry(pcdev->capture.next, | ||
358 | struct omap1_cam_buf, vb.queue); | ||
359 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
360 | pcdev->ready = buf; | ||
361 | list_del_init(&buf->vb.queue); | ||
362 | } | ||
363 | |||
364 | if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) { | ||
365 | /* | ||
366 | * In CONTIG mode, we can safely enter next buffer parameters | ||
367 | * into the DMA programming register set after the DMA | ||
368 | * has already been activated on the previous buffer | ||
369 | */ | ||
370 | set_dma_dest_params(pcdev->dma_ch, buf, pcdev->vb_mode); | ||
371 | } else { | ||
372 | /* | ||
373 | * In SG mode, the above is not safe since there are probably | ||
374 | * a bunch of sgbufs from previous sglist still pending. | ||
375 | * Instead, mark the sglist fresh for the upcoming | ||
376 | * try_next_sgbuf(). | ||
377 | */ | ||
378 | buf->sgbuf = NULL; | ||
379 | } | ||
380 | |||
381 | return buf; | ||
382 | } | ||
383 | |||
384 | static struct scatterlist *try_next_sgbuf(int dma_ch, struct omap1_cam_buf *buf) | ||
385 | { | ||
386 | struct scatterlist *sgbuf; | ||
387 | |||
388 | if (likely(buf->sgbuf)) { | ||
389 | /* current sglist is active */ | ||
390 | if (unlikely(!buf->bytes_left)) { | ||
391 | /* indicate sglist complete */ | ||
392 | sgbuf = NULL; | ||
393 | } else { | ||
394 | /* process next sgbuf */ | ||
395 | sgbuf = sg_next(buf->sgbuf); | ||
396 | if (WARN_ON(!sgbuf)) { | ||
397 | buf->result = VIDEOBUF_ERROR; | ||
398 | } else if (WARN_ON(!sg_dma_len(sgbuf))) { | ||
399 | sgbuf = NULL; | ||
400 | buf->result = VIDEOBUF_ERROR; | ||
401 | } | ||
402 | } | ||
403 | buf->sgbuf = sgbuf; | ||
404 | } else { | ||
405 | /* sglist is fresh, initialize it before using */ | ||
406 | struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); | ||
407 | |||
408 | sgbuf = dma->sglist; | ||
409 | if (!(WARN_ON(!sgbuf))) { | ||
410 | buf->sgbuf = sgbuf; | ||
411 | buf->sgcount = 0; | ||
412 | buf->bytes_left = buf->vb.size; | ||
413 | buf->result = VIDEOBUF_DONE; | ||
414 | } | ||
415 | } | ||
416 | if (sgbuf) | ||
417 | /* | ||
418 | * Put our next sgbuf parameters (address, size) | ||
419 | * into the DMA programming register set. | ||
420 | */ | ||
421 | set_dma_dest_params(dma_ch, buf, OMAP1_CAM_DMA_SG); | ||
422 | |||
423 | return sgbuf; | ||
424 | } | ||
425 | |||
426 | static void start_capture(struct omap1_cam_dev *pcdev) | ||
427 | { | ||
428 | struct omap1_cam_buf *buf = pcdev->active; | ||
429 | u32 ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK); | ||
430 | u32 mode = CAM_READ_CACHE(pcdev, MODE) & ~EN_V_DOWN; | ||
431 | |||
432 | if (WARN_ON(!buf)) | ||
433 | return; | ||
434 | |||
435 | /* | ||
436 | * Enable start of frame interrupt, which we will use for activating | ||
437 | * our end of frame watchdog when capture actually starts. | ||
438 | */ | ||
439 | mode |= EN_V_UP; | ||
440 | |||
441 | if (unlikely(ctrlclock & LCLK_EN)) | ||
442 | /* stop pixel clock before FIFO reset */ | ||
443 | CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN); | ||
444 | /* reset FIFO */ | ||
445 | CAM_WRITE(pcdev, MODE, mode | RAZ_FIFO); | ||
446 | |||
447 | omap_start_dma(pcdev->dma_ch); | ||
448 | |||
449 | if (pcdev->vb_mode == OMAP1_CAM_DMA_SG) { | ||
450 | /* | ||
451 | * In SG mode, it's a good moment for fetching next sgbuf | ||
452 | * from the current sglist and, if available, already putting | ||
453 | * its parameters into the DMA programming register set. | ||
454 | */ | ||
455 | try_next_sgbuf(pcdev->dma_ch, buf); | ||
456 | } | ||
457 | |||
458 | /* (re)enable pixel clock */ | ||
459 | CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock | LCLK_EN); | ||
460 | /* release FIFO reset */ | ||
461 | CAM_WRITE(pcdev, MODE, mode); | ||
462 | } | ||
463 | |||
464 | static void suspend_capture(struct omap1_cam_dev *pcdev) | ||
465 | { | ||
466 | u32 ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK); | ||
467 | |||
468 | CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN); | ||
469 | omap_stop_dma(pcdev->dma_ch); | ||
470 | } | ||
471 | |||
472 | static void disable_capture(struct omap1_cam_dev *pcdev) | ||
473 | { | ||
474 | u32 mode = CAM_READ_CACHE(pcdev, MODE); | ||
475 | |||
476 | CAM_WRITE(pcdev, MODE, mode & ~(IRQ_MASK | DMA)); | ||
477 | } | ||
478 | |||
479 | static void omap1_videobuf_queue(struct videobuf_queue *vq, | ||
480 | struct videobuf_buffer *vb) | ||
481 | { | ||
482 | struct soc_camera_device *icd = vq->priv_data; | ||
483 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
484 | struct omap1_cam_dev *pcdev = ici->priv; | ||
485 | struct omap1_cam_buf *buf; | ||
486 | u32 mode; | ||
487 | |||
488 | list_add_tail(&vb->queue, &pcdev->capture); | ||
489 | vb->state = VIDEOBUF_QUEUED; | ||
490 | |||
491 | if (pcdev->active) { | ||
492 | /* | ||
493 | * Capture in progress, so don't touch pcdev->ready even if | ||
494 | * empty. Since the transfer of the DMA programming register set | ||
495 | * content to the DMA working register set is done automatically | ||
496 | * by the DMA hardware, this can pretty well happen while we | ||
497 | * are keeping the lock here. Leave fetching it from the queue | ||
498 | * to be done when a next DMA interrupt occures instead. | ||
499 | */ | ||
500 | return; | ||
501 | } | ||
502 | |||
503 | WARN_ON(pcdev->ready); | ||
504 | |||
505 | buf = prepare_next_vb(pcdev); | ||
506 | if (WARN_ON(!buf)) | ||
507 | return; | ||
508 | |||
509 | pcdev->active = buf; | ||
510 | pcdev->ready = NULL; | ||
511 | |||
512 | dev_dbg(icd->parent, | ||
513 | "%s: capture not active, setup FIFO, start DMA\n", __func__); | ||
514 | mode = CAM_READ_CACHE(pcdev, MODE) & ~THRESHOLD_MASK; | ||
515 | mode |= THRESHOLD_LEVEL(pcdev->vb_mode) << THRESHOLD_SHIFT; | ||
516 | CAM_WRITE(pcdev, MODE, mode | EN_FIFO_FULL | DMA); | ||
517 | |||
518 | if (pcdev->vb_mode == OMAP1_CAM_DMA_SG) { | ||
519 | /* | ||
520 | * In SG mode, the above prepare_next_vb() didn't actually | ||
521 | * put anything into the DMA programming register set, | ||
522 | * so we have to do it now, before activating DMA. | ||
523 | */ | ||
524 | try_next_sgbuf(pcdev->dma_ch, buf); | ||
525 | } | ||
526 | |||
527 | start_capture(pcdev); | ||
528 | } | ||
529 | |||
530 | static void omap1_videobuf_release(struct videobuf_queue *vq, | ||
531 | struct videobuf_buffer *vb) | ||
532 | { | ||
533 | struct omap1_cam_buf *buf = | ||
534 | container_of(vb, struct omap1_cam_buf, vb); | ||
535 | struct soc_camera_device *icd = vq->priv_data; | ||
536 | struct device *dev = icd->parent; | ||
537 | struct soc_camera_host *ici = to_soc_camera_host(dev); | ||
538 | struct omap1_cam_dev *pcdev = ici->priv; | ||
539 | |||
540 | switch (vb->state) { | ||
541 | case VIDEOBUF_DONE: | ||
542 | dev_dbg(dev, "%s (done)\n", __func__); | ||
543 | break; | ||
544 | case VIDEOBUF_ACTIVE: | ||
545 | dev_dbg(dev, "%s (active)\n", __func__); | ||
546 | break; | ||
547 | case VIDEOBUF_QUEUED: | ||
548 | dev_dbg(dev, "%s (queued)\n", __func__); | ||
549 | break; | ||
550 | case VIDEOBUF_PREPARED: | ||
551 | dev_dbg(dev, "%s (prepared)\n", __func__); | ||
552 | break; | ||
553 | default: | ||
554 | dev_dbg(dev, "%s (unknown %d)\n", __func__, vb->state); | ||
555 | break; | ||
556 | } | ||
557 | |||
558 | free_buffer(vq, buf, pcdev->vb_mode); | ||
559 | } | ||
560 | |||
561 | static void videobuf_done(struct omap1_cam_dev *pcdev, | ||
562 | enum videobuf_state result) | ||
563 | { | ||
564 | struct omap1_cam_buf *buf = pcdev->active; | ||
565 | struct videobuf_buffer *vb; | ||
566 | struct device *dev = pcdev->soc_host.icd->parent; | ||
567 | |||
568 | if (WARN_ON(!buf)) { | ||
569 | suspend_capture(pcdev); | ||
570 | disable_capture(pcdev); | ||
571 | return; | ||
572 | } | ||
573 | |||
574 | if (result == VIDEOBUF_ERROR) | ||
575 | suspend_capture(pcdev); | ||
576 | |||
577 | vb = &buf->vb; | ||
578 | if (waitqueue_active(&vb->done)) { | ||
579 | if (!pcdev->ready && result != VIDEOBUF_ERROR) { | ||
580 | /* | ||
581 | * No next buffer has been entered into the DMA | ||
582 | * programming register set on time (could be done only | ||
583 | * while the previous DMA interurpt was processed, not | ||
584 | * later), so the last DMA block, be it a whole buffer | ||
585 | * if in CONTIG or its last sgbuf if in SG mode, is | ||
586 | * about to be reused by the just autoreinitialized DMA | ||
587 | * engine, and overwritten with next frame data. Best we | ||
588 | * can do is stopping the capture as soon as possible, | ||
589 | * hopefully before the next frame start. | ||
590 | */ | ||
591 | suspend_capture(pcdev); | ||
592 | } | ||
593 | vb->state = result; | ||
594 | v4l2_get_timestamp(&vb->ts); | ||
595 | if (result != VIDEOBUF_ERROR) | ||
596 | vb->field_count++; | ||
597 | wake_up(&vb->done); | ||
598 | |||
599 | /* shift in next buffer */ | ||
600 | buf = pcdev->ready; | ||
601 | pcdev->active = buf; | ||
602 | pcdev->ready = NULL; | ||
603 | |||
604 | if (!buf) { | ||
605 | /* | ||
606 | * No next buffer was ready on time (see above), so | ||
607 | * indicate error condition to force capture restart or | ||
608 | * stop, depending on next buffer already queued or not. | ||
609 | */ | ||
610 | result = VIDEOBUF_ERROR; | ||
611 | prepare_next_vb(pcdev); | ||
612 | |||
613 | buf = pcdev->ready; | ||
614 | pcdev->active = buf; | ||
615 | pcdev->ready = NULL; | ||
616 | } | ||
617 | } else if (pcdev->ready) { | ||
618 | /* | ||
619 | * In both CONTIG and SG mode, the DMA engine has possibly | ||
620 | * been already autoreinitialized with the preprogrammed | ||
621 | * pcdev->ready buffer. We can either accept this fact | ||
622 | * and just swap the buffers, or provoke an error condition | ||
623 | * and restart capture. The former seems less intrusive. | ||
624 | */ | ||
625 | dev_dbg(dev, "%s: nobody waiting on videobuf, swap with next\n", | ||
626 | __func__); | ||
627 | pcdev->active = pcdev->ready; | ||
628 | |||
629 | if (pcdev->vb_mode == OMAP1_CAM_DMA_SG) { | ||
630 | /* | ||
631 | * In SG mode, we have to make sure that the buffer we | ||
632 | * are putting back into the pcdev->ready is marked | ||
633 | * fresh. | ||
634 | */ | ||
635 | buf->sgbuf = NULL; | ||
636 | } | ||
637 | pcdev->ready = buf; | ||
638 | |||
639 | buf = pcdev->active; | ||
640 | } else { | ||
641 | /* | ||
642 | * No next buffer has been entered into | ||
643 | * the DMA programming register set on time. | ||
644 | */ | ||
645 | if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) { | ||
646 | /* | ||
647 | * In CONTIG mode, the DMA engine has already been | ||
648 | * reinitialized with the current buffer. Best we can do | ||
649 | * is not touching it. | ||
650 | */ | ||
651 | dev_dbg(dev, | ||
652 | "%s: nobody waiting on videobuf, reuse it\n", | ||
653 | __func__); | ||
654 | } else { | ||
655 | /* | ||
656 | * In SG mode, the DMA engine has just been | ||
657 | * autoreinitialized with the last sgbuf from the | ||
658 | * current list. Restart capture in order to transfer | ||
659 | * next frame start into the first sgbuf, not the last | ||
660 | * one. | ||
661 | */ | ||
662 | if (result != VIDEOBUF_ERROR) { | ||
663 | suspend_capture(pcdev); | ||
664 | result = VIDEOBUF_ERROR; | ||
665 | } | ||
666 | } | ||
667 | } | ||
668 | |||
669 | if (!buf) { | ||
670 | dev_dbg(dev, "%s: no more videobufs, stop capture\n", __func__); | ||
671 | disable_capture(pcdev); | ||
672 | return; | ||
673 | } | ||
674 | |||
675 | if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) { | ||
676 | /* | ||
677 | * In CONTIG mode, the current buffer parameters had already | ||
678 | * been entered into the DMA programming register set while the | ||
679 | * buffer was fetched with prepare_next_vb(), they may have also | ||
680 | * been transferred into the runtime set and already active if | ||
681 | * the DMA still running. | ||
682 | */ | ||
683 | } else { | ||
684 | /* In SG mode, extra steps are required */ | ||
685 | if (result == VIDEOBUF_ERROR) | ||
686 | /* make sure we (re)use sglist from start on error */ | ||
687 | buf->sgbuf = NULL; | ||
688 | |||
689 | /* | ||
690 | * In any case, enter the next sgbuf parameters into the DMA | ||
691 | * programming register set. They will be used either during | ||
692 | * nearest DMA autoreinitialization or, in case of an error, | ||
693 | * on DMA startup below. | ||
694 | */ | ||
695 | try_next_sgbuf(pcdev->dma_ch, buf); | ||
696 | } | ||
697 | |||
698 | if (result == VIDEOBUF_ERROR) { | ||
699 | dev_dbg(dev, "%s: videobuf error; reset FIFO, restart DMA\n", | ||
700 | __func__); | ||
701 | start_capture(pcdev); | ||
702 | /* | ||
703 | * In SG mode, the above also resulted in the next sgbuf | ||
704 | * parameters being entered into the DMA programming register | ||
705 | * set, making them ready for next DMA autoreinitialization. | ||
706 | */ | ||
707 | } | ||
708 | |||
709 | /* | ||
710 | * Finally, try fetching next buffer. | ||
711 | * In CONTIG mode, it will also enter it into the DMA programming | ||
712 | * register set, making it ready for next DMA autoreinitialization. | ||
713 | */ | ||
714 | prepare_next_vb(pcdev); | ||
715 | } | ||
716 | |||
717 | static void dma_isr(int channel, unsigned short status, void *data) | ||
718 | { | ||
719 | struct omap1_cam_dev *pcdev = data; | ||
720 | struct omap1_cam_buf *buf = pcdev->active; | ||
721 | unsigned long flags; | ||
722 | |||
723 | spin_lock_irqsave(&pcdev->lock, flags); | ||
724 | |||
725 | if (WARN_ON(!buf)) { | ||
726 | suspend_capture(pcdev); | ||
727 | disable_capture(pcdev); | ||
728 | goto out; | ||
729 | } | ||
730 | |||
731 | if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) { | ||
732 | /* | ||
733 | * In CONTIG mode, assume we have just managed to collect the | ||
734 | * whole frame, hopefully before our end of frame watchdog is | ||
735 | * triggered. Then, all we have to do is disabling the watchdog | ||
736 | * for this frame, and calling videobuf_done() with success | ||
737 | * indicated. | ||
738 | */ | ||
739 | CAM_WRITE(pcdev, MODE, | ||
740 | CAM_READ_CACHE(pcdev, MODE) & ~EN_V_DOWN); | ||
741 | videobuf_done(pcdev, VIDEOBUF_DONE); | ||
742 | } else { | ||
743 | /* | ||
744 | * In SG mode, we have to process every sgbuf from the current | ||
745 | * sglist, one after another. | ||
746 | */ | ||
747 | if (buf->sgbuf) { | ||
748 | /* | ||
749 | * Current sglist not completed yet, try fetching next | ||
750 | * sgbuf, hopefully putting it into the DMA programming | ||
751 | * register set, making it ready for next DMA | ||
752 | * autoreinitialization. | ||
753 | */ | ||
754 | try_next_sgbuf(pcdev->dma_ch, buf); | ||
755 | if (buf->sgbuf) | ||
756 | goto out; | ||
757 | |||
758 | /* | ||
759 | * No more sgbufs left in the current sglist. This | ||
760 | * doesn't mean that the whole videobuffer is already | ||
761 | * complete, but only that the last sgbuf from the | ||
762 | * current sglist is about to be filled. It will be | ||
763 | * ready on next DMA interrupt, signalled with the | ||
764 | * buf->sgbuf set back to NULL. | ||
765 | */ | ||
766 | if (buf->result != VIDEOBUF_ERROR) { | ||
767 | /* | ||
768 | * Video frame collected without errors so far, | ||
769 | * we can prepare for collecting a next one | ||
770 | * as soon as DMA gets autoreinitialized | ||
771 | * after the current (last) sgbuf is completed. | ||
772 | */ | ||
773 | buf = prepare_next_vb(pcdev); | ||
774 | if (!buf) | ||
775 | goto out; | ||
776 | |||
777 | try_next_sgbuf(pcdev->dma_ch, buf); | ||
778 | goto out; | ||
779 | } | ||
780 | } | ||
781 | /* end of videobuf */ | ||
782 | videobuf_done(pcdev, buf->result); | ||
783 | } | ||
784 | |||
785 | out: | ||
786 | spin_unlock_irqrestore(&pcdev->lock, flags); | ||
787 | } | ||
788 | |||
789 | static irqreturn_t cam_isr(int irq, void *data) | ||
790 | { | ||
791 | struct omap1_cam_dev *pcdev = data; | ||
792 | struct device *dev = pcdev->soc_host.icd->parent; | ||
793 | struct omap1_cam_buf *buf = pcdev->active; | ||
794 | u32 it_status; | ||
795 | unsigned long flags; | ||
796 | |||
797 | it_status = CAM_READ(pcdev, IT_STATUS); | ||
798 | if (!it_status) | ||
799 | return IRQ_NONE; | ||
800 | |||
801 | spin_lock_irqsave(&pcdev->lock, flags); | ||
802 | |||
803 | if (WARN_ON(!buf)) { | ||
804 | dev_warn(dev, "%s: unhandled camera interrupt, status == %#x\n", | ||
805 | __func__, it_status); | ||
806 | suspend_capture(pcdev); | ||
807 | disable_capture(pcdev); | ||
808 | goto out; | ||
809 | } | ||
810 | |||
811 | if (unlikely(it_status & FIFO_FULL)) { | ||
812 | dev_warn(dev, "%s: FIFO overflow\n", __func__); | ||
813 | |||
814 | } else if (it_status & V_DOWN) { | ||
815 | /* end of video frame watchdog */ | ||
816 | if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) { | ||
817 | /* | ||
818 | * In CONTIG mode, the watchdog is disabled with | ||
819 | * successful DMA end of block interrupt, and reenabled | ||
820 | * on next frame start. If we get here, there is nothing | ||
821 | * to check, we must be out of sync. | ||
822 | */ | ||
823 | } else { | ||
824 | if (buf->sgcount == 2) { | ||
825 | /* | ||
826 | * If exactly 2 sgbufs from the next sglist have | ||
827 | * been programmed into the DMA engine (the | ||
828 | * first one already transferred into the DMA | ||
829 | * runtime register set, the second one still | ||
830 | * in the programming set), then we are in sync. | ||
831 | */ | ||
832 | goto out; | ||
833 | } | ||
834 | } | ||
835 | dev_notice(dev, "%s: unexpected end of video frame\n", | ||
836 | __func__); | ||
837 | |||
838 | } else if (it_status & V_UP) { | ||
839 | u32 mode; | ||
840 | |||
841 | if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) { | ||
842 | /* | ||
843 | * In CONTIG mode, we need this interrupt every frame | ||
844 | * in oredr to reenable our end of frame watchdog. | ||
845 | */ | ||
846 | mode = CAM_READ_CACHE(pcdev, MODE); | ||
847 | } else { | ||
848 | /* | ||
849 | * In SG mode, the below enabled end of frame watchdog | ||
850 | * is kept on permanently, so we can turn this one shot | ||
851 | * setup off. | ||
852 | */ | ||
853 | mode = CAM_READ_CACHE(pcdev, MODE) & ~EN_V_UP; | ||
854 | } | ||
855 | |||
856 | if (!(mode & EN_V_DOWN)) { | ||
857 | /* (re)enable end of frame watchdog interrupt */ | ||
858 | mode |= EN_V_DOWN; | ||
859 | } | ||
860 | CAM_WRITE(pcdev, MODE, mode); | ||
861 | goto out; | ||
862 | |||
863 | } else { | ||
864 | dev_warn(dev, "%s: unhandled camera interrupt, status == %#x\n", | ||
865 | __func__, it_status); | ||
866 | goto out; | ||
867 | } | ||
868 | |||
869 | videobuf_done(pcdev, VIDEOBUF_ERROR); | ||
870 | out: | ||
871 | spin_unlock_irqrestore(&pcdev->lock, flags); | ||
872 | return IRQ_HANDLED; | ||
873 | } | ||
874 | |||
875 | static struct videobuf_queue_ops omap1_videobuf_ops = { | ||
876 | .buf_setup = omap1_videobuf_setup, | ||
877 | .buf_prepare = omap1_videobuf_prepare, | ||
878 | .buf_queue = omap1_videobuf_queue, | ||
879 | .buf_release = omap1_videobuf_release, | ||
880 | }; | ||
881 | |||
882 | |||
883 | /* | ||
884 | * SOC Camera host operations | ||
885 | */ | ||
886 | |||
887 | static void sensor_reset(struct omap1_cam_dev *pcdev, bool reset) | ||
888 | { | ||
889 | /* apply/release camera sensor reset if requested by platform data */ | ||
890 | if (pcdev->pflags & OMAP1_CAMERA_RST_HIGH) | ||
891 | CAM_WRITE(pcdev, GPIO, reset); | ||
892 | else if (pcdev->pflags & OMAP1_CAMERA_RST_LOW) | ||
893 | CAM_WRITE(pcdev, GPIO, !reset); | ||
894 | } | ||
895 | |||
896 | static int omap1_cam_add_device(struct soc_camera_device *icd) | ||
897 | { | ||
898 | dev_dbg(icd->parent, "OMAP1 Camera driver attached to camera %d\n", | ||
899 | icd->devnum); | ||
900 | |||
901 | return 0; | ||
902 | } | ||
903 | |||
904 | static void omap1_cam_remove_device(struct soc_camera_device *icd) | ||
905 | { | ||
906 | dev_dbg(icd->parent, | ||
907 | "OMAP1 Camera driver detached from camera %d\n", icd->devnum); | ||
908 | } | ||
909 | |||
910 | /* | ||
911 | * The following two functions absolutely depend on the fact, that | ||
912 | * there can be only one camera on OMAP1 camera sensor interface | ||
913 | */ | ||
914 | static int omap1_cam_clock_start(struct soc_camera_host *ici) | ||
915 | { | ||
916 | struct omap1_cam_dev *pcdev = ici->priv; | ||
917 | u32 ctrlclock; | ||
918 | |||
919 | clk_enable(pcdev->clk); | ||
920 | |||
921 | /* setup sensor clock */ | ||
922 | ctrlclock = CAM_READ(pcdev, CTRLCLOCK); | ||
923 | ctrlclock &= ~(CAMEXCLK_EN | MCLK_EN | DPLL_EN); | ||
924 | CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock); | ||
925 | |||
926 | ctrlclock &= ~FOSCMOD_MASK; | ||
927 | switch (pcdev->camexclk) { | ||
928 | case 6000000: | ||
929 | ctrlclock |= CAMEXCLK_EN | FOSCMOD_6MHz; | ||
930 | break; | ||
931 | case 8000000: | ||
932 | ctrlclock |= CAMEXCLK_EN | FOSCMOD_8MHz | DPLL_EN; | ||
933 | break; | ||
934 | case 9600000: | ||
935 | ctrlclock |= CAMEXCLK_EN | FOSCMOD_9_6MHz | DPLL_EN; | ||
936 | break; | ||
937 | case 12000000: | ||
938 | ctrlclock |= CAMEXCLK_EN | FOSCMOD_12MHz; | ||
939 | break; | ||
940 | case 24000000: | ||
941 | ctrlclock |= CAMEXCLK_EN | FOSCMOD_24MHz | DPLL_EN; | ||
942 | default: | ||
943 | break; | ||
944 | } | ||
945 | CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~DPLL_EN); | ||
946 | |||
947 | /* enable internal clock */ | ||
948 | ctrlclock |= MCLK_EN; | ||
949 | CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock); | ||
950 | |||
951 | sensor_reset(pcdev, false); | ||
952 | |||
953 | return 0; | ||
954 | } | ||
955 | |||
956 | static void omap1_cam_clock_stop(struct soc_camera_host *ici) | ||
957 | { | ||
958 | struct omap1_cam_dev *pcdev = ici->priv; | ||
959 | u32 ctrlclock; | ||
960 | |||
961 | suspend_capture(pcdev); | ||
962 | disable_capture(pcdev); | ||
963 | |||
964 | sensor_reset(pcdev, true); | ||
965 | |||
966 | /* disable and release system clocks */ | ||
967 | ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK); | ||
968 | ctrlclock &= ~(MCLK_EN | DPLL_EN | CAMEXCLK_EN); | ||
969 | CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock); | ||
970 | |||
971 | ctrlclock = (ctrlclock & ~FOSCMOD_MASK) | FOSCMOD_12MHz; | ||
972 | CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock); | ||
973 | CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock | MCLK_EN); | ||
974 | |||
975 | CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~MCLK_EN); | ||
976 | |||
977 | clk_disable(pcdev->clk); | ||
978 | } | ||
979 | |||
980 | /* Duplicate standard formats based on host capability of byte swapping */ | ||
981 | static const struct soc_mbus_lookup omap1_cam_formats[] = { | ||
982 | { | ||
983 | .code = MEDIA_BUS_FMT_UYVY8_2X8, | ||
984 | .fmt = { | ||
985 | .fourcc = V4L2_PIX_FMT_YUYV, | ||
986 | .name = "YUYV", | ||
987 | .bits_per_sample = 8, | ||
988 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
989 | .order = SOC_MBUS_ORDER_BE, | ||
990 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
991 | }, | ||
992 | }, { | ||
993 | .code = MEDIA_BUS_FMT_VYUY8_2X8, | ||
994 | .fmt = { | ||
995 | .fourcc = V4L2_PIX_FMT_YVYU, | ||
996 | .name = "YVYU", | ||
997 | .bits_per_sample = 8, | ||
998 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
999 | .order = SOC_MBUS_ORDER_BE, | ||
1000 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
1001 | }, | ||
1002 | }, { | ||
1003 | .code = MEDIA_BUS_FMT_YUYV8_2X8, | ||
1004 | .fmt = { | ||
1005 | .fourcc = V4L2_PIX_FMT_UYVY, | ||
1006 | .name = "UYVY", | ||
1007 | .bits_per_sample = 8, | ||
1008 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
1009 | .order = SOC_MBUS_ORDER_BE, | ||
1010 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
1011 | }, | ||
1012 | }, { | ||
1013 | .code = MEDIA_BUS_FMT_YVYU8_2X8, | ||
1014 | .fmt = { | ||
1015 | .fourcc = V4L2_PIX_FMT_VYUY, | ||
1016 | .name = "VYUY", | ||
1017 | .bits_per_sample = 8, | ||
1018 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
1019 | .order = SOC_MBUS_ORDER_BE, | ||
1020 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
1021 | }, | ||
1022 | }, { | ||
1023 | .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, | ||
1024 | .fmt = { | ||
1025 | .fourcc = V4L2_PIX_FMT_RGB555, | ||
1026 | .name = "RGB555", | ||
1027 | .bits_per_sample = 8, | ||
1028 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
1029 | .order = SOC_MBUS_ORDER_BE, | ||
1030 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
1031 | }, | ||
1032 | }, { | ||
1033 | .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, | ||
1034 | .fmt = { | ||
1035 | .fourcc = V4L2_PIX_FMT_RGB555X, | ||
1036 | .name = "RGB555X", | ||
1037 | .bits_per_sample = 8, | ||
1038 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
1039 | .order = SOC_MBUS_ORDER_BE, | ||
1040 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
1041 | }, | ||
1042 | }, { | ||
1043 | .code = MEDIA_BUS_FMT_RGB565_2X8_BE, | ||
1044 | .fmt = { | ||
1045 | .fourcc = V4L2_PIX_FMT_RGB565, | ||
1046 | .name = "RGB565", | ||
1047 | .bits_per_sample = 8, | ||
1048 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
1049 | .order = SOC_MBUS_ORDER_BE, | ||
1050 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
1051 | }, | ||
1052 | }, { | ||
1053 | .code = MEDIA_BUS_FMT_RGB565_2X8_LE, | ||
1054 | .fmt = { | ||
1055 | .fourcc = V4L2_PIX_FMT_RGB565X, | ||
1056 | .name = "RGB565X", | ||
1057 | .bits_per_sample = 8, | ||
1058 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
1059 | .order = SOC_MBUS_ORDER_BE, | ||
1060 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
1061 | }, | ||
1062 | }, | ||
1063 | }; | ||
1064 | |||
1065 | static int omap1_cam_get_formats(struct soc_camera_device *icd, | ||
1066 | unsigned int idx, struct soc_camera_format_xlate *xlate) | ||
1067 | { | ||
1068 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1069 | struct device *dev = icd->parent; | ||
1070 | int formats = 0, ret; | ||
1071 | struct v4l2_subdev_mbus_code_enum code = { | ||
1072 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
1073 | .index = idx, | ||
1074 | }; | ||
1075 | const struct soc_mbus_pixelfmt *fmt; | ||
1076 | |||
1077 | ret = v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code); | ||
1078 | if (ret < 0) | ||
1079 | /* No more formats */ | ||
1080 | return 0; | ||
1081 | |||
1082 | fmt = soc_mbus_get_fmtdesc(code.code); | ||
1083 | if (!fmt) { | ||
1084 | dev_warn(dev, "%s: unsupported format code #%d: %d\n", __func__, | ||
1085 | idx, code.code); | ||
1086 | return 0; | ||
1087 | } | ||
1088 | |||
1089 | /* Check support for the requested bits-per-sample */ | ||
1090 | if (fmt->bits_per_sample != 8) | ||
1091 | return 0; | ||
1092 | |||
1093 | switch (code.code) { | ||
1094 | case MEDIA_BUS_FMT_YUYV8_2X8: | ||
1095 | case MEDIA_BUS_FMT_YVYU8_2X8: | ||
1096 | case MEDIA_BUS_FMT_UYVY8_2X8: | ||
1097 | case MEDIA_BUS_FMT_VYUY8_2X8: | ||
1098 | case MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE: | ||
1099 | case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE: | ||
1100 | case MEDIA_BUS_FMT_RGB565_2X8_BE: | ||
1101 | case MEDIA_BUS_FMT_RGB565_2X8_LE: | ||
1102 | formats++; | ||
1103 | if (xlate) { | ||
1104 | xlate->host_fmt = soc_mbus_find_fmtdesc(code.code, | ||
1105 | omap1_cam_formats, | ||
1106 | ARRAY_SIZE(omap1_cam_formats)); | ||
1107 | xlate->code = code.code; | ||
1108 | xlate++; | ||
1109 | dev_dbg(dev, | ||
1110 | "%s: providing format %s as byte swapped code #%d\n", | ||
1111 | __func__, xlate->host_fmt->name, code.code); | ||
1112 | } | ||
1113 | default: | ||
1114 | if (xlate) | ||
1115 | dev_dbg(dev, | ||
1116 | "%s: providing format %s in pass-through mode\n", | ||
1117 | __func__, fmt->name); | ||
1118 | } | ||
1119 | formats++; | ||
1120 | if (xlate) { | ||
1121 | xlate->host_fmt = fmt; | ||
1122 | xlate->code = code.code; | ||
1123 | xlate++; | ||
1124 | } | ||
1125 | |||
1126 | return formats; | ||
1127 | } | ||
1128 | |||
1129 | static bool is_dma_aligned(s32 bytes_per_line, unsigned int height, | ||
1130 | enum omap1_cam_vb_mode vb_mode) | ||
1131 | { | ||
1132 | int size = bytes_per_line * height; | ||
1133 | |||
1134 | return IS_ALIGNED(bytes_per_line, DMA_ELEMENT_SIZE) && | ||
1135 | IS_ALIGNED(size, DMA_FRAME_SIZE(vb_mode) * DMA_ELEMENT_SIZE); | ||
1136 | } | ||
1137 | |||
1138 | static int dma_align(int *width, int *height, | ||
1139 | const struct soc_mbus_pixelfmt *fmt, | ||
1140 | enum omap1_cam_vb_mode vb_mode, bool enlarge) | ||
1141 | { | ||
1142 | s32 bytes_per_line = soc_mbus_bytes_per_line(*width, fmt); | ||
1143 | |||
1144 | if (bytes_per_line < 0) | ||
1145 | return bytes_per_line; | ||
1146 | |||
1147 | if (!is_dma_aligned(bytes_per_line, *height, vb_mode)) { | ||
1148 | unsigned int pxalign = __fls(bytes_per_line / *width); | ||
1149 | unsigned int salign = DMA_FRAME_SHIFT(vb_mode) + | ||
1150 | DMA_ELEMENT_SHIFT - pxalign; | ||
1151 | unsigned int incr = enlarge << salign; | ||
1152 | |||
1153 | v4l_bound_align_image(width, 1, *width + incr, 0, | ||
1154 | height, 1, *height + incr, 0, salign); | ||
1155 | return 0; | ||
1156 | } | ||
1157 | return 1; | ||
1158 | } | ||
1159 | |||
1160 | #define subdev_call_with_sense(pcdev, dev, icd, sd, op, function, args...) \ | ||
1161 | ({ \ | ||
1162 | struct soc_camera_sense sense = { \ | ||
1163 | .master_clock = pcdev->camexclk, \ | ||
1164 | .pixel_clock_max = 0, \ | ||
1165 | }; \ | ||
1166 | int __ret; \ | ||
1167 | \ | ||
1168 | if (pcdev->pdata) \ | ||
1169 | sense.pixel_clock_max = pcdev->pdata->lclk_khz_max * 1000; \ | ||
1170 | icd->sense = &sense; \ | ||
1171 | __ret = v4l2_subdev_call(sd, op, function, ##args); \ | ||
1172 | icd->sense = NULL; \ | ||
1173 | \ | ||
1174 | if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { \ | ||
1175 | if (sense.pixel_clock > sense.pixel_clock_max) { \ | ||
1176 | dev_err(dev, \ | ||
1177 | "%s: pixel clock %lu set by the camera too high!\n", \ | ||
1178 | __func__, sense.pixel_clock); \ | ||
1179 | __ret = -EINVAL; \ | ||
1180 | } \ | ||
1181 | } \ | ||
1182 | __ret; \ | ||
1183 | }) | ||
1184 | |||
1185 | static int set_format(struct omap1_cam_dev *pcdev, struct device *dev, | ||
1186 | struct soc_camera_device *icd, struct v4l2_subdev *sd, | ||
1187 | struct v4l2_subdev_format *format, | ||
1188 | const struct soc_camera_format_xlate *xlate) | ||
1189 | { | ||
1190 | s32 bytes_per_line; | ||
1191 | struct v4l2_mbus_framefmt *mf = &format->format; | ||
1192 | int ret = subdev_call_with_sense(pcdev, dev, icd, sd, pad, set_fmt, NULL, format); | ||
1193 | |||
1194 | if (ret < 0) { | ||
1195 | dev_err(dev, "%s: set_fmt failed\n", __func__); | ||
1196 | return ret; | ||
1197 | } | ||
1198 | |||
1199 | if (mf->code != xlate->code) { | ||
1200 | dev_err(dev, "%s: unexpected pixel code change\n", __func__); | ||
1201 | return -EINVAL; | ||
1202 | } | ||
1203 | |||
1204 | bytes_per_line = soc_mbus_bytes_per_line(mf->width, xlate->host_fmt); | ||
1205 | if (bytes_per_line < 0) { | ||
1206 | dev_err(dev, "%s: soc_mbus_bytes_per_line() failed\n", | ||
1207 | __func__); | ||
1208 | return bytes_per_line; | ||
1209 | } | ||
1210 | |||
1211 | if (!is_dma_aligned(bytes_per_line, mf->height, pcdev->vb_mode)) { | ||
1212 | dev_err(dev, "%s: resulting geometry %ux%u not DMA aligned\n", | ||
1213 | __func__, mf->width, mf->height); | ||
1214 | return -EINVAL; | ||
1215 | } | ||
1216 | return 0; | ||
1217 | } | ||
1218 | |||
1219 | static int omap1_cam_set_crop(struct soc_camera_device *icd, | ||
1220 | const struct v4l2_crop *crop) | ||
1221 | { | ||
1222 | const struct v4l2_rect *rect = &crop->c; | ||
1223 | const struct soc_camera_format_xlate *xlate = icd->current_fmt; | ||
1224 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1225 | struct device *dev = icd->parent; | ||
1226 | struct soc_camera_host *ici = to_soc_camera_host(dev); | ||
1227 | struct omap1_cam_dev *pcdev = ici->priv; | ||
1228 | struct v4l2_subdev_format fmt = { | ||
1229 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
1230 | }; | ||
1231 | struct v4l2_mbus_framefmt *mf = &fmt.format; | ||
1232 | int ret; | ||
1233 | |||
1234 | ret = subdev_call_with_sense(pcdev, dev, icd, sd, video, s_crop, crop); | ||
1235 | if (ret < 0) { | ||
1236 | dev_warn(dev, "%s: failed to crop to %ux%u@%u:%u\n", __func__, | ||
1237 | rect->width, rect->height, rect->left, rect->top); | ||
1238 | return ret; | ||
1239 | } | ||
1240 | |||
1241 | ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); | ||
1242 | if (ret < 0) { | ||
1243 | dev_warn(dev, "%s: failed to fetch current format\n", __func__); | ||
1244 | return ret; | ||
1245 | } | ||
1246 | |||
1247 | ret = dma_align(&mf->width, &mf->height, xlate->host_fmt, pcdev->vb_mode, | ||
1248 | false); | ||
1249 | if (ret < 0) { | ||
1250 | dev_err(dev, "%s: failed to align %ux%u %s with DMA\n", | ||
1251 | __func__, mf->width, mf->height, | ||
1252 | xlate->host_fmt->name); | ||
1253 | return ret; | ||
1254 | } | ||
1255 | |||
1256 | if (!ret) { | ||
1257 | /* sensor returned geometry not DMA aligned, trying to fix */ | ||
1258 | ret = set_format(pcdev, dev, icd, sd, &fmt, xlate); | ||
1259 | if (ret < 0) { | ||
1260 | dev_err(dev, "%s: failed to set format\n", __func__); | ||
1261 | return ret; | ||
1262 | } | ||
1263 | } | ||
1264 | |||
1265 | icd->user_width = mf->width; | ||
1266 | icd->user_height = mf->height; | ||
1267 | |||
1268 | return 0; | ||
1269 | } | ||
1270 | |||
1271 | static int omap1_cam_set_fmt(struct soc_camera_device *icd, | ||
1272 | struct v4l2_format *f) | ||
1273 | { | ||
1274 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1275 | const struct soc_camera_format_xlate *xlate; | ||
1276 | struct device *dev = icd->parent; | ||
1277 | struct soc_camera_host *ici = to_soc_camera_host(dev); | ||
1278 | struct omap1_cam_dev *pcdev = ici->priv; | ||
1279 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
1280 | struct v4l2_subdev_format format = { | ||
1281 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
1282 | }; | ||
1283 | struct v4l2_mbus_framefmt *mf = &format.format; | ||
1284 | int ret; | ||
1285 | |||
1286 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); | ||
1287 | if (!xlate) { | ||
1288 | dev_warn(dev, "%s: format %#x not found\n", __func__, | ||
1289 | pix->pixelformat); | ||
1290 | return -EINVAL; | ||
1291 | } | ||
1292 | |||
1293 | mf->width = pix->width; | ||
1294 | mf->height = pix->height; | ||
1295 | mf->field = pix->field; | ||
1296 | mf->colorspace = pix->colorspace; | ||
1297 | mf->code = xlate->code; | ||
1298 | |||
1299 | ret = dma_align(&mf->width, &mf->height, xlate->host_fmt, pcdev->vb_mode, | ||
1300 | true); | ||
1301 | if (ret < 0) { | ||
1302 | dev_err(dev, "%s: failed to align %ux%u %s with DMA\n", | ||
1303 | __func__, pix->width, pix->height, | ||
1304 | xlate->host_fmt->name); | ||
1305 | return ret; | ||
1306 | } | ||
1307 | |||
1308 | ret = set_format(pcdev, dev, icd, sd, &format, xlate); | ||
1309 | if (ret < 0) { | ||
1310 | dev_err(dev, "%s: failed to set format\n", __func__); | ||
1311 | return ret; | ||
1312 | } | ||
1313 | |||
1314 | pix->width = mf->width; | ||
1315 | pix->height = mf->height; | ||
1316 | pix->field = mf->field; | ||
1317 | pix->colorspace = mf->colorspace; | ||
1318 | icd->current_fmt = xlate; | ||
1319 | |||
1320 | return 0; | ||
1321 | } | ||
1322 | |||
1323 | static int omap1_cam_try_fmt(struct soc_camera_device *icd, | ||
1324 | struct v4l2_format *f) | ||
1325 | { | ||
1326 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1327 | const struct soc_camera_format_xlate *xlate; | ||
1328 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
1329 | struct v4l2_subdev_pad_config pad_cfg; | ||
1330 | struct v4l2_subdev_format format = { | ||
1331 | .which = V4L2_SUBDEV_FORMAT_TRY, | ||
1332 | }; | ||
1333 | struct v4l2_mbus_framefmt *mf = &format.format; | ||
1334 | int ret; | ||
1335 | /* TODO: limit to mx1 hardware capabilities */ | ||
1336 | |||
1337 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); | ||
1338 | if (!xlate) { | ||
1339 | dev_warn(icd->parent, "Format %#x not found\n", | ||
1340 | pix->pixelformat); | ||
1341 | return -EINVAL; | ||
1342 | } | ||
1343 | |||
1344 | mf->width = pix->width; | ||
1345 | mf->height = pix->height; | ||
1346 | mf->field = pix->field; | ||
1347 | mf->colorspace = pix->colorspace; | ||
1348 | mf->code = xlate->code; | ||
1349 | |||
1350 | /* limit to sensor capabilities */ | ||
1351 | ret = v4l2_subdev_call(sd, pad, set_fmt, &pad_cfg, &format); | ||
1352 | if (ret < 0) | ||
1353 | return ret; | ||
1354 | |||
1355 | pix->width = mf->width; | ||
1356 | pix->height = mf->height; | ||
1357 | pix->field = mf->field; | ||
1358 | pix->colorspace = mf->colorspace; | ||
1359 | |||
1360 | return 0; | ||
1361 | } | ||
1362 | |||
1363 | static bool sg_mode; | ||
1364 | |||
1365 | /* | ||
1366 | * Local mmap_mapper wrapper, | ||
1367 | * used for detecting videobuf-dma-contig buffer allocation failures | ||
1368 | * and switching to videobuf-dma-sg automatically for future attempts. | ||
1369 | */ | ||
1370 | static int omap1_cam_mmap_mapper(struct videobuf_queue *q, | ||
1371 | struct videobuf_buffer *buf, | ||
1372 | struct vm_area_struct *vma) | ||
1373 | { | ||
1374 | struct soc_camera_device *icd = q->priv_data; | ||
1375 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1376 | struct omap1_cam_dev *pcdev = ici->priv; | ||
1377 | int ret; | ||
1378 | |||
1379 | ret = pcdev->mmap_mapper(q, buf, vma); | ||
1380 | |||
1381 | if (ret == -ENOMEM) | ||
1382 | sg_mode = true; | ||
1383 | |||
1384 | return ret; | ||
1385 | } | ||
1386 | |||
1387 | static void omap1_cam_init_videobuf(struct videobuf_queue *q, | ||
1388 | struct soc_camera_device *icd) | ||
1389 | { | ||
1390 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1391 | struct omap1_cam_dev *pcdev = ici->priv; | ||
1392 | |||
1393 | if (!sg_mode) | ||
1394 | videobuf_queue_dma_contig_init(q, &omap1_videobuf_ops, | ||
1395 | icd->parent, &pcdev->lock, | ||
1396 | V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, | ||
1397 | sizeof(struct omap1_cam_buf), icd, &ici->host_lock); | ||
1398 | else | ||
1399 | videobuf_queue_sg_init(q, &omap1_videobuf_ops, | ||
1400 | icd->parent, &pcdev->lock, | ||
1401 | V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, | ||
1402 | sizeof(struct omap1_cam_buf), icd, &ici->host_lock); | ||
1403 | |||
1404 | /* use videobuf mode (auto)selected with the module parameter */ | ||
1405 | pcdev->vb_mode = sg_mode ? OMAP1_CAM_DMA_SG : OMAP1_CAM_DMA_CONTIG; | ||
1406 | |||
1407 | /* | ||
1408 | * Ensure we substitute the videobuf-dma-contig version of the | ||
1409 | * mmap_mapper() callback with our own wrapper, used for switching | ||
1410 | * automatically to videobuf-dma-sg on buffer allocation failure. | ||
1411 | */ | ||
1412 | if (!sg_mode && q->int_ops->mmap_mapper != omap1_cam_mmap_mapper) { | ||
1413 | pcdev->mmap_mapper = q->int_ops->mmap_mapper; | ||
1414 | q->int_ops->mmap_mapper = omap1_cam_mmap_mapper; | ||
1415 | } | ||
1416 | } | ||
1417 | |||
1418 | static int omap1_cam_reqbufs(struct soc_camera_device *icd, | ||
1419 | struct v4l2_requestbuffers *p) | ||
1420 | { | ||
1421 | int i; | ||
1422 | |||
1423 | /* | ||
1424 | * This is for locking debugging only. I removed spinlocks and now I | ||
1425 | * check whether .prepare is ever called on a linked buffer, or whether | ||
1426 | * a dma IRQ can occur for an in-work or unlinked buffer. Until now | ||
1427 | * it hadn't triggered | ||
1428 | */ | ||
1429 | for (i = 0; i < p->count; i++) { | ||
1430 | struct omap1_cam_buf *buf = container_of(icd->vb_vidq.bufs[i], | ||
1431 | struct omap1_cam_buf, vb); | ||
1432 | buf->inwork = 0; | ||
1433 | INIT_LIST_HEAD(&buf->vb.queue); | ||
1434 | } | ||
1435 | |||
1436 | return 0; | ||
1437 | } | ||
1438 | |||
1439 | static int omap1_cam_querycap(struct soc_camera_host *ici, | ||
1440 | struct v4l2_capability *cap) | ||
1441 | { | ||
1442 | /* cap->name is set by the friendly caller:-> */ | ||
1443 | strlcpy(cap->card, "OMAP1 Camera", sizeof(cap->card)); | ||
1444 | cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; | ||
1445 | cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; | ||
1446 | |||
1447 | return 0; | ||
1448 | } | ||
1449 | |||
1450 | static int omap1_cam_set_bus_param(struct soc_camera_device *icd) | ||
1451 | { | ||
1452 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
1453 | struct device *dev = icd->parent; | ||
1454 | struct soc_camera_host *ici = to_soc_camera_host(dev); | ||
1455 | struct omap1_cam_dev *pcdev = ici->priv; | ||
1456 | u32 pixfmt = icd->current_fmt->host_fmt->fourcc; | ||
1457 | const struct soc_camera_format_xlate *xlate; | ||
1458 | const struct soc_mbus_pixelfmt *fmt; | ||
1459 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; | ||
1460 | unsigned long common_flags; | ||
1461 | u32 ctrlclock, mode; | ||
1462 | int ret; | ||
1463 | |||
1464 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); | ||
1465 | if (!ret) { | ||
1466 | common_flags = soc_mbus_config_compatible(&cfg, SOCAM_BUS_FLAGS); | ||
1467 | if (!common_flags) { | ||
1468 | dev_warn(dev, | ||
1469 | "Flags incompatible: camera 0x%x, host 0x%x\n", | ||
1470 | cfg.flags, SOCAM_BUS_FLAGS); | ||
1471 | return -EINVAL; | ||
1472 | } | ||
1473 | } else if (ret != -ENOIOCTLCMD) { | ||
1474 | return ret; | ||
1475 | } else { | ||
1476 | common_flags = SOCAM_BUS_FLAGS; | ||
1477 | } | ||
1478 | |||
1479 | /* Make choices, possibly based on platform configuration */ | ||
1480 | if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && | ||
1481 | (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { | ||
1482 | if (!pcdev->pdata || | ||
1483 | pcdev->pdata->flags & OMAP1_CAMERA_LCLK_RISING) | ||
1484 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; | ||
1485 | else | ||
1486 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; | ||
1487 | } | ||
1488 | |||
1489 | cfg.flags = common_flags; | ||
1490 | ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); | ||
1491 | if (ret < 0 && ret != -ENOIOCTLCMD) { | ||
1492 | dev_dbg(dev, "camera s_mbus_config(0x%lx) returned %d\n", | ||
1493 | common_flags, ret); | ||
1494 | return ret; | ||
1495 | } | ||
1496 | |||
1497 | ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK); | ||
1498 | if (ctrlclock & LCLK_EN) | ||
1499 | CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN); | ||
1500 | |||
1501 | if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) { | ||
1502 | dev_dbg(dev, "CTRLCLOCK_REG |= POLCLK\n"); | ||
1503 | ctrlclock |= POLCLK; | ||
1504 | } else { | ||
1505 | dev_dbg(dev, "CTRLCLOCK_REG &= ~POLCLK\n"); | ||
1506 | ctrlclock &= ~POLCLK; | ||
1507 | } | ||
1508 | CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN); | ||
1509 | |||
1510 | if (ctrlclock & LCLK_EN) | ||
1511 | CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock); | ||
1512 | |||
1513 | /* select bus endianness */ | ||
1514 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | ||
1515 | fmt = xlate->host_fmt; | ||
1516 | |||
1517 | mode = CAM_READ(pcdev, MODE) & ~(RAZ_FIFO | IRQ_MASK | DMA); | ||
1518 | if (fmt->order == SOC_MBUS_ORDER_LE) { | ||
1519 | dev_dbg(dev, "MODE_REG &= ~ORDERCAMD\n"); | ||
1520 | CAM_WRITE(pcdev, MODE, mode & ~ORDERCAMD); | ||
1521 | } else { | ||
1522 | dev_dbg(dev, "MODE_REG |= ORDERCAMD\n"); | ||
1523 | CAM_WRITE(pcdev, MODE, mode | ORDERCAMD); | ||
1524 | } | ||
1525 | |||
1526 | return 0; | ||
1527 | } | ||
1528 | |||
1529 | static unsigned int omap1_cam_poll(struct file *file, poll_table *pt) | ||
1530 | { | ||
1531 | struct soc_camera_device *icd = file->private_data; | ||
1532 | struct omap1_cam_buf *buf; | ||
1533 | |||
1534 | buf = list_entry(icd->vb_vidq.stream.next, struct omap1_cam_buf, | ||
1535 | vb.stream); | ||
1536 | |||
1537 | poll_wait(file, &buf->vb.done, pt); | ||
1538 | |||
1539 | if (buf->vb.state == VIDEOBUF_DONE || | ||
1540 | buf->vb.state == VIDEOBUF_ERROR) | ||
1541 | return POLLIN | POLLRDNORM; | ||
1542 | |||
1543 | return 0; | ||
1544 | } | ||
1545 | |||
1546 | static struct soc_camera_host_ops omap1_host_ops = { | ||
1547 | .owner = THIS_MODULE, | ||
1548 | .add = omap1_cam_add_device, | ||
1549 | .remove = omap1_cam_remove_device, | ||
1550 | .clock_start = omap1_cam_clock_start, | ||
1551 | .clock_stop = omap1_cam_clock_stop, | ||
1552 | .get_formats = omap1_cam_get_formats, | ||
1553 | .set_crop = omap1_cam_set_crop, | ||
1554 | .set_fmt = omap1_cam_set_fmt, | ||
1555 | .try_fmt = omap1_cam_try_fmt, | ||
1556 | .init_videobuf = omap1_cam_init_videobuf, | ||
1557 | .reqbufs = omap1_cam_reqbufs, | ||
1558 | .querycap = omap1_cam_querycap, | ||
1559 | .set_bus_param = omap1_cam_set_bus_param, | ||
1560 | .poll = omap1_cam_poll, | ||
1561 | }; | ||
1562 | |||
1563 | static int omap1_cam_probe(struct platform_device *pdev) | ||
1564 | { | ||
1565 | struct omap1_cam_dev *pcdev; | ||
1566 | struct resource *res; | ||
1567 | struct clk *clk; | ||
1568 | void __iomem *base; | ||
1569 | unsigned int irq; | ||
1570 | int err = 0; | ||
1571 | |||
1572 | irq = platform_get_irq(pdev, 0); | ||
1573 | if ((int)irq <= 0) { | ||
1574 | err = -ENODEV; | ||
1575 | goto exit; | ||
1576 | } | ||
1577 | |||
1578 | clk = devm_clk_get(&pdev->dev, "armper_ck"); | ||
1579 | if (IS_ERR(clk)) | ||
1580 | return PTR_ERR(clk); | ||
1581 | |||
1582 | pcdev = devm_kzalloc(&pdev->dev, sizeof(*pcdev) + resource_size(res), | ||
1583 | GFP_KERNEL); | ||
1584 | if (!pcdev) | ||
1585 | return -ENOMEM; | ||
1586 | |||
1587 | pcdev->clk = clk; | ||
1588 | |||
1589 | pcdev->pdata = pdev->dev.platform_data; | ||
1590 | if (pcdev->pdata) { | ||
1591 | pcdev->pflags = pcdev->pdata->flags; | ||
1592 | pcdev->camexclk = pcdev->pdata->camexclk_khz * 1000; | ||
1593 | } | ||
1594 | |||
1595 | switch (pcdev->camexclk) { | ||
1596 | case 6000000: | ||
1597 | case 8000000: | ||
1598 | case 9600000: | ||
1599 | case 12000000: | ||
1600 | case 24000000: | ||
1601 | break; | ||
1602 | default: | ||
1603 | /* pcdev->camexclk != 0 => pcdev->pdata != NULL */ | ||
1604 | dev_warn(&pdev->dev, | ||
1605 | "Incorrect sensor clock frequency %ld kHz, " | ||
1606 | "should be one of 0, 6, 8, 9.6, 12 or 24 MHz, " | ||
1607 | "please correct your platform data\n", | ||
1608 | pcdev->pdata->camexclk_khz); | ||
1609 | pcdev->camexclk = 0; | ||
1610 | case 0: | ||
1611 | dev_info(&pdev->dev, "Not providing sensor clock\n"); | ||
1612 | } | ||
1613 | |||
1614 | INIT_LIST_HEAD(&pcdev->capture); | ||
1615 | spin_lock_init(&pcdev->lock); | ||
1616 | |||
1617 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1618 | base = devm_ioremap_resource(&pdev->dev, res); | ||
1619 | if (IS_ERR(base)) | ||
1620 | return PTR_ERR(base); | ||
1621 | |||
1622 | pcdev->irq = irq; | ||
1623 | pcdev->base = base; | ||
1624 | |||
1625 | sensor_reset(pcdev, true); | ||
1626 | |||
1627 | err = omap_request_dma(OMAP_DMA_CAMERA_IF_RX, DRIVER_NAME, | ||
1628 | dma_isr, (void *)pcdev, &pcdev->dma_ch); | ||
1629 | if (err < 0) { | ||
1630 | dev_err(&pdev->dev, "Can't request DMA for OMAP1 Camera\n"); | ||
1631 | return -EBUSY; | ||
1632 | } | ||
1633 | dev_dbg(&pdev->dev, "got DMA channel %d\n", pcdev->dma_ch); | ||
1634 | |||
1635 | /* preconfigure DMA */ | ||
1636 | omap_set_dma_src_params(pcdev->dma_ch, OMAP_DMA_PORT_TIPB, | ||
1637 | OMAP_DMA_AMODE_CONSTANT, res->start + REG_CAMDATA, | ||
1638 | 0, 0); | ||
1639 | omap_set_dma_dest_burst_mode(pcdev->dma_ch, OMAP_DMA_DATA_BURST_4); | ||
1640 | /* setup DMA autoinitialization */ | ||
1641 | omap_dma_link_lch(pcdev->dma_ch, pcdev->dma_ch); | ||
1642 | |||
1643 | err = devm_request_irq(&pdev->dev, pcdev->irq, cam_isr, 0, DRIVER_NAME, | ||
1644 | pcdev); | ||
1645 | if (err) { | ||
1646 | dev_err(&pdev->dev, "Camera interrupt register failed\n"); | ||
1647 | goto exit_free_dma; | ||
1648 | } | ||
1649 | |||
1650 | pcdev->soc_host.drv_name = DRIVER_NAME; | ||
1651 | pcdev->soc_host.ops = &omap1_host_ops; | ||
1652 | pcdev->soc_host.priv = pcdev; | ||
1653 | pcdev->soc_host.v4l2_dev.dev = &pdev->dev; | ||
1654 | pcdev->soc_host.nr = pdev->id; | ||
1655 | |||
1656 | err = soc_camera_host_register(&pcdev->soc_host); | ||
1657 | if (err) | ||
1658 | return err; | ||
1659 | |||
1660 | dev_info(&pdev->dev, "OMAP1 Camera Interface driver loaded\n"); | ||
1661 | |||
1662 | return 0; | ||
1663 | |||
1664 | exit_free_dma: | ||
1665 | omap_free_dma(pcdev->dma_ch); | ||
1666 | exit: | ||
1667 | return err; | ||
1668 | } | ||
1669 | |||
1670 | static int omap1_cam_remove(struct platform_device *pdev) | ||
1671 | { | ||
1672 | struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); | ||
1673 | struct omap1_cam_dev *pcdev = container_of(soc_host, | ||
1674 | struct omap1_cam_dev, soc_host); | ||
1675 | |||
1676 | omap_free_dma(pcdev->dma_ch); | ||
1677 | |||
1678 | soc_camera_host_unregister(soc_host); | ||
1679 | |||
1680 | dev_info(&pdev->dev, "OMAP1 Camera Interface driver unloaded\n"); | ||
1681 | |||
1682 | return 0; | ||
1683 | } | ||
1684 | |||
1685 | static struct platform_driver omap1_cam_driver = { | ||
1686 | .driver = { | ||
1687 | .name = DRIVER_NAME, | ||
1688 | }, | ||
1689 | .probe = omap1_cam_probe, | ||
1690 | .remove = omap1_cam_remove, | ||
1691 | }; | ||
1692 | |||
1693 | module_platform_driver(omap1_cam_driver); | ||
1694 | |||
1695 | module_param(sg_mode, bool, 0644); | ||
1696 | MODULE_PARM_DESC(sg_mode, "videobuf mode, 0: dma-contig (default), 1: dma-sg"); | ||
1697 | |||
1698 | MODULE_DESCRIPTION("OMAP1 Camera Interface driver"); | ||
1699 | MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>"); | ||
1700 | MODULE_LICENSE("GPL v2"); | ||
1701 | MODULE_VERSION(DRIVER_VERSION); | ||
1702 | MODULE_ALIAS("platform:" DRIVER_NAME); | ||
diff --git a/drivers/staging/media/timb/Kconfig b/drivers/staging/media/timb/Kconfig deleted file mode 100644 index e413fecc1e67..000000000000 --- a/drivers/staging/media/timb/Kconfig +++ /dev/null | |||
@@ -1,11 +0,0 @@ | |||
1 | config VIDEO_TIMBERDALE | ||
2 | tristate "Support for timberdale Video In/LogiWIN" | ||
3 | depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && HAS_DMA | ||
4 | depends on (MFD_TIMBERDALE && TIMB_DMA) || COMPILE_TEST | ||
5 | select VIDEO_ADV7180 | ||
6 | select VIDEOBUF_DMA_CONTIG | ||
7 | ---help--- | ||
8 | Add support for the Video In peripherial of the timberdale FPGA. | ||
9 | |||
10 | This driver is deprecated and will be removed soon unless someone | ||
11 | will start the work to convert this driver to the vb2 framework. | ||
diff --git a/drivers/staging/media/timb/Makefile b/drivers/staging/media/timb/Makefile deleted file mode 100644 index 4c989c23a0e0..000000000000 --- a/drivers/staging/media/timb/Makefile +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | obj-$(CONFIG_VIDEO_TIMBERDALE) += timblogiw.o | ||
diff --git a/drivers/staging/media/timb/timblogiw.c b/drivers/staging/media/timb/timblogiw.c deleted file mode 100644 index 113c9f3c0b3e..000000000000 --- a/drivers/staging/media/timb/timblogiw.c +++ /dev/null | |||
@@ -1,870 +0,0 @@ | |||
1 | /* | ||
2 | * timblogiw.c timberdale FPGA LogiWin Video In driver | ||
3 | * Copyright (c) 2009-2010 Intel Corporation | ||
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 version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
17 | */ | ||
18 | |||
19 | /* Supports: | ||
20 | * Timberdale FPGA LogiWin Video In | ||
21 | */ | ||
22 | |||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/dmaengine.h> | ||
26 | #include <linux/scatterlist.h> | ||
27 | #include <linux/interrupt.h> | ||
28 | #include <linux/list.h> | ||
29 | #include <linux/i2c.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <media/v4l2-ioctl.h> | ||
32 | #include <media/v4l2-device.h> | ||
33 | #include <media/videobuf-dma-contig.h> | ||
34 | #include <linux/platform_data/media/timb_video.h> | ||
35 | |||
36 | #define DRIVER_NAME "timb-video" | ||
37 | |||
38 | #define TIMBLOGIWIN_NAME "Timberdale Video-In" | ||
39 | #define TIMBLOGIW_VERSION_CODE 0x04 | ||
40 | |||
41 | #define TIMBLOGIW_LINES_PER_DESC 44 | ||
42 | #define TIMBLOGIW_MAX_VIDEO_MEM 16 | ||
43 | |||
44 | #define TIMBLOGIW_HAS_DECODER(lw) (lw->pdata.encoder.module_name) | ||
45 | |||
46 | |||
47 | struct timblogiw { | ||
48 | struct video_device video_dev; | ||
49 | struct v4l2_device v4l2_dev; /* mutual exclusion */ | ||
50 | struct mutex lock; | ||
51 | struct device *dev; | ||
52 | struct timb_video_platform_data pdata; | ||
53 | struct v4l2_subdev *sd_enc; /* encoder */ | ||
54 | bool opened; | ||
55 | }; | ||
56 | |||
57 | struct timblogiw_tvnorm { | ||
58 | v4l2_std_id std; | ||
59 | u16 width; | ||
60 | u16 height; | ||
61 | u8 fps; | ||
62 | }; | ||
63 | |||
64 | struct timblogiw_fh { | ||
65 | struct videobuf_queue vb_vidq; | ||
66 | struct timblogiw_tvnorm const *cur_norm; | ||
67 | struct list_head capture; | ||
68 | struct dma_chan *chan; | ||
69 | spinlock_t queue_lock; /* mutual exclusion */ | ||
70 | unsigned int frame_count; | ||
71 | }; | ||
72 | |||
73 | struct timblogiw_buffer { | ||
74 | /* common v4l buffer stuff -- must be first */ | ||
75 | struct videobuf_buffer vb; | ||
76 | struct scatterlist sg[16]; | ||
77 | dma_cookie_t cookie; | ||
78 | struct timblogiw_fh *fh; | ||
79 | }; | ||
80 | |||
81 | static const struct timblogiw_tvnorm timblogiw_tvnorms[] = { | ||
82 | { | ||
83 | .std = V4L2_STD_PAL, | ||
84 | .width = 720, | ||
85 | .height = 576, | ||
86 | .fps = 25 | ||
87 | }, | ||
88 | { | ||
89 | .std = V4L2_STD_NTSC, | ||
90 | .width = 720, | ||
91 | .height = 480, | ||
92 | .fps = 30 | ||
93 | } | ||
94 | }; | ||
95 | |||
96 | static int timblogiw_bytes_per_line(const struct timblogiw_tvnorm *norm) | ||
97 | { | ||
98 | return norm->width * 2; | ||
99 | } | ||
100 | |||
101 | |||
102 | static int timblogiw_frame_size(const struct timblogiw_tvnorm *norm) | ||
103 | { | ||
104 | return norm->height * timblogiw_bytes_per_line(norm); | ||
105 | } | ||
106 | |||
107 | static const struct timblogiw_tvnorm *timblogiw_get_norm(const v4l2_std_id std) | ||
108 | { | ||
109 | int i; | ||
110 | for (i = 0; i < ARRAY_SIZE(timblogiw_tvnorms); i++) | ||
111 | if (timblogiw_tvnorms[i].std & std) | ||
112 | return timblogiw_tvnorms + i; | ||
113 | |||
114 | /* default to first element */ | ||
115 | return timblogiw_tvnorms; | ||
116 | } | ||
117 | |||
118 | static void timblogiw_dma_cb(void *data) | ||
119 | { | ||
120 | struct timblogiw_buffer *buf = data; | ||
121 | struct timblogiw_fh *fh = buf->fh; | ||
122 | struct videobuf_buffer *vb = &buf->vb; | ||
123 | |||
124 | spin_lock(&fh->queue_lock); | ||
125 | |||
126 | /* mark the transfer done */ | ||
127 | buf->cookie = -1; | ||
128 | |||
129 | fh->frame_count++; | ||
130 | |||
131 | if (vb->state != VIDEOBUF_ERROR) { | ||
132 | list_del(&vb->queue); | ||
133 | v4l2_get_timestamp(&vb->ts); | ||
134 | vb->field_count = fh->frame_count * 2; | ||
135 | vb->state = VIDEOBUF_DONE; | ||
136 | |||
137 | wake_up(&vb->done); | ||
138 | } | ||
139 | |||
140 | if (!list_empty(&fh->capture)) { | ||
141 | vb = list_entry(fh->capture.next, struct videobuf_buffer, | ||
142 | queue); | ||
143 | vb->state = VIDEOBUF_ACTIVE; | ||
144 | } | ||
145 | |||
146 | spin_unlock(&fh->queue_lock); | ||
147 | } | ||
148 | |||
149 | static bool timblogiw_dma_filter_fn(struct dma_chan *chan, void *filter_param) | ||
150 | { | ||
151 | return chan->chan_id == (uintptr_t)filter_param; | ||
152 | } | ||
153 | |||
154 | /* IOCTL functions */ | ||
155 | |||
156 | static int timblogiw_g_fmt(struct file *file, void *priv, | ||
157 | struct v4l2_format *format) | ||
158 | { | ||
159 | struct video_device *vdev = video_devdata(file); | ||
160 | struct timblogiw *lw = video_get_drvdata(vdev); | ||
161 | struct timblogiw_fh *fh = priv; | ||
162 | |||
163 | dev_dbg(&vdev->dev, "%s entry\n", __func__); | ||
164 | |||
165 | if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
166 | return -EINVAL; | ||
167 | |||
168 | mutex_lock(&lw->lock); | ||
169 | |||
170 | format->fmt.pix.width = fh->cur_norm->width; | ||
171 | format->fmt.pix.height = fh->cur_norm->height; | ||
172 | format->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; | ||
173 | format->fmt.pix.bytesperline = timblogiw_bytes_per_line(fh->cur_norm); | ||
174 | format->fmt.pix.sizeimage = timblogiw_frame_size(fh->cur_norm); | ||
175 | format->fmt.pix.field = V4L2_FIELD_NONE; | ||
176 | |||
177 | mutex_unlock(&lw->lock); | ||
178 | |||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | static int timblogiw_try_fmt(struct file *file, void *priv, | ||
183 | struct v4l2_format *format) | ||
184 | { | ||
185 | struct video_device *vdev = video_devdata(file); | ||
186 | struct v4l2_pix_format *pix = &format->fmt.pix; | ||
187 | |||
188 | dev_dbg(&vdev->dev, | ||
189 | "%s - width=%d, height=%d, pixelformat=%d, field=%d\n" | ||
190 | "bytes per line %d, size image: %d, colorspace: %d\n", | ||
191 | __func__, | ||
192 | pix->width, pix->height, pix->pixelformat, pix->field, | ||
193 | pix->bytesperline, pix->sizeimage, pix->colorspace); | ||
194 | |||
195 | if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
196 | return -EINVAL; | ||
197 | |||
198 | if (pix->field != V4L2_FIELD_NONE) | ||
199 | return -EINVAL; | ||
200 | |||
201 | if (pix->pixelformat != V4L2_PIX_FMT_UYVY) | ||
202 | return -EINVAL; | ||
203 | |||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | static int timblogiw_s_fmt(struct file *file, void *priv, | ||
208 | struct v4l2_format *format) | ||
209 | { | ||
210 | struct video_device *vdev = video_devdata(file); | ||
211 | struct timblogiw *lw = video_get_drvdata(vdev); | ||
212 | struct timblogiw_fh *fh = priv; | ||
213 | struct v4l2_pix_format *pix = &format->fmt.pix; | ||
214 | int err; | ||
215 | |||
216 | mutex_lock(&lw->lock); | ||
217 | |||
218 | err = timblogiw_try_fmt(file, priv, format); | ||
219 | if (err) | ||
220 | goto out; | ||
221 | |||
222 | if (videobuf_queue_is_busy(&fh->vb_vidq)) { | ||
223 | dev_err(&vdev->dev, "%s queue busy\n", __func__); | ||
224 | err = -EBUSY; | ||
225 | goto out; | ||
226 | } | ||
227 | |||
228 | pix->width = fh->cur_norm->width; | ||
229 | pix->height = fh->cur_norm->height; | ||
230 | |||
231 | out: | ||
232 | mutex_unlock(&lw->lock); | ||
233 | return err; | ||
234 | } | ||
235 | |||
236 | static int timblogiw_querycap(struct file *file, void *priv, | ||
237 | struct v4l2_capability *cap) | ||
238 | { | ||
239 | struct video_device *vdev = video_devdata(file); | ||
240 | |||
241 | dev_dbg(&vdev->dev, "%s: Entry\n", __func__); | ||
242 | strncpy(cap->card, TIMBLOGIWIN_NAME, sizeof(cap->card)-1); | ||
243 | strncpy(cap->driver, DRIVER_NAME, sizeof(cap->driver) - 1); | ||
244 | snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", vdev->name); | ||
245 | cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | | ||
246 | V4L2_CAP_READWRITE; | ||
247 | cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; | ||
248 | |||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | static int timblogiw_enum_fmt(struct file *file, void *priv, | ||
253 | struct v4l2_fmtdesc *fmt) | ||
254 | { | ||
255 | struct video_device *vdev = video_devdata(file); | ||
256 | |||
257 | dev_dbg(&vdev->dev, "%s, index: %d\n", __func__, fmt->index); | ||
258 | |||
259 | if (fmt->index != 0) | ||
260 | return -EINVAL; | ||
261 | memset(fmt, 0, sizeof(*fmt)); | ||
262 | fmt->index = 0; | ||
263 | fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
264 | strncpy(fmt->description, "4:2:2, packed, YUYV", | ||
265 | sizeof(fmt->description)-1); | ||
266 | fmt->pixelformat = V4L2_PIX_FMT_UYVY; | ||
267 | |||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | static int timblogiw_g_parm(struct file *file, void *priv, | ||
272 | struct v4l2_streamparm *sp) | ||
273 | { | ||
274 | struct timblogiw_fh *fh = priv; | ||
275 | struct v4l2_captureparm *cp = &sp->parm.capture; | ||
276 | |||
277 | cp->capability = V4L2_CAP_TIMEPERFRAME; | ||
278 | cp->timeperframe.numerator = 1; | ||
279 | cp->timeperframe.denominator = fh->cur_norm->fps; | ||
280 | |||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | static int timblogiw_reqbufs(struct file *file, void *priv, | ||
285 | struct v4l2_requestbuffers *rb) | ||
286 | { | ||
287 | struct video_device *vdev = video_devdata(file); | ||
288 | struct timblogiw_fh *fh = priv; | ||
289 | |||
290 | dev_dbg(&vdev->dev, "%s: entry\n", __func__); | ||
291 | |||
292 | return videobuf_reqbufs(&fh->vb_vidq, rb); | ||
293 | } | ||
294 | |||
295 | static int timblogiw_querybuf(struct file *file, void *priv, | ||
296 | struct v4l2_buffer *b) | ||
297 | { | ||
298 | struct video_device *vdev = video_devdata(file); | ||
299 | struct timblogiw_fh *fh = priv; | ||
300 | |||
301 | dev_dbg(&vdev->dev, "%s: entry\n", __func__); | ||
302 | |||
303 | return videobuf_querybuf(&fh->vb_vidq, b); | ||
304 | } | ||
305 | |||
306 | static int timblogiw_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) | ||
307 | { | ||
308 | struct video_device *vdev = video_devdata(file); | ||
309 | struct timblogiw_fh *fh = priv; | ||
310 | |||
311 | dev_dbg(&vdev->dev, "%s: entry\n", __func__); | ||
312 | |||
313 | return videobuf_qbuf(&fh->vb_vidq, b); | ||
314 | } | ||
315 | |||
316 | static int timblogiw_dqbuf(struct file *file, void *priv, | ||
317 | struct v4l2_buffer *b) | ||
318 | { | ||
319 | struct video_device *vdev = video_devdata(file); | ||
320 | struct timblogiw_fh *fh = priv; | ||
321 | |||
322 | dev_dbg(&vdev->dev, "%s: entry\n", __func__); | ||
323 | |||
324 | return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK); | ||
325 | } | ||
326 | |||
327 | static int timblogiw_g_std(struct file *file, void *priv, v4l2_std_id *std) | ||
328 | { | ||
329 | struct video_device *vdev = video_devdata(file); | ||
330 | struct timblogiw_fh *fh = priv; | ||
331 | |||
332 | dev_dbg(&vdev->dev, "%s: entry\n", __func__); | ||
333 | |||
334 | *std = fh->cur_norm->std; | ||
335 | return 0; | ||
336 | } | ||
337 | |||
338 | static int timblogiw_s_std(struct file *file, void *priv, v4l2_std_id std) | ||
339 | { | ||
340 | struct video_device *vdev = video_devdata(file); | ||
341 | struct timblogiw *lw = video_get_drvdata(vdev); | ||
342 | struct timblogiw_fh *fh = priv; | ||
343 | int err = 0; | ||
344 | |||
345 | dev_dbg(&vdev->dev, "%s: entry\n", __func__); | ||
346 | |||
347 | mutex_lock(&lw->lock); | ||
348 | |||
349 | if (TIMBLOGIW_HAS_DECODER(lw)) | ||
350 | err = v4l2_subdev_call(lw->sd_enc, video, s_std, std); | ||
351 | |||
352 | if (!err) | ||
353 | fh->cur_norm = timblogiw_get_norm(std); | ||
354 | |||
355 | mutex_unlock(&lw->lock); | ||
356 | |||
357 | return err; | ||
358 | } | ||
359 | |||
360 | static int timblogiw_enuminput(struct file *file, void *priv, | ||
361 | struct v4l2_input *inp) | ||
362 | { | ||
363 | struct video_device *vdev = video_devdata(file); | ||
364 | int i; | ||
365 | |||
366 | dev_dbg(&vdev->dev, "%s: Entry\n", __func__); | ||
367 | |||
368 | if (inp->index != 0) | ||
369 | return -EINVAL; | ||
370 | |||
371 | inp->index = 0; | ||
372 | |||
373 | strncpy(inp->name, "Timb input 1", sizeof(inp->name) - 1); | ||
374 | inp->type = V4L2_INPUT_TYPE_CAMERA; | ||
375 | |||
376 | inp->std = 0; | ||
377 | for (i = 0; i < ARRAY_SIZE(timblogiw_tvnorms); i++) | ||
378 | inp->std |= timblogiw_tvnorms[i].std; | ||
379 | |||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | static int timblogiw_g_input(struct file *file, void *priv, | ||
384 | unsigned int *input) | ||
385 | { | ||
386 | struct video_device *vdev = video_devdata(file); | ||
387 | |||
388 | dev_dbg(&vdev->dev, "%s: Entry\n", __func__); | ||
389 | |||
390 | *input = 0; | ||
391 | |||
392 | return 0; | ||
393 | } | ||
394 | |||
395 | static int timblogiw_s_input(struct file *file, void *priv, unsigned int input) | ||
396 | { | ||
397 | struct video_device *vdev = video_devdata(file); | ||
398 | |||
399 | dev_dbg(&vdev->dev, "%s: Entry\n", __func__); | ||
400 | |||
401 | if (input != 0) | ||
402 | return -EINVAL; | ||
403 | return 0; | ||
404 | } | ||
405 | |||
406 | static int timblogiw_streamon(struct file *file, void *priv, enum v4l2_buf_type type) | ||
407 | { | ||
408 | struct video_device *vdev = video_devdata(file); | ||
409 | struct timblogiw_fh *fh = priv; | ||
410 | |||
411 | dev_dbg(&vdev->dev, "%s: entry\n", __func__); | ||
412 | |||
413 | if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { | ||
414 | dev_dbg(&vdev->dev, "%s - No capture device\n", __func__); | ||
415 | return -EINVAL; | ||
416 | } | ||
417 | |||
418 | fh->frame_count = 0; | ||
419 | return videobuf_streamon(&fh->vb_vidq); | ||
420 | } | ||
421 | |||
422 | static int timblogiw_streamoff(struct file *file, void *priv, | ||
423 | enum v4l2_buf_type type) | ||
424 | { | ||
425 | struct video_device *vdev = video_devdata(file); | ||
426 | struct timblogiw_fh *fh = priv; | ||
427 | |||
428 | dev_dbg(&vdev->dev, "%s entry\n", __func__); | ||
429 | |||
430 | if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
431 | return -EINVAL; | ||
432 | |||
433 | return videobuf_streamoff(&fh->vb_vidq); | ||
434 | } | ||
435 | |||
436 | static int timblogiw_querystd(struct file *file, void *priv, v4l2_std_id *std) | ||
437 | { | ||
438 | struct video_device *vdev = video_devdata(file); | ||
439 | struct timblogiw *lw = video_get_drvdata(vdev); | ||
440 | struct timblogiw_fh *fh = priv; | ||
441 | |||
442 | dev_dbg(&vdev->dev, "%s entry\n", __func__); | ||
443 | |||
444 | if (TIMBLOGIW_HAS_DECODER(lw)) | ||
445 | return v4l2_subdev_call(lw->sd_enc, video, querystd, std); | ||
446 | else { | ||
447 | *std = fh->cur_norm->std; | ||
448 | return 0; | ||
449 | } | ||
450 | } | ||
451 | |||
452 | static int timblogiw_enum_framesizes(struct file *file, void *priv, | ||
453 | struct v4l2_frmsizeenum *fsize) | ||
454 | { | ||
455 | struct video_device *vdev = video_devdata(file); | ||
456 | struct timblogiw_fh *fh = priv; | ||
457 | |||
458 | dev_dbg(&vdev->dev, "%s - index: %d, format: %d\n", __func__, | ||
459 | fsize->index, fsize->pixel_format); | ||
460 | |||
461 | if ((fsize->index != 0) || | ||
462 | (fsize->pixel_format != V4L2_PIX_FMT_UYVY)) | ||
463 | return -EINVAL; | ||
464 | |||
465 | fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; | ||
466 | fsize->discrete.width = fh->cur_norm->width; | ||
467 | fsize->discrete.height = fh->cur_norm->height; | ||
468 | |||
469 | return 0; | ||
470 | } | ||
471 | |||
472 | /* Video buffer functions */ | ||
473 | |||
474 | static int buffer_setup(struct videobuf_queue *vq, unsigned int *count, | ||
475 | unsigned int *size) | ||
476 | { | ||
477 | struct timblogiw_fh *fh = vq->priv_data; | ||
478 | |||
479 | *size = timblogiw_frame_size(fh->cur_norm); | ||
480 | |||
481 | if (!*count) | ||
482 | *count = 32; | ||
483 | |||
484 | while (*size * *count > TIMBLOGIW_MAX_VIDEO_MEM * 1024 * 1024) | ||
485 | (*count)--; | ||
486 | |||
487 | return 0; | ||
488 | } | ||
489 | |||
490 | static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, | ||
491 | enum v4l2_field field) | ||
492 | { | ||
493 | struct timblogiw_fh *fh = vq->priv_data; | ||
494 | struct timblogiw_buffer *buf = container_of(vb, struct timblogiw_buffer, | ||
495 | vb); | ||
496 | unsigned int data_size = timblogiw_frame_size(fh->cur_norm); | ||
497 | int err = 0; | ||
498 | |||
499 | if (vb->baddr && vb->bsize < data_size) | ||
500 | /* User provided buffer, but it is too small */ | ||
501 | return -ENOMEM; | ||
502 | |||
503 | vb->size = data_size; | ||
504 | vb->width = fh->cur_norm->width; | ||
505 | vb->height = fh->cur_norm->height; | ||
506 | vb->field = field; | ||
507 | |||
508 | if (vb->state == VIDEOBUF_NEEDS_INIT) { | ||
509 | int i; | ||
510 | unsigned int size; | ||
511 | unsigned int bytes_per_desc = TIMBLOGIW_LINES_PER_DESC * | ||
512 | timblogiw_bytes_per_line(fh->cur_norm); | ||
513 | dma_addr_t addr; | ||
514 | |||
515 | sg_init_table(buf->sg, ARRAY_SIZE(buf->sg)); | ||
516 | |||
517 | err = videobuf_iolock(vq, vb, NULL); | ||
518 | if (err) | ||
519 | goto err; | ||
520 | |||
521 | addr = videobuf_to_dma_contig(vb); | ||
522 | for (i = 0, size = 0; size < data_size; i++) { | ||
523 | sg_dma_address(buf->sg + i) = addr + size; | ||
524 | size += bytes_per_desc; | ||
525 | sg_dma_len(buf->sg + i) = (size > data_size) ? | ||
526 | (bytes_per_desc - (size - data_size)) : | ||
527 | bytes_per_desc; | ||
528 | } | ||
529 | |||
530 | vb->state = VIDEOBUF_PREPARED; | ||
531 | buf->cookie = -1; | ||
532 | buf->fh = fh; | ||
533 | } | ||
534 | |||
535 | return 0; | ||
536 | |||
537 | err: | ||
538 | videobuf_dma_contig_free(vq, vb); | ||
539 | vb->state = VIDEOBUF_NEEDS_INIT; | ||
540 | return err; | ||
541 | } | ||
542 | |||
543 | static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) | ||
544 | { | ||
545 | struct timblogiw_fh *fh = vq->priv_data; | ||
546 | struct timblogiw_buffer *buf = container_of(vb, struct timblogiw_buffer, | ||
547 | vb); | ||
548 | struct dma_async_tx_descriptor *desc; | ||
549 | int sg_elems; | ||
550 | int bytes_per_desc = TIMBLOGIW_LINES_PER_DESC * | ||
551 | timblogiw_bytes_per_line(fh->cur_norm); | ||
552 | |||
553 | sg_elems = timblogiw_frame_size(fh->cur_norm) / bytes_per_desc; | ||
554 | sg_elems += | ||
555 | (timblogiw_frame_size(fh->cur_norm) % bytes_per_desc) ? 1 : 0; | ||
556 | |||
557 | if (list_empty(&fh->capture)) | ||
558 | vb->state = VIDEOBUF_ACTIVE; | ||
559 | else | ||
560 | vb->state = VIDEOBUF_QUEUED; | ||
561 | |||
562 | list_add_tail(&vb->queue, &fh->capture); | ||
563 | |||
564 | spin_unlock_irq(&fh->queue_lock); | ||
565 | |||
566 | desc = dmaengine_prep_slave_sg(fh->chan, | ||
567 | buf->sg, sg_elems, DMA_DEV_TO_MEM, | ||
568 | DMA_PREP_INTERRUPT); | ||
569 | if (!desc) { | ||
570 | spin_lock_irq(&fh->queue_lock); | ||
571 | list_del_init(&vb->queue); | ||
572 | vb->state = VIDEOBUF_PREPARED; | ||
573 | return; | ||
574 | } | ||
575 | |||
576 | desc->callback_param = buf; | ||
577 | desc->callback = timblogiw_dma_cb; | ||
578 | |||
579 | buf->cookie = desc->tx_submit(desc); | ||
580 | |||
581 | spin_lock_irq(&fh->queue_lock); | ||
582 | } | ||
583 | |||
584 | static void buffer_release(struct videobuf_queue *vq, | ||
585 | struct videobuf_buffer *vb) | ||
586 | { | ||
587 | struct timblogiw_fh *fh = vq->priv_data; | ||
588 | struct timblogiw_buffer *buf = container_of(vb, struct timblogiw_buffer, | ||
589 | vb); | ||
590 | |||
591 | videobuf_waiton(vq, vb, 0, 0); | ||
592 | if (buf->cookie >= 0) | ||
593 | dma_sync_wait(fh->chan, buf->cookie); | ||
594 | |||
595 | videobuf_dma_contig_free(vq, vb); | ||
596 | vb->state = VIDEOBUF_NEEDS_INIT; | ||
597 | } | ||
598 | |||
599 | static struct videobuf_queue_ops timblogiw_video_qops = { | ||
600 | .buf_setup = buffer_setup, | ||
601 | .buf_prepare = buffer_prepare, | ||
602 | .buf_queue = buffer_queue, | ||
603 | .buf_release = buffer_release, | ||
604 | }; | ||
605 | |||
606 | /* Device Operations functions */ | ||
607 | |||
608 | static int timblogiw_open(struct file *file) | ||
609 | { | ||
610 | struct video_device *vdev = video_devdata(file); | ||
611 | struct timblogiw *lw = video_get_drvdata(vdev); | ||
612 | struct timblogiw_fh *fh; | ||
613 | v4l2_std_id std; | ||
614 | dma_cap_mask_t mask; | ||
615 | int err = 0; | ||
616 | |||
617 | dev_dbg(&vdev->dev, "%s: entry\n", __func__); | ||
618 | |||
619 | mutex_lock(&lw->lock); | ||
620 | if (lw->opened) { | ||
621 | err = -EBUSY; | ||
622 | goto out; | ||
623 | } | ||
624 | |||
625 | if (TIMBLOGIW_HAS_DECODER(lw) && !lw->sd_enc) { | ||
626 | struct i2c_adapter *adapt; | ||
627 | |||
628 | /* find the video decoder */ | ||
629 | adapt = i2c_get_adapter(lw->pdata.i2c_adapter); | ||
630 | if (!adapt) { | ||
631 | dev_err(&vdev->dev, "No I2C bus #%d\n", | ||
632 | lw->pdata.i2c_adapter); | ||
633 | err = -ENODEV; | ||
634 | goto out; | ||
635 | } | ||
636 | |||
637 | /* now find the encoder */ | ||
638 | lw->sd_enc = v4l2_i2c_new_subdev_board(&lw->v4l2_dev, adapt, | ||
639 | lw->pdata.encoder.info, NULL); | ||
640 | |||
641 | i2c_put_adapter(adapt); | ||
642 | |||
643 | if (!lw->sd_enc) { | ||
644 | dev_err(&vdev->dev, "Failed to get encoder: %s\n", | ||
645 | lw->pdata.encoder.module_name); | ||
646 | err = -ENODEV; | ||
647 | goto out; | ||
648 | } | ||
649 | } | ||
650 | |||
651 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | ||
652 | if (!fh) { | ||
653 | err = -ENOMEM; | ||
654 | goto out; | ||
655 | } | ||
656 | |||
657 | fh->cur_norm = timblogiw_tvnorms; | ||
658 | timblogiw_querystd(file, fh, &std); | ||
659 | fh->cur_norm = timblogiw_get_norm(std); | ||
660 | |||
661 | INIT_LIST_HEAD(&fh->capture); | ||
662 | spin_lock_init(&fh->queue_lock); | ||
663 | |||
664 | dma_cap_zero(mask); | ||
665 | dma_cap_set(DMA_SLAVE, mask); | ||
666 | dma_cap_set(DMA_PRIVATE, mask); | ||
667 | |||
668 | /* find the DMA channel */ | ||
669 | fh->chan = dma_request_channel(mask, timblogiw_dma_filter_fn, | ||
670 | (void *)(uintptr_t)lw->pdata.dma_channel); | ||
671 | if (!fh->chan) { | ||
672 | dev_err(&vdev->dev, "Failed to get DMA channel\n"); | ||
673 | kfree(fh); | ||
674 | err = -ENODEV; | ||
675 | goto out; | ||
676 | } | ||
677 | |||
678 | file->private_data = fh; | ||
679 | videobuf_queue_dma_contig_init(&fh->vb_vidq, | ||
680 | &timblogiw_video_qops, lw->dev, &fh->queue_lock, | ||
681 | V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, | ||
682 | sizeof(struct timblogiw_buffer), fh, NULL); | ||
683 | |||
684 | lw->opened = true; | ||
685 | out: | ||
686 | mutex_unlock(&lw->lock); | ||
687 | |||
688 | return err; | ||
689 | } | ||
690 | |||
691 | static int timblogiw_close(struct file *file) | ||
692 | { | ||
693 | struct video_device *vdev = video_devdata(file); | ||
694 | struct timblogiw *lw = video_get_drvdata(vdev); | ||
695 | struct timblogiw_fh *fh = file->private_data; | ||
696 | |||
697 | dev_dbg(&vdev->dev, "%s: Entry\n", __func__); | ||
698 | |||
699 | videobuf_stop(&fh->vb_vidq); | ||
700 | videobuf_mmap_free(&fh->vb_vidq); | ||
701 | |||
702 | dma_release_channel(fh->chan); | ||
703 | |||
704 | kfree(fh); | ||
705 | |||
706 | mutex_lock(&lw->lock); | ||
707 | lw->opened = false; | ||
708 | mutex_unlock(&lw->lock); | ||
709 | return 0; | ||
710 | } | ||
711 | |||
712 | static ssize_t timblogiw_read(struct file *file, char __user *data, | ||
713 | size_t count, loff_t *ppos) | ||
714 | { | ||
715 | struct video_device *vdev = video_devdata(file); | ||
716 | struct timblogiw_fh *fh = file->private_data; | ||
717 | |||
718 | dev_dbg(&vdev->dev, "%s: entry\n", __func__); | ||
719 | |||
720 | return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0, | ||
721 | file->f_flags & O_NONBLOCK); | ||
722 | } | ||
723 | |||
724 | static unsigned int timblogiw_poll(struct file *file, | ||
725 | struct poll_table_struct *wait) | ||
726 | { | ||
727 | struct video_device *vdev = video_devdata(file); | ||
728 | struct timblogiw_fh *fh = file->private_data; | ||
729 | |||
730 | dev_dbg(&vdev->dev, "%s: entry\n", __func__); | ||
731 | |||
732 | return videobuf_poll_stream(file, &fh->vb_vidq, wait); | ||
733 | } | ||
734 | |||
735 | static int timblogiw_mmap(struct file *file, struct vm_area_struct *vma) | ||
736 | { | ||
737 | struct video_device *vdev = video_devdata(file); | ||
738 | struct timblogiw_fh *fh = file->private_data; | ||
739 | |||
740 | dev_dbg(&vdev->dev, "%s: entry\n", __func__); | ||
741 | |||
742 | return videobuf_mmap_mapper(&fh->vb_vidq, vma); | ||
743 | } | ||
744 | |||
745 | /* Platform device functions */ | ||
746 | |||
747 | static struct v4l2_ioctl_ops timblogiw_ioctl_ops = { | ||
748 | .vidioc_querycap = timblogiw_querycap, | ||
749 | .vidioc_enum_fmt_vid_cap = timblogiw_enum_fmt, | ||
750 | .vidioc_g_fmt_vid_cap = timblogiw_g_fmt, | ||
751 | .vidioc_try_fmt_vid_cap = timblogiw_try_fmt, | ||
752 | .vidioc_s_fmt_vid_cap = timblogiw_s_fmt, | ||
753 | .vidioc_g_parm = timblogiw_g_parm, | ||
754 | .vidioc_reqbufs = timblogiw_reqbufs, | ||
755 | .vidioc_querybuf = timblogiw_querybuf, | ||
756 | .vidioc_qbuf = timblogiw_qbuf, | ||
757 | .vidioc_dqbuf = timblogiw_dqbuf, | ||
758 | .vidioc_g_std = timblogiw_g_std, | ||
759 | .vidioc_s_std = timblogiw_s_std, | ||
760 | .vidioc_enum_input = timblogiw_enuminput, | ||
761 | .vidioc_g_input = timblogiw_g_input, | ||
762 | .vidioc_s_input = timblogiw_s_input, | ||
763 | .vidioc_streamon = timblogiw_streamon, | ||
764 | .vidioc_streamoff = timblogiw_streamoff, | ||
765 | .vidioc_querystd = timblogiw_querystd, | ||
766 | .vidioc_enum_framesizes = timblogiw_enum_framesizes, | ||
767 | }; | ||
768 | |||
769 | static struct v4l2_file_operations timblogiw_fops = { | ||
770 | .owner = THIS_MODULE, | ||
771 | .open = timblogiw_open, | ||
772 | .release = timblogiw_close, | ||
773 | .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ | ||
774 | .mmap = timblogiw_mmap, | ||
775 | .read = timblogiw_read, | ||
776 | .poll = timblogiw_poll, | ||
777 | }; | ||
778 | |||
779 | static struct video_device timblogiw_template = { | ||
780 | .name = TIMBLOGIWIN_NAME, | ||
781 | .fops = &timblogiw_fops, | ||
782 | .ioctl_ops = &timblogiw_ioctl_ops, | ||
783 | .release = video_device_release_empty, | ||
784 | .minor = -1, | ||
785 | .tvnorms = V4L2_STD_PAL | V4L2_STD_NTSC | ||
786 | }; | ||
787 | |||
788 | static int timblogiw_probe(struct platform_device *pdev) | ||
789 | { | ||
790 | int err; | ||
791 | struct timblogiw *lw = NULL; | ||
792 | struct timb_video_platform_data *pdata = pdev->dev.platform_data; | ||
793 | |||
794 | if (!pdata) { | ||
795 | dev_err(&pdev->dev, "No platform data\n"); | ||
796 | err = -EINVAL; | ||
797 | goto err; | ||
798 | } | ||
799 | |||
800 | if (!pdata->encoder.module_name) | ||
801 | dev_info(&pdev->dev, "Running without decoder\n"); | ||
802 | |||
803 | lw = devm_kzalloc(&pdev->dev, sizeof(*lw), GFP_KERNEL); | ||
804 | if (!lw) { | ||
805 | err = -ENOMEM; | ||
806 | goto err; | ||
807 | } | ||
808 | |||
809 | if (pdev->dev.parent) | ||
810 | lw->dev = pdev->dev.parent; | ||
811 | else | ||
812 | lw->dev = &pdev->dev; | ||
813 | |||
814 | memcpy(&lw->pdata, pdata, sizeof(lw->pdata)); | ||
815 | |||
816 | mutex_init(&lw->lock); | ||
817 | |||
818 | lw->video_dev = timblogiw_template; | ||
819 | |||
820 | strlcpy(lw->v4l2_dev.name, DRIVER_NAME, sizeof(lw->v4l2_dev.name)); | ||
821 | err = v4l2_device_register(NULL, &lw->v4l2_dev); | ||
822 | if (err) | ||
823 | goto err; | ||
824 | |||
825 | lw->video_dev.v4l2_dev = &lw->v4l2_dev; | ||
826 | |||
827 | platform_set_drvdata(pdev, lw); | ||
828 | video_set_drvdata(&lw->video_dev, lw); | ||
829 | |||
830 | err = video_register_device(&lw->video_dev, VFL_TYPE_GRABBER, 0); | ||
831 | if (err) { | ||
832 | dev_err(&pdev->dev, "Error reg video: %d\n", err); | ||
833 | goto err_request; | ||
834 | } | ||
835 | |||
836 | return 0; | ||
837 | |||
838 | err_request: | ||
839 | v4l2_device_unregister(&lw->v4l2_dev); | ||
840 | err: | ||
841 | dev_err(&pdev->dev, "Failed to register: %d\n", err); | ||
842 | |||
843 | return err; | ||
844 | } | ||
845 | |||
846 | static int timblogiw_remove(struct platform_device *pdev) | ||
847 | { | ||
848 | struct timblogiw *lw = platform_get_drvdata(pdev); | ||
849 | |||
850 | video_unregister_device(&lw->video_dev); | ||
851 | |||
852 | v4l2_device_unregister(&lw->v4l2_dev); | ||
853 | |||
854 | return 0; | ||
855 | } | ||
856 | |||
857 | static struct platform_driver timblogiw_platform_driver = { | ||
858 | .driver = { | ||
859 | .name = DRIVER_NAME, | ||
860 | }, | ||
861 | .probe = timblogiw_probe, | ||
862 | .remove = timblogiw_remove, | ||
863 | }; | ||
864 | |||
865 | module_platform_driver(timblogiw_platform_driver); | ||
866 | |||
867 | MODULE_DESCRIPTION(TIMBLOGIWIN_NAME); | ||
868 | MODULE_AUTHOR("Pelagicore AB <info@pelagicore.com>"); | ||
869 | MODULE_LICENSE("GPL v2"); | ||
870 | MODULE_ALIAS("platform:"DRIVER_NAME); | ||
diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h index c201060e0c6d..f8e1992d6423 100644 --- a/include/linux/of_reserved_mem.h +++ b/include/linux/of_reserved_mem.h | |||
@@ -1,7 +1,8 @@ | |||
1 | #ifndef __OF_RESERVED_MEM_H | 1 | #ifndef __OF_RESERVED_MEM_H |
2 | #define __OF_RESERVED_MEM_H | 2 | #define __OF_RESERVED_MEM_H |
3 | 3 | ||
4 | struct device; | 4 | #include <linux/device.h> |
5 | |||
5 | struct of_phandle_args; | 6 | struct of_phandle_args; |
6 | struct reserved_mem_ops; | 7 | struct reserved_mem_ops; |
7 | 8 | ||
@@ -28,7 +29,9 @@ typedef int (*reservedmem_of_init_fn)(struct reserved_mem *rmem); | |||
28 | _OF_DECLARE(reservedmem, name, compat, init, reservedmem_of_init_fn) | 29 | _OF_DECLARE(reservedmem, name, compat, init, reservedmem_of_init_fn) |
29 | 30 | ||
30 | #ifdef CONFIG_OF_RESERVED_MEM | 31 | #ifdef CONFIG_OF_RESERVED_MEM |
31 | int of_reserved_mem_device_init(struct device *dev); | 32 | |
33 | int of_reserved_mem_device_init_by_idx(struct device *dev, | ||
34 | struct device_node *np, int idx); | ||
32 | void of_reserved_mem_device_release(struct device *dev); | 35 | void of_reserved_mem_device_release(struct device *dev); |
33 | 36 | ||
34 | int early_init_dt_alloc_reserved_memory_arch(phys_addr_t size, | 37 | int early_init_dt_alloc_reserved_memory_arch(phys_addr_t size, |
@@ -42,7 +45,8 @@ void fdt_init_reserved_mem(void); | |||
42 | void fdt_reserved_mem_save_node(unsigned long node, const char *uname, | 45 | void fdt_reserved_mem_save_node(unsigned long node, const char *uname, |
43 | phys_addr_t base, phys_addr_t size); | 46 | phys_addr_t base, phys_addr_t size); |
44 | #else | 47 | #else |
45 | static inline int of_reserved_mem_device_init(struct device *dev) | 48 | static inline int of_reserved_mem_device_init_by_idx(struct device *dev, |
49 | struct device_node *np, int idx) | ||
46 | { | 50 | { |
47 | return -ENOSYS; | 51 | return -ENOSYS; |
48 | } | 52 | } |
@@ -53,4 +57,19 @@ static inline void fdt_reserved_mem_save_node(unsigned long node, | |||
53 | const char *uname, phys_addr_t base, phys_addr_t size) { } | 57 | const char *uname, phys_addr_t base, phys_addr_t size) { } |
54 | #endif | 58 | #endif |
55 | 59 | ||
60 | /** | ||
61 | * of_reserved_mem_device_init() - assign reserved memory region to given device | ||
62 | * @dev: Pointer to the device to configure | ||
63 | * | ||
64 | * This function assigns respective DMA-mapping operations based on the first | ||
65 | * reserved memory region specified by 'memory-region' property in device tree | ||
66 | * node of the given device. | ||
67 | * | ||
68 | * Returns error code or zero on success. | ||
69 | */ | ||
70 | static inline int of_reserved_mem_device_init(struct device *dev) | ||
71 | { | ||
72 | return of_reserved_mem_device_init_by_idx(dev, dev->of_node, 0); | ||
73 | } | ||
74 | |||
56 | #endif /* __OF_RESERVED_MEM_H */ | 75 | #endif /* __OF_RESERVED_MEM_H */ |
diff --git a/include/media/media-device.h b/include/media/media-device.h index a9b33c47310d..f743ae2210ee 100644 --- a/include/media/media-device.h +++ b/include/media/media-device.h | |||
@@ -347,7 +347,7 @@ struct media_entity_notify { | |||
347 | struct media_device { | 347 | struct media_device { |
348 | /* dev->driver_data points to this struct. */ | 348 | /* dev->driver_data points to this struct. */ |
349 | struct device *dev; | 349 | struct device *dev; |
350 | struct media_devnode devnode; | 350 | struct media_devnode *devnode; |
351 | 351 | ||
352 | char model[32]; | 352 | char model[32]; |
353 | char driver_name[32]; | 353 | char driver_name[32]; |
@@ -393,9 +393,6 @@ struct usb_device; | |||
393 | #define MEDIA_DEV_NOTIFY_PRE_LINK_CH 0 | 393 | #define MEDIA_DEV_NOTIFY_PRE_LINK_CH 0 |
394 | #define MEDIA_DEV_NOTIFY_POST_LINK_CH 1 | 394 | #define MEDIA_DEV_NOTIFY_POST_LINK_CH 1 |
395 | 395 | ||
396 | /* media_devnode to media_device */ | ||
397 | #define to_media_device(node) container_of(node, struct media_device, devnode) | ||
398 | |||
399 | /** | 396 | /** |
400 | * media_entity_enum_init - Initialise an entity enumeration | 397 | * media_entity_enum_init - Initialise an entity enumeration |
401 | * | 398 | * |
diff --git a/include/media/media-devnode.h b/include/media/media-devnode.h index fe42f08e72bd..37d494805944 100644 --- a/include/media/media-devnode.h +++ b/include/media/media-devnode.h | |||
@@ -33,6 +33,8 @@ | |||
33 | #include <linux/device.h> | 33 | #include <linux/device.h> |
34 | #include <linux/cdev.h> | 34 | #include <linux/cdev.h> |
35 | 35 | ||
36 | struct media_device; | ||
37 | |||
36 | /* | 38 | /* |
37 | * Flag to mark the media_devnode struct as registered. Drivers must not touch | 39 | * Flag to mark the media_devnode struct as registered. Drivers must not touch |
38 | * this flag directly, it will be set and cleared by media_devnode_register and | 40 | * this flag directly, it will be set and cleared by media_devnode_register and |
@@ -67,8 +69,9 @@ struct media_file_operations { | |||
67 | 69 | ||
68 | /** | 70 | /** |
69 | * struct media_devnode - Media device node | 71 | * struct media_devnode - Media device node |
72 | * @media_dev: pointer to struct &media_device | ||
70 | * @fops: pointer to struct &media_file_operations with media device ops | 73 | * @fops: pointer to struct &media_file_operations with media device ops |
71 | * @dev: struct device pointer for the media controller device | 74 | * @dev: pointer to struct &device containing the media controller device |
72 | * @cdev: struct cdev pointer character device | 75 | * @cdev: struct cdev pointer character device |
73 | * @parent: parent device | 76 | * @parent: parent device |
74 | * @minor: device node minor number | 77 | * @minor: device node minor number |
@@ -81,6 +84,8 @@ struct media_file_operations { | |||
81 | * before registering the node. | 84 | * before registering the node. |
82 | */ | 85 | */ |
83 | struct media_devnode { | 86 | struct media_devnode { |
87 | struct media_device *media_dev; | ||
88 | |||
84 | /* device ops */ | 89 | /* device ops */ |
85 | const struct media_file_operations *fops; | 90 | const struct media_file_operations *fops; |
86 | 91 | ||
@@ -94,7 +99,7 @@ struct media_devnode { | |||
94 | unsigned long flags; /* Use bitops to access flags */ | 99 | unsigned long flags; /* Use bitops to access flags */ |
95 | 100 | ||
96 | /* callbacks */ | 101 | /* callbacks */ |
97 | void (*release)(struct media_devnode *mdev); | 102 | void (*release)(struct media_devnode *devnode); |
98 | }; | 103 | }; |
99 | 104 | ||
100 | /* dev to media_devnode */ | 105 | /* dev to media_devnode */ |
@@ -103,7 +108,8 @@ struct media_devnode { | |||
103 | /** | 108 | /** |
104 | * media_devnode_register - register a media device node | 109 | * media_devnode_register - register a media device node |
105 | * | 110 | * |
106 | * @mdev: media device node structure we want to register | 111 | * @mdev: struct media_device we want to register a device node |
112 | * @devnode: media device node structure we want to register | ||
107 | * @owner: should be filled with %THIS_MODULE | 113 | * @owner: should be filled with %THIS_MODULE |
108 | * | 114 | * |
109 | * The registration code assigns minor numbers and registers the new device node | 115 | * The registration code assigns minor numbers and registers the new device node |
@@ -116,20 +122,33 @@ struct media_devnode { | |||
116 | * the media_devnode structure is *not* called, so the caller is responsible for | 122 | * the media_devnode structure is *not* called, so the caller is responsible for |
117 | * freeing any data. | 123 | * freeing any data. |
118 | */ | 124 | */ |
119 | int __must_check media_devnode_register(struct media_devnode *mdev, | 125 | int __must_check media_devnode_register(struct media_device *mdev, |
126 | struct media_devnode *devnode, | ||
120 | struct module *owner); | 127 | struct module *owner); |
121 | 128 | ||
122 | /** | 129 | /** |
130 | * media_devnode_unregister_prepare - clear the media device node register bit | ||
131 | * @devnode: the device node to prepare for unregister | ||
132 | * | ||
133 | * This clears the passed device register bit. Future open calls will be met | ||
134 | * with errors. Should be called before media_devnode_unregister() to avoid | ||
135 | * races with unregister and device file open calls. | ||
136 | * | ||
137 | * This function can safely be called if the device node has never been | ||
138 | * registered or has already been unregistered. | ||
139 | */ | ||
140 | void media_devnode_unregister_prepare(struct media_devnode *devnode); | ||
141 | |||
142 | /** | ||
123 | * media_devnode_unregister - unregister a media device node | 143 | * media_devnode_unregister - unregister a media device node |
124 | * @mdev: the device node to unregister | 144 | * @devnode: the device node to unregister |
125 | * | 145 | * |
126 | * This unregisters the passed device. Future open calls will be met with | 146 | * This unregisters the passed device. Future open calls will be met with |
127 | * errors. | 147 | * errors. |
128 | * | 148 | * |
129 | * This function can safely be called if the device node has never been | 149 | * Should be called after media_devnode_unregister_prepare() |
130 | * registered or has already been unregistered. | ||
131 | */ | 150 | */ |
132 | void media_devnode_unregister(struct media_devnode *mdev); | 151 | void media_devnode_unregister(struct media_devnode *devnode); |
133 | 152 | ||
134 | /** | 153 | /** |
135 | * media_devnode_data - returns a pointer to the &media_devnode | 154 | * media_devnode_data - returns a pointer to the &media_devnode |
@@ -145,11 +164,16 @@ static inline struct media_devnode *media_devnode_data(struct file *filp) | |||
145 | * media_devnode_is_registered - returns true if &media_devnode is registered; | 164 | * media_devnode_is_registered - returns true if &media_devnode is registered; |
146 | * false otherwise. | 165 | * false otherwise. |
147 | * | 166 | * |
148 | * @mdev: pointer to struct &media_devnode. | 167 | * @devnode: pointer to struct &media_devnode. |
168 | * | ||
169 | * Note: If mdev is NULL, it also returns false. | ||
149 | */ | 170 | */ |
150 | static inline int media_devnode_is_registered(struct media_devnode *mdev) | 171 | static inline int media_devnode_is_registered(struct media_devnode *devnode) |
151 | { | 172 | { |
152 | return test_bit(MEDIA_FLAG_REGISTERED, &mdev->flags); | 173 | if (!devnode) |
174 | return false; | ||
175 | |||
176 | return test_bit(MEDIA_FLAG_REGISTERED, &devnode->flags); | ||
153 | } | 177 | } |
154 | 178 | ||
155 | #endif /* _MEDIA_DEVNODE_H */ | 179 | #endif /* _MEDIA_DEVNODE_H */ |
diff --git a/include/media/rcar-fcp.h b/include/media/rcar-fcp.h new file mode 100644 index 000000000000..4c7fc77eaf29 --- /dev/null +++ b/include/media/rcar-fcp.h | |||
@@ -0,0 +1,37 @@ | |||
1 | /* | ||
2 | * rcar-fcp.h -- R-Car Frame Compression Processor Driver | ||
3 | * | ||
4 | * Copyright (C) 2016 Renesas Electronics Corporation | ||
5 | * | ||
6 | * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | */ | ||
13 | #ifndef __MEDIA_RCAR_FCP_H__ | ||
14 | #define __MEDIA_RCAR_FCP_H__ | ||
15 | |||
16 | struct device_node; | ||
17 | struct rcar_fcp_device; | ||
18 | |||
19 | #if IS_ENABLED(CONFIG_VIDEO_RENESAS_FCP) | ||
20 | struct rcar_fcp_device *rcar_fcp_get(const struct device_node *np); | ||
21 | void rcar_fcp_put(struct rcar_fcp_device *fcp); | ||
22 | int rcar_fcp_enable(struct rcar_fcp_device *fcp); | ||
23 | void rcar_fcp_disable(struct rcar_fcp_device *fcp); | ||
24 | #else | ||
25 | static inline struct rcar_fcp_device *rcar_fcp_get(const struct device_node *np) | ||
26 | { | ||
27 | return ERR_PTR(-ENOENT); | ||
28 | } | ||
29 | static inline void rcar_fcp_put(struct rcar_fcp_device *fcp) { } | ||
30 | static inline int rcar_fcp_enable(struct rcar_fcp_device *fcp) | ||
31 | { | ||
32 | return -ENOSYS; | ||
33 | } | ||
34 | static inline void rcar_fcp_disable(struct rcar_fcp_device *fcp) { } | ||
35 | #endif | ||
36 | |||
37 | #endif /* __MEDIA_RCAR_FCP_H__ */ | ||
diff --git a/include/media/videobuf2-dma-contig.h b/include/media/videobuf2-dma-contig.h index 2087c9a68be3..f7dc8401817e 100644 --- a/include/media/videobuf2-dma-contig.h +++ b/include/media/videobuf2-dma-contig.h | |||
@@ -35,6 +35,8 @@ static inline void *vb2_dma_contig_init_ctx(struct device *dev) | |||
35 | } | 35 | } |
36 | 36 | ||
37 | void vb2_dma_contig_cleanup_ctx(void *alloc_ctx); | 37 | void vb2_dma_contig_cleanup_ctx(void *alloc_ctx); |
38 | int vb2_dma_contig_set_max_seg_size(struct device *dev, unsigned int size); | ||
39 | void vb2_dma_contig_clear_max_seg_size(struct device *dev); | ||
38 | 40 | ||
39 | extern const struct vb2_mem_ops vb2_dma_contig_memops; | 41 | extern const struct vb2_mem_ops vb2_dma_contig_memops; |
40 | 42 | ||
diff --git a/include/media/vsp1.h b/include/media/vsp1.h index 3e654a0455bd..9322d9775fb7 100644 --- a/include/media/vsp1.h +++ b/include/media/vsp1.h | |||
@@ -14,31 +14,28 @@ | |||
14 | #define __MEDIA_VSP1_H__ | 14 | #define __MEDIA_VSP1_H__ |
15 | 15 | ||
16 | #include <linux/types.h> | 16 | #include <linux/types.h> |
17 | #include <linux/videodev2.h> | ||
17 | 18 | ||
18 | struct device; | 19 | struct device; |
19 | struct v4l2_rect; | ||
20 | 20 | ||
21 | int vsp1_du_init(struct device *dev); | 21 | int vsp1_du_init(struct device *dev); |
22 | 22 | ||
23 | int vsp1_du_setup_lif(struct device *dev, unsigned int width, | 23 | int vsp1_du_setup_lif(struct device *dev, unsigned int width, |
24 | unsigned int height); | 24 | unsigned int height); |
25 | 25 | ||
26 | struct vsp1_du_atomic_config { | ||
27 | u32 pixelformat; | ||
28 | unsigned int pitch; | ||
29 | dma_addr_t mem[2]; | ||
30 | struct v4l2_rect src; | ||
31 | struct v4l2_rect dst; | ||
32 | unsigned int alpha; | ||
33 | unsigned int zpos; | ||
34 | }; | ||
35 | |||
26 | void vsp1_du_atomic_begin(struct device *dev); | 36 | void vsp1_du_atomic_begin(struct device *dev); |
27 | int vsp1_du_atomic_update_ext(struct device *dev, unsigned int rpf, | 37 | int vsp1_du_atomic_update(struct device *dev, unsigned int rpf, |
28 | u32 pixelformat, unsigned int pitch, | 38 | const struct vsp1_du_atomic_config *cfg); |
29 | dma_addr_t mem[2], const struct v4l2_rect *src, | ||
30 | const struct v4l2_rect *dst, unsigned int alpha, | ||
31 | unsigned int zpos); | ||
32 | void vsp1_du_atomic_flush(struct device *dev); | 39 | void vsp1_du_atomic_flush(struct device *dev); |
33 | 40 | ||
34 | static inline int vsp1_du_atomic_update(struct device *dev, | ||
35 | unsigned int rpf_index, u32 pixelformat, | ||
36 | unsigned int pitch, dma_addr_t mem[2], | ||
37 | const struct v4l2_rect *src, | ||
38 | const struct v4l2_rect *dst) | ||
39 | { | ||
40 | return vsp1_du_atomic_update_ext(dev, rpf_index, pixelformat, pitch, | ||
41 | mem, src, dst, 255, 0); | ||
42 | } | ||
43 | |||
44 | #endif /* __MEDIA_VSP1_H__ */ | 41 | #endif /* __MEDIA_VSP1_H__ */ |
diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h index df59edee25d1..7acf0f634f70 100644 --- a/include/uapi/linux/media.h +++ b/include/uapi/linux/media.h | |||
@@ -95,6 +95,16 @@ struct media_device_info { | |||
95 | #define MEDIA_ENT_F_AUDIO_MIXER (MEDIA_ENT_F_BASE + 0x03003) | 95 | #define MEDIA_ENT_F_AUDIO_MIXER (MEDIA_ENT_F_BASE + 0x03003) |
96 | 96 | ||
97 | /* | 97 | /* |
98 | * Processing entities | ||
99 | */ | ||
100 | #define MEDIA_ENT_F_PROC_VIDEO_COMPOSER (MEDIA_ENT_F_BASE + 0x4001) | ||
101 | #define MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER (MEDIA_ENT_F_BASE + 0x4002) | ||
102 | #define MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV (MEDIA_ENT_F_BASE + 0x4003) | ||
103 | #define MEDIA_ENT_F_PROC_VIDEO_LUT (MEDIA_ENT_F_BASE + 0x4004) | ||
104 | #define MEDIA_ENT_F_PROC_VIDEO_SCALER (MEDIA_ENT_F_BASE + 0x4005) | ||
105 | #define MEDIA_ENT_F_PROC_VIDEO_STATISTICS (MEDIA_ENT_F_BASE + 0x4006) | ||
106 | |||
107 | /* | ||
98 | * Connectors | 108 | * Connectors |
99 | */ | 109 | */ |
100 | /* It is a responsibility of the entity drivers to add connectors and links */ | 110 | /* It is a responsibility of the entity drivers to add connectors and links */ |
diff --git a/include/uapi/linux/vsp1.h b/include/uapi/linux/vsp1.h deleted file mode 100644 index 9a823696d816..000000000000 --- a/include/uapi/linux/vsp1.h +++ /dev/null | |||
@@ -1,34 +0,0 @@ | |||
1 | /* | ||
2 | * vsp1.h | ||
3 | * | ||
4 | * Renesas R-Car VSP1 - User-space API | ||
5 | * | ||
6 | * Copyright (C) 2013 Renesas Corporation | ||
7 | * | ||
8 | * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #ifndef __VSP1_USER_H__ | ||
16 | #define __VSP1_USER_H__ | ||
17 | |||
18 | #include <linux/types.h> | ||
19 | #include <linux/videodev2.h> | ||
20 | |||
21 | /* | ||
22 | * Private IOCTLs | ||
23 | * | ||
24 | * VIDIOC_VSP1_LUT_CONFIG - Configure the lookup table | ||
25 | */ | ||
26 | |||
27 | #define VIDIOC_VSP1_LUT_CONFIG \ | ||
28 | _IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct vsp1_lut_config) | ||
29 | |||
30 | struct vsp1_lut_config { | ||
31 | __u32 lut[256]; | ||
32 | }; | ||
33 | |||
34 | #endif /* __VSP1_USER_H__ */ | ||