1 // SPDX-License-Identifier: GPL-2.0+
3 * Driver for Analog Devices ADV748X HDMI receiver and Component Processor (CP)
5 * Copyright (C) 2017 Renesas Electronics Corp.
8 #include <linux/module.h>
9 #include <linux/mutex.h>
11 #include <media/v4l2-ctrls.h>
12 #include <media/v4l2-device.h>
13 #include <media/v4l2-dv-timings.h>
14 #include <media/v4l2-ioctl.h>
16 #include <uapi/linux/v4l2-dv-timings.h>
20 /* -----------------------------------------------------------------------------
24 #define ADV748X_HDMI_MIN_WIDTH 640
25 #define ADV748X_HDMI_MAX_WIDTH 1920
26 #define ADV748X_HDMI_MIN_HEIGHT 480
27 #define ADV748X_HDMI_MAX_HEIGHT 1200
29 /* V4L2_DV_BT_CEA_720X480I59_94 - 0.5 MHz */
30 #define ADV748X_HDMI_MIN_PIXELCLOCK 13000000
31 /* V4L2_DV_BT_DMT_1600X1200P60 */
32 #define ADV748X_HDMI_MAX_PIXELCLOCK 162000000
34 static const struct v4l2_dv_timings_cap adv748x_hdmi_timings_cap
= {
35 .type
= V4L2_DV_BT_656_1120
,
36 /* keep this initialization for compatibility with GCC < 4.4.6 */
39 V4L2_INIT_BT_TIMINGS(ADV748X_HDMI_MIN_WIDTH
, ADV748X_HDMI_MAX_WIDTH
,
40 ADV748X_HDMI_MIN_HEIGHT
, ADV748X_HDMI_MAX_HEIGHT
,
41 ADV748X_HDMI_MIN_PIXELCLOCK
,
42 ADV748X_HDMI_MAX_PIXELCLOCK
,
43 V4L2_DV_BT_STD_CEA861
| V4L2_DV_BT_STD_DMT
,
44 V4L2_DV_BT_CAP_PROGRESSIVE
)
47 struct adv748x_hdmi_video_standards
{
48 struct v4l2_dv_timings timings
;
53 static const struct adv748x_hdmi_video_standards
54 adv748x_hdmi_video_standards
[] = {
55 { V4L2_DV_BT_CEA_720X480P59_94
, 0x4a, 0x00 },
56 { V4L2_DV_BT_CEA_720X576P50
, 0x4b, 0x00 },
57 { V4L2_DV_BT_CEA_1280X720P60
, 0x53, 0x00 },
58 { V4L2_DV_BT_CEA_1280X720P50
, 0x53, 0x01 },
59 { V4L2_DV_BT_CEA_1280X720P30
, 0x53, 0x02 },
60 { V4L2_DV_BT_CEA_1280X720P25
, 0x53, 0x03 },
61 { V4L2_DV_BT_CEA_1280X720P24
, 0x53, 0x04 },
62 { V4L2_DV_BT_CEA_1920X1080P60
, 0x5e, 0x00 },
63 { V4L2_DV_BT_CEA_1920X1080P50
, 0x5e, 0x01 },
64 { V4L2_DV_BT_CEA_1920X1080P30
, 0x5e, 0x02 },
65 { V4L2_DV_BT_CEA_1920X1080P25
, 0x5e, 0x03 },
66 { V4L2_DV_BT_CEA_1920X1080P24
, 0x5e, 0x04 },
68 { V4L2_DV_BT_DMT_800X600P56
, 0x80, 0x00 },
69 { V4L2_DV_BT_DMT_800X600P60
, 0x81, 0x00 },
70 { V4L2_DV_BT_DMT_800X600P72
, 0x82, 0x00 },
71 { V4L2_DV_BT_DMT_800X600P75
, 0x83, 0x00 },
72 { V4L2_DV_BT_DMT_800X600P85
, 0x84, 0x00 },
74 { V4L2_DV_BT_DMT_1280X1024P60
, 0x85, 0x00 },
75 { V4L2_DV_BT_DMT_1280X1024P75
, 0x86, 0x00 },
77 { V4L2_DV_BT_DMT_640X480P60
, 0x88, 0x00 },
78 { V4L2_DV_BT_DMT_640X480P72
, 0x89, 0x00 },
79 { V4L2_DV_BT_DMT_640X480P75
, 0x8a, 0x00 },
80 { V4L2_DV_BT_DMT_640X480P85
, 0x8b, 0x00 },
82 { V4L2_DV_BT_DMT_1024X768P60
, 0x8c, 0x00 },
83 { V4L2_DV_BT_DMT_1024X768P70
, 0x8d, 0x00 },
84 { V4L2_DV_BT_DMT_1024X768P75
, 0x8e, 0x00 },
85 { V4L2_DV_BT_DMT_1024X768P85
, 0x8f, 0x00 },
87 { V4L2_DV_BT_DMT_1600X1200P60
, 0x96, 0x00 },
90 static void adv748x_hdmi_fill_format(struct adv748x_hdmi
*hdmi
,
91 struct v4l2_mbus_framefmt
*fmt
)
93 memset(fmt
, 0, sizeof(*fmt
));
95 fmt
->code
= MEDIA_BUS_FMT_RGB888_1X24
;
96 fmt
->field
= hdmi
->timings
.bt
.interlaced
?
97 V4L2_FIELD_ALTERNATE
: V4L2_FIELD_NONE
;
99 /* TODO: The colorspace depends on the AVI InfoFrame contents */
100 fmt
->colorspace
= V4L2_COLORSPACE_SRGB
;
102 fmt
->width
= hdmi
->timings
.bt
.width
;
103 fmt
->height
= hdmi
->timings
.bt
.height
;
105 if (fmt
->field
== V4L2_FIELD_ALTERNATE
)
109 static void adv748x_fill_optional_dv_timings(struct v4l2_dv_timings
*timings
)
111 v4l2_find_dv_timings_cap(timings
, &adv748x_hdmi_timings_cap
,
115 static bool adv748x_hdmi_has_signal(struct adv748x_state
*state
)
119 /* Check that VERT_FILTER and DE_REGEN is locked */
120 val
= hdmi_read(state
, ADV748X_HDMI_LW1
);
121 return (val
& ADV748X_HDMI_LW1_VERT_FILTER
) &&
122 (val
& ADV748X_HDMI_LW1_DE_REGEN
);
125 static int adv748x_hdmi_read_pixelclock(struct adv748x_state
*state
)
129 a
= hdmi_read(state
, ADV748X_HDMI_TMDS_1
);
130 b
= hdmi_read(state
, ADV748X_HDMI_TMDS_2
);
135 * The high 9 bits store TMDS frequency measurement in MHz
136 * The low 7 bits of TMDS_2 store the 7-bit TMDS fractional frequency
137 * measurement in 1/128 MHz
139 return ((a
<< 1) | (b
>> 7)) * 1000000 + (b
& 0x7f) * 1000000 / 128;
143 * adv748x_hdmi_set_de_timings: Adjust horizontal picture offset through DE
145 * HDMI CP uses a Data Enable synchronisation timing reference
147 * Vary the leading and trailing edge position of the DE signal output by the CP
148 * core. Values are stored as signed-twos-complement in one-pixel-clock units
150 * The start and end are shifted equally by the 10-bit shift value.
152 static void adv748x_hdmi_set_de_timings(struct adv748x_state
*state
, int shift
)
156 /* POS_HIGH stores bits 8 and 9 of both the start and end */
157 high
= ADV748X_CP_DE_POS_HIGH_SET
;
158 high
|= (shift
& 0x300) >> 8;
161 /* The sequence of the writes is important and must be followed */
162 cp_write(state
, ADV748X_CP_DE_POS_HIGH
, high
);
163 cp_write(state
, ADV748X_CP_DE_POS_END_LOW
, low
);
165 high
|= (shift
& 0x300) >> 6;
167 cp_write(state
, ADV748X_CP_DE_POS_HIGH
, high
);
168 cp_write(state
, ADV748X_CP_DE_POS_START_LOW
, low
);
171 static int adv748x_hdmi_set_video_timings(struct adv748x_state
*state
,
172 const struct v4l2_dv_timings
*timings
)
174 const struct adv748x_hdmi_video_standards
*stds
=
175 adv748x_hdmi_video_standards
;
178 for (i
= 0; i
< ARRAY_SIZE(adv748x_hdmi_video_standards
); i
++) {
179 if (v4l2_match_dv_timings(timings
, &stds
[i
].timings
, 250000,
184 if (i
>= ARRAY_SIZE(adv748x_hdmi_video_standards
))
188 * When setting cp_vid_std to either 720p, 1080i, or 1080p, the video
189 * will get shifted horizontally to the left in active video mode.
190 * The de_h_start and de_h_end controls are used to centre the picture
193 switch (stds
[i
].vid_std
) {
194 case 0x53: /* 720p */
195 adv748x_hdmi_set_de_timings(state
, -40);
197 case 0x54: /* 1080i */
198 case 0x5e: /* 1080p */
199 adv748x_hdmi_set_de_timings(state
, -44);
202 adv748x_hdmi_set_de_timings(state
, 0);
206 io_write(state
, ADV748X_IO_VID_STD
, stds
[i
].vid_std
);
207 io_clrset(state
, ADV748X_IO_DATAPATH
, ADV748X_IO_DATAPATH_VFREQ_M
,
208 stds
[i
].v_freq
<< ADV748X_IO_DATAPATH_VFREQ_SHIFT
);
213 /* -----------------------------------------------------------------------------
214 * v4l2_subdev_video_ops
217 static int adv748x_hdmi_s_dv_timings(struct v4l2_subdev
*sd
, unsigned int pad
,
218 struct v4l2_dv_timings
*timings
)
220 struct adv748x_hdmi
*hdmi
= adv748x_sd_to_hdmi(sd
);
221 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
227 if (v4l2_match_dv_timings(&hdmi
->timings
, timings
, 0, false))
230 if (!v4l2_valid_dv_timings(timings
, &adv748x_hdmi_timings_cap
,
234 adv748x_fill_optional_dv_timings(timings
);
236 mutex_lock(&state
->mutex
);
238 ret
= adv748x_hdmi_set_video_timings(state
, timings
);
242 hdmi
->timings
= *timings
;
244 cp_clrset(state
, ADV748X_CP_VID_ADJ_2
, ADV748X_CP_VID_ADJ_2_INTERLACED
,
245 timings
->bt
.interlaced
?
246 ADV748X_CP_VID_ADJ_2_INTERLACED
: 0);
248 mutex_unlock(&state
->mutex
);
253 mutex_unlock(&state
->mutex
);
257 static int adv748x_hdmi_g_dv_timings(struct v4l2_subdev
*sd
, unsigned int pad
,
258 struct v4l2_dv_timings
*timings
)
260 struct adv748x_hdmi
*hdmi
= adv748x_sd_to_hdmi(sd
);
261 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
263 mutex_lock(&state
->mutex
);
265 *timings
= hdmi
->timings
;
267 mutex_unlock(&state
->mutex
);
272 static int adv748x_hdmi_query_dv_timings(struct v4l2_subdev
*sd
, unsigned int pad
,
273 struct v4l2_dv_timings
*timings
)
275 struct adv748x_hdmi
*hdmi
= adv748x_sd_to_hdmi(sd
);
276 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
277 struct v4l2_bt_timings
*bt
= &timings
->bt
;
284 memset(timings
, 0, sizeof(struct v4l2_dv_timings
));
287 * If the pattern generator is enabled the device shall not be queried
288 * for timings. Instead the timings programmed shall be reported as they
289 * are the ones being used to generate the pattern.
291 if (cp_read(state
, ADV748X_CP_PAT_GEN
) & ADV748X_CP_PAT_GEN_EN
) {
292 *timings
= hdmi
->timings
;
296 if (!adv748x_hdmi_has_signal(state
))
299 pixelclock
= adv748x_hdmi_read_pixelclock(state
);
303 timings
->type
= V4L2_DV_BT_656_1120
;
305 bt
->pixelclock
= pixelclock
;
306 bt
->interlaced
= hdmi_read(state
, ADV748X_HDMI_F1H1
) &
307 ADV748X_HDMI_F1H1_INTERLACED
?
308 V4L2_DV_INTERLACED
: V4L2_DV_PROGRESSIVE
;
309 bt
->width
= hdmi_read16(state
, ADV748X_HDMI_LW1
,
310 ADV748X_HDMI_LW1_WIDTH_MASK
);
311 bt
->height
= hdmi_read16(state
, ADV748X_HDMI_F0H1
,
312 ADV748X_HDMI_F0H1_HEIGHT_MASK
);
313 bt
->hfrontporch
= hdmi_read16(state
, ADV748X_HDMI_HFRONT_PORCH
,
314 ADV748X_HDMI_HFRONT_PORCH_MASK
);
315 bt
->hsync
= hdmi_read16(state
, ADV748X_HDMI_HSYNC_WIDTH
,
316 ADV748X_HDMI_HSYNC_WIDTH_MASK
);
317 bt
->hbackporch
= hdmi_read16(state
, ADV748X_HDMI_HBACK_PORCH
,
318 ADV748X_HDMI_HBACK_PORCH_MASK
);
319 bt
->vfrontporch
= hdmi_read16(state
, ADV748X_HDMI_VFRONT_PORCH
,
320 ADV748X_HDMI_VFRONT_PORCH_MASK
) / 2;
321 bt
->vsync
= hdmi_read16(state
, ADV748X_HDMI_VSYNC_WIDTH
,
322 ADV748X_HDMI_VSYNC_WIDTH_MASK
) / 2;
323 bt
->vbackporch
= hdmi_read16(state
, ADV748X_HDMI_VBACK_PORCH
,
324 ADV748X_HDMI_VBACK_PORCH_MASK
) / 2;
326 polarity
= hdmi_read(state
, 0x05);
327 bt
->polarities
= (polarity
& BIT(4) ? V4L2_DV_VSYNC_POS_POL
: 0) |
328 (polarity
& BIT(5) ? V4L2_DV_HSYNC_POS_POL
: 0);
330 if (bt
->interlaced
== V4L2_DV_INTERLACED
) {
331 bt
->height
+= hdmi_read16(state
, 0x0b, 0x1fff);
332 bt
->il_vfrontporch
= hdmi_read16(state
, 0x2c, 0x3fff) / 2;
333 bt
->il_vsync
= hdmi_read16(state
, 0x30, 0x3fff) / 2;
334 bt
->il_vbackporch
= hdmi_read16(state
, 0x34, 0x3fff) / 2;
337 adv748x_fill_optional_dv_timings(timings
);
340 * No interrupt handling is implemented yet.
341 * There should be an IRQ when a cable is plugged and the new timings
342 * should be figured out and stored to state.
344 hdmi
->timings
= *timings
;
349 static int adv748x_hdmi_g_input_status(struct v4l2_subdev
*sd
, u32
*status
)
351 struct adv748x_hdmi
*hdmi
= adv748x_sd_to_hdmi(sd
);
352 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
354 mutex_lock(&state
->mutex
);
356 *status
= adv748x_hdmi_has_signal(state
) ? 0 : V4L2_IN_ST_NO_SIGNAL
;
358 mutex_unlock(&state
->mutex
);
363 static int adv748x_hdmi_s_stream(struct v4l2_subdev
*sd
, int enable
)
365 struct adv748x_hdmi
*hdmi
= adv748x_sd_to_hdmi(sd
);
366 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
369 mutex_lock(&state
->mutex
);
371 ret
= adv748x_tx_power(hdmi
->tx
, enable
);
375 if (adv748x_hdmi_has_signal(state
))
376 adv_dbg(state
, "Detected HDMI signal\n");
378 adv_dbg(state
, "Couldn't detect HDMI video signal\n");
381 mutex_unlock(&state
->mutex
);
385 static int adv748x_hdmi_g_pixelaspect(struct v4l2_subdev
*sd
,
386 struct v4l2_fract
*aspect
)
388 aspect
->numerator
= 1;
389 aspect
->denominator
= 1;
394 static const struct v4l2_subdev_video_ops adv748x_video_ops_hdmi
= {
395 .g_input_status
= adv748x_hdmi_g_input_status
,
396 .s_stream
= adv748x_hdmi_s_stream
,
397 .g_pixelaspect
= adv748x_hdmi_g_pixelaspect
,
400 /* -----------------------------------------------------------------------------
401 * v4l2_subdev_pad_ops
404 static int adv748x_hdmi_propagate_pixelrate(struct adv748x_hdmi
*hdmi
)
406 struct v4l2_subdev
*tx
;
407 struct v4l2_dv_timings timings
;
409 tx
= adv748x_get_remote_sd(&hdmi
->pads
[ADV748X_HDMI_SOURCE
]);
413 adv748x_hdmi_query_dv_timings(&hdmi
->sd
, 0, &timings
);
415 return adv748x_csi2_set_pixelrate(tx
, timings
.bt
.pixelclock
);
418 static int adv748x_hdmi_enum_mbus_code(struct v4l2_subdev
*sd
,
419 struct v4l2_subdev_state
*sd_state
,
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_state
*sd_state
,
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_state_get_format(sd_state
,
443 sdformat
->format
= *mbusformat
;
445 adv748x_hdmi_fill_format(hdmi
, &sdformat
->format
);
446 adv748x_hdmi_propagate_pixelrate(hdmi
);
452 static int adv748x_hdmi_set_format(struct v4l2_subdev
*sd
,
453 struct v4l2_subdev_state
*sd_state
,
454 struct v4l2_subdev_format
*sdformat
)
456 struct v4l2_mbus_framefmt
*mbusformat
;
458 if (sdformat
->pad
!= ADV748X_HDMI_SOURCE
)
461 if (sdformat
->which
== V4L2_SUBDEV_FORMAT_ACTIVE
)
462 return adv748x_hdmi_get_format(sd
, sd_state
, sdformat
);
464 mbusformat
= v4l2_subdev_state_get_format(sd_state
, sdformat
->pad
);
465 *mbusformat
= sdformat
->format
;
470 static int adv748x_hdmi_get_edid(struct v4l2_subdev
*sd
, struct v4l2_edid
*edid
)
472 struct adv748x_hdmi
*hdmi
= adv748x_sd_to_hdmi(sd
);
474 memset(edid
->reserved
, 0, sizeof(edid
->reserved
));
476 if (!hdmi
->edid
.present
)
479 if (edid
->start_block
== 0 && edid
->blocks
== 0) {
480 edid
->blocks
= hdmi
->edid
.blocks
;
484 if (edid
->start_block
>= hdmi
->edid
.blocks
)
487 if (edid
->start_block
+ edid
->blocks
> hdmi
->edid
.blocks
)
488 edid
->blocks
= hdmi
->edid
.blocks
- edid
->start_block
;
490 memcpy(edid
->edid
, hdmi
->edid
.edid
+ edid
->start_block
* 128,
496 static inline int adv748x_hdmi_edid_write_block(struct adv748x_hdmi
*hdmi
,
497 unsigned int total_len
, const u8
*val
)
499 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
504 adv_dbg(state
, "%s: write EDID block (%d byte)\n",
505 __func__
, total_len
);
507 while (!err
&& i
< total_len
) {
508 len
= (total_len
- i
) > I2C_SMBUS_BLOCK_MAX
?
509 I2C_SMBUS_BLOCK_MAX
:
512 err
= adv748x_write_block(state
, ADV748X_PAGE_EDID
,
520 static int adv748x_hdmi_set_edid(struct v4l2_subdev
*sd
, struct v4l2_edid
*edid
)
522 struct adv748x_hdmi
*hdmi
= adv748x_sd_to_hdmi(sd
);
523 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
526 memset(edid
->reserved
, 0, sizeof(edid
->reserved
));
528 if (edid
->start_block
!= 0)
531 if (edid
->blocks
== 0) {
532 hdmi
->edid
.blocks
= 0;
533 hdmi
->edid
.present
= 0;
535 /* Fall back to a 16:9 aspect ratio */
536 hdmi
->aspect_ratio
.numerator
= 16;
537 hdmi
->aspect_ratio
.denominator
= 9;
539 /* Disable the EDID */
540 repeater_write(state
, ADV748X_REPEATER_EDID_SZ
,
541 edid
->blocks
<< ADV748X_REPEATER_EDID_SZ_SHIFT
);
543 repeater_write(state
, ADV748X_REPEATER_EDID_CTL
, 0);
548 if (edid
->blocks
> 4) {
553 memcpy(hdmi
->edid
.edid
, edid
->edid
, 128 * edid
->blocks
);
554 hdmi
->edid
.blocks
= edid
->blocks
;
555 hdmi
->edid
.present
= true;
557 hdmi
->aspect_ratio
= v4l2_calc_aspect_ratio(edid
->edid
[0x15],
560 err
= adv748x_hdmi_edid_write_block(hdmi
, 128 * edid
->blocks
,
563 v4l2_err(sd
, "error %d writing edid pad %d\n", err
, edid
->pad
);
567 repeater_write(state
, ADV748X_REPEATER_EDID_SZ
,
568 edid
->blocks
<< ADV748X_REPEATER_EDID_SZ_SHIFT
);
570 repeater_write(state
, ADV748X_REPEATER_EDID_CTL
,
571 ADV748X_REPEATER_EDID_CTL_EN
);
576 static bool adv748x_hdmi_check_dv_timings(const struct v4l2_dv_timings
*timings
,
579 const struct adv748x_hdmi_video_standards
*stds
=
580 adv748x_hdmi_video_standards
;
583 for (i
= 0; stds
[i
].timings
.bt
.width
; i
++)
584 if (v4l2_match_dv_timings(timings
, &stds
[i
].timings
, 0, false))
590 static int adv748x_hdmi_enum_dv_timings(struct v4l2_subdev
*sd
,
591 struct v4l2_enum_dv_timings
*timings
)
593 return v4l2_enum_dv_timings_cap(timings
, &adv748x_hdmi_timings_cap
,
594 adv748x_hdmi_check_dv_timings
, NULL
);
597 static int adv748x_hdmi_dv_timings_cap(struct v4l2_subdev
*sd
,
598 struct v4l2_dv_timings_cap
*cap
)
600 *cap
= adv748x_hdmi_timings_cap
;
604 static const struct v4l2_subdev_pad_ops adv748x_pad_ops_hdmi
= {
605 .enum_mbus_code
= adv748x_hdmi_enum_mbus_code
,
606 .set_fmt
= adv748x_hdmi_set_format
,
607 .get_fmt
= adv748x_hdmi_get_format
,
608 .get_edid
= adv748x_hdmi_get_edid
,
609 .set_edid
= adv748x_hdmi_set_edid
,
610 .s_dv_timings
= adv748x_hdmi_s_dv_timings
,
611 .g_dv_timings
= adv748x_hdmi_g_dv_timings
,
612 .query_dv_timings
= adv748x_hdmi_query_dv_timings
,
613 .dv_timings_cap
= adv748x_hdmi_dv_timings_cap
,
614 .enum_dv_timings
= adv748x_hdmi_enum_dv_timings
,
617 /* -----------------------------------------------------------------------------
621 static const struct v4l2_subdev_ops adv748x_ops_hdmi
= {
622 .video
= &adv748x_video_ops_hdmi
,
623 .pad
= &adv748x_pad_ops_hdmi
,
626 /* -----------------------------------------------------------------------------
630 static const char * const hdmi_ctrl_patgen_menu
[] = {
640 static int adv748x_hdmi_s_ctrl(struct v4l2_ctrl
*ctrl
)
642 struct adv748x_hdmi
*hdmi
= adv748x_ctrl_to_hdmi(ctrl
);
643 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
647 /* Enable video adjustment first */
648 ret
= cp_clrset(state
, ADV748X_CP_VID_ADJ
,
649 ADV748X_CP_VID_ADJ_ENABLE
,
650 ADV748X_CP_VID_ADJ_ENABLE
);
655 case V4L2_CID_BRIGHTNESS
:
656 ret
= cp_write(state
, ADV748X_CP_BRI
, ctrl
->val
);
659 ret
= cp_write(state
, ADV748X_CP_HUE
, ctrl
->val
);
661 case V4L2_CID_CONTRAST
:
662 ret
= cp_write(state
, ADV748X_CP_CON
, ctrl
->val
);
664 case V4L2_CID_SATURATION
:
665 ret
= cp_write(state
, ADV748X_CP_SAT
, ctrl
->val
);
667 case V4L2_CID_TEST_PATTERN
:
670 /* Pattern is 0-indexed. Ctrl Menu is 1-indexed */
673 pattern
|= ADV748X_CP_PAT_GEN_EN
;
676 ret
= cp_write(state
, ADV748X_CP_PAT_GEN
, pattern
);
686 static const struct v4l2_ctrl_ops adv748x_hdmi_ctrl_ops
= {
687 .s_ctrl
= adv748x_hdmi_s_ctrl
,
690 static int adv748x_hdmi_init_controls(struct adv748x_hdmi
*hdmi
)
692 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
694 v4l2_ctrl_handler_init(&hdmi
->ctrl_hdl
, 5);
696 /* Use our mutex for the controls */
697 hdmi
->ctrl_hdl
.lock
= &state
->mutex
;
699 v4l2_ctrl_new_std(&hdmi
->ctrl_hdl
, &adv748x_hdmi_ctrl_ops
,
700 V4L2_CID_BRIGHTNESS
, ADV748X_CP_BRI_MIN
,
701 ADV748X_CP_BRI_MAX
, 1, ADV748X_CP_BRI_DEF
);
702 v4l2_ctrl_new_std(&hdmi
->ctrl_hdl
, &adv748x_hdmi_ctrl_ops
,
703 V4L2_CID_CONTRAST
, ADV748X_CP_CON_MIN
,
704 ADV748X_CP_CON_MAX
, 1, ADV748X_CP_CON_DEF
);
705 v4l2_ctrl_new_std(&hdmi
->ctrl_hdl
, &adv748x_hdmi_ctrl_ops
,
706 V4L2_CID_SATURATION
, ADV748X_CP_SAT_MIN
,
707 ADV748X_CP_SAT_MAX
, 1, ADV748X_CP_SAT_DEF
);
708 v4l2_ctrl_new_std(&hdmi
->ctrl_hdl
, &adv748x_hdmi_ctrl_ops
,
709 V4L2_CID_HUE
, ADV748X_CP_HUE_MIN
,
710 ADV748X_CP_HUE_MAX
, 1, ADV748X_CP_HUE_DEF
);
713 * Todo: V4L2_CID_DV_RX_POWER_PRESENT should also be supported when
714 * interrupts are handled correctly
717 v4l2_ctrl_new_std_menu_items(&hdmi
->ctrl_hdl
, &adv748x_hdmi_ctrl_ops
,
718 V4L2_CID_TEST_PATTERN
,
719 ARRAY_SIZE(hdmi_ctrl_patgen_menu
) - 1,
720 0, 0, hdmi_ctrl_patgen_menu
);
722 hdmi
->sd
.ctrl_handler
= &hdmi
->ctrl_hdl
;
723 if (hdmi
->ctrl_hdl
.error
) {
724 v4l2_ctrl_handler_free(&hdmi
->ctrl_hdl
);
725 return hdmi
->ctrl_hdl
.error
;
728 return v4l2_ctrl_handler_setup(&hdmi
->ctrl_hdl
);
731 int adv748x_hdmi_init(struct adv748x_hdmi
*hdmi
)
733 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
734 struct v4l2_dv_timings cea1280x720
= V4L2_DV_BT_CEA_1280X720P30
;
737 adv748x_hdmi_s_dv_timings(&hdmi
->sd
, 0, &cea1280x720
);
739 /* Initialise a default 16:9 aspect ratio */
740 hdmi
->aspect_ratio
.numerator
= 16;
741 hdmi
->aspect_ratio
.denominator
= 9;
743 adv748x_subdev_init(&hdmi
->sd
, state
, &adv748x_ops_hdmi
,
744 MEDIA_ENT_F_IO_DTV
, "hdmi");
746 hdmi
->pads
[ADV748X_HDMI_SINK
].flags
= MEDIA_PAD_FL_SINK
;
747 hdmi
->pads
[ADV748X_HDMI_SOURCE
].flags
= MEDIA_PAD_FL_SOURCE
;
749 ret
= media_entity_pads_init(&hdmi
->sd
.entity
,
750 ADV748X_HDMI_NR_PADS
, hdmi
->pads
);
754 ret
= adv748x_hdmi_init_controls(hdmi
);
761 media_entity_cleanup(&hdmi
->sd
.entity
);
766 void adv748x_hdmi_cleanup(struct adv748x_hdmi
*hdmi
)
768 v4l2_device_unregister_subdev(&hdmi
->sd
);
769 media_entity_cleanup(&hdmi
->sd
.entity
);
770 v4l2_ctrl_handler_free(&hdmi
->ctrl_hdl
);