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
,
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
,
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
,
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
));
286 if (!adv748x_hdmi_has_signal(state
))
289 pixelclock
= adv748x_hdmi_read_pixelclock(state
);
293 timings
->type
= V4L2_DV_BT_656_1120
;
295 bt
->pixelclock
= pixelclock
;
296 bt
->interlaced
= hdmi_read(state
, ADV748X_HDMI_F1H1
) &
297 ADV748X_HDMI_F1H1_INTERLACED
?
298 V4L2_DV_INTERLACED
: V4L2_DV_PROGRESSIVE
;
299 bt
->width
= hdmi_read16(state
, ADV748X_HDMI_LW1
,
300 ADV748X_HDMI_LW1_WIDTH_MASK
);
301 bt
->height
= hdmi_read16(state
, ADV748X_HDMI_F0H1
,
302 ADV748X_HDMI_F0H1_HEIGHT_MASK
);
303 bt
->hfrontporch
= hdmi_read16(state
, ADV748X_HDMI_HFRONT_PORCH
,
304 ADV748X_HDMI_HFRONT_PORCH_MASK
);
305 bt
->hsync
= hdmi_read16(state
, ADV748X_HDMI_HSYNC_WIDTH
,
306 ADV748X_HDMI_HSYNC_WIDTH_MASK
);
307 bt
->hbackporch
= hdmi_read16(state
, ADV748X_HDMI_HBACK_PORCH
,
308 ADV748X_HDMI_HBACK_PORCH_MASK
);
309 bt
->vfrontporch
= hdmi_read16(state
, ADV748X_HDMI_VFRONT_PORCH
,
310 ADV748X_HDMI_VFRONT_PORCH_MASK
) / 2;
311 bt
->vsync
= hdmi_read16(state
, ADV748X_HDMI_VSYNC_WIDTH
,
312 ADV748X_HDMI_VSYNC_WIDTH_MASK
) / 2;
313 bt
->vbackporch
= hdmi_read16(state
, ADV748X_HDMI_VBACK_PORCH
,
314 ADV748X_HDMI_VBACK_PORCH_MASK
) / 2;
316 polarity
= hdmi_read(state
, 0x05);
317 bt
->polarities
= (polarity
& BIT(4) ? V4L2_DV_VSYNC_POS_POL
: 0) |
318 (polarity
& BIT(5) ? V4L2_DV_HSYNC_POS_POL
: 0);
320 if (bt
->interlaced
== V4L2_DV_INTERLACED
) {
321 bt
->height
+= hdmi_read16(state
, 0x0b, 0x1fff);
322 bt
->il_vfrontporch
= hdmi_read16(state
, 0x2c, 0x3fff) / 2;
323 bt
->il_vsync
= hdmi_read16(state
, 0x30, 0x3fff) / 2;
324 bt
->il_vbackporch
= hdmi_read16(state
, 0x34, 0x3fff) / 2;
327 adv748x_fill_optional_dv_timings(timings
);
330 * No interrupt handling is implemented yet.
331 * There should be an IRQ when a cable is plugged and the new timings
332 * should be figured out and stored to state.
334 hdmi
->timings
= *timings
;
339 static int adv748x_hdmi_g_input_status(struct v4l2_subdev
*sd
, u32
*status
)
341 struct adv748x_hdmi
*hdmi
= adv748x_sd_to_hdmi(sd
);
342 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
344 mutex_lock(&state
->mutex
);
346 *status
= adv748x_hdmi_has_signal(state
) ? 0 : V4L2_IN_ST_NO_SIGNAL
;
348 mutex_unlock(&state
->mutex
);
353 static int adv748x_hdmi_s_stream(struct v4l2_subdev
*sd
, int enable
)
355 struct adv748x_hdmi
*hdmi
= adv748x_sd_to_hdmi(sd
);
356 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
359 mutex_lock(&state
->mutex
);
361 ret
= adv748x_tx_power(hdmi
->tx
, enable
);
365 if (adv748x_hdmi_has_signal(state
))
366 adv_dbg(state
, "Detected HDMI signal\n");
368 adv_dbg(state
, "Couldn't detect HDMI video signal\n");
371 mutex_unlock(&state
->mutex
);
375 static int adv748x_hdmi_g_pixelaspect(struct v4l2_subdev
*sd
,
376 struct v4l2_fract
*aspect
)
378 aspect
->numerator
= 1;
379 aspect
->denominator
= 1;
384 static const struct v4l2_subdev_video_ops adv748x_video_ops_hdmi
= {
385 .s_dv_timings
= adv748x_hdmi_s_dv_timings
,
386 .g_dv_timings
= adv748x_hdmi_g_dv_timings
,
387 .query_dv_timings
= adv748x_hdmi_query_dv_timings
,
388 .g_input_status
= adv748x_hdmi_g_input_status
,
389 .s_stream
= adv748x_hdmi_s_stream
,
390 .g_pixelaspect
= adv748x_hdmi_g_pixelaspect
,
393 /* -----------------------------------------------------------------------------
394 * v4l2_subdev_pad_ops
397 static int adv748x_hdmi_propagate_pixelrate(struct adv748x_hdmi
*hdmi
)
399 struct v4l2_subdev
*tx
;
400 struct v4l2_dv_timings timings
;
402 tx
= adv748x_get_remote_sd(&hdmi
->pads
[ADV748X_HDMI_SOURCE
]);
406 adv748x_hdmi_query_dv_timings(&hdmi
->sd
, &timings
);
408 return adv748x_csi2_set_pixelrate(tx
, timings
.bt
.pixelclock
);
411 static int adv748x_hdmi_enum_mbus_code(struct v4l2_subdev
*sd
,
412 struct v4l2_subdev_pad_config
*cfg
,
413 struct v4l2_subdev_mbus_code_enum
*code
)
415 if (code
->index
!= 0)
418 code
->code
= MEDIA_BUS_FMT_RGB888_1X24
;
423 static int adv748x_hdmi_get_format(struct v4l2_subdev
*sd
,
424 struct v4l2_subdev_pad_config
*cfg
,
425 struct v4l2_subdev_format
*sdformat
)
427 struct adv748x_hdmi
*hdmi
= adv748x_sd_to_hdmi(sd
);
428 struct v4l2_mbus_framefmt
*mbusformat
;
430 if (sdformat
->pad
!= ADV748X_HDMI_SOURCE
)
433 if (sdformat
->which
== V4L2_SUBDEV_FORMAT_TRY
) {
434 mbusformat
= v4l2_subdev_get_try_format(sd
, cfg
, sdformat
->pad
);
435 sdformat
->format
= *mbusformat
;
437 adv748x_hdmi_fill_format(hdmi
, &sdformat
->format
);
438 adv748x_hdmi_propagate_pixelrate(hdmi
);
444 static int adv748x_hdmi_set_format(struct v4l2_subdev
*sd
,
445 struct v4l2_subdev_pad_config
*cfg
,
446 struct v4l2_subdev_format
*sdformat
)
448 struct v4l2_mbus_framefmt
*mbusformat
;
450 if (sdformat
->pad
!= ADV748X_HDMI_SOURCE
)
453 if (sdformat
->which
== V4L2_SUBDEV_FORMAT_ACTIVE
)
454 return adv748x_hdmi_get_format(sd
, cfg
, sdformat
);
456 mbusformat
= v4l2_subdev_get_try_format(sd
, cfg
, sdformat
->pad
);
457 *mbusformat
= sdformat
->format
;
462 static int adv748x_hdmi_get_edid(struct v4l2_subdev
*sd
, struct v4l2_edid
*edid
)
464 struct adv748x_hdmi
*hdmi
= adv748x_sd_to_hdmi(sd
);
466 memset(edid
->reserved
, 0, sizeof(edid
->reserved
));
468 if (!hdmi
->edid
.present
)
471 if (edid
->start_block
== 0 && edid
->blocks
== 0) {
472 edid
->blocks
= hdmi
->edid
.blocks
;
476 if (edid
->start_block
>= hdmi
->edid
.blocks
)
479 if (edid
->start_block
+ edid
->blocks
> hdmi
->edid
.blocks
)
480 edid
->blocks
= hdmi
->edid
.blocks
- edid
->start_block
;
482 memcpy(edid
->edid
, hdmi
->edid
.edid
+ edid
->start_block
* 128,
488 static inline int adv748x_hdmi_edid_write_block(struct adv748x_hdmi
*hdmi
,
489 unsigned int total_len
, const u8
*val
)
491 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
496 adv_dbg(state
, "%s: write EDID block (%d byte)\n",
497 __func__
, total_len
);
499 while (!err
&& i
< total_len
) {
500 len
= (total_len
- i
) > I2C_SMBUS_BLOCK_MAX
?
501 I2C_SMBUS_BLOCK_MAX
:
504 err
= adv748x_write_block(state
, ADV748X_PAGE_EDID
,
512 static int adv748x_hdmi_set_edid(struct v4l2_subdev
*sd
, struct v4l2_edid
*edid
)
514 struct adv748x_hdmi
*hdmi
= adv748x_sd_to_hdmi(sd
);
515 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
518 memset(edid
->reserved
, 0, sizeof(edid
->reserved
));
520 if (edid
->start_block
!= 0)
523 if (edid
->blocks
== 0) {
524 hdmi
->edid
.blocks
= 0;
525 hdmi
->edid
.present
= 0;
527 /* Fall back to a 16:9 aspect ratio */
528 hdmi
->aspect_ratio
.numerator
= 16;
529 hdmi
->aspect_ratio
.denominator
= 9;
531 /* Disable the EDID */
532 repeater_write(state
, ADV748X_REPEATER_EDID_SZ
,
533 edid
->blocks
<< ADV748X_REPEATER_EDID_SZ_SHIFT
);
535 repeater_write(state
, ADV748X_REPEATER_EDID_CTL
, 0);
540 if (edid
->blocks
> 4) {
545 memcpy(hdmi
->edid
.edid
, edid
->edid
, 128 * edid
->blocks
);
546 hdmi
->edid
.blocks
= edid
->blocks
;
547 hdmi
->edid
.present
= true;
549 hdmi
->aspect_ratio
= v4l2_calc_aspect_ratio(edid
->edid
[0x15],
552 err
= adv748x_hdmi_edid_write_block(hdmi
, 128 * edid
->blocks
,
555 v4l2_err(sd
, "error %d writing edid pad %d\n", err
, edid
->pad
);
559 repeater_write(state
, ADV748X_REPEATER_EDID_SZ
,
560 edid
->blocks
<< ADV748X_REPEATER_EDID_SZ_SHIFT
);
562 repeater_write(state
, ADV748X_REPEATER_EDID_CTL
,
563 ADV748X_REPEATER_EDID_CTL_EN
);
568 static bool adv748x_hdmi_check_dv_timings(const struct v4l2_dv_timings
*timings
,
571 const struct adv748x_hdmi_video_standards
*stds
=
572 adv748x_hdmi_video_standards
;
575 for (i
= 0; stds
[i
].timings
.bt
.width
; i
++)
576 if (v4l2_match_dv_timings(timings
, &stds
[i
].timings
, 0, false))
582 static int adv748x_hdmi_enum_dv_timings(struct v4l2_subdev
*sd
,
583 struct v4l2_enum_dv_timings
*timings
)
585 return v4l2_enum_dv_timings_cap(timings
, &adv748x_hdmi_timings_cap
,
586 adv748x_hdmi_check_dv_timings
, NULL
);
589 static int adv748x_hdmi_dv_timings_cap(struct v4l2_subdev
*sd
,
590 struct v4l2_dv_timings_cap
*cap
)
592 *cap
= adv748x_hdmi_timings_cap
;
596 static const struct v4l2_subdev_pad_ops adv748x_pad_ops_hdmi
= {
597 .enum_mbus_code
= adv748x_hdmi_enum_mbus_code
,
598 .set_fmt
= adv748x_hdmi_set_format
,
599 .get_fmt
= adv748x_hdmi_get_format
,
600 .get_edid
= adv748x_hdmi_get_edid
,
601 .set_edid
= adv748x_hdmi_set_edid
,
602 .dv_timings_cap
= adv748x_hdmi_dv_timings_cap
,
603 .enum_dv_timings
= adv748x_hdmi_enum_dv_timings
,
606 /* -----------------------------------------------------------------------------
610 static const struct v4l2_subdev_ops adv748x_ops_hdmi
= {
611 .video
= &adv748x_video_ops_hdmi
,
612 .pad
= &adv748x_pad_ops_hdmi
,
615 /* -----------------------------------------------------------------------------
619 static const char * const hdmi_ctrl_patgen_menu
[] = {
629 static int adv748x_hdmi_s_ctrl(struct v4l2_ctrl
*ctrl
)
631 struct adv748x_hdmi
*hdmi
= adv748x_ctrl_to_hdmi(ctrl
);
632 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
636 /* Enable video adjustment first */
637 ret
= cp_clrset(state
, ADV748X_CP_VID_ADJ
,
638 ADV748X_CP_VID_ADJ_ENABLE
,
639 ADV748X_CP_VID_ADJ_ENABLE
);
644 case V4L2_CID_BRIGHTNESS
:
645 ret
= cp_write(state
, ADV748X_CP_BRI
, ctrl
->val
);
648 ret
= cp_write(state
, ADV748X_CP_HUE
, ctrl
->val
);
650 case V4L2_CID_CONTRAST
:
651 ret
= cp_write(state
, ADV748X_CP_CON
, ctrl
->val
);
653 case V4L2_CID_SATURATION
:
654 ret
= cp_write(state
, ADV748X_CP_SAT
, ctrl
->val
);
656 case V4L2_CID_TEST_PATTERN
:
659 /* Pattern is 0-indexed. Ctrl Menu is 1-indexed */
662 pattern
|= ADV748X_CP_PAT_GEN_EN
;
665 ret
= cp_write(state
, ADV748X_CP_PAT_GEN
, pattern
);
675 static const struct v4l2_ctrl_ops adv748x_hdmi_ctrl_ops
= {
676 .s_ctrl
= adv748x_hdmi_s_ctrl
,
679 static int adv748x_hdmi_init_controls(struct adv748x_hdmi
*hdmi
)
681 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
683 v4l2_ctrl_handler_init(&hdmi
->ctrl_hdl
, 5);
685 /* Use our mutex for the controls */
686 hdmi
->ctrl_hdl
.lock
= &state
->mutex
;
688 v4l2_ctrl_new_std(&hdmi
->ctrl_hdl
, &adv748x_hdmi_ctrl_ops
,
689 V4L2_CID_BRIGHTNESS
, ADV748X_CP_BRI_MIN
,
690 ADV748X_CP_BRI_MAX
, 1, ADV748X_CP_BRI_DEF
);
691 v4l2_ctrl_new_std(&hdmi
->ctrl_hdl
, &adv748x_hdmi_ctrl_ops
,
692 V4L2_CID_CONTRAST
, ADV748X_CP_CON_MIN
,
693 ADV748X_CP_CON_MAX
, 1, ADV748X_CP_CON_DEF
);
694 v4l2_ctrl_new_std(&hdmi
->ctrl_hdl
, &adv748x_hdmi_ctrl_ops
,
695 V4L2_CID_SATURATION
, ADV748X_CP_SAT_MIN
,
696 ADV748X_CP_SAT_MAX
, 1, ADV748X_CP_SAT_DEF
);
697 v4l2_ctrl_new_std(&hdmi
->ctrl_hdl
, &adv748x_hdmi_ctrl_ops
,
698 V4L2_CID_HUE
, ADV748X_CP_HUE_MIN
,
699 ADV748X_CP_HUE_MAX
, 1, ADV748X_CP_HUE_DEF
);
702 * Todo: V4L2_CID_DV_RX_POWER_PRESENT should also be supported when
703 * interrupts are handled correctly
706 v4l2_ctrl_new_std_menu_items(&hdmi
->ctrl_hdl
, &adv748x_hdmi_ctrl_ops
,
707 V4L2_CID_TEST_PATTERN
,
708 ARRAY_SIZE(hdmi_ctrl_patgen_menu
) - 1,
709 0, 0, hdmi_ctrl_patgen_menu
);
711 hdmi
->sd
.ctrl_handler
= &hdmi
->ctrl_hdl
;
712 if (hdmi
->ctrl_hdl
.error
) {
713 v4l2_ctrl_handler_free(&hdmi
->ctrl_hdl
);
714 return hdmi
->ctrl_hdl
.error
;
717 return v4l2_ctrl_handler_setup(&hdmi
->ctrl_hdl
);
720 int adv748x_hdmi_init(struct adv748x_hdmi
*hdmi
)
722 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
723 static const struct v4l2_dv_timings cea1280x720
=
724 V4L2_DV_BT_CEA_1280X720P30
;
727 hdmi
->timings
= cea1280x720
;
729 /* Initialise a default 16:9 aspect ratio */
730 hdmi
->aspect_ratio
.numerator
= 16;
731 hdmi
->aspect_ratio
.denominator
= 9;
733 adv748x_subdev_init(&hdmi
->sd
, state
, &adv748x_ops_hdmi
,
734 MEDIA_ENT_F_IO_DTV
, "hdmi");
736 hdmi
->pads
[ADV748X_HDMI_SINK
].flags
= MEDIA_PAD_FL_SINK
;
737 hdmi
->pads
[ADV748X_HDMI_SOURCE
].flags
= MEDIA_PAD_FL_SOURCE
;
739 ret
= media_entity_pads_init(&hdmi
->sd
.entity
,
740 ADV748X_HDMI_NR_PADS
, hdmi
->pads
);
744 ret
= adv748x_hdmi_init_controls(hdmi
);
751 media_entity_cleanup(&hdmi
->sd
.entity
);
756 void adv748x_hdmi_cleanup(struct adv748x_hdmi
*hdmi
)
758 v4l2_device_unregister_subdev(&hdmi
->sd
);
759 media_entity_cleanup(&hdmi
->sd
.entity
);
760 v4l2_ctrl_handler_free(&hdmi
->ctrl_hdl
);