]>
Commit | Line | Data |
---|---|---|
07b1747c VH |
1 | /* |
2 | * drivers/media/video/tvp514x.c | |
3 | * | |
4 | * TI TVP5146/47 decoder driver | |
5 | * | |
6 | * Copyright (C) 2008 Texas Instruments Inc | |
7 | * Author: Vaibhav Hiremath <hvaibhav@ti.com> | |
8 | * | |
9 | * Contributors: | |
10 | * Sivaraj R <sivaraj@ti.com> | |
11 | * Brijesh R Jadav <brijesh.j@ti.com> | |
12 | * Hardik Shah <hardik.shah@ti.com> | |
13 | * Manjunath Hadli <mrh@ti.com> | |
14 | * Karicheri Muralidharan <m-karicheri2@ti.com> | |
15 | * | |
16 | * This package is free software; you can redistribute it and/or modify | |
17 | * it under the terms of the GNU General Public License version 2 as | |
18 | * published by the Free Software Foundation. | |
19 | * | |
20 | * This program is distributed in the hope that it will be useful, | |
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
23 | * GNU General Public License for more details. | |
24 | * | |
25 | * You should have received a copy of the GNU General Public License | |
26 | * along with this program; if not, write to the Free Software | |
27 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
28 | * | |
29 | */ | |
30 | ||
31 | #include <linux/i2c.h> | |
5a0e3ad6 | 32 | #include <linux/slab.h> |
07b1747c VH |
33 | #include <linux/delay.h> |
34 | #include <linux/videodev2.h> | |
62ef80a1 MK |
35 | |
36 | #include <media/v4l2-device.h> | |
37 | #include <media/v4l2-common.h> | |
83811913 | 38 | #include <media/v4l2-mediabus.h> |
62ef80a1 | 39 | #include <media/v4l2-chip-ident.h> |
07b1747c VH |
40 | #include <media/tvp514x.h> |
41 | ||
42 | #include "tvp514x_regs.h" | |
43 | ||
44 | /* Module Name */ | |
45 | #define TVP514X_MODULE_NAME "tvp514x" | |
46 | ||
47 | /* Private macros for TVP */ | |
48 | #define I2C_RETRY_COUNT (5) | |
49 | #define LOCK_RETRY_COUNT (5) | |
50 | #define LOCK_RETRY_DELAY (200) | |
51 | ||
52 | /* Debug functions */ | |
53 | static int debug; | |
54 | module_param(debug, bool, 0644); | |
55 | MODULE_PARM_DESC(debug, "Debug level (0-1)"); | |
56 | ||
62ef80a1 MK |
57 | MODULE_AUTHOR("Texas Instruments"); |
58 | MODULE_DESCRIPTION("TVP514X linux decoder driver"); | |
59 | MODULE_LICENSE("GPL"); | |
07b1747c | 60 | |
c1c9d09c | 61 | /* enum tvp514x_std - enum for supported standards */ |
07b1747c VH |
62 | enum tvp514x_std { |
63 | STD_NTSC_MJ = 0, | |
64 | STD_PAL_BDGHIN, | |
65 | STD_INVALID | |
66 | }; | |
67 | ||
c1c9d09c | 68 | /** |
07b1747c VH |
69 | * struct tvp514x_std_info - Structure to store standard informations |
70 | * @width: Line width in pixels | |
71 | * @height:Number of active lines | |
72 | * @video_std: Value to write in REG_VIDEO_STD register | |
73 | * @standard: v4l2 standard structure information | |
74 | */ | |
75 | struct tvp514x_std_info { | |
76 | unsigned long width; | |
77 | unsigned long height; | |
78 | u8 video_std; | |
79 | struct v4l2_standard standard; | |
80 | }; | |
81 | ||
6722e0ef | 82 | static struct tvp514x_reg tvp514x_reg_list_default[0x40]; |
63b59cec VH |
83 | |
84 | static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable); | |
c1c9d09c | 85 | /** |
6722e0ef | 86 | * struct tvp514x_decoder - TVP5146/47 decoder object |
62ef80a1 | 87 | * @sd: Subdevice Slave handle |
6722e0ef | 88 | * @tvp514x_regs: copy of hw's regs with preset values. |
07b1747c | 89 | * @pdata: Board specific |
07b1747c | 90 | * @ver: Chip version |
62ef80a1 | 91 | * @streaming: TVP5146/47 decoder streaming - enabled or disabled. |
07b1747c VH |
92 | * @current_std: Current standard |
93 | * @num_stds: Number of standards | |
94 | * @std_list: Standards list | |
62ef80a1 MK |
95 | * @input: Input routing at chip level |
96 | * @output: Output routing at chip level | |
07b1747c VH |
97 | */ |
98 | struct tvp514x_decoder { | |
62ef80a1 | 99 | struct v4l2_subdev sd; |
6722e0ef | 100 | struct tvp514x_reg tvp514x_regs[ARRAY_SIZE(tvp514x_reg_list_default)]; |
07b1747c | 101 | const struct tvp514x_platform_data *pdata; |
07b1747c VH |
102 | |
103 | int ver; | |
62ef80a1 | 104 | int streaming; |
07b1747c | 105 | |
07b1747c VH |
106 | enum tvp514x_std current_std; |
107 | int num_stds; | |
a75ffc12 | 108 | const struct tvp514x_std_info *std_list; |
c1c9d09c | 109 | /* Input and Output Routing parameters */ |
62ef80a1 MK |
110 | u32 input; |
111 | u32 output; | |
07b1747c VH |
112 | }; |
113 | ||
114 | /* TVP514x default register values */ | |
6722e0ef | 115 | static struct tvp514x_reg tvp514x_reg_list_default[] = { |
c1c9d09c MK |
116 | /* Composite selected */ |
117 | {TOK_WRITE, REG_INPUT_SEL, 0x05}, | |
07b1747c | 118 | {TOK_WRITE, REG_AFE_GAIN_CTRL, 0x0F}, |
c1c9d09c MK |
119 | /* Auto mode */ |
120 | {TOK_WRITE, REG_VIDEO_STD, 0x00}, | |
07b1747c VH |
121 | {TOK_WRITE, REG_OPERATION_MODE, 0x00}, |
122 | {TOK_SKIP, REG_AUTOSWITCH_MASK, 0x3F}, | |
123 | {TOK_WRITE, REG_COLOR_KILLER, 0x10}, | |
124 | {TOK_WRITE, REG_LUMA_CONTROL1, 0x00}, | |
125 | {TOK_WRITE, REG_LUMA_CONTROL2, 0x00}, | |
126 | {TOK_WRITE, REG_LUMA_CONTROL3, 0x02}, | |
127 | {TOK_WRITE, REG_BRIGHTNESS, 0x80}, | |
128 | {TOK_WRITE, REG_CONTRAST, 0x80}, | |
129 | {TOK_WRITE, REG_SATURATION, 0x80}, | |
130 | {TOK_WRITE, REG_HUE, 0x00}, | |
131 | {TOK_WRITE, REG_CHROMA_CONTROL1, 0x00}, | |
132 | {TOK_WRITE, REG_CHROMA_CONTROL2, 0x0E}, | |
c1c9d09c MK |
133 | /* Reserved */ |
134 | {TOK_SKIP, 0x0F, 0x00}, | |
07b1747c VH |
135 | {TOK_WRITE, REG_COMP_PR_SATURATION, 0x80}, |
136 | {TOK_WRITE, REG_COMP_Y_CONTRAST, 0x80}, | |
137 | {TOK_WRITE, REG_COMP_PB_SATURATION, 0x80}, | |
c1c9d09c MK |
138 | /* Reserved */ |
139 | {TOK_SKIP, 0x13, 0x00}, | |
07b1747c | 140 | {TOK_WRITE, REG_COMP_Y_BRIGHTNESS, 0x80}, |
c1c9d09c MK |
141 | /* Reserved */ |
142 | {TOK_SKIP, 0x15, 0x00}, | |
143 | /* NTSC timing */ | |
144 | {TOK_SKIP, REG_AVID_START_PIXEL_LSB, 0x55}, | |
07b1747c VH |
145 | {TOK_SKIP, REG_AVID_START_PIXEL_MSB, 0x00}, |
146 | {TOK_SKIP, REG_AVID_STOP_PIXEL_LSB, 0x25}, | |
147 | {TOK_SKIP, REG_AVID_STOP_PIXEL_MSB, 0x03}, | |
c1c9d09c MK |
148 | /* NTSC timing */ |
149 | {TOK_SKIP, REG_HSYNC_START_PIXEL_LSB, 0x00}, | |
07b1747c VH |
150 | {TOK_SKIP, REG_HSYNC_START_PIXEL_MSB, 0x00}, |
151 | {TOK_SKIP, REG_HSYNC_STOP_PIXEL_LSB, 0x40}, | |
152 | {TOK_SKIP, REG_HSYNC_STOP_PIXEL_MSB, 0x00}, | |
c1c9d09c MK |
153 | /* NTSC timing */ |
154 | {TOK_SKIP, REG_VSYNC_START_LINE_LSB, 0x04}, | |
07b1747c VH |
155 | {TOK_SKIP, REG_VSYNC_START_LINE_MSB, 0x00}, |
156 | {TOK_SKIP, REG_VSYNC_STOP_LINE_LSB, 0x07}, | |
157 | {TOK_SKIP, REG_VSYNC_STOP_LINE_MSB, 0x00}, | |
c1c9d09c MK |
158 | /* NTSC timing */ |
159 | {TOK_SKIP, REG_VBLK_START_LINE_LSB, 0x01}, | |
07b1747c VH |
160 | {TOK_SKIP, REG_VBLK_START_LINE_MSB, 0x00}, |
161 | {TOK_SKIP, REG_VBLK_STOP_LINE_LSB, 0x15}, | |
162 | {TOK_SKIP, REG_VBLK_STOP_LINE_MSB, 0x00}, | |
c1c9d09c MK |
163 | /* Reserved */ |
164 | {TOK_SKIP, 0x26, 0x00}, | |
165 | /* Reserved */ | |
166 | {TOK_SKIP, 0x27, 0x00}, | |
07b1747c | 167 | {TOK_SKIP, REG_FAST_SWTICH_CONTROL, 0xCC}, |
c1c9d09c MK |
168 | /* Reserved */ |
169 | {TOK_SKIP, 0x29, 0x00}, | |
07b1747c | 170 | {TOK_SKIP, REG_FAST_SWTICH_SCART_DELAY, 0x00}, |
c1c9d09c MK |
171 | /* Reserved */ |
172 | {TOK_SKIP, 0x2B, 0x00}, | |
07b1747c VH |
173 | {TOK_SKIP, REG_SCART_DELAY, 0x00}, |
174 | {TOK_SKIP, REG_CTI_DELAY, 0x00}, | |
175 | {TOK_SKIP, REG_CTI_CONTROL, 0x00}, | |
c1c9d09c MK |
176 | /* Reserved */ |
177 | {TOK_SKIP, 0x2F, 0x00}, | |
178 | /* Reserved */ | |
179 | {TOK_SKIP, 0x30, 0x00}, | |
180 | /* Reserved */ | |
181 | {TOK_SKIP, 0x31, 0x00}, | |
182 | /* HS, VS active high */ | |
183 | {TOK_WRITE, REG_SYNC_CONTROL, 0x00}, | |
184 | /* 10-bit BT.656 */ | |
185 | {TOK_WRITE, REG_OUTPUT_FORMATTER1, 0x00}, | |
186 | /* Enable clk & data */ | |
187 | {TOK_WRITE, REG_OUTPUT_FORMATTER2, 0x11}, | |
188 | /* Enable AVID & FLD */ | |
189 | {TOK_WRITE, REG_OUTPUT_FORMATTER3, 0xEE}, | |
190 | /* Enable VS & HS */ | |
191 | {TOK_WRITE, REG_OUTPUT_FORMATTER4, 0xAF}, | |
07b1747c VH |
192 | {TOK_WRITE, REG_OUTPUT_FORMATTER5, 0xFF}, |
193 | {TOK_WRITE, REG_OUTPUT_FORMATTER6, 0xFF}, | |
c1c9d09c MK |
194 | /* Clear status */ |
195 | {TOK_WRITE, REG_CLEAR_LOST_LOCK, 0x01}, | |
07b1747c VH |
196 | {TOK_TERM, 0, 0}, |
197 | }; | |
198 | ||
c1c9d09c | 199 | /** |
07b1747c VH |
200 | * Supported standards - |
201 | * | |
202 | * Currently supports two standards only, need to add support for rest of the | |
203 | * modes, like SECAM, etc... | |
204 | */ | |
a75ffc12 | 205 | static const struct tvp514x_std_info tvp514x_std_list[] = { |
07b1747c VH |
206 | /* Standard: STD_NTSC_MJ */ |
207 | [STD_NTSC_MJ] = { | |
208 | .width = NTSC_NUM_ACTIVE_PIXELS, | |
209 | .height = NTSC_NUM_ACTIVE_LINES, | |
210 | .video_std = VIDEO_STD_NTSC_MJ_BIT, | |
211 | .standard = { | |
212 | .index = 0, | |
213 | .id = V4L2_STD_NTSC, | |
214 | .name = "NTSC", | |
215 | .frameperiod = {1001, 30000}, | |
216 | .framelines = 525 | |
217 | }, | |
218 | /* Standard: STD_PAL_BDGHIN */ | |
219 | }, | |
220 | [STD_PAL_BDGHIN] = { | |
221 | .width = PAL_NUM_ACTIVE_PIXELS, | |
222 | .height = PAL_NUM_ACTIVE_LINES, | |
223 | .video_std = VIDEO_STD_PAL_BDGHIN_BIT, | |
224 | .standard = { | |
225 | .index = 1, | |
226 | .id = V4L2_STD_PAL, | |
227 | .name = "PAL", | |
228 | .frameperiod = {1, 25}, | |
229 | .framelines = 625 | |
230 | }, | |
231 | }, | |
232 | /* Standard: need to add for additional standard */ | |
233 | }; | |
62ef80a1 MK |
234 | |
235 | ||
236 | static inline struct tvp514x_decoder *to_decoder(struct v4l2_subdev *sd) | |
237 | { | |
238 | return container_of(sd, struct tvp514x_decoder, sd); | |
239 | } | |
240 | ||
07b1747c | 241 | |
c1c9d09c MK |
242 | /** |
243 | * tvp514x_read_reg() - Read a value from a register in an TVP5146/47. | |
244 | * @sd: ptr to v4l2_subdev struct | |
245 | * @reg: TVP5146/47 register address | |
246 | * | |
07b1747c VH |
247 | * Returns value read if successful, or non-zero (-1) otherwise. |
248 | */ | |
62ef80a1 | 249 | static int tvp514x_read_reg(struct v4l2_subdev *sd, u8 reg) |
07b1747c | 250 | { |
62ef80a1 MK |
251 | int err, retry = 0; |
252 | struct i2c_client *client = v4l2_get_subdevdata(sd); | |
253 | ||
07b1747c VH |
254 | read_again: |
255 | ||
256 | err = i2c_smbus_read_byte_data(client, reg); | |
6f901a99 | 257 | if (err < 0) { |
07b1747c | 258 | if (retry <= I2C_RETRY_COUNT) { |
62ef80a1 | 259 | v4l2_warn(sd, "Read: retry ... %d\n", retry); |
07b1747c VH |
260 | retry++; |
261 | msleep_interruptible(10); | |
262 | goto read_again; | |
263 | } | |
264 | } | |
265 | ||
266 | return err; | |
267 | } | |
268 | ||
c1c9d09c MK |
269 | /** |
270 | * dump_reg() - dump the register content of TVP5146/47. | |
271 | * @sd: ptr to v4l2_subdev struct | |
272 | * @reg: TVP5146/47 register address | |
273 | */ | |
62ef80a1 MK |
274 | static void dump_reg(struct v4l2_subdev *sd, u8 reg) |
275 | { | |
276 | u32 val; | |
277 | ||
278 | val = tvp514x_read_reg(sd, reg); | |
279 | v4l2_info(sd, "Reg(0x%.2X): 0x%.2X\n", reg, val); | |
280 | } | |
281 | ||
c1c9d09c MK |
282 | /** |
283 | * tvp514x_write_reg() - Write a value to a register in TVP5146/47 | |
284 | * @sd: ptr to v4l2_subdev struct | |
285 | * @reg: TVP5146/47 register address | |
286 | * @val: value to be written to the register | |
287 | * | |
07b1747c VH |
288 | * Write a value to a register in an TVP5146/47 decoder device. |
289 | * Returns zero if successful, or non-zero otherwise. | |
290 | */ | |
62ef80a1 | 291 | static int tvp514x_write_reg(struct v4l2_subdev *sd, u8 reg, u8 val) |
07b1747c | 292 | { |
62ef80a1 MK |
293 | int err, retry = 0; |
294 | struct i2c_client *client = v4l2_get_subdevdata(sd); | |
295 | ||
07b1747c VH |
296 | write_again: |
297 | ||
298 | err = i2c_smbus_write_byte_data(client, reg, val); | |
299 | if (err) { | |
300 | if (retry <= I2C_RETRY_COUNT) { | |
62ef80a1 | 301 | v4l2_warn(sd, "Write: retry ... %d\n", retry); |
07b1747c VH |
302 | retry++; |
303 | msleep_interruptible(10); | |
304 | goto write_again; | |
305 | } | |
306 | } | |
307 | ||
308 | return err; | |
309 | } | |
310 | ||
c1c9d09c MK |
311 | /** |
312 | * tvp514x_write_regs() : Initializes a list of TVP5146/47 registers | |
313 | * @sd: ptr to v4l2_subdev struct | |
314 | * @reglist: list of TVP5146/47 registers and values | |
315 | * | |
316 | * Initializes a list of TVP5146/47 registers:- | |
07b1747c VH |
317 | * if token is TOK_TERM, then entire write operation terminates |
318 | * if token is TOK_DELAY, then a delay of 'val' msec is introduced | |
319 | * if token is TOK_SKIP, then the register write is skipped | |
320 | * if token is TOK_WRITE, then the register write is performed | |
07b1747c VH |
321 | * Returns zero if successful, or non-zero otherwise. |
322 | */ | |
62ef80a1 | 323 | static int tvp514x_write_regs(struct v4l2_subdev *sd, |
07b1747c VH |
324 | const struct tvp514x_reg reglist[]) |
325 | { | |
326 | int err; | |
327 | const struct tvp514x_reg *next = reglist; | |
328 | ||
329 | for (; next->token != TOK_TERM; next++) { | |
330 | if (next->token == TOK_DELAY) { | |
331 | msleep(next->val); | |
332 | continue; | |
333 | } | |
334 | ||
335 | if (next->token == TOK_SKIP) | |
336 | continue; | |
337 | ||
62ef80a1 | 338 | err = tvp514x_write_reg(sd, next->reg, (u8) next->val); |
07b1747c | 339 | if (err) { |
62ef80a1 | 340 | v4l2_err(sd, "Write failed. Err[%d]\n", err); |
07b1747c VH |
341 | return err; |
342 | } | |
343 | } | |
344 | return 0; | |
345 | } | |
346 | ||
c1c9d09c | 347 | /** |
2db4e78f | 348 | * tvp514x_query_current_std() : Query the current standard detected by TVP5146/47 |
c1c9d09c MK |
349 | * @sd: ptr to v4l2_subdev struct |
350 | * | |
2db4e78f | 351 | * Returns the current standard detected by TVP5146/47, STD_INVALID if there is no |
c1c9d09c | 352 | * standard detected. |
07b1747c | 353 | */ |
2db4e78f | 354 | static enum tvp514x_std tvp514x_query_current_std(struct v4l2_subdev *sd) |
07b1747c VH |
355 | { |
356 | u8 std, std_status; | |
357 | ||
62ef80a1 MK |
358 | std = tvp514x_read_reg(sd, REG_VIDEO_STD); |
359 | if ((std & VIDEO_STD_MASK) == VIDEO_STD_AUTO_SWITCH_BIT) | |
07b1747c | 360 | /* use the standard status register */ |
62ef80a1 MK |
361 | std_status = tvp514x_read_reg(sd, REG_VIDEO_STD_STATUS); |
362 | else | |
c1c9d09c MK |
363 | /* use the standard register itself */ |
364 | std_status = std; | |
07b1747c VH |
365 | |
366 | switch (std_status & VIDEO_STD_MASK) { | |
367 | case VIDEO_STD_NTSC_MJ_BIT: | |
368 | return STD_NTSC_MJ; | |
369 | ||
370 | case VIDEO_STD_PAL_BDGHIN_BIT: | |
371 | return STD_PAL_BDGHIN; | |
372 | ||
373 | default: | |
374 | return STD_INVALID; | |
375 | } | |
376 | ||
377 | return STD_INVALID; | |
378 | } | |
379 | ||
c1c9d09c | 380 | /* TVP5146/47 register dump function */ |
62ef80a1 | 381 | static void tvp514x_reg_dump(struct v4l2_subdev *sd) |
07b1747c | 382 | { |
62ef80a1 MK |
383 | dump_reg(sd, REG_INPUT_SEL); |
384 | dump_reg(sd, REG_AFE_GAIN_CTRL); | |
385 | dump_reg(sd, REG_VIDEO_STD); | |
386 | dump_reg(sd, REG_OPERATION_MODE); | |
387 | dump_reg(sd, REG_COLOR_KILLER); | |
388 | dump_reg(sd, REG_LUMA_CONTROL1); | |
389 | dump_reg(sd, REG_LUMA_CONTROL2); | |
390 | dump_reg(sd, REG_LUMA_CONTROL3); | |
391 | dump_reg(sd, REG_BRIGHTNESS); | |
392 | dump_reg(sd, REG_CONTRAST); | |
393 | dump_reg(sd, REG_SATURATION); | |
394 | dump_reg(sd, REG_HUE); | |
395 | dump_reg(sd, REG_CHROMA_CONTROL1); | |
396 | dump_reg(sd, REG_CHROMA_CONTROL2); | |
397 | dump_reg(sd, REG_COMP_PR_SATURATION); | |
398 | dump_reg(sd, REG_COMP_Y_CONTRAST); | |
399 | dump_reg(sd, REG_COMP_PB_SATURATION); | |
400 | dump_reg(sd, REG_COMP_Y_BRIGHTNESS); | |
401 | dump_reg(sd, REG_AVID_START_PIXEL_LSB); | |
402 | dump_reg(sd, REG_AVID_START_PIXEL_MSB); | |
403 | dump_reg(sd, REG_AVID_STOP_PIXEL_LSB); | |
404 | dump_reg(sd, REG_AVID_STOP_PIXEL_MSB); | |
405 | dump_reg(sd, REG_HSYNC_START_PIXEL_LSB); | |
406 | dump_reg(sd, REG_HSYNC_START_PIXEL_MSB); | |
407 | dump_reg(sd, REG_HSYNC_STOP_PIXEL_LSB); | |
408 | dump_reg(sd, REG_HSYNC_STOP_PIXEL_MSB); | |
409 | dump_reg(sd, REG_VSYNC_START_LINE_LSB); | |
410 | dump_reg(sd, REG_VSYNC_START_LINE_MSB); | |
411 | dump_reg(sd, REG_VSYNC_STOP_LINE_LSB); | |
412 | dump_reg(sd, REG_VSYNC_STOP_LINE_MSB); | |
413 | dump_reg(sd, REG_VBLK_START_LINE_LSB); | |
414 | dump_reg(sd, REG_VBLK_START_LINE_MSB); | |
415 | dump_reg(sd, REG_VBLK_STOP_LINE_LSB); | |
416 | dump_reg(sd, REG_VBLK_STOP_LINE_MSB); | |
417 | dump_reg(sd, REG_SYNC_CONTROL); | |
418 | dump_reg(sd, REG_OUTPUT_FORMATTER1); | |
419 | dump_reg(sd, REG_OUTPUT_FORMATTER2); | |
420 | dump_reg(sd, REG_OUTPUT_FORMATTER3); | |
421 | dump_reg(sd, REG_OUTPUT_FORMATTER4); | |
422 | dump_reg(sd, REG_OUTPUT_FORMATTER5); | |
423 | dump_reg(sd, REG_OUTPUT_FORMATTER6); | |
424 | dump_reg(sd, REG_CLEAR_LOST_LOCK); | |
07b1747c VH |
425 | } |
426 | ||
c1c9d09c MK |
427 | /** |
428 | * tvp514x_configure() - Configure the TVP5146/47 registers | |
429 | * @sd: ptr to v4l2_subdev struct | |
430 | * @decoder: ptr to tvp514x_decoder structure | |
431 | * | |
07b1747c VH |
432 | * Returns zero if successful, or non-zero otherwise. |
433 | */ | |
62ef80a1 MK |
434 | static int tvp514x_configure(struct v4l2_subdev *sd, |
435 | struct tvp514x_decoder *decoder) | |
07b1747c VH |
436 | { |
437 | int err; | |
438 | ||
439 | /* common register initialization */ | |
440 | err = | |
62ef80a1 | 441 | tvp514x_write_regs(sd, decoder->tvp514x_regs); |
07b1747c VH |
442 | if (err) |
443 | return err; | |
444 | ||
445 | if (debug) | |
62ef80a1 | 446 | tvp514x_reg_dump(sd); |
07b1747c VH |
447 | |
448 | return 0; | |
449 | } | |
450 | ||
c1c9d09c MK |
451 | /** |
452 | * tvp514x_detect() - Detect if an tvp514x is present, and if so which revision. | |
453 | * @sd: pointer to standard V4L2 sub-device structure | |
454 | * @decoder: pointer to tvp514x_decoder structure | |
455 | * | |
07b1747c VH |
456 | * A device is considered to be detected if the chip ID (LSB and MSB) |
457 | * registers match the expected values. | |
458 | * Any value of the rom version register is accepted. | |
459 | * Returns ENODEV error number if no device is detected, or zero | |
460 | * if a device is detected. | |
461 | */ | |
62ef80a1 MK |
462 | static int tvp514x_detect(struct v4l2_subdev *sd, |
463 | struct tvp514x_decoder *decoder) | |
07b1747c VH |
464 | { |
465 | u8 chip_id_msb, chip_id_lsb, rom_ver; | |
62ef80a1 | 466 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
07b1747c | 467 | |
62ef80a1 MK |
468 | chip_id_msb = tvp514x_read_reg(sd, REG_CHIP_ID_MSB); |
469 | chip_id_lsb = tvp514x_read_reg(sd, REG_CHIP_ID_LSB); | |
470 | rom_ver = tvp514x_read_reg(sd, REG_ROM_VERSION); | |
07b1747c | 471 | |
62ef80a1 | 472 | v4l2_dbg(1, debug, sd, |
07b1747c VH |
473 | "chip id detected msb:0x%x lsb:0x%x rom version:0x%x\n", |
474 | chip_id_msb, chip_id_lsb, rom_ver); | |
475 | if ((chip_id_msb != TVP514X_CHIP_ID_MSB) | |
476 | || ((chip_id_lsb != TVP5146_CHIP_ID_LSB) | |
477 | && (chip_id_lsb != TVP5147_CHIP_ID_LSB))) { | |
478 | /* We didn't read the values we expected, so this must not be | |
479 | * an TVP5146/47. | |
480 | */ | |
62ef80a1 MK |
481 | v4l2_err(sd, "chip id mismatch msb:0x%x lsb:0x%x\n", |
482 | chip_id_msb, chip_id_lsb); | |
07b1747c VH |
483 | return -ENODEV; |
484 | } | |
485 | ||
486 | decoder->ver = rom_ver; | |
07b1747c | 487 | |
62ef80a1 MK |
488 | v4l2_info(sd, "%s (Version - 0x%.2x) found at 0x%x (%s)\n", |
489 | client->name, decoder->ver, | |
490 | client->addr << 1, client->adapter->name); | |
07b1747c VH |
491 | return 0; |
492 | } | |
493 | ||
c1c9d09c MK |
494 | /** |
495 | * tvp514x_querystd() - V4L2 decoder interface handler for querystd | |
62ef80a1 | 496 | * @sd: pointer to standard V4L2 sub-device structure |
07b1747c VH |
497 | * @std_id: standard V4L2 std_id ioctl enum |
498 | * | |
499 | * Returns the current standard detected by TVP5146/47. If no active input is | |
2db4e78f | 500 | * detected then *std_id is set to 0 and the function returns 0. |
07b1747c | 501 | */ |
62ef80a1 | 502 | static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id) |
07b1747c | 503 | { |
62ef80a1 | 504 | struct tvp514x_decoder *decoder = to_decoder(sd); |
07b1747c VH |
505 | enum tvp514x_std current_std; |
506 | enum tvp514x_input input_sel; | |
507 | u8 sync_lock_status, lock_mask; | |
508 | ||
509 | if (std_id == NULL) | |
510 | return -EINVAL; | |
511 | ||
2db4e78f HV |
512 | *std_id = V4L2_STD_UNKNOWN; |
513 | ||
514 | /* query the current standard */ | |
515 | current_std = tvp514x_query_current_std(sd); | |
07b1747c | 516 | if (current_std == STD_INVALID) |
2db4e78f | 517 | return 0; |
07b1747c | 518 | |
62ef80a1 | 519 | input_sel = decoder->input; |
07b1747c VH |
520 | |
521 | switch (input_sel) { | |
522 | case INPUT_CVBS_VI1A: | |
523 | case INPUT_CVBS_VI1B: | |
524 | case INPUT_CVBS_VI1C: | |
525 | case INPUT_CVBS_VI2A: | |
526 | case INPUT_CVBS_VI2B: | |
527 | case INPUT_CVBS_VI2C: | |
528 | case INPUT_CVBS_VI3A: | |
529 | case INPUT_CVBS_VI3B: | |
530 | case INPUT_CVBS_VI3C: | |
531 | case INPUT_CVBS_VI4A: | |
532 | lock_mask = STATUS_CLR_SUBCAR_LOCK_BIT | | |
533 | STATUS_HORZ_SYNC_LOCK_BIT | | |
534 | STATUS_VIRT_SYNC_LOCK_BIT; | |
535 | break; | |
536 | ||
537 | case INPUT_SVIDEO_VI2A_VI1A: | |
538 | case INPUT_SVIDEO_VI2B_VI1B: | |
539 | case INPUT_SVIDEO_VI2C_VI1C: | |
540 | case INPUT_SVIDEO_VI2A_VI3A: | |
541 | case INPUT_SVIDEO_VI2B_VI3B: | |
542 | case INPUT_SVIDEO_VI2C_VI3C: | |
543 | case INPUT_SVIDEO_VI4A_VI1A: | |
544 | case INPUT_SVIDEO_VI4A_VI1B: | |
545 | case INPUT_SVIDEO_VI4A_VI1C: | |
546 | case INPUT_SVIDEO_VI4A_VI3A: | |
547 | case INPUT_SVIDEO_VI4A_VI3B: | |
548 | case INPUT_SVIDEO_VI4A_VI3C: | |
549 | lock_mask = STATUS_HORZ_SYNC_LOCK_BIT | | |
550 | STATUS_VIRT_SYNC_LOCK_BIT; | |
551 | break; | |
552 | /*Need to add other interfaces*/ | |
553 | default: | |
554 | return -EINVAL; | |
555 | } | |
556 | /* check whether signal is locked */ | |
62ef80a1 | 557 | sync_lock_status = tvp514x_read_reg(sd, REG_STATUS1); |
07b1747c | 558 | if (lock_mask != (sync_lock_status & lock_mask)) |
2db4e78f | 559 | return 0; /* No input detected */ |
07b1747c | 560 | |
07b1747c VH |
561 | *std_id = decoder->std_list[current_std].standard.id; |
562 | ||
2db4e78f | 563 | v4l2_dbg(1, debug, sd, "Current STD: %s\n", |
07b1747c VH |
564 | decoder->std_list[current_std].standard.name); |
565 | return 0; | |
566 | } | |
567 | ||
c1c9d09c MK |
568 | /** |
569 | * tvp514x_s_std() - V4L2 decoder interface handler for s_std | |
62ef80a1 | 570 | * @sd: pointer to standard V4L2 sub-device structure |
07b1747c VH |
571 | * @std_id: standard V4L2 v4l2_std_id ioctl enum |
572 | * | |
573 | * If std_id is supported, sets the requested standard. Otherwise, returns | |
574 | * -EINVAL | |
575 | */ | |
62ef80a1 | 576 | static int tvp514x_s_std(struct v4l2_subdev *sd, v4l2_std_id std_id) |
07b1747c | 577 | { |
62ef80a1 | 578 | struct tvp514x_decoder *decoder = to_decoder(sd); |
07b1747c VH |
579 | int err, i; |
580 | ||
07b1747c | 581 | for (i = 0; i < decoder->num_stds; i++) |
62ef80a1 | 582 | if (std_id & decoder->std_list[i].standard.id) |
07b1747c VH |
583 | break; |
584 | ||
585 | if ((i == decoder->num_stds) || (i == STD_INVALID)) | |
586 | return -EINVAL; | |
587 | ||
62ef80a1 | 588 | err = tvp514x_write_reg(sd, REG_VIDEO_STD, |
07b1747c VH |
589 | decoder->std_list[i].video_std); |
590 | if (err) | |
591 | return err; | |
592 | ||
593 | decoder->current_std = i; | |
6722e0ef SAS |
594 | decoder->tvp514x_regs[REG_VIDEO_STD].val = |
595 | decoder->std_list[i].video_std; | |
07b1747c | 596 | |
3907b072 | 597 | v4l2_dbg(1, debug, sd, "Standard set to: %s\n", |
07b1747c VH |
598 | decoder->std_list[i].standard.name); |
599 | return 0; | |
600 | } | |
601 | ||
c1c9d09c MK |
602 | /** |
603 | * tvp514x_s_routing() - V4L2 decoder interface handler for s_routing | |
62ef80a1 | 604 | * @sd: pointer to standard V4L2 sub-device structure |
c1c9d09c MK |
605 | * @input: input selector for routing the signal |
606 | * @output: output selector for routing the signal | |
607 | * @config: config value. Not used | |
07b1747c VH |
608 | * |
609 | * If index is valid, selects the requested input. Otherwise, returns -EINVAL if | |
610 | * the input is not supported or there is no active signal present in the | |
611 | * selected input. | |
612 | */ | |
62ef80a1 MK |
613 | static int tvp514x_s_routing(struct v4l2_subdev *sd, |
614 | u32 input, u32 output, u32 config) | |
07b1747c | 615 | { |
62ef80a1 | 616 | struct tvp514x_decoder *decoder = to_decoder(sd); |
07b1747c VH |
617 | int err; |
618 | enum tvp514x_input input_sel; | |
619 | enum tvp514x_output output_sel; | |
07b1747c VH |
620 | u8 sync_lock_status, lock_mask; |
621 | int try_count = LOCK_RETRY_COUNT; | |
622 | ||
62ef80a1 MK |
623 | if ((input >= INPUT_INVALID) || |
624 | (output >= OUTPUT_INVALID)) | |
c1c9d09c MK |
625 | /* Index out of bound */ |
626 | return -EINVAL; | |
07b1747c | 627 | |
63b59cec VH |
628 | /* |
629 | * For the sequence streamon -> streamoff and again s_input | |
630 | * it fails to lock the signal, since streamoff puts TVP514x | |
631 | * into power off state which leads to failure in sub-sequent s_input. | |
632 | * | |
633 | * So power up the TVP514x device here, since it is important to lock | |
634 | * the signal at this stage. | |
635 | */ | |
636 | if (!decoder->streaming) | |
637 | tvp514x_s_stream(sd, 1); | |
638 | ||
62ef80a1 MK |
639 | input_sel = input; |
640 | output_sel = output; | |
07b1747c | 641 | |
62ef80a1 | 642 | err = tvp514x_write_reg(sd, REG_INPUT_SEL, input_sel); |
07b1747c VH |
643 | if (err) |
644 | return err; | |
645 | ||
62ef80a1 | 646 | output_sel |= tvp514x_read_reg(sd, |
07b1747c | 647 | REG_OUTPUT_FORMATTER1) & 0x7; |
62ef80a1 | 648 | err = tvp514x_write_reg(sd, REG_OUTPUT_FORMATTER1, |
07b1747c VH |
649 | output_sel); |
650 | if (err) | |
651 | return err; | |
652 | ||
6722e0ef SAS |
653 | decoder->tvp514x_regs[REG_INPUT_SEL].val = input_sel; |
654 | decoder->tvp514x_regs[REG_OUTPUT_FORMATTER1].val = output_sel; | |
07b1747c VH |
655 | |
656 | /* Clear status */ | |
657 | msleep(LOCK_RETRY_DELAY); | |
658 | err = | |
62ef80a1 | 659 | tvp514x_write_reg(sd, REG_CLEAR_LOST_LOCK, 0x01); |
07b1747c VH |
660 | if (err) |
661 | return err; | |
662 | ||
663 | switch (input_sel) { | |
664 | case INPUT_CVBS_VI1A: | |
665 | case INPUT_CVBS_VI1B: | |
666 | case INPUT_CVBS_VI1C: | |
667 | case INPUT_CVBS_VI2A: | |
668 | case INPUT_CVBS_VI2B: | |
669 | case INPUT_CVBS_VI2C: | |
670 | case INPUT_CVBS_VI3A: | |
671 | case INPUT_CVBS_VI3B: | |
672 | case INPUT_CVBS_VI3C: | |
673 | case INPUT_CVBS_VI4A: | |
674 | lock_mask = STATUS_CLR_SUBCAR_LOCK_BIT | | |
675 | STATUS_HORZ_SYNC_LOCK_BIT | | |
676 | STATUS_VIRT_SYNC_LOCK_BIT; | |
677 | break; | |
678 | ||
679 | case INPUT_SVIDEO_VI2A_VI1A: | |
680 | case INPUT_SVIDEO_VI2B_VI1B: | |
681 | case INPUT_SVIDEO_VI2C_VI1C: | |
682 | case INPUT_SVIDEO_VI2A_VI3A: | |
683 | case INPUT_SVIDEO_VI2B_VI3B: | |
684 | case INPUT_SVIDEO_VI2C_VI3C: | |
685 | case INPUT_SVIDEO_VI4A_VI1A: | |
686 | case INPUT_SVIDEO_VI4A_VI1B: | |
687 | case INPUT_SVIDEO_VI4A_VI1C: | |
688 | case INPUT_SVIDEO_VI4A_VI3A: | |
689 | case INPUT_SVIDEO_VI4A_VI3B: | |
690 | case INPUT_SVIDEO_VI4A_VI3C: | |
691 | lock_mask = STATUS_HORZ_SYNC_LOCK_BIT | | |
692 | STATUS_VIRT_SYNC_LOCK_BIT; | |
693 | break; | |
c1c9d09c | 694 | /* Need to add other interfaces*/ |
07b1747c VH |
695 | default: |
696 | return -EINVAL; | |
697 | } | |
698 | ||
699 | while (try_count-- > 0) { | |
700 | /* Allow decoder to sync up with new input */ | |
701 | msleep(LOCK_RETRY_DELAY); | |
702 | ||
62ef80a1 | 703 | sync_lock_status = tvp514x_read_reg(sd, |
07b1747c VH |
704 | REG_STATUS1); |
705 | if (lock_mask == (sync_lock_status & lock_mask)) | |
c1c9d09c MK |
706 | /* Input detected */ |
707 | break; | |
07b1747c VH |
708 | } |
709 | ||
2db4e78f | 710 | if (try_count < 0) |
07b1747c VH |
711 | return -EINVAL; |
712 | ||
62ef80a1 MK |
713 | decoder->input = input; |
714 | decoder->output = output; | |
07b1747c | 715 | |
2db4e78f | 716 | v4l2_dbg(1, debug, sd, "Input set to: %d\n", input_sel); |
07b1747c VH |
717 | |
718 | return 0; | |
719 | } | |
720 | ||
c1c9d09c MK |
721 | /** |
722 | * tvp514x_queryctrl() - V4L2 decoder interface handler for queryctrl | |
62ef80a1 | 723 | * @sd: pointer to standard V4L2 sub-device structure |
07b1747c VH |
724 | * @qctrl: standard V4L2 v4l2_queryctrl structure |
725 | * | |
726 | * If the requested control is supported, returns the control information. | |
727 | * Otherwise, returns -EINVAL if the control is not supported. | |
728 | */ | |
729 | static int | |
62ef80a1 | 730 | tvp514x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qctrl) |
07b1747c | 731 | { |
07b1747c VH |
732 | int err = -EINVAL; |
733 | ||
734 | if (qctrl == NULL) | |
735 | return err; | |
736 | ||
737 | switch (qctrl->id) { | |
738 | case V4L2_CID_BRIGHTNESS: | |
c1c9d09c | 739 | /* Brightness supported is (0-255), */ |
10afbef1 | 740 | err = v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128); |
07b1747c VH |
741 | break; |
742 | case V4L2_CID_CONTRAST: | |
743 | case V4L2_CID_SATURATION: | |
c1c9d09c MK |
744 | /** |
745 | * Saturation and Contrast supported is - | |
07b1747c VH |
746 | * Contrast: 0 - 255 (Default - 128) |
747 | * Saturation: 0 - 255 (Default - 128) | |
748 | */ | |
749 | err = v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128); | |
750 | break; | |
751 | case V4L2_CID_HUE: | |
752 | /* Hue Supported is - | |
753 | * Hue - -180 - +180 (Default - 0, Step - +180) | |
754 | */ | |
755 | err = v4l2_ctrl_query_fill(qctrl, -180, 180, 180, 0); | |
756 | break; | |
757 | case V4L2_CID_AUTOGAIN: | |
c1c9d09c | 758 | /** |
62ef80a1 MK |
759 | * Auto Gain supported is - |
760 | * 0 - 1 (Default - 1) | |
761 | */ | |
762 | err = v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 1); | |
07b1747c VH |
763 | break; |
764 | default: | |
62ef80a1 | 765 | v4l2_err(sd, "invalid control id %d\n", qctrl->id); |
07b1747c VH |
766 | return err; |
767 | } | |
768 | ||
3907b072 | 769 | v4l2_dbg(1, debug, sd, "Query Control:%s: Min - %d, Max - %d, Def - %d\n", |
62ef80a1 | 770 | qctrl->name, qctrl->minimum, qctrl->maximum, |
07b1747c VH |
771 | qctrl->default_value); |
772 | ||
773 | return err; | |
774 | } | |
775 | ||
c1c9d09c MK |
776 | /** |
777 | * tvp514x_g_ctrl() - V4L2 decoder interface handler for g_ctrl | |
62ef80a1 | 778 | * @sd: pointer to standard V4L2 sub-device structure |
07b1747c VH |
779 | * @ctrl: pointer to v4l2_control structure |
780 | * | |
781 | * If the requested control is supported, returns the control's current | |
782 | * value from the decoder. Otherwise, returns -EINVAL if the control is not | |
783 | * supported. | |
784 | */ | |
785 | static int | |
62ef80a1 | 786 | tvp514x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
07b1747c | 787 | { |
62ef80a1 | 788 | struct tvp514x_decoder *decoder = to_decoder(sd); |
07b1747c VH |
789 | |
790 | if (ctrl == NULL) | |
791 | return -EINVAL; | |
792 | ||
793 | switch (ctrl->id) { | |
794 | case V4L2_CID_BRIGHTNESS: | |
6722e0ef | 795 | ctrl->value = decoder->tvp514x_regs[REG_BRIGHTNESS].val; |
07b1747c VH |
796 | break; |
797 | case V4L2_CID_CONTRAST: | |
6722e0ef | 798 | ctrl->value = decoder->tvp514x_regs[REG_CONTRAST].val; |
07b1747c VH |
799 | break; |
800 | case V4L2_CID_SATURATION: | |
6722e0ef | 801 | ctrl->value = decoder->tvp514x_regs[REG_SATURATION].val; |
07b1747c VH |
802 | break; |
803 | case V4L2_CID_HUE: | |
6722e0ef | 804 | ctrl->value = decoder->tvp514x_regs[REG_HUE].val; |
07b1747c VH |
805 | if (ctrl->value == 0x7F) |
806 | ctrl->value = 180; | |
807 | else if (ctrl->value == 0x80) | |
808 | ctrl->value = -180; | |
809 | else | |
810 | ctrl->value = 0; | |
811 | ||
812 | break; | |
813 | case V4L2_CID_AUTOGAIN: | |
6722e0ef | 814 | ctrl->value = decoder->tvp514x_regs[REG_AFE_GAIN_CTRL].val; |
07b1747c VH |
815 | if ((ctrl->value & 0x3) == 3) |
816 | ctrl->value = 1; | |
817 | else | |
818 | ctrl->value = 0; | |
819 | ||
820 | break; | |
821 | default: | |
62ef80a1 | 822 | v4l2_err(sd, "invalid control id %d\n", ctrl->id); |
07b1747c VH |
823 | return -EINVAL; |
824 | } | |
825 | ||
3907b072 | 826 | v4l2_dbg(1, debug, sd, "Get Control: ID - %d - %d\n", |
07b1747c VH |
827 | ctrl->id, ctrl->value); |
828 | return 0; | |
829 | } | |
830 | ||
c1c9d09c MK |
831 | /** |
832 | * tvp514x_s_ctrl() - V4L2 decoder interface handler for s_ctrl | |
62ef80a1 | 833 | * @sd: pointer to standard V4L2 sub-device structure |
07b1747c VH |
834 | * @ctrl: pointer to v4l2_control structure |
835 | * | |
836 | * If the requested control is supported, sets the control's current | |
837 | * value in HW. Otherwise, returns -EINVAL if the control is not supported. | |
838 | */ | |
839 | static int | |
62ef80a1 | 840 | tvp514x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
07b1747c | 841 | { |
62ef80a1 | 842 | struct tvp514x_decoder *decoder = to_decoder(sd); |
07b1747c VH |
843 | int err = -EINVAL, value; |
844 | ||
845 | if (ctrl == NULL) | |
846 | return err; | |
847 | ||
62ef80a1 | 848 | value = ctrl->value; |
07b1747c VH |
849 | |
850 | switch (ctrl->id) { | |
851 | case V4L2_CID_BRIGHTNESS: | |
852 | if (ctrl->value < 0 || ctrl->value > 255) { | |
62ef80a1 | 853 | v4l2_err(sd, "invalid brightness setting %d\n", |
07b1747c VH |
854 | ctrl->value); |
855 | return -ERANGE; | |
856 | } | |
62ef80a1 | 857 | err = tvp514x_write_reg(sd, REG_BRIGHTNESS, |
07b1747c VH |
858 | value); |
859 | if (err) | |
860 | return err; | |
62ef80a1 | 861 | |
6722e0ef | 862 | decoder->tvp514x_regs[REG_BRIGHTNESS].val = value; |
07b1747c VH |
863 | break; |
864 | case V4L2_CID_CONTRAST: | |
865 | if (ctrl->value < 0 || ctrl->value > 255) { | |
62ef80a1 | 866 | v4l2_err(sd, "invalid contrast setting %d\n", |
07b1747c VH |
867 | ctrl->value); |
868 | return -ERANGE; | |
869 | } | |
62ef80a1 | 870 | err = tvp514x_write_reg(sd, REG_CONTRAST, value); |
07b1747c VH |
871 | if (err) |
872 | return err; | |
62ef80a1 | 873 | |
6722e0ef | 874 | decoder->tvp514x_regs[REG_CONTRAST].val = value; |
07b1747c VH |
875 | break; |
876 | case V4L2_CID_SATURATION: | |
877 | if (ctrl->value < 0 || ctrl->value > 255) { | |
62ef80a1 | 878 | v4l2_err(sd, "invalid saturation setting %d\n", |
07b1747c VH |
879 | ctrl->value); |
880 | return -ERANGE; | |
881 | } | |
62ef80a1 | 882 | err = tvp514x_write_reg(sd, REG_SATURATION, value); |
07b1747c VH |
883 | if (err) |
884 | return err; | |
62ef80a1 | 885 | |
6722e0ef | 886 | decoder->tvp514x_regs[REG_SATURATION].val = value; |
07b1747c VH |
887 | break; |
888 | case V4L2_CID_HUE: | |
889 | if (value == 180) | |
890 | value = 0x7F; | |
891 | else if (value == -180) | |
892 | value = 0x80; | |
893 | else if (value == 0) | |
894 | value = 0; | |
895 | else { | |
62ef80a1 | 896 | v4l2_err(sd, "invalid hue setting %d\n", ctrl->value); |
07b1747c VH |
897 | return -ERANGE; |
898 | } | |
62ef80a1 | 899 | err = tvp514x_write_reg(sd, REG_HUE, value); |
07b1747c VH |
900 | if (err) |
901 | return err; | |
62ef80a1 | 902 | |
6722e0ef | 903 | decoder->tvp514x_regs[REG_HUE].val = value; |
07b1747c VH |
904 | break; |
905 | case V4L2_CID_AUTOGAIN: | |
906 | if (value == 1) | |
907 | value = 0x0F; | |
908 | else if (value == 0) | |
909 | value = 0x0C; | |
910 | else { | |
62ef80a1 | 911 | v4l2_err(sd, "invalid auto gain setting %d\n", |
07b1747c VH |
912 | ctrl->value); |
913 | return -ERANGE; | |
914 | } | |
62ef80a1 | 915 | err = tvp514x_write_reg(sd, REG_AFE_GAIN_CTRL, value); |
07b1747c VH |
916 | if (err) |
917 | return err; | |
62ef80a1 | 918 | |
6722e0ef | 919 | decoder->tvp514x_regs[REG_AFE_GAIN_CTRL].val = value; |
07b1747c VH |
920 | break; |
921 | default: | |
62ef80a1 | 922 | v4l2_err(sd, "invalid control id %d\n", ctrl->id); |
07b1747c VH |
923 | return err; |
924 | } | |
925 | ||
3907b072 | 926 | v4l2_dbg(1, debug, sd, "Set Control: ID - %d - %d\n", |
07b1747c VH |
927 | ctrl->id, ctrl->value); |
928 | ||
929 | return err; | |
930 | } | |
931 | ||
83811913 HV |
932 | /** |
933 | * tvp514x_enum_mbus_fmt() - V4L2 decoder interface handler for enum_mbus_fmt | |
934 | * @sd: pointer to standard V4L2 sub-device structure | |
935 | * @index: index of pixelcode to retrieve | |
936 | * @code: receives the pixelcode | |
937 | * | |
938 | * Enumerates supported mediabus formats | |
939 | */ | |
940 | static int | |
941 | tvp514x_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, | |
942 | enum v4l2_mbus_pixelcode *code) | |
943 | { | |
944 | if (index) | |
945 | return -EINVAL; | |
946 | ||
947 | *code = V4L2_MBUS_FMT_YUYV10_2X10; | |
948 | return 0; | |
949 | } | |
950 | ||
83811913 HV |
951 | /** |
952 | * tvp514x_mbus_fmt_cap() - V4L2 decoder interface handler for try/s/g_mbus_fmt | |
953 | * @sd: pointer to standard V4L2 sub-device structure | |
954 | * @f: pointer to the mediabus format structure | |
955 | * | |
956 | * Negotiates the image capture size and mediabus format. | |
957 | */ | |
958 | static int | |
959 | tvp514x_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f) | |
960 | { | |
961 | struct tvp514x_decoder *decoder = to_decoder(sd); | |
962 | enum tvp514x_std current_std; | |
963 | ||
964 | if (f == NULL) | |
965 | return -EINVAL; | |
966 | ||
967 | /* Calculate height and width based on current standard */ | |
968 | current_std = decoder->current_std; | |
969 | ||
970 | f->code = V4L2_MBUS_FMT_YUYV10_2X10; | |
971 | f->width = decoder->std_list[current_std].width; | |
972 | f->height = decoder->std_list[current_std].height; | |
973 | f->field = V4L2_FIELD_INTERLACED; | |
974 | f->colorspace = V4L2_COLORSPACE_SMPTE170M; | |
975 | ||
976 | v4l2_dbg(1, debug, sd, "MBUS_FMT: Width - %d, Height - %d\n", | |
977 | f->width, f->height); | |
978 | return 0; | |
979 | } | |
980 | ||
c1c9d09c MK |
981 | /** |
982 | * tvp514x_g_parm() - V4L2 decoder interface handler for g_parm | |
62ef80a1 | 983 | * @sd: pointer to standard V4L2 sub-device structure |
07b1747c VH |
984 | * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure |
985 | * | |
986 | * Returns the decoder's video CAPTURE parameters. | |
987 | */ | |
988 | static int | |
62ef80a1 | 989 | tvp514x_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a) |
07b1747c | 990 | { |
62ef80a1 | 991 | struct tvp514x_decoder *decoder = to_decoder(sd); |
07b1747c VH |
992 | struct v4l2_captureparm *cparm; |
993 | enum tvp514x_std current_std; | |
994 | ||
995 | if (a == NULL) | |
996 | return -EINVAL; | |
997 | ||
998 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
c1c9d09c MK |
999 | /* only capture is supported */ |
1000 | return -EINVAL; | |
07b1747c | 1001 | |
07b1747c | 1002 | /* get the current standard */ |
2db4e78f | 1003 | current_std = decoder->current_std; |
07b1747c VH |
1004 | |
1005 | cparm = &a->parm.capture; | |
1006 | cparm->capability = V4L2_CAP_TIMEPERFRAME; | |
1007 | cparm->timeperframe = | |
1008 | decoder->std_list[current_std].standard.frameperiod; | |
1009 | ||
1010 | return 0; | |
1011 | } | |
1012 | ||
c1c9d09c MK |
1013 | /** |
1014 | * tvp514x_s_parm() - V4L2 decoder interface handler for s_parm | |
62ef80a1 | 1015 | * @sd: pointer to standard V4L2 sub-device structure |
07b1747c VH |
1016 | * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure |
1017 | * | |
1018 | * Configures the decoder to use the input parameters, if possible. If | |
1019 | * not possible, returns the appropriate error code. | |
1020 | */ | |
1021 | static int | |
62ef80a1 | 1022 | tvp514x_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a) |
07b1747c | 1023 | { |
62ef80a1 | 1024 | struct tvp514x_decoder *decoder = to_decoder(sd); |
07b1747c VH |
1025 | struct v4l2_fract *timeperframe; |
1026 | enum tvp514x_std current_std; | |
1027 | ||
1028 | if (a == NULL) | |
1029 | return -EINVAL; | |
1030 | ||
1031 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
c1c9d09c MK |
1032 | /* only capture is supported */ |
1033 | return -EINVAL; | |
07b1747c VH |
1034 | |
1035 | timeperframe = &a->parm.capture.timeperframe; | |
1036 | ||
1037 | /* get the current standard */ | |
2db4e78f | 1038 | current_std = decoder->current_std; |
07b1747c VH |
1039 | |
1040 | *timeperframe = | |
1041 | decoder->std_list[current_std].standard.frameperiod; | |
1042 | ||
1043 | return 0; | |
1044 | } | |
1045 | ||
c1c9d09c MK |
1046 | /** |
1047 | * tvp514x_s_stream() - V4L2 decoder i/f handler for s_stream | |
62ef80a1 MK |
1048 | * @sd: pointer to standard V4L2 sub-device structure |
1049 | * @enable: streaming enable or disable | |
07b1747c | 1050 | * |
62ef80a1 | 1051 | * Sets streaming to enable or disable, if possible. |
07b1747c | 1052 | */ |
62ef80a1 | 1053 | static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable) |
07b1747c | 1054 | { |
07b1747c | 1055 | int err = 0; |
62ef80a1 MK |
1056 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
1057 | struct tvp514x_decoder *decoder = to_decoder(sd); | |
07b1747c | 1058 | |
62ef80a1 MK |
1059 | if (decoder->streaming == enable) |
1060 | return 0; | |
07b1747c | 1061 | |
62ef80a1 MK |
1062 | switch (enable) { |
1063 | case 0: | |
1064 | { | |
1065 | /* Power Down Sequence */ | |
1066 | err = tvp514x_write_reg(sd, REG_OPERATION_MODE, 0x01); | |
1067 | if (err) { | |
1068 | v4l2_err(sd, "Unable to turn off decoder\n"); | |
1069 | return err; | |
1070 | } | |
1071 | decoder->streaming = enable; | |
07b1747c | 1072 | break; |
62ef80a1 MK |
1073 | } |
1074 | case 1: | |
1075 | { | |
1076 | struct tvp514x_reg *int_seq = (struct tvp514x_reg *) | |
1077 | client->driver->id_table->driver_data; | |
07b1747c | 1078 | |
62ef80a1 MK |
1079 | /* Power Up Sequence */ |
1080 | err = tvp514x_write_regs(sd, int_seq); | |
1081 | if (err) { | |
1082 | v4l2_err(sd, "Unable to turn on decoder\n"); | |
1083 | return err; | |
1084 | } | |
1085 | /* Detect if not already detected */ | |
1086 | err = tvp514x_detect(sd, decoder); | |
1087 | if (err) { | |
1088 | v4l2_err(sd, "Unable to detect decoder\n"); | |
1089 | return err; | |
07b1747c | 1090 | } |
62ef80a1 MK |
1091 | err = tvp514x_configure(sd, decoder); |
1092 | if (err) { | |
1093 | v4l2_err(sd, "Unable to configure decoder\n"); | |
1094 | return err; | |
1095 | } | |
1096 | decoder->streaming = enable; | |
07b1747c | 1097 | break; |
62ef80a1 | 1098 | } |
07b1747c VH |
1099 | default: |
1100 | err = -ENODEV; | |
1101 | break; | |
1102 | } | |
1103 | ||
1104 | return err; | |
1105 | } | |
1106 | ||
62ef80a1 MK |
1107 | static const struct v4l2_subdev_core_ops tvp514x_core_ops = { |
1108 | .queryctrl = tvp514x_queryctrl, | |
1109 | .g_ctrl = tvp514x_g_ctrl, | |
1110 | .s_ctrl = tvp514x_s_ctrl, | |
1111 | .s_std = tvp514x_s_std, | |
1112 | }; | |
07b1747c | 1113 | |
62ef80a1 MK |
1114 | static const struct v4l2_subdev_video_ops tvp514x_video_ops = { |
1115 | .s_routing = tvp514x_s_routing, | |
1116 | .querystd = tvp514x_querystd, | |
83811913 HV |
1117 | .enum_mbus_fmt = tvp514x_enum_mbus_fmt, |
1118 | .g_mbus_fmt = tvp514x_mbus_fmt, | |
1119 | .try_mbus_fmt = tvp514x_mbus_fmt, | |
1120 | .s_mbus_fmt = tvp514x_mbus_fmt, | |
62ef80a1 MK |
1121 | .g_parm = tvp514x_g_parm, |
1122 | .s_parm = tvp514x_s_parm, | |
1123 | .s_stream = tvp514x_s_stream, | |
1124 | }; | |
07b1747c | 1125 | |
62ef80a1 MK |
1126 | static const struct v4l2_subdev_ops tvp514x_ops = { |
1127 | .core = &tvp514x_core_ops, | |
1128 | .video = &tvp514x_video_ops, | |
07b1747c VH |
1129 | }; |
1130 | ||
07b1747c | 1131 | static struct tvp514x_decoder tvp514x_dev = { |
62ef80a1 | 1132 | .streaming = 0, |
07b1747c VH |
1133 | .current_std = STD_NTSC_MJ, |
1134 | .std_list = tvp514x_std_list, | |
1135 | .num_stds = ARRAY_SIZE(tvp514x_std_list), | |
62ef80a1 | 1136 | |
07b1747c VH |
1137 | }; |
1138 | ||
c1c9d09c MK |
1139 | /** |
1140 | * tvp514x_probe() - decoder driver i2c probe handler | |
07b1747c | 1141 | * @client: i2c driver client device structure |
62ef80a1 | 1142 | * @id: i2c driver id table |
07b1747c VH |
1143 | * |
1144 | * Register decoder as an i2c client device and V4L2 | |
1145 | * device. | |
1146 | */ | |
1147 | static int | |
1148 | tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id) | |
1149 | { | |
6722e0ef | 1150 | struct tvp514x_decoder *decoder; |
62ef80a1 | 1151 | struct v4l2_subdev *sd; |
07b1747c VH |
1152 | |
1153 | /* Check if the adapter supports the needed features */ | |
1154 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | |
1155 | return -EIO; | |
1156 | ||
62ef80a1 MK |
1157 | if (!client->dev.platform_data) { |
1158 | v4l2_err(client, "No platform data!!\n"); | |
1159 | return -ENODEV; | |
1160 | } | |
1161 | ||
6722e0ef SAS |
1162 | decoder = kzalloc(sizeof(*decoder), GFP_KERNEL); |
1163 | if (!decoder) | |
1164 | return -ENOMEM; | |
1165 | ||
c1c9d09c | 1166 | /* Initialize the tvp514x_decoder with default configuration */ |
6722e0ef | 1167 | *decoder = tvp514x_dev; |
62ef80a1 | 1168 | /* Copy default register configuration */ |
6722e0ef SAS |
1169 | memcpy(decoder->tvp514x_regs, tvp514x_reg_list_default, |
1170 | sizeof(tvp514x_reg_list_default)); | |
62ef80a1 | 1171 | |
c1c9d09c | 1172 | /* Copy board specific information here */ |
62ef80a1 MK |
1173 | decoder->pdata = client->dev.platform_data; |
1174 | ||
c1c9d09c | 1175 | /** |
07b1747c VH |
1176 | * Fetch platform specific data, and configure the |
1177 | * tvp514x_reg_list[] accordingly. Since this is one | |
1178 | * time configuration, no need to preserve. | |
1179 | */ | |
6722e0ef | 1180 | decoder->tvp514x_regs[REG_OUTPUT_FORMATTER2].val |= |
62ef80a1 | 1181 | (decoder->pdata->clk_polarity << 1); |
6722e0ef | 1182 | decoder->tvp514x_regs[REG_SYNC_CONTROL].val |= |
62ef80a1 MK |
1183 | ((decoder->pdata->hs_polarity << 2) | |
1184 | (decoder->pdata->vs_polarity << 3)); | |
1185 | /* Set default standard to auto */ | |
1186 | decoder->tvp514x_regs[REG_VIDEO_STD].val = | |
1187 | VIDEO_STD_AUTO_SWITCH_BIT; | |
07b1747c VH |
1188 | |
1189 | /* Register with V4L2 layer as slave device */ | |
62ef80a1 MK |
1190 | sd = &decoder->sd; |
1191 | v4l2_i2c_subdev_init(sd, client, &tvp514x_ops); | |
1192 | ||
1193 | v4l2_info(sd, "%s decoder driver registered !!\n", sd->name); | |
1194 | ||
07b1747c | 1195 | return 0; |
6722e0ef | 1196 | |
07b1747c VH |
1197 | } |
1198 | ||
c1c9d09c MK |
1199 | /** |
1200 | * tvp514x_remove() - decoder driver i2c remove handler | |
07b1747c VH |
1201 | * @client: i2c driver client device structure |
1202 | * | |
1203 | * Unregister decoder as an i2c client device and V4L2 | |
1204 | * device. Complement of tvp514x_probe(). | |
1205 | */ | |
62ef80a1 | 1206 | static int tvp514x_remove(struct i2c_client *client) |
07b1747c | 1207 | { |
62ef80a1 MK |
1208 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
1209 | struct tvp514x_decoder *decoder = to_decoder(sd); | |
07b1747c | 1210 | |
62ef80a1 | 1211 | v4l2_device_unregister_subdev(sd); |
6722e0ef | 1212 | kfree(decoder); |
07b1747c VH |
1213 | return 0; |
1214 | } | |
c1c9d09c | 1215 | /* TVP5146 Init/Power on Sequence */ |
07b1747c VH |
1216 | static const struct tvp514x_reg tvp5146_init_reg_seq[] = { |
1217 | {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x02}, | |
1218 | {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00}, | |
1219 | {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0x80}, | |
1220 | {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01}, | |
1221 | {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x60}, | |
1222 | {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00}, | |
1223 | {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xB0}, | |
1224 | {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01}, | |
1225 | {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x00}, | |
1226 | {TOK_WRITE, REG_OPERATION_MODE, 0x01}, | |
1227 | {TOK_WRITE, REG_OPERATION_MODE, 0x00}, | |
62ef80a1 | 1228 | {TOK_TERM, 0, 0}, |
07b1747c | 1229 | }; |
62ef80a1 | 1230 | |
c1c9d09c | 1231 | /* TVP5147 Init/Power on Sequence */ |
07b1747c VH |
1232 | static const struct tvp514x_reg tvp5147_init_reg_seq[] = { |
1233 | {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x02}, | |
1234 | {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00}, | |
1235 | {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0x80}, | |
1236 | {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01}, | |
1237 | {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x60}, | |
1238 | {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00}, | |
1239 | {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xB0}, | |
1240 | {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x01}, | |
1241 | {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x16}, | |
1242 | {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00}, | |
1243 | {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xA0}, | |
1244 | {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x16}, | |
1245 | {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS1, 0x60}, | |
1246 | {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS2, 0x00}, | |
1247 | {TOK_WRITE, REG_VBUS_ADDRESS_ACCESS3, 0xB0}, | |
1248 | {TOK_WRITE, REG_VBUS_DATA_ACCESS_NO_VBUS_ADDR_INCR, 0x00}, | |
1249 | {TOK_WRITE, REG_OPERATION_MODE, 0x01}, | |
1250 | {TOK_WRITE, REG_OPERATION_MODE, 0x00}, | |
62ef80a1 | 1251 | {TOK_TERM, 0, 0}, |
07b1747c | 1252 | }; |
62ef80a1 | 1253 | |
c1c9d09c | 1254 | /* TVP5146M2/TVP5147M1 Init/Power on Sequence */ |
07b1747c VH |
1255 | static const struct tvp514x_reg tvp514xm_init_reg_seq[] = { |
1256 | {TOK_WRITE, REG_OPERATION_MODE, 0x01}, | |
1257 | {TOK_WRITE, REG_OPERATION_MODE, 0x00}, | |
62ef80a1 | 1258 | {TOK_TERM, 0, 0}, |
07b1747c | 1259 | }; |
62ef80a1 | 1260 | |
c1c9d09c | 1261 | /** |
07b1747c VH |
1262 | * I2C Device Table - |
1263 | * | |
1264 | * name - Name of the actual device/chip. | |
1265 | * driver_data - Driver data | |
1266 | */ | |
1267 | static const struct i2c_device_id tvp514x_id[] = { | |
62ef80a1 MK |
1268 | {"tvp5146", (unsigned long)tvp5146_init_reg_seq}, |
1269 | {"tvp5146m2", (unsigned long)tvp514xm_init_reg_seq}, | |
1270 | {"tvp5147", (unsigned long)tvp5147_init_reg_seq}, | |
1271 | {"tvp5147m1", (unsigned long)tvp514xm_init_reg_seq}, | |
07b1747c VH |
1272 | {}, |
1273 | }; | |
1274 | ||
1275 | MODULE_DEVICE_TABLE(i2c, tvp514x_id); | |
1276 | ||
62ef80a1 | 1277 | static struct i2c_driver tvp514x_driver = { |
07b1747c | 1278 | .driver = { |
62ef80a1 MK |
1279 | .owner = THIS_MODULE, |
1280 | .name = TVP514X_MODULE_NAME, | |
1281 | }, | |
07b1747c | 1282 | .probe = tvp514x_probe, |
62ef80a1 | 1283 | .remove = tvp514x_remove, |
07b1747c VH |
1284 | .id_table = tvp514x_id, |
1285 | }; | |
1286 | ||
07b1747c VH |
1287 | static int __init tvp514x_init(void) |
1288 | { | |
62ef80a1 | 1289 | return i2c_add_driver(&tvp514x_driver); |
07b1747c VH |
1290 | } |
1291 | ||
62ef80a1 | 1292 | static void __exit tvp514x_exit(void) |
07b1747c | 1293 | { |
62ef80a1 | 1294 | i2c_del_driver(&tvp514x_driver); |
07b1747c VH |
1295 | } |
1296 | ||
1297 | module_init(tvp514x_init); | |
62ef80a1 | 1298 | module_exit(tvp514x_exit); |