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(q: dev->queue);
45 mutex_unlock(lock: 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, fmt: "%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, fmt: "%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(s: buf, base: 10, res: &val);
98 if (ret)
99 return ret;
100 if (val > 3)
101 return -EINVAL;
102
103 if (test_and_set_bit(nr: 0, addr: &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(dev: &mgbdev->vin[i]->vdev))
109 goto end;
110 for (i = 0; i < MGB4_VOUT_DEVICES; i++)
111 if (mgbdev->vout[i] && is_busy(dev: &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(vindev: loopin_old) == 1)
123 mgb4_mask_reg(regs: &mgbdev->video, reg: loopin_old->config->regs.config,
124 mask: 0x2, val: 0x0);
125 if (loopin_new)
126 mgb4_mask_reg(regs: &mgbdev->video, reg: loopin_new->config->regs.config,
127 mask: 0x2, val: 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(regs: &mgbdev->video, reg: voutdev->config->regs.config, mask: 0xc,
137 val: val << 2);
138
139 ret = count;
140end:
141 clear_bit(nr: 0, addr: &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, fmt: "%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(s: buf, base: 10, res: &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(q: voutdev->vdev.queue)) {
174 mutex_unlock(lock: voutdev->vdev.lock);
175 return -EBUSY;
176 }
177
178 mgb4_mask_reg(regs: &voutdev->mgbdev->video, reg: voutdev->config->regs.resolution,
179 mask: 0xFFFF0000, val: val << 16);
180
181 mutex_unlock(lock: 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, fmt: "%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(s: buf, base: 10, res: &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(q: voutdev->vdev.queue)) {
214 mutex_unlock(lock: voutdev->vdev.lock);
215 return -EBUSY;
216 }
217
218 mgb4_mask_reg(regs: &voutdev->mgbdev->video, reg: voutdev->config->regs.resolution,
219 mask: 0xFFFF, val);
220
221 mutex_unlock(lock: 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, fmt: "%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(s: buf, base: 10, res: &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, fmt: "%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(s: buf, base: 10, res: &val);
285 if (ret)
286 return ret;
287 if (val > 0xFF)
288 return -EINVAL;
289
290 mgb4_mask_reg(regs: &voutdev->mgbdev->video, reg: voutdev->config->regs.hsync,
291 mask: 0x00FF0000, val: 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, fmt: "%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(s: buf, base: 10, res: &val);
321 if (ret)
322 return ret;
323 if (val > 0xFF)
324 return -EINVAL;
325
326 mgb4_mask_reg(regs: &voutdev->mgbdev->video, reg: voutdev->config->regs.vsync,
327 mask: 0x00FF0000, val: 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, fmt: "%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(s: buf, base: 10, res: &val);
357 if (ret)
358 return ret;
359 if (val > 0xFF)
360 return -EINVAL;
361
362 mgb4_mask_reg(regs: &voutdev->mgbdev->video, reg: voutdev->config->regs.hsync,
363 mask: 0x0000FF00, val: 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, fmt: "%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(s: buf, base: 10, res: &val);
393 if (ret)
394 return ret;
395 if (val > 0xFF)
396 return -EINVAL;
397
398 mgb4_mask_reg(regs: &voutdev->mgbdev->video, reg: voutdev->config->regs.vsync,
399 mask: 0x0000FF00, val: 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, fmt: "%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(s: buf, base: 10, res: &val);
429 if (ret)
430 return ret;
431 if (val > 0xFF)
432 return -EINVAL;
433
434 mgb4_mask_reg(regs: &voutdev->mgbdev->video, reg: voutdev->config->regs.hsync,
435 mask: 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, fmt: "%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(s: buf, base: 10, res: &val);
465 if (ret)
466 return ret;
467 if (val > 0xFF)
468 return -EINVAL;
469
470 mgb4_mask_reg(regs: &voutdev->mgbdev->video, reg: voutdev->config->regs.vsync,
471 mask: 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, fmt: "%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(s: buf, base: 10, res: &val);
503 if (ret)
504 return ret;
505 if (val > 1)
506 return -EINVAL;
507
508 mgb4_mask_reg(regs: &voutdev->mgbdev->video, reg: voutdev->config->regs.hsync,
509 mask: (1U << 31), val: 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, fmt: "%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(s: buf, base: 10, res: &val);
539 if (ret)
540 return ret;
541 if (val > 1)
542 return -EINVAL;
543
544 mgb4_mask_reg(regs: &voutdev->mgbdev->video, reg: voutdev->config->regs.vsync,
545 mask: (1U << 31), val: 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, fmt: "%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(s: buf, base: 10, res: &val);
575 if (ret)
576 return ret;
577 if (val > 1)
578 return -EINVAL;
579
580 mgb4_mask_reg(regs: &voutdev->mgbdev->video, reg: voutdev->config->regs.vsync,
581 mask: (1U << 30), val: 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(client: &voutdev->ser, reg: 0x5B);
595 mutex_unlock(lock: &voutdev->mgbdev->i2c_lock);
596 if (ret < 0)
597 return -EIO;
598
599 switch ((u8)ret & 0x03) {
600 case 0:
601 return sprintf(buf, fmt: "0\n");
602 case 1:
603 return sprintf(buf, fmt: "1\n");
604 case 3:
605 return sprintf(buf, fmt: "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(s: buf, base: 10, res: &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(client: &voutdev->ser, reg: 0x5B, mask: 0x03, val: i2c_data);
645 mutex_unlock(lock: &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, fmt: "%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(s: buf, base: 10, res: &val);
672 if (ret)
673 return ret;
674
675 mutex_lock(voutdev->vdev.lock);
676 if (vb2_is_busy(q: voutdev->vdev.queue)) {
677 mutex_unlock(lock: voutdev->vdev.lock);
678 return -EBUSY;
679 }
680
681 dp = (val > 50000) ? 1 : 0;
682 voutdev->freq = mgb4_cmt_set_vout_freq(voutdev, freq: val >> dp) << dp;
683
684 mgb4_mask_reg(regs: &voutdev->mgbdev->video, reg: voutdev->config->regs.config,
685 mask: 0x10, val: dp << 4);
686 mutex_lock(&voutdev->mgbdev->i2c_lock);
687 ret = mgb4_i2c_mask_byte(client: &voutdev->ser, reg: 0x4F, mask: 1 << 6, val: ((~dp) & 1) << 6);
688 mutex_unlock(lock: &voutdev->mgbdev->i2c_lock);
689
690 mutex_unlock(lock: 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};
741

source code of linux/drivers/media/pci/mgb4/mgb4_sysfs_out.c