0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/module.h>
0009 #include <linux/mutex.h>
0010
0011 #include <media/v4l2-ctrls.h>
0012 #include <media/v4l2-device.h>
0013 #include <media/v4l2-dv-timings.h>
0014 #include <media/v4l2-ioctl.h>
0015
0016 #include <uapi/linux/v4l2-dv-timings.h>
0017
0018 #include "adv748x.h"
0019
0020
0021
0022
0023
0024 #define ADV748X_HDMI_MIN_WIDTH 640
0025 #define ADV748X_HDMI_MAX_WIDTH 1920
0026 #define ADV748X_HDMI_MIN_HEIGHT 480
0027 #define ADV748X_HDMI_MAX_HEIGHT 1200
0028
0029
0030 #define ADV748X_HDMI_MIN_PIXELCLOCK 13000000
0031
0032 #define ADV748X_HDMI_MAX_PIXELCLOCK 162000000
0033
0034 static const struct v4l2_dv_timings_cap adv748x_hdmi_timings_cap = {
0035 .type = V4L2_DV_BT_656_1120,
0036
0037 .reserved = { 0 },
0038
0039 V4L2_INIT_BT_TIMINGS(ADV748X_HDMI_MIN_WIDTH, ADV748X_HDMI_MAX_WIDTH,
0040 ADV748X_HDMI_MIN_HEIGHT, ADV748X_HDMI_MAX_HEIGHT,
0041 ADV748X_HDMI_MIN_PIXELCLOCK,
0042 ADV748X_HDMI_MAX_PIXELCLOCK,
0043 V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT,
0044 V4L2_DV_BT_CAP_PROGRESSIVE)
0045 };
0046
0047 struct adv748x_hdmi_video_standards {
0048 struct v4l2_dv_timings timings;
0049 u8 vid_std;
0050 u8 v_freq;
0051 };
0052
0053 static const struct adv748x_hdmi_video_standards
0054 adv748x_hdmi_video_standards[] = {
0055 { V4L2_DV_BT_CEA_720X480P59_94, 0x4a, 0x00 },
0056 { V4L2_DV_BT_CEA_720X576P50, 0x4b, 0x00 },
0057 { V4L2_DV_BT_CEA_1280X720P60, 0x53, 0x00 },
0058 { V4L2_DV_BT_CEA_1280X720P50, 0x53, 0x01 },
0059 { V4L2_DV_BT_CEA_1280X720P30, 0x53, 0x02 },
0060 { V4L2_DV_BT_CEA_1280X720P25, 0x53, 0x03 },
0061 { V4L2_DV_BT_CEA_1280X720P24, 0x53, 0x04 },
0062 { V4L2_DV_BT_CEA_1920X1080P60, 0x5e, 0x00 },
0063 { V4L2_DV_BT_CEA_1920X1080P50, 0x5e, 0x01 },
0064 { V4L2_DV_BT_CEA_1920X1080P30, 0x5e, 0x02 },
0065 { V4L2_DV_BT_CEA_1920X1080P25, 0x5e, 0x03 },
0066 { V4L2_DV_BT_CEA_1920X1080P24, 0x5e, 0x04 },
0067
0068 { V4L2_DV_BT_DMT_800X600P56, 0x80, 0x00 },
0069 { V4L2_DV_BT_DMT_800X600P60, 0x81, 0x00 },
0070 { V4L2_DV_BT_DMT_800X600P72, 0x82, 0x00 },
0071 { V4L2_DV_BT_DMT_800X600P75, 0x83, 0x00 },
0072 { V4L2_DV_BT_DMT_800X600P85, 0x84, 0x00 },
0073
0074 { V4L2_DV_BT_DMT_1280X1024P60, 0x85, 0x00 },
0075 { V4L2_DV_BT_DMT_1280X1024P75, 0x86, 0x00 },
0076
0077 { V4L2_DV_BT_DMT_640X480P60, 0x88, 0x00 },
0078 { V4L2_DV_BT_DMT_640X480P72, 0x89, 0x00 },
0079 { V4L2_DV_BT_DMT_640X480P75, 0x8a, 0x00 },
0080 { V4L2_DV_BT_DMT_640X480P85, 0x8b, 0x00 },
0081
0082 { V4L2_DV_BT_DMT_1024X768P60, 0x8c, 0x00 },
0083 { V4L2_DV_BT_DMT_1024X768P70, 0x8d, 0x00 },
0084 { V4L2_DV_BT_DMT_1024X768P75, 0x8e, 0x00 },
0085 { V4L2_DV_BT_DMT_1024X768P85, 0x8f, 0x00 },
0086
0087 { V4L2_DV_BT_DMT_1600X1200P60, 0x96, 0x00 },
0088 };
0089
0090 static void adv748x_hdmi_fill_format(struct adv748x_hdmi *hdmi,
0091 struct v4l2_mbus_framefmt *fmt)
0092 {
0093 memset(fmt, 0, sizeof(*fmt));
0094
0095 fmt->code = MEDIA_BUS_FMT_RGB888_1X24;
0096 fmt->field = hdmi->timings.bt.interlaced ?
0097 V4L2_FIELD_ALTERNATE : V4L2_FIELD_NONE;
0098
0099
0100 fmt->colorspace = V4L2_COLORSPACE_SRGB;
0101
0102 fmt->width = hdmi->timings.bt.width;
0103 fmt->height = hdmi->timings.bt.height;
0104
0105 if (fmt->field == V4L2_FIELD_ALTERNATE)
0106 fmt->height /= 2;
0107 }
0108
0109 static void adv748x_fill_optional_dv_timings(struct v4l2_dv_timings *timings)
0110 {
0111 v4l2_find_dv_timings_cap(timings, &adv748x_hdmi_timings_cap,
0112 250000, NULL, NULL);
0113 }
0114
0115 static bool adv748x_hdmi_has_signal(struct adv748x_state *state)
0116 {
0117 int val;
0118
0119
0120 val = hdmi_read(state, ADV748X_HDMI_LW1);
0121 return (val & ADV748X_HDMI_LW1_VERT_FILTER) &&
0122 (val & ADV748X_HDMI_LW1_DE_REGEN);
0123 }
0124
0125 static int adv748x_hdmi_read_pixelclock(struct adv748x_state *state)
0126 {
0127 int a, b;
0128
0129 a = hdmi_read(state, ADV748X_HDMI_TMDS_1);
0130 b = hdmi_read(state, ADV748X_HDMI_TMDS_2);
0131 if (a < 0 || b < 0)
0132 return -ENODATA;
0133
0134
0135
0136
0137
0138
0139 return ((a << 1) | (b >> 7)) * 1000000 + (b & 0x7f) * 1000000 / 128;
0140 }
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152 static void adv748x_hdmi_set_de_timings(struct adv748x_state *state, int shift)
0153 {
0154 u8 high, low;
0155
0156
0157 high = ADV748X_CP_DE_POS_HIGH_SET;
0158 high |= (shift & 0x300) >> 8;
0159 low = shift & 0xff;
0160
0161
0162 cp_write(state, ADV748X_CP_DE_POS_HIGH, high);
0163 cp_write(state, ADV748X_CP_DE_POS_END_LOW, low);
0164
0165 high |= (shift & 0x300) >> 6;
0166
0167 cp_write(state, ADV748X_CP_DE_POS_HIGH, high);
0168 cp_write(state, ADV748X_CP_DE_POS_START_LOW, low);
0169 }
0170
0171 static int adv748x_hdmi_set_video_timings(struct adv748x_state *state,
0172 const struct v4l2_dv_timings *timings)
0173 {
0174 const struct adv748x_hdmi_video_standards *stds =
0175 adv748x_hdmi_video_standards;
0176 unsigned int i;
0177
0178 for (i = 0; i < ARRAY_SIZE(adv748x_hdmi_video_standards); i++) {
0179 if (!v4l2_match_dv_timings(timings, &stds[i].timings, 250000,
0180 false))
0181 continue;
0182 }
0183
0184 if (i >= ARRAY_SIZE(adv748x_hdmi_video_standards))
0185 return -EINVAL;
0186
0187
0188
0189
0190
0191
0192
0193 switch (stds[i].vid_std) {
0194 case 0x53:
0195 adv748x_hdmi_set_de_timings(state, -40);
0196 break;
0197 case 0x54:
0198 case 0x5e:
0199 adv748x_hdmi_set_de_timings(state, -44);
0200 break;
0201 default:
0202 adv748x_hdmi_set_de_timings(state, 0);
0203 break;
0204 }
0205
0206 io_write(state, ADV748X_IO_VID_STD, stds[i].vid_std);
0207 io_clrset(state, ADV748X_IO_DATAPATH, ADV748X_IO_DATAPATH_VFREQ_M,
0208 stds[i].v_freq << ADV748X_IO_DATAPATH_VFREQ_SHIFT);
0209
0210 return 0;
0211 }
0212
0213
0214
0215
0216
0217 static int adv748x_hdmi_s_dv_timings(struct v4l2_subdev *sd,
0218 struct v4l2_dv_timings *timings)
0219 {
0220 struct adv748x_hdmi *hdmi = adv748x_sd_to_hdmi(sd);
0221 struct adv748x_state *state = adv748x_hdmi_to_state(hdmi);
0222 int ret;
0223
0224 if (!timings)
0225 return -EINVAL;
0226
0227 if (v4l2_match_dv_timings(&hdmi->timings, timings, 0, false))
0228 return 0;
0229
0230 if (!v4l2_valid_dv_timings(timings, &adv748x_hdmi_timings_cap,
0231 NULL, NULL))
0232 return -ERANGE;
0233
0234 adv748x_fill_optional_dv_timings(timings);
0235
0236 mutex_lock(&state->mutex);
0237
0238 ret = adv748x_hdmi_set_video_timings(state, timings);
0239 if (ret)
0240 goto error;
0241
0242 hdmi->timings = *timings;
0243
0244 cp_clrset(state, ADV748X_CP_VID_ADJ_2, ADV748X_CP_VID_ADJ_2_INTERLACED,
0245 timings->bt.interlaced ?
0246 ADV748X_CP_VID_ADJ_2_INTERLACED : 0);
0247
0248 mutex_unlock(&state->mutex);
0249
0250 return 0;
0251
0252 error:
0253 mutex_unlock(&state->mutex);
0254 return ret;
0255 }
0256
0257 static int adv748x_hdmi_g_dv_timings(struct v4l2_subdev *sd,
0258 struct v4l2_dv_timings *timings)
0259 {
0260 struct adv748x_hdmi *hdmi = adv748x_sd_to_hdmi(sd);
0261 struct adv748x_state *state = adv748x_hdmi_to_state(hdmi);
0262
0263 mutex_lock(&state->mutex);
0264
0265 *timings = hdmi->timings;
0266
0267 mutex_unlock(&state->mutex);
0268
0269 return 0;
0270 }
0271
0272 static int adv748x_hdmi_query_dv_timings(struct v4l2_subdev *sd,
0273 struct v4l2_dv_timings *timings)
0274 {
0275 struct adv748x_hdmi *hdmi = adv748x_sd_to_hdmi(sd);
0276 struct adv748x_state *state = adv748x_hdmi_to_state(hdmi);
0277 struct v4l2_bt_timings *bt = &timings->bt;
0278 int pixelclock;
0279 int polarity;
0280
0281 if (!timings)
0282 return -EINVAL;
0283
0284 memset(timings, 0, sizeof(struct v4l2_dv_timings));
0285
0286 if (!adv748x_hdmi_has_signal(state))
0287 return -ENOLINK;
0288
0289 pixelclock = adv748x_hdmi_read_pixelclock(state);
0290 if (pixelclock < 0)
0291 return -ENODATA;
0292
0293 timings->type = V4L2_DV_BT_656_1120;
0294
0295 bt->pixelclock = pixelclock;
0296 bt->interlaced = hdmi_read(state, ADV748X_HDMI_F1H1) &
0297 ADV748X_HDMI_F1H1_INTERLACED ?
0298 V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE;
0299 bt->width = hdmi_read16(state, ADV748X_HDMI_LW1,
0300 ADV748X_HDMI_LW1_WIDTH_MASK);
0301 bt->height = hdmi_read16(state, ADV748X_HDMI_F0H1,
0302 ADV748X_HDMI_F0H1_HEIGHT_MASK);
0303 bt->hfrontporch = hdmi_read16(state, ADV748X_HDMI_HFRONT_PORCH,
0304 ADV748X_HDMI_HFRONT_PORCH_MASK);
0305 bt->hsync = hdmi_read16(state, ADV748X_HDMI_HSYNC_WIDTH,
0306 ADV748X_HDMI_HSYNC_WIDTH_MASK);
0307 bt->hbackporch = hdmi_read16(state, ADV748X_HDMI_HBACK_PORCH,
0308 ADV748X_HDMI_HBACK_PORCH_MASK);
0309 bt->vfrontporch = hdmi_read16(state, ADV748X_HDMI_VFRONT_PORCH,
0310 ADV748X_HDMI_VFRONT_PORCH_MASK) / 2;
0311 bt->vsync = hdmi_read16(state, ADV748X_HDMI_VSYNC_WIDTH,
0312 ADV748X_HDMI_VSYNC_WIDTH_MASK) / 2;
0313 bt->vbackporch = hdmi_read16(state, ADV748X_HDMI_VBACK_PORCH,
0314 ADV748X_HDMI_VBACK_PORCH_MASK) / 2;
0315
0316 polarity = hdmi_read(state, 0x05);
0317 bt->polarities = (polarity & BIT(4) ? V4L2_DV_VSYNC_POS_POL : 0) |
0318 (polarity & BIT(5) ? V4L2_DV_HSYNC_POS_POL : 0);
0319
0320 if (bt->interlaced == V4L2_DV_INTERLACED) {
0321 bt->height += hdmi_read16(state, 0x0b, 0x1fff);
0322 bt->il_vfrontporch = hdmi_read16(state, 0x2c, 0x3fff) / 2;
0323 bt->il_vsync = hdmi_read16(state, 0x30, 0x3fff) / 2;
0324 bt->il_vbackporch = hdmi_read16(state, 0x34, 0x3fff) / 2;
0325 }
0326
0327 adv748x_fill_optional_dv_timings(timings);
0328
0329
0330
0331
0332
0333
0334 hdmi->timings = *timings;
0335
0336 return 0;
0337 }
0338
0339 static int adv748x_hdmi_g_input_status(struct v4l2_subdev *sd, u32 *status)
0340 {
0341 struct adv748x_hdmi *hdmi = adv748x_sd_to_hdmi(sd);
0342 struct adv748x_state *state = adv748x_hdmi_to_state(hdmi);
0343
0344 mutex_lock(&state->mutex);
0345
0346 *status = adv748x_hdmi_has_signal(state) ? 0 : V4L2_IN_ST_NO_SIGNAL;
0347
0348 mutex_unlock(&state->mutex);
0349
0350 return 0;
0351 }
0352
0353 static int adv748x_hdmi_s_stream(struct v4l2_subdev *sd, int enable)
0354 {
0355 struct adv748x_hdmi *hdmi = adv748x_sd_to_hdmi(sd);
0356 struct adv748x_state *state = adv748x_hdmi_to_state(hdmi);
0357 int ret;
0358
0359 mutex_lock(&state->mutex);
0360
0361 ret = adv748x_tx_power(hdmi->tx, enable);
0362 if (ret)
0363 goto done;
0364
0365 if (adv748x_hdmi_has_signal(state))
0366 adv_dbg(state, "Detected HDMI signal\n");
0367 else
0368 adv_dbg(state, "Couldn't detect HDMI video signal\n");
0369
0370 done:
0371 mutex_unlock(&state->mutex);
0372 return ret;
0373 }
0374
0375 static int adv748x_hdmi_g_pixelaspect(struct v4l2_subdev *sd,
0376 struct v4l2_fract *aspect)
0377 {
0378 aspect->numerator = 1;
0379 aspect->denominator = 1;
0380
0381 return 0;
0382 }
0383
0384 static const struct v4l2_subdev_video_ops adv748x_video_ops_hdmi = {
0385 .s_dv_timings = adv748x_hdmi_s_dv_timings,
0386 .g_dv_timings = adv748x_hdmi_g_dv_timings,
0387 .query_dv_timings = adv748x_hdmi_query_dv_timings,
0388 .g_input_status = adv748x_hdmi_g_input_status,
0389 .s_stream = adv748x_hdmi_s_stream,
0390 .g_pixelaspect = adv748x_hdmi_g_pixelaspect,
0391 };
0392
0393
0394
0395
0396
0397 static int adv748x_hdmi_propagate_pixelrate(struct adv748x_hdmi *hdmi)
0398 {
0399 struct v4l2_subdev *tx;
0400 struct v4l2_dv_timings timings;
0401
0402 tx = adv748x_get_remote_sd(&hdmi->pads[ADV748X_HDMI_SOURCE]);
0403 if (!tx)
0404 return -ENOLINK;
0405
0406 adv748x_hdmi_query_dv_timings(&hdmi->sd, &timings);
0407
0408 return adv748x_csi2_set_pixelrate(tx, timings.bt.pixelclock);
0409 }
0410
0411 static int adv748x_hdmi_enum_mbus_code(struct v4l2_subdev *sd,
0412 struct v4l2_subdev_state *sd_state,
0413 struct v4l2_subdev_mbus_code_enum *code)
0414 {
0415 if (code->index != 0)
0416 return -EINVAL;
0417
0418 code->code = MEDIA_BUS_FMT_RGB888_1X24;
0419
0420 return 0;
0421 }
0422
0423 static int adv748x_hdmi_get_format(struct v4l2_subdev *sd,
0424 struct v4l2_subdev_state *sd_state,
0425 struct v4l2_subdev_format *sdformat)
0426 {
0427 struct adv748x_hdmi *hdmi = adv748x_sd_to_hdmi(sd);
0428 struct v4l2_mbus_framefmt *mbusformat;
0429
0430 if (sdformat->pad != ADV748X_HDMI_SOURCE)
0431 return -EINVAL;
0432
0433 if (sdformat->which == V4L2_SUBDEV_FORMAT_TRY) {
0434 mbusformat = v4l2_subdev_get_try_format(sd, sd_state,
0435 sdformat->pad);
0436 sdformat->format = *mbusformat;
0437 } else {
0438 adv748x_hdmi_fill_format(hdmi, &sdformat->format);
0439 adv748x_hdmi_propagate_pixelrate(hdmi);
0440 }
0441
0442 return 0;
0443 }
0444
0445 static int adv748x_hdmi_set_format(struct v4l2_subdev *sd,
0446 struct v4l2_subdev_state *sd_state,
0447 struct v4l2_subdev_format *sdformat)
0448 {
0449 struct v4l2_mbus_framefmt *mbusformat;
0450
0451 if (sdformat->pad != ADV748X_HDMI_SOURCE)
0452 return -EINVAL;
0453
0454 if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE)
0455 return adv748x_hdmi_get_format(sd, sd_state, sdformat);
0456
0457 mbusformat = v4l2_subdev_get_try_format(sd, sd_state, sdformat->pad);
0458 *mbusformat = sdformat->format;
0459
0460 return 0;
0461 }
0462
0463 static int adv748x_hdmi_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
0464 {
0465 struct adv748x_hdmi *hdmi = adv748x_sd_to_hdmi(sd);
0466
0467 memset(edid->reserved, 0, sizeof(edid->reserved));
0468
0469 if (!hdmi->edid.present)
0470 return -ENODATA;
0471
0472 if (edid->start_block == 0 && edid->blocks == 0) {
0473 edid->blocks = hdmi->edid.blocks;
0474 return 0;
0475 }
0476
0477 if (edid->start_block >= hdmi->edid.blocks)
0478 return -EINVAL;
0479
0480 if (edid->start_block + edid->blocks > hdmi->edid.blocks)
0481 edid->blocks = hdmi->edid.blocks - edid->start_block;
0482
0483 memcpy(edid->edid, hdmi->edid.edid + edid->start_block * 128,
0484 edid->blocks * 128);
0485
0486 return 0;
0487 }
0488
0489 static inline int adv748x_hdmi_edid_write_block(struct adv748x_hdmi *hdmi,
0490 unsigned int total_len, const u8 *val)
0491 {
0492 struct adv748x_state *state = adv748x_hdmi_to_state(hdmi);
0493 int err = 0;
0494 int i = 0;
0495 int len = 0;
0496
0497 adv_dbg(state, "%s: write EDID block (%d byte)\n",
0498 __func__, total_len);
0499
0500 while (!err && i < total_len) {
0501 len = (total_len - i) > I2C_SMBUS_BLOCK_MAX ?
0502 I2C_SMBUS_BLOCK_MAX :
0503 (total_len - i);
0504
0505 err = adv748x_write_block(state, ADV748X_PAGE_EDID,
0506 i, val + i, len);
0507 i += len;
0508 }
0509
0510 return err;
0511 }
0512
0513 static int adv748x_hdmi_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
0514 {
0515 struct adv748x_hdmi *hdmi = adv748x_sd_to_hdmi(sd);
0516 struct adv748x_state *state = adv748x_hdmi_to_state(hdmi);
0517 int err;
0518
0519 memset(edid->reserved, 0, sizeof(edid->reserved));
0520
0521 if (edid->start_block != 0)
0522 return -EINVAL;
0523
0524 if (edid->blocks == 0) {
0525 hdmi->edid.blocks = 0;
0526 hdmi->edid.present = 0;
0527
0528
0529 hdmi->aspect_ratio.numerator = 16;
0530 hdmi->aspect_ratio.denominator = 9;
0531
0532
0533 repeater_write(state, ADV748X_REPEATER_EDID_SZ,
0534 edid->blocks << ADV748X_REPEATER_EDID_SZ_SHIFT);
0535
0536 repeater_write(state, ADV748X_REPEATER_EDID_CTL, 0);
0537
0538 return 0;
0539 }
0540
0541 if (edid->blocks > 4) {
0542 edid->blocks = 4;
0543 return -E2BIG;
0544 }
0545
0546 memcpy(hdmi->edid.edid, edid->edid, 128 * edid->blocks);
0547 hdmi->edid.blocks = edid->blocks;
0548 hdmi->edid.present = true;
0549
0550 hdmi->aspect_ratio = v4l2_calc_aspect_ratio(edid->edid[0x15],
0551 edid->edid[0x16]);
0552
0553 err = adv748x_hdmi_edid_write_block(hdmi, 128 * edid->blocks,
0554 hdmi->edid.edid);
0555 if (err < 0) {
0556 v4l2_err(sd, "error %d writing edid pad %d\n", err, edid->pad);
0557 return err;
0558 }
0559
0560 repeater_write(state, ADV748X_REPEATER_EDID_SZ,
0561 edid->blocks << ADV748X_REPEATER_EDID_SZ_SHIFT);
0562
0563 repeater_write(state, ADV748X_REPEATER_EDID_CTL,
0564 ADV748X_REPEATER_EDID_CTL_EN);
0565
0566 return 0;
0567 }
0568
0569 static bool adv748x_hdmi_check_dv_timings(const struct v4l2_dv_timings *timings,
0570 void *hdl)
0571 {
0572 const struct adv748x_hdmi_video_standards *stds =
0573 adv748x_hdmi_video_standards;
0574 unsigned int i;
0575
0576 for (i = 0; stds[i].timings.bt.width; i++)
0577 if (v4l2_match_dv_timings(timings, &stds[i].timings, 0, false))
0578 return true;
0579
0580 return false;
0581 }
0582
0583 static int adv748x_hdmi_enum_dv_timings(struct v4l2_subdev *sd,
0584 struct v4l2_enum_dv_timings *timings)
0585 {
0586 return v4l2_enum_dv_timings_cap(timings, &adv748x_hdmi_timings_cap,
0587 adv748x_hdmi_check_dv_timings, NULL);
0588 }
0589
0590 static int adv748x_hdmi_dv_timings_cap(struct v4l2_subdev *sd,
0591 struct v4l2_dv_timings_cap *cap)
0592 {
0593 *cap = adv748x_hdmi_timings_cap;
0594 return 0;
0595 }
0596
0597 static const struct v4l2_subdev_pad_ops adv748x_pad_ops_hdmi = {
0598 .enum_mbus_code = adv748x_hdmi_enum_mbus_code,
0599 .set_fmt = adv748x_hdmi_set_format,
0600 .get_fmt = adv748x_hdmi_get_format,
0601 .get_edid = adv748x_hdmi_get_edid,
0602 .set_edid = adv748x_hdmi_set_edid,
0603 .dv_timings_cap = adv748x_hdmi_dv_timings_cap,
0604 .enum_dv_timings = adv748x_hdmi_enum_dv_timings,
0605 };
0606
0607
0608
0609
0610
0611 static const struct v4l2_subdev_ops adv748x_ops_hdmi = {
0612 .video = &adv748x_video_ops_hdmi,
0613 .pad = &adv748x_pad_ops_hdmi,
0614 };
0615
0616
0617
0618
0619
0620 static const char * const hdmi_ctrl_patgen_menu[] = {
0621 "Disabled",
0622 "Solid Color",
0623 "Color Bars",
0624 "Ramp Grey",
0625 "Ramp Blue",
0626 "Ramp Red",
0627 "Checkered"
0628 };
0629
0630 static int adv748x_hdmi_s_ctrl(struct v4l2_ctrl *ctrl)
0631 {
0632 struct adv748x_hdmi *hdmi = adv748x_ctrl_to_hdmi(ctrl);
0633 struct adv748x_state *state = adv748x_hdmi_to_state(hdmi);
0634 int ret;
0635 u8 pattern;
0636
0637
0638 ret = cp_clrset(state, ADV748X_CP_VID_ADJ,
0639 ADV748X_CP_VID_ADJ_ENABLE,
0640 ADV748X_CP_VID_ADJ_ENABLE);
0641 if (ret < 0)
0642 return ret;
0643
0644 switch (ctrl->id) {
0645 case V4L2_CID_BRIGHTNESS:
0646 ret = cp_write(state, ADV748X_CP_BRI, ctrl->val);
0647 break;
0648 case V4L2_CID_HUE:
0649 ret = cp_write(state, ADV748X_CP_HUE, ctrl->val);
0650 break;
0651 case V4L2_CID_CONTRAST:
0652 ret = cp_write(state, ADV748X_CP_CON, ctrl->val);
0653 break;
0654 case V4L2_CID_SATURATION:
0655 ret = cp_write(state, ADV748X_CP_SAT, ctrl->val);
0656 break;
0657 case V4L2_CID_TEST_PATTERN:
0658 pattern = ctrl->val;
0659
0660
0661 if (pattern) {
0662 pattern--;
0663 pattern |= ADV748X_CP_PAT_GEN_EN;
0664 }
0665
0666 ret = cp_write(state, ADV748X_CP_PAT_GEN, pattern);
0667
0668 break;
0669 default:
0670 return -EINVAL;
0671 }
0672
0673 return ret;
0674 }
0675
0676 static const struct v4l2_ctrl_ops adv748x_hdmi_ctrl_ops = {
0677 .s_ctrl = adv748x_hdmi_s_ctrl,
0678 };
0679
0680 static int adv748x_hdmi_init_controls(struct adv748x_hdmi *hdmi)
0681 {
0682 struct adv748x_state *state = adv748x_hdmi_to_state(hdmi);
0683
0684 v4l2_ctrl_handler_init(&hdmi->ctrl_hdl, 5);
0685
0686
0687 hdmi->ctrl_hdl.lock = &state->mutex;
0688
0689 v4l2_ctrl_new_std(&hdmi->ctrl_hdl, &adv748x_hdmi_ctrl_ops,
0690 V4L2_CID_BRIGHTNESS, ADV748X_CP_BRI_MIN,
0691 ADV748X_CP_BRI_MAX, 1, ADV748X_CP_BRI_DEF);
0692 v4l2_ctrl_new_std(&hdmi->ctrl_hdl, &adv748x_hdmi_ctrl_ops,
0693 V4L2_CID_CONTRAST, ADV748X_CP_CON_MIN,
0694 ADV748X_CP_CON_MAX, 1, ADV748X_CP_CON_DEF);
0695 v4l2_ctrl_new_std(&hdmi->ctrl_hdl, &adv748x_hdmi_ctrl_ops,
0696 V4L2_CID_SATURATION, ADV748X_CP_SAT_MIN,
0697 ADV748X_CP_SAT_MAX, 1, ADV748X_CP_SAT_DEF);
0698 v4l2_ctrl_new_std(&hdmi->ctrl_hdl, &adv748x_hdmi_ctrl_ops,
0699 V4L2_CID_HUE, ADV748X_CP_HUE_MIN,
0700 ADV748X_CP_HUE_MAX, 1, ADV748X_CP_HUE_DEF);
0701
0702
0703
0704
0705
0706
0707 v4l2_ctrl_new_std_menu_items(&hdmi->ctrl_hdl, &adv748x_hdmi_ctrl_ops,
0708 V4L2_CID_TEST_PATTERN,
0709 ARRAY_SIZE(hdmi_ctrl_patgen_menu) - 1,
0710 0, 0, hdmi_ctrl_patgen_menu);
0711
0712 hdmi->sd.ctrl_handler = &hdmi->ctrl_hdl;
0713 if (hdmi->ctrl_hdl.error) {
0714 v4l2_ctrl_handler_free(&hdmi->ctrl_hdl);
0715 return hdmi->ctrl_hdl.error;
0716 }
0717
0718 return v4l2_ctrl_handler_setup(&hdmi->ctrl_hdl);
0719 }
0720
0721 int adv748x_hdmi_init(struct adv748x_hdmi *hdmi)
0722 {
0723 struct adv748x_state *state = adv748x_hdmi_to_state(hdmi);
0724 static const struct v4l2_dv_timings cea1280x720 =
0725 V4L2_DV_BT_CEA_1280X720P30;
0726 int ret;
0727
0728 hdmi->timings = cea1280x720;
0729
0730
0731 hdmi->aspect_ratio.numerator = 16;
0732 hdmi->aspect_ratio.denominator = 9;
0733
0734 adv748x_subdev_init(&hdmi->sd, state, &adv748x_ops_hdmi,
0735 MEDIA_ENT_F_IO_DTV, "hdmi");
0736
0737 hdmi->pads[ADV748X_HDMI_SINK].flags = MEDIA_PAD_FL_SINK;
0738 hdmi->pads[ADV748X_HDMI_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
0739
0740 ret = media_entity_pads_init(&hdmi->sd.entity,
0741 ADV748X_HDMI_NR_PADS, hdmi->pads);
0742 if (ret)
0743 return ret;
0744
0745 ret = adv748x_hdmi_init_controls(hdmi);
0746 if (ret)
0747 goto err_free_media;
0748
0749 return 0;
0750
0751 err_free_media:
0752 media_entity_cleanup(&hdmi->sd.entity);
0753
0754 return ret;
0755 }
0756
0757 void adv748x_hdmi_cleanup(struct adv748x_hdmi *hdmi)
0758 {
0759 v4l2_device_unregister_subdev(&hdmi->sd);
0760 media_entity_cleanup(&hdmi->sd.entity);
0761 v4l2_ctrl_handler_free(&hdmi->ctrl_hdl);
0762 }