Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.2.
  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
 19static 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
 39static 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
 52static 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
 61static 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 */
 84static 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;
140end:
141	clear_bit(0, &mgbdev->io_reconfig);
142
143	return ret;
144}
145
146static 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
157static 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
186static 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
197static 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
226static 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 */
241static 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
260static 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 */
275static 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
296static 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 */
311static 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
332static 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 */
347static 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
368static 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 */
383static 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
404static 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 */
419static 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
440static 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 */
455static 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
478static 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 */
493static 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
514static 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 */
529static 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
550static 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 */
565static 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
586static 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 */
615static 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
652static 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
661static 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
695static DEVICE_ATTR_RO(output_id);
696static DEVICE_ATTR_RW(video_source);
697static DEVICE_ATTR_RW(display_width);
698static DEVICE_ATTR_RW(display_height);
699static DEVICE_ATTR_RW(frame_rate);
700static DEVICE_ATTR_RW(hsync_polarity);
701static DEVICE_ATTR_RW(vsync_polarity);
702static DEVICE_ATTR_RW(de_polarity);
703static DEVICE_ATTR_RW(pclk_frequency);
704static DEVICE_ATTR_RW(hsync_width);
705static DEVICE_ATTR_RW(vsync_width);
706static DEVICE_ATTR_RW(hback_porch);
707static DEVICE_ATTR_RW(hfront_porch);
708static DEVICE_ATTR_RW(vback_porch);
709static DEVICE_ATTR_RW(vfront_porch);
710
711static DEVICE_ATTR_RW(fpdl3_output_width);
712
713struct 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
733struct 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};