2 * Driver for Analog Devices ADV748X HDMI receiver and Component Processor (CP)
4 * Copyright (C) 2017 Renesas Electronics Corp.
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
12 #include <linux/module.h>
13 #include <linux/mutex.h>
15 #include <media/v4l2-ctrls.h>
16 #include <media/v4l2-device.h>
17 #include <media/v4l2-dv-timings.h>
18 #include <media/v4l2-ioctl.h>
20 #include <uapi/linux/v4l2-dv-timings.h>
24 /* -----------------------------------------------------------------------------
28 #define ADV748X_HDMI_MIN_WIDTH 640
29 #define ADV748X_HDMI_MAX_WIDTH 1920
30 #define ADV748X_HDMI_MIN_HEIGHT 480
31 #define ADV748X_HDMI_MAX_HEIGHT 1200
33 /* V4L2_DV_BT_CEA_720X480I59_94 - 0.5 MHz */
34 #define ADV748X_HDMI_MIN_PIXELCLOCK 13000000
35 /* V4L2_DV_BT_DMT_1600X1200P60 */
36 #define ADV748X_HDMI_MAX_PIXELCLOCK 162000000
38 static const struct v4l2_dv_timings_cap adv748x_hdmi_timings_cap
= {
39 .type
= V4L2_DV_BT_656_1120
,
40 /* keep this initialization for compatibility with GCC < 4.4.6 */
43 V4L2_INIT_BT_TIMINGS(ADV748X_HDMI_MIN_WIDTH
, ADV748X_HDMI_MAX_WIDTH
,
44 ADV748X_HDMI_MIN_HEIGHT
, ADV748X_HDMI_MAX_HEIGHT
,
45 ADV748X_HDMI_MIN_PIXELCLOCK
,
46 ADV748X_HDMI_MAX_PIXELCLOCK
,
47 V4L2_DV_BT_STD_CEA861
| V4L2_DV_BT_STD_DMT
,
48 V4L2_DV_BT_CAP_PROGRESSIVE
)
51 struct adv748x_hdmi_video_standards
{
52 struct v4l2_dv_timings timings
;
57 static const struct adv748x_hdmi_video_standards
58 adv748x_hdmi_video_standards
[] = {
59 { V4L2_DV_BT_CEA_720X480P59_94
, 0x4a, 0x00 },
60 { V4L2_DV_BT_CEA_720X576P50
, 0x4b, 0x00 },
61 { V4L2_DV_BT_CEA_1280X720P60
, 0x53, 0x00 },
62 { V4L2_DV_BT_CEA_1280X720P50
, 0x53, 0x01 },
63 { V4L2_DV_BT_CEA_1280X720P30
, 0x53, 0x02 },
64 { V4L2_DV_BT_CEA_1280X720P25
, 0x53, 0x03 },
65 { V4L2_DV_BT_CEA_1280X720P24
, 0x53, 0x04 },
66 { V4L2_DV_BT_CEA_1920X1080P60
, 0x5e, 0x00 },
67 { V4L2_DV_BT_CEA_1920X1080P50
, 0x5e, 0x01 },
68 { V4L2_DV_BT_CEA_1920X1080P30
, 0x5e, 0x02 },
69 { V4L2_DV_BT_CEA_1920X1080P25
, 0x5e, 0x03 },
70 { V4L2_DV_BT_CEA_1920X1080P24
, 0x5e, 0x04 },
72 { V4L2_DV_BT_DMT_800X600P56
, 0x80, 0x00 },
73 { V4L2_DV_BT_DMT_800X600P60
, 0x81, 0x00 },
74 { V4L2_DV_BT_DMT_800X600P72
, 0x82, 0x00 },
75 { V4L2_DV_BT_DMT_800X600P75
, 0x83, 0x00 },
76 { V4L2_DV_BT_DMT_800X600P85
, 0x84, 0x00 },
78 { V4L2_DV_BT_DMT_1280X1024P60
, 0x85, 0x00 },
79 { V4L2_DV_BT_DMT_1280X1024P75
, 0x86, 0x00 },
81 { V4L2_DV_BT_DMT_640X480P60
, 0x88, 0x00 },
82 { V4L2_DV_BT_DMT_640X480P72
, 0x89, 0x00 },
83 { V4L2_DV_BT_DMT_640X480P75
, 0x8a, 0x00 },
84 { V4L2_DV_BT_DMT_640X480P85
, 0x8b, 0x00 },
86 { V4L2_DV_BT_DMT_1024X768P60
, 0x8c, 0x00 },
87 { V4L2_DV_BT_DMT_1024X768P70
, 0x8d, 0x00 },
88 { V4L2_DV_BT_DMT_1024X768P75
, 0x8e, 0x00 },
89 { V4L2_DV_BT_DMT_1024X768P85
, 0x8f, 0x00 },
91 { V4L2_DV_BT_DMT_1600X1200P60
, 0x96, 0x00 },
94 static void adv748x_hdmi_fill_format(struct adv748x_hdmi
*hdmi
,
95 struct v4l2_mbus_framefmt
*fmt
)
97 memset(fmt
, 0, sizeof(*fmt
));
99 fmt
->code
= MEDIA_BUS_FMT_RGB888_1X24
;
100 fmt
->field
= hdmi
->timings
.bt
.interlaced
?
101 V4L2_FIELD_ALTERNATE
: V4L2_FIELD_NONE
;
103 /* TODO: The colorspace depends on the AVI InfoFrame contents */
104 fmt
->colorspace
= V4L2_COLORSPACE_SRGB
;
106 fmt
->width
= hdmi
->timings
.bt
.width
;
107 fmt
->height
= hdmi
->timings
.bt
.height
;
110 static void adv748x_fill_optional_dv_timings(struct v4l2_dv_timings
*timings
)
112 v4l2_find_dv_timings_cap(timings
, &adv748x_hdmi_timings_cap
,
116 static bool adv748x_hdmi_has_signal(struct adv748x_state
*state
)
120 /* Check that VERT_FILTER and DE_REGEN is locked */
121 val
= hdmi_read(state
, ADV748X_HDMI_LW1
);
122 return (val
& ADV748X_HDMI_LW1_VERT_FILTER
) &&
123 (val
& ADV748X_HDMI_LW1_DE_REGEN
);
126 static int adv748x_hdmi_read_pixelclock(struct adv748x_state
*state
)
130 a
= hdmi_read(state
, ADV748X_HDMI_TMDS_1
);
131 b
= hdmi_read(state
, ADV748X_HDMI_TMDS_2
);
136 * The high 9 bits store TMDS frequency measurement in MHz
137 * The low 7 bits of TMDS_2 store the 7-bit TMDS fractional frequency
138 * measurement in 1/128 MHz
140 return ((a
<< 1) | (b
>> 7)) * 1000000 + (b
& 0x7f) * 1000000 / 128;
144 * adv748x_hdmi_set_de_timings: Adjust horizontal picture offset through DE
146 * HDMI CP uses a Data Enable synchronisation timing reference
148 * Vary the leading and trailing edge position of the DE signal output by the CP
149 * core. Values are stored as signed-twos-complement in one-pixel-clock units
151 * The start and end are shifted equally by the 10-bit shift value.
153 static void adv748x_hdmi_set_de_timings(struct adv748x_state
*state
, int shift
)
157 /* POS_HIGH stores bits 8 and 9 of both the start and end */
158 high
= ADV748X_CP_DE_POS_HIGH_SET
;
159 high
|= (shift
& 0x300) >> 8;
162 /* The sequence of the writes is important and must be followed */
163 cp_write(state
, ADV748X_CP_DE_POS_HIGH
, high
);
164 cp_write(state
, ADV748X_CP_DE_POS_END_LOW
, low
);
166 high
|= (shift
& 0x300) >> 6;
168 cp_write(state
, ADV748X_CP_DE_POS_HIGH
, high
);
169 cp_write(state
, ADV748X_CP_DE_POS_START_LOW
, low
);
172 static int adv748x_hdmi_set_video_timings(struct adv748x_state
*state
,
173 const struct v4l2_dv_timings
*timings
)
175 const struct adv748x_hdmi_video_standards
*stds
=
176 adv748x_hdmi_video_standards
;
179 for (i
= 0; i
< ARRAY_SIZE(adv748x_hdmi_video_standards
); i
++) {
180 if (!v4l2_match_dv_timings(timings
, &stds
[i
].timings
, 250000,
185 if (i
>= ARRAY_SIZE(adv748x_hdmi_video_standards
))
189 * When setting cp_vid_std to either 720p, 1080i, or 1080p, the video
190 * will get shifted horizontally to the left in active video mode.
191 * The de_h_start and de_h_end controls are used to centre the picture
194 switch (stds
[i
].vid_std
) {
195 case 0x53: /* 720p */
196 adv748x_hdmi_set_de_timings(state
, -40);
198 case 0x54: /* 1080i */
199 case 0x5e: /* 1080p */
200 adv748x_hdmi_set_de_timings(state
, -44);
203 adv748x_hdmi_set_de_timings(state
, 0);
207 io_write(state
, ADV748X_IO_VID_STD
, stds
[i
].vid_std
);
208 io_clrset(state
, ADV748X_IO_DATAPATH
, ADV748X_IO_DATAPATH_VFREQ_M
,
209 stds
[i
].v_freq
<< ADV748X_IO_DATAPATH_VFREQ_SHIFT
);
214 /* -----------------------------------------------------------------------------
215 * v4l2_subdev_video_ops
218 static int adv748x_hdmi_s_dv_timings(struct v4l2_subdev
*sd
,
219 struct v4l2_dv_timings
*timings
)
221 struct adv748x_hdmi
*hdmi
= adv748x_sd_to_hdmi(sd
);
222 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
228 if (v4l2_match_dv_timings(&hdmi
->timings
, timings
, 0, false))
231 if (!v4l2_valid_dv_timings(timings
, &adv748x_hdmi_timings_cap
,
235 adv748x_fill_optional_dv_timings(timings
);
237 mutex_lock(&state
->mutex
);
239 ret
= adv748x_hdmi_set_video_timings(state
, timings
);
243 hdmi
->timings
= *timings
;
245 cp_clrset(state
, ADV748X_CP_VID_ADJ_2
, ADV748X_CP_VID_ADJ_2_INTERLACED
,
246 timings
->bt
.interlaced
?
247 ADV748X_CP_VID_ADJ_2_INTERLACED
: 0);
249 mutex_unlock(&state
->mutex
);
254 mutex_unlock(&state
->mutex
);
258 static int adv748x_hdmi_g_dv_timings(struct v4l2_subdev
*sd
,
259 struct v4l2_dv_timings
*timings
)
261 struct adv748x_hdmi
*hdmi
= adv748x_sd_to_hdmi(sd
);
262 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
264 mutex_lock(&state
->mutex
);
266 *timings
= hdmi
->timings
;
268 mutex_unlock(&state
->mutex
);
273 static int adv748x_hdmi_query_dv_timings(struct v4l2_subdev
*sd
,
274 struct v4l2_dv_timings
*timings
)
276 struct adv748x_hdmi
*hdmi
= adv748x_sd_to_hdmi(sd
);
277 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
278 struct v4l2_bt_timings
*bt
= &timings
->bt
;
285 memset(timings
, 0, sizeof(struct v4l2_dv_timings
));
287 if (!adv748x_hdmi_has_signal(state
))
290 pixelclock
= adv748x_hdmi_read_pixelclock(state
);
294 timings
->type
= V4L2_DV_BT_656_1120
;
296 bt
->pixelclock
= pixelclock
;
297 bt
->interlaced
= hdmi_read(state
, ADV748X_HDMI_F1H1
) &
298 ADV748X_HDMI_F1H1_INTERLACED
?
299 V4L2_DV_INTERLACED
: V4L2_DV_PROGRESSIVE
;
300 bt
->width
= hdmi_read16(state
, ADV748X_HDMI_LW1
,
301 ADV748X_HDMI_LW1_WIDTH_MASK
);
302 bt
->height
= hdmi_read16(state
, ADV748X_HDMI_F0H1
,
303 ADV748X_HDMI_F0H1_HEIGHT_MASK
);
304 bt
->hfrontporch
= hdmi_read16(state
, ADV748X_HDMI_HFRONT_PORCH
,
305 ADV748X_HDMI_HFRONT_PORCH_MASK
);
306 bt
->hsync
= hdmi_read16(state
, ADV748X_HDMI_HSYNC_WIDTH
,
307 ADV748X_HDMI_HSYNC_WIDTH_MASK
);
308 bt
->hbackporch
= hdmi_read16(state
, ADV748X_HDMI_HBACK_PORCH
,
309 ADV748X_HDMI_HBACK_PORCH_MASK
);
310 bt
->vfrontporch
= hdmi_read16(state
, ADV748X_HDMI_VFRONT_PORCH
,
311 ADV748X_HDMI_VFRONT_PORCH_MASK
) / 2;
312 bt
->vsync
= hdmi_read16(state
, ADV748X_HDMI_VSYNC_WIDTH
,
313 ADV748X_HDMI_VSYNC_WIDTH_MASK
) / 2;
314 bt
->vbackporch
= hdmi_read16(state
, ADV748X_HDMI_VBACK_PORCH
,
315 ADV748X_HDMI_VBACK_PORCH_MASK
) / 2;
317 polarity
= hdmi_read(state
, 0x05);
318 bt
->polarities
= (polarity
& BIT(4) ? V4L2_DV_VSYNC_POS_POL
: 0) |
319 (polarity
& BIT(5) ? V4L2_DV_HSYNC_POS_POL
: 0);
321 if (bt
->interlaced
== V4L2_DV_INTERLACED
) {
322 bt
->height
+= hdmi_read16(state
, 0x0b, 0x1fff);
323 bt
->il_vfrontporch
= hdmi_read16(state
, 0x2c, 0x3fff) / 2;
324 bt
->il_vsync
= hdmi_read16(state
, 0x30, 0x3fff) / 2;
325 bt
->il_vbackporch
= hdmi_read16(state
, 0x34, 0x3fff) / 2;
328 adv748x_fill_optional_dv_timings(timings
);
331 * No interrupt handling is implemented yet.
332 * There should be an IRQ when a cable is plugged and the new timings
333 * should be figured out and stored to state.
335 hdmi
->timings
= *timings
;
340 static int adv748x_hdmi_g_input_status(struct v4l2_subdev
*sd
, u32
*status
)
342 struct adv748x_hdmi
*hdmi
= adv748x_sd_to_hdmi(sd
);
343 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
345 mutex_lock(&state
->mutex
);
347 *status
= adv748x_hdmi_has_signal(state
) ? 0 : V4L2_IN_ST_NO_SIGNAL
;
349 mutex_unlock(&state
->mutex
);
354 static int adv748x_hdmi_s_stream(struct v4l2_subdev
*sd
, int enable
)
356 struct adv748x_hdmi
*hdmi
= adv748x_sd_to_hdmi(sd
);
357 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
360 mutex_lock(&state
->mutex
);
362 ret
= adv748x_txa_power(state
, enable
);
366 if (adv748x_hdmi_has_signal(state
))
367 adv_dbg(state
, "Detected HDMI signal\n");
369 adv_dbg(state
, "Couldn't detect HDMI video signal\n");
372 mutex_unlock(&state
->mutex
);
376 static int adv748x_hdmi_g_pixelaspect(struct v4l2_subdev
*sd
,
377 struct v4l2_fract
*aspect
)
379 aspect
->numerator
= 1;
380 aspect
->denominator
= 1;
385 static const struct v4l2_subdev_video_ops adv748x_video_ops_hdmi
= {
386 .s_dv_timings
= adv748x_hdmi_s_dv_timings
,
387 .g_dv_timings
= adv748x_hdmi_g_dv_timings
,
388 .query_dv_timings
= adv748x_hdmi_query_dv_timings
,
389 .g_input_status
= adv748x_hdmi_g_input_status
,
390 .s_stream
= adv748x_hdmi_s_stream
,
391 .g_pixelaspect
= adv748x_hdmi_g_pixelaspect
,
394 /* -----------------------------------------------------------------------------
395 * v4l2_subdev_pad_ops
398 static int adv748x_hdmi_propagate_pixelrate(struct adv748x_hdmi
*hdmi
)
400 struct v4l2_subdev
*tx
;
401 struct v4l2_dv_timings timings
;
402 struct v4l2_bt_timings
*bt
= &timings
.bt
;
405 tx
= adv748x_get_remote_sd(&hdmi
->pads
[ADV748X_HDMI_SOURCE
]);
409 adv748x_hdmi_query_dv_timings(&hdmi
->sd
, &timings
);
411 fps
= DIV_ROUND_CLOSEST_ULL(bt
->pixelclock
,
412 V4L2_DV_BT_FRAME_WIDTH(bt
) *
413 V4L2_DV_BT_FRAME_HEIGHT(bt
));
415 return adv748x_csi2_set_pixelrate(tx
, bt
->width
* bt
->height
* fps
);
418 static int adv748x_hdmi_enum_mbus_code(struct v4l2_subdev
*sd
,
419 struct v4l2_subdev_pad_config
*cfg
,
420 struct v4l2_subdev_mbus_code_enum
*code
)
422 if (code
->index
!= 0)
425 code
->code
= MEDIA_BUS_FMT_RGB888_1X24
;
430 static int adv748x_hdmi_get_format(struct v4l2_subdev
*sd
,
431 struct v4l2_subdev_pad_config
*cfg
,
432 struct v4l2_subdev_format
*sdformat
)
434 struct adv748x_hdmi
*hdmi
= adv748x_sd_to_hdmi(sd
);
435 struct v4l2_mbus_framefmt
*mbusformat
;
437 if (sdformat
->pad
!= ADV748X_HDMI_SOURCE
)
440 if (sdformat
->which
== V4L2_SUBDEV_FORMAT_TRY
) {
441 mbusformat
= v4l2_subdev_get_try_format(sd
, cfg
, sdformat
->pad
);
442 sdformat
->format
= *mbusformat
;
444 adv748x_hdmi_fill_format(hdmi
, &sdformat
->format
);
445 adv748x_hdmi_propagate_pixelrate(hdmi
);
451 static int adv748x_hdmi_set_format(struct v4l2_subdev
*sd
,
452 struct v4l2_subdev_pad_config
*cfg
,
453 struct v4l2_subdev_format
*sdformat
)
455 struct v4l2_mbus_framefmt
*mbusformat
;
457 if (sdformat
->pad
!= ADV748X_HDMI_SOURCE
)
460 if (sdformat
->which
== V4L2_SUBDEV_FORMAT_ACTIVE
)
461 return adv748x_hdmi_get_format(sd
, cfg
, sdformat
);
463 mbusformat
= v4l2_subdev_get_try_format(sd
, cfg
, sdformat
->pad
);
464 *mbusformat
= sdformat
->format
;
469 static int adv748x_hdmi_get_edid(struct v4l2_subdev
*sd
, struct v4l2_edid
*edid
)
471 struct adv748x_hdmi
*hdmi
= adv748x_sd_to_hdmi(sd
);
473 memset(edid
->reserved
, 0, sizeof(edid
->reserved
));
475 if (!hdmi
->edid
.present
)
478 if (edid
->start_block
== 0 && edid
->blocks
== 0) {
479 edid
->blocks
= hdmi
->edid
.blocks
;
483 if (edid
->start_block
>= hdmi
->edid
.blocks
)
486 if (edid
->start_block
+ edid
->blocks
> hdmi
->edid
.blocks
)
487 edid
->blocks
= hdmi
->edid
.blocks
- edid
->start_block
;
489 memcpy(edid
->edid
, hdmi
->edid
.edid
+ edid
->start_block
* 128,
495 static inline int adv748x_hdmi_edid_write_block(struct adv748x_hdmi
*hdmi
,
496 unsigned int total_len
, const u8
*val
)
498 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
503 adv_dbg(state
, "%s: write EDID block (%d byte)\n",
504 __func__
, total_len
);
506 while (!err
&& i
< total_len
) {
507 len
= (total_len
- i
) > I2C_SMBUS_BLOCK_MAX
?
508 I2C_SMBUS_BLOCK_MAX
:
511 err
= adv748x_write_block(state
, ADV748X_PAGE_EDID
,
519 static int adv748x_hdmi_set_edid(struct v4l2_subdev
*sd
, struct v4l2_edid
*edid
)
521 struct adv748x_hdmi
*hdmi
= adv748x_sd_to_hdmi(sd
);
522 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
525 memset(edid
->reserved
, 0, sizeof(edid
->reserved
));
527 if (edid
->start_block
!= 0)
530 if (edid
->blocks
== 0) {
531 hdmi
->edid
.blocks
= 0;
532 hdmi
->edid
.present
= 0;
534 /* Fall back to a 16:9 aspect ratio */
535 hdmi
->aspect_ratio
.numerator
= 16;
536 hdmi
->aspect_ratio
.denominator
= 9;
538 /* Disable the EDID */
539 repeater_write(state
, ADV748X_REPEATER_EDID_SZ
,
540 edid
->blocks
<< ADV748X_REPEATER_EDID_SZ_SHIFT
);
542 repeater_write(state
, ADV748X_REPEATER_EDID_CTL
, 0);
547 if (edid
->blocks
> 4) {
552 memcpy(hdmi
->edid
.edid
, edid
->edid
, 128 * edid
->blocks
);
553 hdmi
->edid
.blocks
= edid
->blocks
;
554 hdmi
->edid
.present
= true;
556 hdmi
->aspect_ratio
= v4l2_calc_aspect_ratio(edid
->edid
[0x15],
559 err
= adv748x_hdmi_edid_write_block(hdmi
, 128 * edid
->blocks
,
562 v4l2_err(sd
, "error %d writing edid pad %d\n", err
, edid
->pad
);
566 repeater_write(state
, ADV748X_REPEATER_EDID_SZ
,
567 edid
->blocks
<< ADV748X_REPEATER_EDID_SZ_SHIFT
);
569 repeater_write(state
, ADV748X_REPEATER_EDID_CTL
,
570 ADV748X_REPEATER_EDID_CTL_EN
);
575 static bool adv748x_hdmi_check_dv_timings(const struct v4l2_dv_timings
*timings
,
578 const struct adv748x_hdmi_video_standards
*stds
=
579 adv748x_hdmi_video_standards
;
582 for (i
= 0; stds
[i
].timings
.bt
.width
; i
++)
583 if (v4l2_match_dv_timings(timings
, &stds
[i
].timings
, 0, false))
589 static int adv748x_hdmi_enum_dv_timings(struct v4l2_subdev
*sd
,
590 struct v4l2_enum_dv_timings
*timings
)
592 return v4l2_enum_dv_timings_cap(timings
, &adv748x_hdmi_timings_cap
,
593 adv748x_hdmi_check_dv_timings
, NULL
);
596 static int adv748x_hdmi_dv_timings_cap(struct v4l2_subdev
*sd
,
597 struct v4l2_dv_timings_cap
*cap
)
599 *cap
= adv748x_hdmi_timings_cap
;
603 static const struct v4l2_subdev_pad_ops adv748x_pad_ops_hdmi
= {
604 .enum_mbus_code
= adv748x_hdmi_enum_mbus_code
,
605 .set_fmt
= adv748x_hdmi_set_format
,
606 .get_fmt
= adv748x_hdmi_get_format
,
607 .get_edid
= adv748x_hdmi_get_edid
,
608 .set_edid
= adv748x_hdmi_set_edid
,
609 .dv_timings_cap
= adv748x_hdmi_dv_timings_cap
,
610 .enum_dv_timings
= adv748x_hdmi_enum_dv_timings
,
613 /* -----------------------------------------------------------------------------
617 static const struct v4l2_subdev_ops adv748x_ops_hdmi
= {
618 .video
= &adv748x_video_ops_hdmi
,
619 .pad
= &adv748x_pad_ops_hdmi
,
622 /* -----------------------------------------------------------------------------
626 static const char * const hdmi_ctrl_patgen_menu
[] = {
636 static int adv748x_hdmi_s_ctrl(struct v4l2_ctrl
*ctrl
)
638 struct adv748x_hdmi
*hdmi
= adv748x_ctrl_to_hdmi(ctrl
);
639 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
643 /* Enable video adjustment first */
644 ret
= cp_clrset(state
, ADV748X_CP_VID_ADJ
,
645 ADV748X_CP_VID_ADJ_ENABLE
,
646 ADV748X_CP_VID_ADJ_ENABLE
);
651 case V4L2_CID_BRIGHTNESS
:
652 ret
= cp_write(state
, ADV748X_CP_BRI
, ctrl
->val
);
655 ret
= cp_write(state
, ADV748X_CP_HUE
, ctrl
->val
);
657 case V4L2_CID_CONTRAST
:
658 ret
= cp_write(state
, ADV748X_CP_CON
, ctrl
->val
);
660 case V4L2_CID_SATURATION
:
661 ret
= cp_write(state
, ADV748X_CP_SAT
, ctrl
->val
);
663 case V4L2_CID_TEST_PATTERN
:
666 /* Pattern is 0-indexed. Ctrl Menu is 1-indexed */
669 pattern
|= ADV748X_CP_PAT_GEN_EN
;
672 ret
= cp_write(state
, ADV748X_CP_PAT_GEN
, pattern
);
682 static const struct v4l2_ctrl_ops adv748x_hdmi_ctrl_ops
= {
683 .s_ctrl
= adv748x_hdmi_s_ctrl
,
686 static int adv748x_hdmi_init_controls(struct adv748x_hdmi
*hdmi
)
688 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
690 v4l2_ctrl_handler_init(&hdmi
->ctrl_hdl
, 5);
692 /* Use our mutex for the controls */
693 hdmi
->ctrl_hdl
.lock
= &state
->mutex
;
695 v4l2_ctrl_new_std(&hdmi
->ctrl_hdl
, &adv748x_hdmi_ctrl_ops
,
696 V4L2_CID_BRIGHTNESS
, ADV748X_CP_BRI_MIN
,
697 ADV748X_CP_BRI_MAX
, 1, ADV748X_CP_BRI_DEF
);
698 v4l2_ctrl_new_std(&hdmi
->ctrl_hdl
, &adv748x_hdmi_ctrl_ops
,
699 V4L2_CID_CONTRAST
, ADV748X_CP_CON_MIN
,
700 ADV748X_CP_CON_MAX
, 1, ADV748X_CP_CON_DEF
);
701 v4l2_ctrl_new_std(&hdmi
->ctrl_hdl
, &adv748x_hdmi_ctrl_ops
,
702 V4L2_CID_SATURATION
, ADV748X_CP_SAT_MIN
,
703 ADV748X_CP_SAT_MAX
, 1, ADV748X_CP_SAT_DEF
);
704 v4l2_ctrl_new_std(&hdmi
->ctrl_hdl
, &adv748x_hdmi_ctrl_ops
,
705 V4L2_CID_HUE
, ADV748X_CP_HUE_MIN
,
706 ADV748X_CP_HUE_MAX
, 1, ADV748X_CP_HUE_DEF
);
709 * Todo: V4L2_CID_DV_RX_POWER_PRESENT should also be supported when
710 * interrupts are handled correctly
713 v4l2_ctrl_new_std_menu_items(&hdmi
->ctrl_hdl
, &adv748x_hdmi_ctrl_ops
,
714 V4L2_CID_TEST_PATTERN
,
715 ARRAY_SIZE(hdmi_ctrl_patgen_menu
) - 1,
716 0, 0, hdmi_ctrl_patgen_menu
);
718 hdmi
->sd
.ctrl_handler
= &hdmi
->ctrl_hdl
;
719 if (hdmi
->ctrl_hdl
.error
) {
720 v4l2_ctrl_handler_free(&hdmi
->ctrl_hdl
);
721 return hdmi
->ctrl_hdl
.error
;
724 return v4l2_ctrl_handler_setup(&hdmi
->ctrl_hdl
);
727 int adv748x_hdmi_init(struct adv748x_hdmi
*hdmi
)
729 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
730 static const struct v4l2_dv_timings cea1280x720
=
731 V4L2_DV_BT_CEA_1280X720P30
;
734 hdmi
->timings
= cea1280x720
;
736 /* Initialise a default 16:9 aspect ratio */
737 hdmi
->aspect_ratio
.numerator
= 16;
738 hdmi
->aspect_ratio
.denominator
= 9;
740 adv748x_subdev_init(&hdmi
->sd
, state
, &adv748x_ops_hdmi
,
741 MEDIA_ENT_F_IO_DTV
, "hdmi");
743 hdmi
->pads
[ADV748X_HDMI_SINK
].flags
= MEDIA_PAD_FL_SINK
;
744 hdmi
->pads
[ADV748X_HDMI_SOURCE
].flags
= MEDIA_PAD_FL_SOURCE
;
746 ret
= media_entity_pads_init(&hdmi
->sd
.entity
,
747 ADV748X_HDMI_NR_PADS
, hdmi
->pads
);
751 ret
= adv748x_hdmi_init_controls(hdmi
);
758 media_entity_cleanup(&hdmi
->sd
.entity
);
763 void adv748x_hdmi_cleanup(struct adv748x_hdmi
*hdmi
)
765 v4l2_device_unregister_subdev(&hdmi
->sd
);
766 media_entity_cleanup(&hdmi
->sd
.entity
);
767 v4l2_ctrl_handler_free(&hdmi
->ctrl_hdl
);