1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2021-2023 Digiteq Automotive 4 * author: Martin Tuma <martin.tuma@digiteqautomotive.com> 5 * 6 * This module handles all the sysfs info/configuration that is related to the 7 * v4l2 output devices. 8 */ 9 10 #include <linux/device.h> 11 #include <linux/nospec.h> 12 #include "mgb4_core.h" 13 #include "mgb4_i2c.h" 14 #include "mgb4_vout.h" 15 #include "mgb4_vin.h" 16 #include "mgb4_cmt.h" 17 #include "mgb4_sysfs.h" 18 19 static int loopin_cnt(struct mgb4_vin_dev *vindev) 20 { 21 struct mgb4_vout_dev *voutdev; 22 u32 config; 23 int i, cnt = 0; 24 25 for (i = 0; i < MGB4_VOUT_DEVICES; i++) { 26 voutdev = vindev->mgbdev->vout[i]; 27 if (!voutdev) 28 continue; 29 30 config = mgb4_read_reg(&voutdev->mgbdev->video, 31 voutdev->config->regs.config); 32 if ((config & 0xc) >> 2 == vindev->config->id) 33 cnt++; 34 } 35 36 return cnt; 37 } 38 39 static bool is_busy(struct video_device *dev) 40 { 41 bool ret; 42 43 mutex_lock(dev->lock); 44 ret = vb2_is_busy(dev->queue); 45 mutex_unlock(dev->lock); 46 47 return ret; 48 } 49 50 /* Common for both FPDL3 and GMSL */ 51 52 static ssize_t output_id_show(struct device *dev, 53 struct device_attribute *attr, char *buf) 54 { 55 struct video_device *vdev = to_video_device(dev); 56 struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); 57 58 return sprintf(buf, "%d\n", voutdev->config->id); 59 } 60 61 static ssize_t video_source_show(struct device *dev, 62 struct device_attribute *attr, char *buf) 63 { 64 struct video_device *vdev = to_video_device(dev); 65 struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); 66 u32 config = mgb4_read_reg(&voutdev->mgbdev->video, 67 voutdev->config->regs.config); 68 69 return sprintf(buf, "%u\n", (config & 0xc) >> 2); 70 } 71 72 /* 73 * Video source change may affect the buffer queue of ANY video input/output on 74 * the card thus if any of the inputs/outputs is in use, we do not allow 75 * the change. 76 * 77 * As we do not want to lock all the video devices at the same time, a two-stage 78 * locking strategy is used. In addition to the video device locking there is 79 * a global (PCI device) variable "io_reconfig" atomically checked/set when 80 * the reconfiguration is running. All the video devices check the variable in 81 * their queue_setup() functions and do not allow to start the queue when 82 * the reconfiguration has started. 83 */ 84 static ssize_t video_source_store(struct device *dev, 85 struct device_attribute *attr, 86 const char *buf, size_t count) 87 { 88 struct video_device *vdev = to_video_device(dev); 89 struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); 90 struct mgb4_dev *mgbdev = voutdev->mgbdev; 91 struct mgb4_vin_dev *loopin_new = NULL, *loopin_old = NULL; 92 unsigned long val; 93 ssize_t ret; 94 u32 config; 95 int i; 96 97 ret = kstrtoul(buf, 10, &val); 98 if (ret) 99 return ret; 100 if (val > 3) 101 return -EINVAL; 102 103 if (test_and_set_bit(0, &mgbdev->io_reconfig)) 104 return -EBUSY; 105 106 ret = -EBUSY; 107 for (i = 0; i < MGB4_VIN_DEVICES; i++) 108 if (mgbdev->vin[i] && is_busy(&mgbdev->vin[i]->vdev)) 109 goto end; 110 for (i = 0; i < MGB4_VOUT_DEVICES; i++) 111 if (mgbdev->vout[i] && is_busy(&mgbdev->vout[i]->vdev)) 112 goto end; 113 114 config = mgb4_read_reg(&mgbdev->video, voutdev->config->regs.config); 115 116 if (((config & 0xc) >> 2) < MGB4_VIN_DEVICES) 117 loopin_old = mgbdev->vin[(config & 0xc) >> 2]; 118 if (val < MGB4_VIN_DEVICES) { 119 val = array_index_nospec(val, MGB4_VIN_DEVICES); 120 loopin_new = mgbdev->vin[val]; 121 } 122 if (loopin_old && loopin_cnt(loopin_old) == 1) 123 mgb4_mask_reg(&mgbdev->video, loopin_old->config->regs.config, 124 0x2, 0x0); 125 if (loopin_new) 126 mgb4_mask_reg(&mgbdev->video, loopin_new->config->regs.config, 127 0x2, 0x2); 128 129 if (val == voutdev->config->id + MGB4_VIN_DEVICES) 130 mgb4_write_reg(&mgbdev->video, voutdev->config->regs.config, 131 config & ~(1 << 1)); 132 else 133 mgb4_write_reg(&mgbdev->video, voutdev->config->regs.config, 134 config | (1U << 1)); 135 136 mgb4_mask_reg(&mgbdev->video, voutdev->config->regs.config, 0xc, 137 val << 2); 138 139 ret = count; 140 end: 141 clear_bit(0, &mgbdev->io_reconfig); 142 143 return ret; 144 } 145 146 static ssize_t display_width_show(struct device *dev, 147 struct device_attribute *attr, char *buf) 148 { 149 struct video_device *vdev = to_video_device(dev); 150 struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); 151 u32 config = mgb4_read_reg(&voutdev->mgbdev->video, 152 voutdev->config->regs.resolution); 153 154 return sprintf(buf, "%u\n", config >> 16); 155 } 156 157 static ssize_t display_width_store(struct device *dev, 158 struct device_attribute *attr, 159 const char *buf, size_t count) 160 { 161 struct video_device *vdev = to_video_device(dev); 162 struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); 163 unsigned long val; 164 int ret; 165 166 ret = kstrtoul(buf, 10, &val); 167 if (ret) 168 return ret; 169 if (val > 0xFFFF) 170 return -EINVAL; 171 172 mutex_lock(voutdev->vdev.lock); 173 if (vb2_is_busy(voutdev->vdev.queue)) { 174 mutex_unlock(voutdev->vdev.lock); 175 return -EBUSY; 176 } 177 178 mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.resolution, 179 0xFFFF0000, val << 16); 180 181 mutex_unlock(voutdev->vdev.lock); 182 183 return count; 184 } 185 186 static ssize_t display_height_show(struct device *dev, 187 struct device_attribute *attr, char *buf) 188 { 189 struct video_device *vdev = to_video_device(dev); 190 struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); 191 u32 config = mgb4_read_reg(&voutdev->mgbdev->video, 192 voutdev->config->regs.resolution); 193 194 return sprintf(buf, "%u\n", config & 0xFFFF); 195 } 196 197 static ssize_t display_height_store(struct device *dev, 198 struct device_attribute *attr, 199 const char *buf, size_t count) 200 { 201 struct video_device *vdev = to_video_device(dev); 202 struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); 203 unsigned long val; 204 int ret; 205 206 ret = kstrtoul(buf, 10, &val); 207 if (ret) 208 return ret; 209 if (val > 0xFFFF) 210 return -EINVAL; 211 212 mutex_lock(voutdev->vdev.lock); 213 if (vb2_is_busy(voutdev->vdev.queue)) { 214 mutex_unlock(voutdev->vdev.lock); 215 return -EBUSY; 216 } 217 218 mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.resolution, 219 0xFFFF, val); 220 221 mutex_unlock(voutdev->vdev.lock); 222 223 return count; 224 } 225 226 static ssize_t frame_rate_show(struct device *dev, 227 struct device_attribute *attr, char *buf) 228 { 229 struct video_device *vdev = to_video_device(dev); 230 struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); 231 u32 period = mgb4_read_reg(&voutdev->mgbdev->video, 232 voutdev->config->regs.frame_period); 233 234 return sprintf(buf, "%u\n", 125000000 / period); 235 } 236 237 /* 238 * Frame rate change is expected to be called on live streams. Video device 239 * locking/queue check is not needed. 240 */ 241 static ssize_t frame_rate_store(struct device *dev, 242 struct device_attribute *attr, const char *buf, 243 size_t count) 244 { 245 struct video_device *vdev = to_video_device(dev); 246 struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); 247 unsigned long val; 248 int ret; 249 250 ret = kstrtoul(buf, 10, &val); 251 if (ret) 252 return ret; 253 254 mgb4_write_reg(&voutdev->mgbdev->video, 255 voutdev->config->regs.frame_period, 125000000 / val); 256 257 return count; 258 } 259 260 static ssize_t hsync_width_show(struct device *dev, 261 struct device_attribute *attr, char *buf) 262 { 263 struct video_device *vdev = to_video_device(dev); 264 struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); 265 u32 sig = mgb4_read_reg(&voutdev->mgbdev->video, 266 voutdev->config->regs.hsync); 267 268 return sprintf(buf, "%u\n", (sig & 0x00FF0000) >> 16); 269 } 270 271 /* 272 * HSYNC width change is expected to be called on live streams. Video device 273 * locking/queue check is not needed. 274 */ 275 static ssize_t hsync_width_store(struct device *dev, 276 struct device_attribute *attr, const char *buf, 277 size_t count) 278 { 279 struct video_device *vdev = to_video_device(dev); 280 struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); 281 unsigned long val; 282 int ret; 283 284 ret = kstrtoul(buf, 10, &val); 285 if (ret) 286 return ret; 287 if (val > 0xFF) 288 return -EINVAL; 289 290 mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.hsync, 291 0x00FF0000, val << 16); 292 293 return count; 294 } 295 296 static ssize_t vsync_width_show(struct device *dev, 297 struct device_attribute *attr, char *buf) 298 { 299 struct video_device *vdev = to_video_device(dev); 300 struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); 301 u32 sig = mgb4_read_reg(&voutdev->mgbdev->video, 302 voutdev->config->regs.vsync); 303 304 return sprintf(buf, "%u\n", (sig & 0x00FF0000) >> 16); 305 } 306 307 /* 308 * VSYNC vidth change is expected to be called on live streams. Video device 309 * locking/queue check is not needed. 310 */ 311 static ssize_t vsync_width_store(struct device *dev, 312 struct device_attribute *attr, const char *buf, 313 size_t count) 314 { 315 struct video_device *vdev = to_video_device(dev); 316 struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); 317 unsigned long val; 318 int ret; 319 320 ret = kstrtoul(buf, 10, &val); 321 if (ret) 322 return ret; 323 if (val > 0xFF) 324 return -EINVAL; 325 326 mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.vsync, 327 0x00FF0000, val << 16); 328 329 return count; 330 } 331 332 static ssize_t hback_porch_show(struct device *dev, 333 struct device_attribute *attr, char *buf) 334 { 335 struct video_device *vdev = to_video_device(dev); 336 struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); 337 u32 sig = mgb4_read_reg(&voutdev->mgbdev->video, 338 voutdev->config->regs.hsync); 339 340 return sprintf(buf, "%u\n", (sig & 0x0000FF00) >> 8); 341 } 342 343 /* 344 * hback porch change is expected to be called on live streams. Video device 345 * locking/queue check is not needed. 346 */ 347 static ssize_t hback_porch_store(struct device *dev, 348 struct device_attribute *attr, const char *buf, 349 size_t count) 350 { 351 struct video_device *vdev = to_video_device(dev); 352 struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); 353 unsigned long val; 354 int ret; 355 356 ret = kstrtoul(buf, 10, &val); 357 if (ret) 358 return ret; 359 if (val > 0xFF) 360 return -EINVAL; 361 362 mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.hsync, 363 0x0000FF00, val << 8); 364 365 return count; 366 } 367 368 static ssize_t vback_porch_show(struct device *dev, 369 struct device_attribute *attr, char *buf) 370 { 371 struct video_device *vdev = to_video_device(dev); 372 struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); 373 u32 sig = mgb4_read_reg(&voutdev->mgbdev->video, 374 voutdev->config->regs.vsync); 375 376 return sprintf(buf, "%u\n", (sig & 0x0000FF00) >> 8); 377 } 378 379 /* 380 * vback porch change is expected to be called on live streams. Video device 381 * locking/queue check is not needed. 382 */ 383 static ssize_t vback_porch_store(struct device *dev, 384 struct device_attribute *attr, const char *buf, 385 size_t count) 386 { 387 struct video_device *vdev = to_video_device(dev); 388 struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); 389 unsigned long val; 390 int ret; 391 392 ret = kstrtoul(buf, 10, &val); 393 if (ret) 394 return ret; 395 if (val > 0xFF) 396 return -EINVAL; 397 398 mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.vsync, 399 0x0000FF00, val << 8); 400 401 return count; 402 } 403 404 static ssize_t hfront_porch_show(struct device *dev, 405 struct device_attribute *attr, char *buf) 406 { 407 struct video_device *vdev = to_video_device(dev); 408 struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); 409 u32 sig = mgb4_read_reg(&voutdev->mgbdev->video, 410 voutdev->config->regs.hsync); 411 412 return sprintf(buf, "%u\n", (sig & 0x000000FF)); 413 } 414 415 /* 416 * hfront porch change is expected to be called on live streams. Video device 417 * locking/queue check is not needed. 418 */ 419 static ssize_t hfront_porch_store(struct device *dev, 420 struct device_attribute *attr, 421 const char *buf, size_t count) 422 { 423 struct video_device *vdev = to_video_device(dev); 424 struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); 425 unsigned long val; 426 int ret; 427 428 ret = kstrtoul(buf, 10, &val); 429 if (ret) 430 return ret; 431 if (val > 0xFF) 432 return -EINVAL; 433 434 mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.hsync, 435 0x000000FF, val); 436 437 return count; 438 } 439 440 static ssize_t vfront_porch_show(struct device *dev, 441 struct device_attribute *attr, char *buf) 442 { 443 struct video_device *vdev = to_video_device(dev); 444 struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); 445 u32 sig = mgb4_read_reg(&voutdev->mgbdev->video, 446 voutdev->config->regs.vsync); 447 448 return sprintf(buf, "%u\n", (sig & 0x000000FF)); 449 } 450 451 /* 452 * vfront porch change is expected to be called on live streams. Video device 453 * locking/queue check is not needed. 454 */ 455 static ssize_t vfront_porch_store(struct device *dev, 456 struct device_attribute *attr, const char *buf, 457 size_t count) 458 { 459 struct video_device *vdev = to_video_device(dev); 460 struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); 461 unsigned long val; 462 int ret; 463 464 ret = kstrtoul(buf, 10, &val); 465 if (ret) 466 return ret; 467 if (val > 0xFF) 468 return -EINVAL; 469 470 mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.vsync, 471 0x000000FF, val); 472 473 return count; 474 } 475 476 /* FPDL3 only */ 477 478 static ssize_t hsync_polarity_show(struct device *dev, 479 struct device_attribute *attr, char *buf) 480 { 481 struct video_device *vdev = to_video_device(dev); 482 struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); 483 u32 config = mgb4_read_reg(&voutdev->mgbdev->video, 484 voutdev->config->regs.hsync); 485 486 return sprintf(buf, "%u\n", (config & (1U << 31)) >> 31); 487 } 488 489 /* 490 * HSYNC polarity change is expected to be called on live streams. Video device 491 * locking/queue check is not needed. 492 */ 493 static ssize_t hsync_polarity_store(struct device *dev, 494 struct device_attribute *attr, 495 const char *buf, size_t count) 496 { 497 struct video_device *vdev = to_video_device(dev); 498 struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); 499 unsigned long val; 500 int ret; 501 502 ret = kstrtoul(buf, 10, &val); 503 if (ret) 504 return ret; 505 if (val > 1) 506 return -EINVAL; 507 508 mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.hsync, 509 (1U << 31), val << 31); 510 511 return count; 512 } 513 514 static ssize_t vsync_polarity_show(struct device *dev, 515 struct device_attribute *attr, char *buf) 516 { 517 struct video_device *vdev = to_video_device(dev); 518 struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); 519 u32 config = mgb4_read_reg(&voutdev->mgbdev->video, 520 voutdev->config->regs.vsync); 521 522 return sprintf(buf, "%u\n", (config & (1U << 31)) >> 31); 523 } 524 525 /* 526 * VSYNC polarity change is expected to be called on live streams. Video device 527 * locking/queue check is not needed. 528 */ 529 static ssize_t vsync_polarity_store(struct device *dev, 530 struct device_attribute *attr, 531 const char *buf, size_t count) 532 { 533 struct video_device *vdev = to_video_device(dev); 534 struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); 535 unsigned long val; 536 int ret; 537 538 ret = kstrtoul(buf, 10, &val); 539 if (ret) 540 return ret; 541 if (val > 1) 542 return -EINVAL; 543 544 mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.vsync, 545 (1U << 31), val << 31); 546 547 return count; 548 } 549 550 static ssize_t de_polarity_show(struct device *dev, 551 struct device_attribute *attr, char *buf) 552 { 553 struct video_device *vdev = to_video_device(dev); 554 struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); 555 u32 config = mgb4_read_reg(&voutdev->mgbdev->video, 556 voutdev->config->regs.vsync); 557 558 return sprintf(buf, "%u\n", (config & (1U << 30)) >> 30); 559 } 560 561 /* 562 * DE polarity change is expected to be called on live streams. Video device 563 * locking/queue check is not needed. 564 */ 565 static ssize_t de_polarity_store(struct device *dev, 566 struct device_attribute *attr, const char *buf, 567 size_t count) 568 { 569 struct video_device *vdev = to_video_device(dev); 570 struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); 571 unsigned long val; 572 int ret; 573 574 ret = kstrtoul(buf, 10, &val); 575 if (ret) 576 return ret; 577 if (val > 1) 578 return -EINVAL; 579 580 mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.vsync, 581 (1U << 30), val << 30); 582 583 return count; 584 } 585 586 static ssize_t fpdl3_output_width_show(struct device *dev, 587 struct device_attribute *attr, char *buf) 588 { 589 struct video_device *vdev = to_video_device(dev); 590 struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); 591 s32 ret; 592 593 mutex_lock(&voutdev->mgbdev->i2c_lock); 594 ret = mgb4_i2c_read_byte(&voutdev->ser, 0x5B); 595 mutex_unlock(&voutdev->mgbdev->i2c_lock); 596 if (ret < 0) 597 return -EIO; 598 599 switch ((u8)ret & 0x03) { 600 case 0: 601 return sprintf(buf, "0\n"); 602 case 1: 603 return sprintf(buf, "1\n"); 604 case 3: 605 return sprintf(buf, "2\n"); 606 default: 607 return -EINVAL; 608 } 609 } 610 611 /* 612 * FPD-Link width change is expected to be called on live streams. Video device 613 * locking/queue check is not needed. 614 */ 615 static ssize_t fpdl3_output_width_store(struct device *dev, 616 struct device_attribute *attr, 617 const char *buf, size_t count) 618 { 619 struct video_device *vdev = to_video_device(dev); 620 struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); 621 u8 i2c_data; 622 unsigned long val; 623 int ret; 624 625 ret = kstrtoul(buf, 10, &val); 626 if (ret) 627 return ret; 628 629 switch (val) { 630 case 0: /* auto */ 631 i2c_data = 0x00; 632 break; 633 case 1: /* single */ 634 i2c_data = 0x01; 635 break; 636 case 2: /* dual */ 637 i2c_data = 0x03; 638 break; 639 default: 640 return -EINVAL; 641 } 642 643 mutex_lock(&voutdev->mgbdev->i2c_lock); 644 ret = mgb4_i2c_mask_byte(&voutdev->ser, 0x5B, 0x03, i2c_data); 645 mutex_unlock(&voutdev->mgbdev->i2c_lock); 646 if (ret < 0) 647 return -EIO; 648 649 return count; 650 } 651 652 static ssize_t pclk_frequency_show(struct device *dev, 653 struct device_attribute *attr, char *buf) 654 { 655 struct video_device *vdev = to_video_device(dev); 656 struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); 657 658 return sprintf(buf, "%u\n", voutdev->freq); 659 } 660 661 static ssize_t pclk_frequency_store(struct device *dev, 662 struct device_attribute *attr, 663 const char *buf, size_t count) 664 { 665 struct video_device *vdev = to_video_device(dev); 666 struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev); 667 unsigned long val; 668 int ret; 669 unsigned int dp; 670 671 ret = kstrtoul(buf, 10, &val); 672 if (ret) 673 return ret; 674 675 mutex_lock(voutdev->vdev.lock); 676 if (vb2_is_busy(voutdev->vdev.queue)) { 677 mutex_unlock(voutdev->vdev.lock); 678 return -EBUSY; 679 } 680 681 dp = (val > 50000) ? 1 : 0; 682 voutdev->freq = mgb4_cmt_set_vout_freq(voutdev, val >> dp) << dp; 683 684 mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.config, 685 0x10, dp << 4); 686 mutex_lock(&voutdev->mgbdev->i2c_lock); 687 ret = mgb4_i2c_mask_byte(&voutdev->ser, 0x4F, 1 << 6, ((~dp) & 1) << 6); 688 mutex_unlock(&voutdev->mgbdev->i2c_lock); 689 690 mutex_unlock(voutdev->vdev.lock); 691 692 return (ret < 0) ? -EIO : count; 693 } 694 695 static DEVICE_ATTR_RO(output_id); 696 static DEVICE_ATTR_RW(video_source); 697 static DEVICE_ATTR_RW(display_width); 698 static DEVICE_ATTR_RW(display_height); 699 static DEVICE_ATTR_RW(frame_rate); 700 static DEVICE_ATTR_RW(hsync_polarity); 701 static DEVICE_ATTR_RW(vsync_polarity); 702 static DEVICE_ATTR_RW(de_polarity); 703 static DEVICE_ATTR_RW(pclk_frequency); 704 static DEVICE_ATTR_RW(hsync_width); 705 static DEVICE_ATTR_RW(vsync_width); 706 static DEVICE_ATTR_RW(hback_porch); 707 static DEVICE_ATTR_RW(hfront_porch); 708 static DEVICE_ATTR_RW(vback_porch); 709 static DEVICE_ATTR_RW(vfront_porch); 710 711 static DEVICE_ATTR_RW(fpdl3_output_width); 712 713 struct attribute *mgb4_fpdl3_out_attrs[] = { 714 &dev_attr_output_id.attr, 715 &dev_attr_video_source.attr, 716 &dev_attr_display_width.attr, 717 &dev_attr_display_height.attr, 718 &dev_attr_frame_rate.attr, 719 &dev_attr_hsync_polarity.attr, 720 &dev_attr_vsync_polarity.attr, 721 &dev_attr_de_polarity.attr, 722 &dev_attr_pclk_frequency.attr, 723 &dev_attr_hsync_width.attr, 724 &dev_attr_vsync_width.attr, 725 &dev_attr_hback_porch.attr, 726 &dev_attr_hfront_porch.attr, 727 &dev_attr_vback_porch.attr, 728 &dev_attr_vfront_porch.attr, 729 &dev_attr_fpdl3_output_width.attr, 730 NULL 731 }; 732 733 struct attribute *mgb4_gmsl_out_attrs[] = { 734 &dev_attr_output_id.attr, 735 &dev_attr_video_source.attr, 736 &dev_attr_display_width.attr, 737 &dev_attr_display_height.attr, 738 &dev_attr_frame_rate.attr, 739 NULL 740 }; 741