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
;
109 if (fmt
->field
== V4L2_FIELD_ALTERNATE
)
113 static void adv748x_fill_optional_dv_timings(struct v4l2_dv_timings
*timings
)
115 v4l2_find_dv_timings_cap(timings
, &adv748x_hdmi_timings_cap
,
119 static bool adv748x_hdmi_has_signal(struct adv748x_state
*state
)
123 /* Check that VERT_FILTER and DE_REGEN is locked */
124 val
= hdmi_read(state
, ADV748X_HDMI_LW1
);
125 return (val
& ADV748X_HDMI_LW1_VERT_FILTER
) &&
126 (val
& ADV748X_HDMI_LW1_DE_REGEN
);
129 static int adv748x_hdmi_read_pixelclock(struct adv748x_state
*state
)
133 a
= hdmi_read(state
, ADV748X_HDMI_TMDS_1
);
134 b
= hdmi_read(state
, ADV748X_HDMI_TMDS_2
);
139 * The high 9 bits store TMDS frequency measurement in MHz
140 * The low 7 bits of TMDS_2 store the 7-bit TMDS fractional frequency
141 * measurement in 1/128 MHz
143 return ((a
<< 1) | (b
>> 7)) * 1000000 + (b
& 0x7f) * 1000000 / 128;
147 * adv748x_hdmi_set_de_timings: Adjust horizontal picture offset through DE
149 * HDMI CP uses a Data Enable synchronisation timing reference
151 * Vary the leading and trailing edge position of the DE signal output by the CP
152 * core. Values are stored as signed-twos-complement in one-pixel-clock units
154 * The start and end are shifted equally by the 10-bit shift value.
156 static void adv748x_hdmi_set_de_timings(struct adv748x_state
*state
, int shift
)
160 /* POS_HIGH stores bits 8 and 9 of both the start and end */
161 high
= ADV748X_CP_DE_POS_HIGH_SET
;
162 high
|= (shift
& 0x300) >> 8;
165 /* The sequence of the writes is important and must be followed */
166 cp_write(state
, ADV748X_CP_DE_POS_HIGH
, high
);
167 cp_write(state
, ADV748X_CP_DE_POS_END_LOW
, low
);
169 high
|= (shift
& 0x300) >> 6;
171 cp_write(state
, ADV748X_CP_DE_POS_HIGH
, high
);
172 cp_write(state
, ADV748X_CP_DE_POS_START_LOW
, low
);
175 static int adv748x_hdmi_set_video_timings(struct adv748x_state
*state
,
176 const struct v4l2_dv_timings
*timings
)
178 const struct adv748x_hdmi_video_standards
*stds
=
179 adv748x_hdmi_video_standards
;
182 for (i
= 0; i
< ARRAY_SIZE(adv748x_hdmi_video_standards
); i
++) {
183 if (!v4l2_match_dv_timings(timings
, &stds
[i
].timings
, 250000,
188 if (i
>= ARRAY_SIZE(adv748x_hdmi_video_standards
))
192 * When setting cp_vid_std to either 720p, 1080i, or 1080p, the video
193 * will get shifted horizontally to the left in active video mode.
194 * The de_h_start and de_h_end controls are used to centre the picture
197 switch (stds
[i
].vid_std
) {
198 case 0x53: /* 720p */
199 adv748x_hdmi_set_de_timings(state
, -40);
201 case 0x54: /* 1080i */
202 case 0x5e: /* 1080p */
203 adv748x_hdmi_set_de_timings(state
, -44);
206 adv748x_hdmi_set_de_timings(state
, 0);
210 io_write(state
, ADV748X_IO_VID_STD
, stds
[i
].vid_std
);
211 io_clrset(state
, ADV748X_IO_DATAPATH
, ADV748X_IO_DATAPATH_VFREQ_M
,
212 stds
[i
].v_freq
<< ADV748X_IO_DATAPATH_VFREQ_SHIFT
);
217 /* -----------------------------------------------------------------------------
218 * v4l2_subdev_video_ops
221 static int adv748x_hdmi_s_dv_timings(struct v4l2_subdev
*sd
,
222 struct v4l2_dv_timings
*timings
)
224 struct adv748x_hdmi
*hdmi
= adv748x_sd_to_hdmi(sd
);
225 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
231 if (v4l2_match_dv_timings(&hdmi
->timings
, timings
, 0, false))
234 if (!v4l2_valid_dv_timings(timings
, &adv748x_hdmi_timings_cap
,
238 adv748x_fill_optional_dv_timings(timings
);
240 mutex_lock(&state
->mutex
);
242 ret
= adv748x_hdmi_set_video_timings(state
, timings
);
246 hdmi
->timings
= *timings
;
248 cp_clrset(state
, ADV748X_CP_VID_ADJ_2
, ADV748X_CP_VID_ADJ_2_INTERLACED
,
249 timings
->bt
.interlaced
?
250 ADV748X_CP_VID_ADJ_2_INTERLACED
: 0);
252 mutex_unlock(&state
->mutex
);
257 mutex_unlock(&state
->mutex
);
261 static int adv748x_hdmi_g_dv_timings(struct v4l2_subdev
*sd
,
262 struct v4l2_dv_timings
*timings
)
264 struct adv748x_hdmi
*hdmi
= adv748x_sd_to_hdmi(sd
);
265 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
267 mutex_lock(&state
->mutex
);
269 *timings
= hdmi
->timings
;
271 mutex_unlock(&state
->mutex
);
276 static int adv748x_hdmi_query_dv_timings(struct v4l2_subdev
*sd
,
277 struct v4l2_dv_timings
*timings
)
279 struct adv748x_hdmi
*hdmi
= adv748x_sd_to_hdmi(sd
);
280 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
281 struct v4l2_bt_timings
*bt
= &timings
->bt
;
288 memset(timings
, 0, sizeof(struct v4l2_dv_timings
));
290 if (!adv748x_hdmi_has_signal(state
))
293 pixelclock
= adv748x_hdmi_read_pixelclock(state
);
297 timings
->type
= V4L2_DV_BT_656_1120
;
299 bt
->pixelclock
= pixelclock
;
300 bt
->interlaced
= hdmi_read(state
, ADV748X_HDMI_F1H1
) &
301 ADV748X_HDMI_F1H1_INTERLACED
?
302 V4L2_DV_INTERLACED
: V4L2_DV_PROGRESSIVE
;
303 bt
->width
= hdmi_read16(state
, ADV748X_HDMI_LW1
,
304 ADV748X_HDMI_LW1_WIDTH_MASK
);
305 bt
->height
= hdmi_read16(state
, ADV748X_HDMI_F0H1
,
306 ADV748X_HDMI_F0H1_HEIGHT_MASK
);
307 bt
->hfrontporch
= hdmi_read16(state
, ADV748X_HDMI_HFRONT_PORCH
,
308 ADV748X_HDMI_HFRONT_PORCH_MASK
);
309 bt
->hsync
= hdmi_read16(state
, ADV748X_HDMI_HSYNC_WIDTH
,
310 ADV748X_HDMI_HSYNC_WIDTH_MASK
);
311 bt
->hbackporch
= hdmi_read16(state
, ADV748X_HDMI_HBACK_PORCH
,
312 ADV748X_HDMI_HBACK_PORCH_MASK
);
313 bt
->vfrontporch
= hdmi_read16(state
, ADV748X_HDMI_VFRONT_PORCH
,
314 ADV748X_HDMI_VFRONT_PORCH_MASK
) / 2;
315 bt
->vsync
= hdmi_read16(state
, ADV748X_HDMI_VSYNC_WIDTH
,
316 ADV748X_HDMI_VSYNC_WIDTH_MASK
) / 2;
317 bt
->vbackporch
= hdmi_read16(state
, ADV748X_HDMI_VBACK_PORCH
,
318 ADV748X_HDMI_VBACK_PORCH_MASK
) / 2;
320 polarity
= hdmi_read(state
, 0x05);
321 bt
->polarities
= (polarity
& BIT(4) ? V4L2_DV_VSYNC_POS_POL
: 0) |
322 (polarity
& BIT(5) ? V4L2_DV_HSYNC_POS_POL
: 0);
324 if (bt
->interlaced
== V4L2_DV_INTERLACED
) {
325 bt
->height
+= hdmi_read16(state
, 0x0b, 0x1fff);
326 bt
->il_vfrontporch
= hdmi_read16(state
, 0x2c, 0x3fff) / 2;
327 bt
->il_vsync
= hdmi_read16(state
, 0x30, 0x3fff) / 2;
328 bt
->il_vbackporch
= hdmi_read16(state
, 0x34, 0x3fff) / 2;
331 adv748x_fill_optional_dv_timings(timings
);
334 * No interrupt handling is implemented yet.
335 * There should be an IRQ when a cable is plugged and the new timings
336 * should be figured out and stored to state.
338 hdmi
->timings
= *timings
;
343 static int adv748x_hdmi_g_input_status(struct v4l2_subdev
*sd
, u32
*status
)
345 struct adv748x_hdmi
*hdmi
= adv748x_sd_to_hdmi(sd
);
346 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
348 mutex_lock(&state
->mutex
);
350 *status
= adv748x_hdmi_has_signal(state
) ? 0 : V4L2_IN_ST_NO_SIGNAL
;
352 mutex_unlock(&state
->mutex
);
357 static int adv748x_hdmi_s_stream(struct v4l2_subdev
*sd
, int enable
)
359 struct adv748x_hdmi
*hdmi
= adv748x_sd_to_hdmi(sd
);
360 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
363 mutex_lock(&state
->mutex
);
365 ret
= adv748x_txa_power(state
, enable
);
369 if (adv748x_hdmi_has_signal(state
))
370 adv_dbg(state
, "Detected HDMI signal\n");
372 adv_dbg(state
, "Couldn't detect HDMI video signal\n");
375 mutex_unlock(&state
->mutex
);
379 static int adv748x_hdmi_g_pixelaspect(struct v4l2_subdev
*sd
,
380 struct v4l2_fract
*aspect
)
382 aspect
->numerator
= 1;
383 aspect
->denominator
= 1;
388 static const struct v4l2_subdev_video_ops adv748x_video_ops_hdmi
= {
389 .s_dv_timings
= adv748x_hdmi_s_dv_timings
,
390 .g_dv_timings
= adv748x_hdmi_g_dv_timings
,
391 .query_dv_timings
= adv748x_hdmi_query_dv_timings
,
392 .g_input_status
= adv748x_hdmi_g_input_status
,
393 .s_stream
= adv748x_hdmi_s_stream
,
394 .g_pixelaspect
= adv748x_hdmi_g_pixelaspect
,
397 /* -----------------------------------------------------------------------------
398 * v4l2_subdev_pad_ops
401 static int adv748x_hdmi_propagate_pixelrate(struct adv748x_hdmi
*hdmi
)
403 struct v4l2_subdev
*tx
;
404 struct v4l2_dv_timings timings
;
406 tx
= adv748x_get_remote_sd(&hdmi
->pads
[ADV748X_HDMI_SOURCE
]);
410 adv748x_hdmi_query_dv_timings(&hdmi
->sd
, &timings
);
412 return adv748x_csi2_set_pixelrate(tx
, timings
.bt
.pixelclock
);
415 static int adv748x_hdmi_enum_mbus_code(struct v4l2_subdev
*sd
,
416 struct v4l2_subdev_pad_config
*cfg
,
417 struct v4l2_subdev_mbus_code_enum
*code
)
419 if (code
->index
!= 0)
422 code
->code
= MEDIA_BUS_FMT_RGB888_1X24
;
427 static int adv748x_hdmi_get_format(struct v4l2_subdev
*sd
,
428 struct v4l2_subdev_pad_config
*cfg
,
429 struct v4l2_subdev_format
*sdformat
)
431 struct adv748x_hdmi
*hdmi
= adv748x_sd_to_hdmi(sd
);
432 struct v4l2_mbus_framefmt
*mbusformat
;
434 if (sdformat
->pad
!= ADV748X_HDMI_SOURCE
)
437 if (sdformat
->which
== V4L2_SUBDEV_FORMAT_TRY
) {
438 mbusformat
= v4l2_subdev_get_try_format(sd
, cfg
, sdformat
->pad
);
439 sdformat
->format
= *mbusformat
;
441 adv748x_hdmi_fill_format(hdmi
, &sdformat
->format
);
442 adv748x_hdmi_propagate_pixelrate(hdmi
);
448 static int adv748x_hdmi_set_format(struct v4l2_subdev
*sd
,
449 struct v4l2_subdev_pad_config
*cfg
,
450 struct v4l2_subdev_format
*sdformat
)
452 struct v4l2_mbus_framefmt
*mbusformat
;
454 if (sdformat
->pad
!= ADV748X_HDMI_SOURCE
)
457 if (sdformat
->which
== V4L2_SUBDEV_FORMAT_ACTIVE
)
458 return adv748x_hdmi_get_format(sd
, cfg
, sdformat
);
460 mbusformat
= v4l2_subdev_get_try_format(sd
, cfg
, sdformat
->pad
);
461 *mbusformat
= sdformat
->format
;
466 static int adv748x_hdmi_get_edid(struct v4l2_subdev
*sd
, struct v4l2_edid
*edid
)
468 struct adv748x_hdmi
*hdmi
= adv748x_sd_to_hdmi(sd
);
470 memset(edid
->reserved
, 0, sizeof(edid
->reserved
));
472 if (!hdmi
->edid
.present
)
475 if (edid
->start_block
== 0 && edid
->blocks
== 0) {
476 edid
->blocks
= hdmi
->edid
.blocks
;
480 if (edid
->start_block
>= hdmi
->edid
.blocks
)
483 if (edid
->start_block
+ edid
->blocks
> hdmi
->edid
.blocks
)
484 edid
->blocks
= hdmi
->edid
.blocks
- edid
->start_block
;
486 memcpy(edid
->edid
, hdmi
->edid
.edid
+ edid
->start_block
* 128,
492 static inline int adv748x_hdmi_edid_write_block(struct adv748x_hdmi
*hdmi
,
493 unsigned int total_len
, const u8
*val
)
495 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
500 adv_dbg(state
, "%s: write EDID block (%d byte)\n",
501 __func__
, total_len
);
503 while (!err
&& i
< total_len
) {
504 len
= (total_len
- i
) > I2C_SMBUS_BLOCK_MAX
?
505 I2C_SMBUS_BLOCK_MAX
:
508 err
= adv748x_write_block(state
, ADV748X_PAGE_EDID
,
516 static int adv748x_hdmi_set_edid(struct v4l2_subdev
*sd
, struct v4l2_edid
*edid
)
518 struct adv748x_hdmi
*hdmi
= adv748x_sd_to_hdmi(sd
);
519 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
522 memset(edid
->reserved
, 0, sizeof(edid
->reserved
));
524 if (edid
->start_block
!= 0)
527 if (edid
->blocks
== 0) {
528 hdmi
->edid
.blocks
= 0;
529 hdmi
->edid
.present
= 0;
531 /* Fall back to a 16:9 aspect ratio */
532 hdmi
->aspect_ratio
.numerator
= 16;
533 hdmi
->aspect_ratio
.denominator
= 9;
535 /* Disable the EDID */
536 repeater_write(state
, ADV748X_REPEATER_EDID_SZ
,
537 edid
->blocks
<< ADV748X_REPEATER_EDID_SZ_SHIFT
);
539 repeater_write(state
, ADV748X_REPEATER_EDID_CTL
, 0);
544 if (edid
->blocks
> 4) {
549 memcpy(hdmi
->edid
.edid
, edid
->edid
, 128 * edid
->blocks
);
550 hdmi
->edid
.blocks
= edid
->blocks
;
551 hdmi
->edid
.present
= true;
553 hdmi
->aspect_ratio
= v4l2_calc_aspect_ratio(edid
->edid
[0x15],
556 err
= adv748x_hdmi_edid_write_block(hdmi
, 128 * edid
->blocks
,
559 v4l2_err(sd
, "error %d writing edid pad %d\n", err
, edid
->pad
);
563 repeater_write(state
, ADV748X_REPEATER_EDID_SZ
,
564 edid
->blocks
<< ADV748X_REPEATER_EDID_SZ_SHIFT
);
566 repeater_write(state
, ADV748X_REPEATER_EDID_CTL
,
567 ADV748X_REPEATER_EDID_CTL_EN
);
572 static bool adv748x_hdmi_check_dv_timings(const struct v4l2_dv_timings
*timings
,
575 const struct adv748x_hdmi_video_standards
*stds
=
576 adv748x_hdmi_video_standards
;
579 for (i
= 0; stds
[i
].timings
.bt
.width
; i
++)
580 if (v4l2_match_dv_timings(timings
, &stds
[i
].timings
, 0, false))
586 static int adv748x_hdmi_enum_dv_timings(struct v4l2_subdev
*sd
,
587 struct v4l2_enum_dv_timings
*timings
)
589 return v4l2_enum_dv_timings_cap(timings
, &adv748x_hdmi_timings_cap
,
590 adv748x_hdmi_check_dv_timings
, NULL
);
593 static int adv748x_hdmi_dv_timings_cap(struct v4l2_subdev
*sd
,
594 struct v4l2_dv_timings_cap
*cap
)
596 *cap
= adv748x_hdmi_timings_cap
;
600 static const struct v4l2_subdev_pad_ops adv748x_pad_ops_hdmi
= {
601 .enum_mbus_code
= adv748x_hdmi_enum_mbus_code
,
602 .set_fmt
= adv748x_hdmi_set_format
,
603 .get_fmt
= adv748x_hdmi_get_format
,
604 .get_edid
= adv748x_hdmi_get_edid
,
605 .set_edid
= adv748x_hdmi_set_edid
,
606 .dv_timings_cap
= adv748x_hdmi_dv_timings_cap
,
607 .enum_dv_timings
= adv748x_hdmi_enum_dv_timings
,
610 /* -----------------------------------------------------------------------------
614 static const struct v4l2_subdev_ops adv748x_ops_hdmi
= {
615 .video
= &adv748x_video_ops_hdmi
,
616 .pad
= &adv748x_pad_ops_hdmi
,
619 /* -----------------------------------------------------------------------------
623 static const char * const hdmi_ctrl_patgen_menu
[] = {
633 static int adv748x_hdmi_s_ctrl(struct v4l2_ctrl
*ctrl
)
635 struct adv748x_hdmi
*hdmi
= adv748x_ctrl_to_hdmi(ctrl
);
636 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
640 /* Enable video adjustment first */
641 ret
= cp_clrset(state
, ADV748X_CP_VID_ADJ
,
642 ADV748X_CP_VID_ADJ_ENABLE
,
643 ADV748X_CP_VID_ADJ_ENABLE
);
648 case V4L2_CID_BRIGHTNESS
:
649 ret
= cp_write(state
, ADV748X_CP_BRI
, ctrl
->val
);
652 ret
= cp_write(state
, ADV748X_CP_HUE
, ctrl
->val
);
654 case V4L2_CID_CONTRAST
:
655 ret
= cp_write(state
, ADV748X_CP_CON
, ctrl
->val
);
657 case V4L2_CID_SATURATION
:
658 ret
= cp_write(state
, ADV748X_CP_SAT
, ctrl
->val
);
660 case V4L2_CID_TEST_PATTERN
:
663 /* Pattern is 0-indexed. Ctrl Menu is 1-indexed */
666 pattern
|= ADV748X_CP_PAT_GEN_EN
;
669 ret
= cp_write(state
, ADV748X_CP_PAT_GEN
, pattern
);
679 static const struct v4l2_ctrl_ops adv748x_hdmi_ctrl_ops
= {
680 .s_ctrl
= adv748x_hdmi_s_ctrl
,
683 static int adv748x_hdmi_init_controls(struct adv748x_hdmi
*hdmi
)
685 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
687 v4l2_ctrl_handler_init(&hdmi
->ctrl_hdl
, 5);
689 /* Use our mutex for the controls */
690 hdmi
->ctrl_hdl
.lock
= &state
->mutex
;
692 v4l2_ctrl_new_std(&hdmi
->ctrl_hdl
, &adv748x_hdmi_ctrl_ops
,
693 V4L2_CID_BRIGHTNESS
, ADV748X_CP_BRI_MIN
,
694 ADV748X_CP_BRI_MAX
, 1, ADV748X_CP_BRI_DEF
);
695 v4l2_ctrl_new_std(&hdmi
->ctrl_hdl
, &adv748x_hdmi_ctrl_ops
,
696 V4L2_CID_CONTRAST
, ADV748X_CP_CON_MIN
,
697 ADV748X_CP_CON_MAX
, 1, ADV748X_CP_CON_DEF
);
698 v4l2_ctrl_new_std(&hdmi
->ctrl_hdl
, &adv748x_hdmi_ctrl_ops
,
699 V4L2_CID_SATURATION
, ADV748X_CP_SAT_MIN
,
700 ADV748X_CP_SAT_MAX
, 1, ADV748X_CP_SAT_DEF
);
701 v4l2_ctrl_new_std(&hdmi
->ctrl_hdl
, &adv748x_hdmi_ctrl_ops
,
702 V4L2_CID_HUE
, ADV748X_CP_HUE_MIN
,
703 ADV748X_CP_HUE_MAX
, 1, ADV748X_CP_HUE_DEF
);
706 * Todo: V4L2_CID_DV_RX_POWER_PRESENT should also be supported when
707 * interrupts are handled correctly
710 v4l2_ctrl_new_std_menu_items(&hdmi
->ctrl_hdl
, &adv748x_hdmi_ctrl_ops
,
711 V4L2_CID_TEST_PATTERN
,
712 ARRAY_SIZE(hdmi_ctrl_patgen_menu
) - 1,
713 0, 0, hdmi_ctrl_patgen_menu
);
715 hdmi
->sd
.ctrl_handler
= &hdmi
->ctrl_hdl
;
716 if (hdmi
->ctrl_hdl
.error
) {
717 v4l2_ctrl_handler_free(&hdmi
->ctrl_hdl
);
718 return hdmi
->ctrl_hdl
.error
;
721 return v4l2_ctrl_handler_setup(&hdmi
->ctrl_hdl
);
724 int adv748x_hdmi_init(struct adv748x_hdmi
*hdmi
)
726 struct adv748x_state
*state
= adv748x_hdmi_to_state(hdmi
);
727 static const struct v4l2_dv_timings cea1280x720
=
728 V4L2_DV_BT_CEA_1280X720P30
;
731 hdmi
->timings
= cea1280x720
;
733 /* Initialise a default 16:9 aspect ratio */
734 hdmi
->aspect_ratio
.numerator
= 16;
735 hdmi
->aspect_ratio
.denominator
= 9;
737 adv748x_subdev_init(&hdmi
->sd
, state
, &adv748x_ops_hdmi
,
738 MEDIA_ENT_F_IO_DTV
, "hdmi");
740 hdmi
->pads
[ADV748X_HDMI_SINK
].flags
= MEDIA_PAD_FL_SINK
;
741 hdmi
->pads
[ADV748X_HDMI_SOURCE
].flags
= MEDIA_PAD_FL_SOURCE
;
743 ret
= media_entity_pads_init(&hdmi
->sd
.entity
,
744 ADV748X_HDMI_NR_PADS
, hdmi
->pads
);
748 ret
= adv748x_hdmi_init_controls(hdmi
);
755 media_entity_cleanup(&hdmi
->sd
.entity
);
760 void adv748x_hdmi_cleanup(struct adv748x_hdmi
*hdmi
)
762 v4l2_device_unregister_subdev(&hdmi
->sd
);
763 media_entity_cleanup(&hdmi
->sd
.entity
);
764 v4l2_ctrl_handler_free(&hdmi
->ctrl_hdl
);