xref: /linux/drivers/media/pci/mgb4/mgb4_sysfs_out.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
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 
loopin_cnt(struct mgb4_vin_dev * vindev)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 
is_busy(struct video_device * dev)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 
output_id_show(struct device * dev,struct device_attribute * attr,char * buf)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 
video_source_show(struct device * dev,struct device_attribute * attr,char * buf)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  */
video_source_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)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 
display_width_show(struct device * dev,struct device_attribute * attr,char * buf)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 
display_width_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)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 
display_height_show(struct device * dev,struct device_attribute * attr,char * buf)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 
display_height_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)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 
frame_rate_show(struct device * dev,struct device_attribute * attr,char * buf)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_limit);
233 
234 	return sprintf(buf, "%u\n", period ? MGB4_HW_FREQ / period : 0);
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  */
frame_rate_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)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 limit, ret;
249 
250 	ret = kstrtoul(buf, 10, &val);
251 	if (ret)
252 		return ret;
253 
254 	limit = val ? MGB4_HW_FREQ / val : 0;
255 	mgb4_write_reg(&voutdev->mgbdev->video,
256 		       voutdev->config->regs.frame_limit, limit);
257 
258 	return count;
259 }
260 
hsync_width_show(struct device * dev,struct device_attribute * attr,char * buf)261 static ssize_t hsync_width_show(struct device *dev,
262 				struct device_attribute *attr, char *buf)
263 {
264 	struct video_device *vdev = to_video_device(dev);
265 	struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev);
266 	u32 sig = mgb4_read_reg(&voutdev->mgbdev->video,
267 				voutdev->config->regs.hsync);
268 
269 	return sprintf(buf, "%u\n", (sig & 0x00FF0000) >> 16);
270 }
271 
272 /*
273  * HSYNC width change is expected to be called on live streams. Video device
274  * locking/queue check is not needed.
275  */
hsync_width_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)276 static ssize_t hsync_width_store(struct device *dev,
277 				 struct device_attribute *attr, const char *buf,
278 				 size_t count)
279 {
280 	struct video_device *vdev = to_video_device(dev);
281 	struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev);
282 	unsigned long val;
283 	int ret;
284 
285 	ret = kstrtoul(buf, 10, &val);
286 	if (ret)
287 		return ret;
288 	if (val > 0xFF)
289 		return -EINVAL;
290 
291 	mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.hsync,
292 		      0x00FF0000, val << 16);
293 
294 	return count;
295 }
296 
vsync_width_show(struct device * dev,struct device_attribute * attr,char * buf)297 static ssize_t vsync_width_show(struct device *dev,
298 				struct device_attribute *attr, char *buf)
299 {
300 	struct video_device *vdev = to_video_device(dev);
301 	struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev);
302 	u32 sig = mgb4_read_reg(&voutdev->mgbdev->video,
303 				voutdev->config->regs.vsync);
304 
305 	return sprintf(buf, "%u\n", (sig & 0x00FF0000) >> 16);
306 }
307 
308 /*
309  * VSYNC vidth change is expected to be called on live streams. Video device
310  * locking/queue check is not needed.
311  */
vsync_width_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)312 static ssize_t vsync_width_store(struct device *dev,
313 				 struct device_attribute *attr, const char *buf,
314 				 size_t count)
315 {
316 	struct video_device *vdev = to_video_device(dev);
317 	struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev);
318 	unsigned long val;
319 	int ret;
320 
321 	ret = kstrtoul(buf, 10, &val);
322 	if (ret)
323 		return ret;
324 	if (val > 0xFF)
325 		return -EINVAL;
326 
327 	mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.vsync,
328 		      0x00FF0000, val << 16);
329 
330 	return count;
331 }
332 
hback_porch_show(struct device * dev,struct device_attribute * attr,char * buf)333 static ssize_t hback_porch_show(struct device *dev,
334 				struct device_attribute *attr, char *buf)
335 {
336 	struct video_device *vdev = to_video_device(dev);
337 	struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev);
338 	u32 sig = mgb4_read_reg(&voutdev->mgbdev->video,
339 				voutdev->config->regs.hsync);
340 
341 	return sprintf(buf, "%u\n", (sig & 0x0000FF00) >> 8);
342 }
343 
344 /*
345  * hback porch change is expected to be called on live streams. Video device
346  * locking/queue check is not needed.
347  */
hback_porch_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)348 static ssize_t hback_porch_store(struct device *dev,
349 				 struct device_attribute *attr, const char *buf,
350 				 size_t count)
351 {
352 	struct video_device *vdev = to_video_device(dev);
353 	struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev);
354 	unsigned long val;
355 	int ret;
356 
357 	ret = kstrtoul(buf, 10, &val);
358 	if (ret)
359 		return ret;
360 	if (val > 0xFF)
361 		return -EINVAL;
362 
363 	mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.hsync,
364 		      0x0000FF00, val << 8);
365 
366 	return count;
367 }
368 
vback_porch_show(struct device * dev,struct device_attribute * attr,char * buf)369 static ssize_t vback_porch_show(struct device *dev,
370 				struct device_attribute *attr, char *buf)
371 {
372 	struct video_device *vdev = to_video_device(dev);
373 	struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev);
374 	u32 sig = mgb4_read_reg(&voutdev->mgbdev->video,
375 				voutdev->config->regs.vsync);
376 
377 	return sprintf(buf, "%u\n", (sig & 0x0000FF00) >> 8);
378 }
379 
380 /*
381  * vback porch change is expected to be called on live streams. Video device
382  * locking/queue check is not needed.
383  */
vback_porch_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)384 static ssize_t vback_porch_store(struct device *dev,
385 				 struct device_attribute *attr, const char *buf,
386 				 size_t count)
387 {
388 	struct video_device *vdev = to_video_device(dev);
389 	struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev);
390 	unsigned long val;
391 	int ret;
392 
393 	ret = kstrtoul(buf, 10, &val);
394 	if (ret)
395 		return ret;
396 	if (val > 0xFF)
397 		return -EINVAL;
398 
399 	mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.vsync,
400 		      0x0000FF00, val << 8);
401 
402 	return count;
403 }
404 
hfront_porch_show(struct device * dev,struct device_attribute * attr,char * buf)405 static ssize_t hfront_porch_show(struct device *dev,
406 				 struct device_attribute *attr, char *buf)
407 {
408 	struct video_device *vdev = to_video_device(dev);
409 	struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev);
410 	u32 sig = mgb4_read_reg(&voutdev->mgbdev->video,
411 				voutdev->config->regs.hsync);
412 
413 	return sprintf(buf, "%u\n", (sig & 0x000000FF));
414 }
415 
416 /*
417  * hfront porch change is expected to be called on live streams. Video device
418  * locking/queue check is not needed.
419  */
hfront_porch_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)420 static ssize_t hfront_porch_store(struct device *dev,
421 				  struct device_attribute *attr,
422 				  const char *buf, size_t count)
423 {
424 	struct video_device *vdev = to_video_device(dev);
425 	struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev);
426 	unsigned long val;
427 	int ret;
428 
429 	ret = kstrtoul(buf, 10, &val);
430 	if (ret)
431 		return ret;
432 	if (val > 0xFF)
433 		return -EINVAL;
434 
435 	mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.hsync,
436 		      0x000000FF, val);
437 
438 	return count;
439 }
440 
vfront_porch_show(struct device * dev,struct device_attribute * attr,char * buf)441 static ssize_t vfront_porch_show(struct device *dev,
442 				 struct device_attribute *attr, char *buf)
443 {
444 	struct video_device *vdev = to_video_device(dev);
445 	struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev);
446 	u32 sig = mgb4_read_reg(&voutdev->mgbdev->video,
447 				voutdev->config->regs.vsync);
448 
449 	return sprintf(buf, "%u\n", (sig & 0x000000FF));
450 }
451 
452 /*
453  * vfront porch change is expected to be called on live streams. Video device
454  * locking/queue check is not needed.
455  */
vfront_porch_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)456 static ssize_t vfront_porch_store(struct device *dev,
457 				  struct device_attribute *attr, const char *buf,
458 				  size_t count)
459 {
460 	struct video_device *vdev = to_video_device(dev);
461 	struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev);
462 	unsigned long val;
463 	int ret;
464 
465 	ret = kstrtoul(buf, 10, &val);
466 	if (ret)
467 		return ret;
468 	if (val > 0xFF)
469 		return -EINVAL;
470 
471 	mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.vsync,
472 		      0x000000FF, val);
473 
474 	return count;
475 }
476 
477 /* FPDL3 only */
478 
hsync_polarity_show(struct device * dev,struct device_attribute * attr,char * buf)479 static ssize_t hsync_polarity_show(struct device *dev,
480 				   struct device_attribute *attr, char *buf)
481 {
482 	struct video_device *vdev = to_video_device(dev);
483 	struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev);
484 	u32 config = mgb4_read_reg(&voutdev->mgbdev->video,
485 	  voutdev->config->regs.hsync);
486 
487 	return sprintf(buf, "%u\n", (config & (1U << 31)) >> 31);
488 }
489 
490 /*
491  * HSYNC polarity change is expected to be called on live streams. Video device
492  * locking/queue check is not needed.
493  */
hsync_polarity_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)494 static ssize_t hsync_polarity_store(struct device *dev,
495 				    struct device_attribute *attr,
496 				    const char *buf, size_t count)
497 {
498 	struct video_device *vdev = to_video_device(dev);
499 	struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev);
500 	unsigned long val;
501 	int ret;
502 
503 	ret = kstrtoul(buf, 10, &val);
504 	if (ret)
505 		return ret;
506 	if (val > 1)
507 		return -EINVAL;
508 
509 	mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.hsync,
510 		      (1U << 31), val << 31);
511 
512 	return count;
513 }
514 
vsync_polarity_show(struct device * dev,struct device_attribute * attr,char * buf)515 static ssize_t vsync_polarity_show(struct device *dev,
516 				   struct device_attribute *attr, char *buf)
517 {
518 	struct video_device *vdev = to_video_device(dev);
519 	struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev);
520 	u32 config = mgb4_read_reg(&voutdev->mgbdev->video,
521 	  voutdev->config->regs.vsync);
522 
523 	return sprintf(buf, "%u\n", (config & (1U << 31)) >> 31);
524 }
525 
526 /*
527  * VSYNC polarity change is expected to be called on live streams. Video device
528  * locking/queue check is not needed.
529  */
vsync_polarity_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)530 static ssize_t vsync_polarity_store(struct device *dev,
531 				    struct device_attribute *attr,
532 				    const char *buf, size_t count)
533 {
534 	struct video_device *vdev = to_video_device(dev);
535 	struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev);
536 	unsigned long val;
537 	int ret;
538 
539 	ret = kstrtoul(buf, 10, &val);
540 	if (ret)
541 		return ret;
542 	if (val > 1)
543 		return -EINVAL;
544 
545 	mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.vsync,
546 		      (1U << 31), val << 31);
547 
548 	return count;
549 }
550 
de_polarity_show(struct device * dev,struct device_attribute * attr,char * buf)551 static ssize_t de_polarity_show(struct device *dev,
552 				struct device_attribute *attr, char *buf)
553 {
554 	struct video_device *vdev = to_video_device(dev);
555 	struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev);
556 	u32 config = mgb4_read_reg(&voutdev->mgbdev->video,
557 	  voutdev->config->regs.vsync);
558 
559 	return sprintf(buf, "%u\n", (config & (1U << 30)) >> 30);
560 }
561 
562 /*
563  * DE polarity change is expected to be called on live streams. Video device
564  * locking/queue check is not needed.
565  */
de_polarity_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)566 static ssize_t de_polarity_store(struct device *dev,
567 				 struct device_attribute *attr, const char *buf,
568 				 size_t count)
569 {
570 	struct video_device *vdev = to_video_device(dev);
571 	struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev);
572 	unsigned long val;
573 	int ret;
574 
575 	ret = kstrtoul(buf, 10, &val);
576 	if (ret)
577 		return ret;
578 	if (val > 1)
579 		return -EINVAL;
580 
581 	mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.vsync,
582 		      (1U << 30), val << 30);
583 
584 	return count;
585 }
586 
fpdl3_output_width_show(struct device * dev,struct device_attribute * attr,char * buf)587 static ssize_t fpdl3_output_width_show(struct device *dev,
588 				       struct device_attribute *attr, char *buf)
589 {
590 	struct video_device *vdev = to_video_device(dev);
591 	struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev);
592 	s32 ret;
593 
594 	mutex_lock(&voutdev->mgbdev->i2c_lock);
595 	ret = mgb4_i2c_read_byte(&voutdev->ser, 0x5B);
596 	mutex_unlock(&voutdev->mgbdev->i2c_lock);
597 	if (ret < 0)
598 		return -EIO;
599 
600 	switch ((u8)ret & 0x03) {
601 	case 0:
602 		return sprintf(buf, "0\n");
603 	case 1:
604 		return sprintf(buf, "1\n");
605 	case 3:
606 		return sprintf(buf, "2\n");
607 	default:
608 		return -EINVAL;
609 	}
610 }
611 
612 /*
613  * FPD-Link width change is expected to be called on live streams. Video device
614  * locking/queue check is not needed.
615  */
fpdl3_output_width_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)616 static ssize_t fpdl3_output_width_store(struct device *dev,
617 					struct device_attribute *attr,
618 					const char *buf, size_t count)
619 {
620 	struct video_device *vdev = to_video_device(dev);
621 	struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev);
622 	u8 i2c_data;
623 	unsigned long val;
624 	int ret;
625 
626 	ret = kstrtoul(buf, 10, &val);
627 	if (ret)
628 		return ret;
629 
630 	switch (val) {
631 	case 0: /* auto */
632 		i2c_data = 0x00;
633 		break;
634 	case 1: /* single */
635 		i2c_data = 0x01;
636 		break;
637 	case 2: /* dual */
638 		i2c_data = 0x03;
639 		break;
640 	default:
641 		return -EINVAL;
642 	}
643 
644 	mutex_lock(&voutdev->mgbdev->i2c_lock);
645 	ret = mgb4_i2c_mask_byte(&voutdev->ser, 0x5B, 0x03, i2c_data);
646 	mutex_unlock(&voutdev->mgbdev->i2c_lock);
647 	if (ret < 0)
648 		return -EIO;
649 
650 	return count;
651 }
652 
pclk_frequency_show(struct device * dev,struct device_attribute * attr,char * buf)653 static ssize_t pclk_frequency_show(struct device *dev,
654 				   struct device_attribute *attr, char *buf)
655 {
656 	struct video_device *vdev = to_video_device(dev);
657 	struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev);
658 
659 	return sprintf(buf, "%u\n", voutdev->freq);
660 }
661 
pclk_frequency_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)662 static ssize_t pclk_frequency_store(struct device *dev,
663 				    struct device_attribute *attr,
664 				    const char *buf, size_t count)
665 {
666 	struct video_device *vdev = to_video_device(dev);
667 	struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev);
668 	unsigned long val;
669 	int ret;
670 	unsigned int dp;
671 
672 	ret = kstrtoul(buf, 10, &val);
673 	if (ret)
674 		return ret;
675 
676 	mutex_lock(voutdev->vdev.lock);
677 	if (vb2_is_busy(voutdev->vdev.queue)) {
678 		mutex_unlock(voutdev->vdev.lock);
679 		return -EBUSY;
680 	}
681 
682 	dp = (val > 50000) ? 1 : 0;
683 	voutdev->freq = mgb4_cmt_set_vout_freq(voutdev, val >> dp) << dp;
684 
685 	mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.config,
686 		      0x10, dp << 4);
687 	mutex_lock(&voutdev->mgbdev->i2c_lock);
688 	ret = mgb4_i2c_mask_byte(&voutdev->ser, 0x4F, 1 << 6, ((~dp) & 1) << 6);
689 	mutex_unlock(&voutdev->mgbdev->i2c_lock);
690 
691 	mutex_unlock(voutdev->vdev.lock);
692 
693 	return (ret < 0) ? -EIO : count;
694 }
695 
696 static DEVICE_ATTR_RO(output_id);
697 static DEVICE_ATTR_RW(video_source);
698 static DEVICE_ATTR_RW(display_width);
699 static DEVICE_ATTR_RW(display_height);
700 static DEVICE_ATTR_RW(frame_rate);
701 static DEVICE_ATTR_RW(hsync_polarity);
702 static DEVICE_ATTR_RW(vsync_polarity);
703 static DEVICE_ATTR_RW(de_polarity);
704 static DEVICE_ATTR_RW(pclk_frequency);
705 static DEVICE_ATTR_RW(hsync_width);
706 static DEVICE_ATTR_RW(vsync_width);
707 static DEVICE_ATTR_RW(hback_porch);
708 static DEVICE_ATTR_RW(hfront_porch);
709 static DEVICE_ATTR_RW(vback_porch);
710 static DEVICE_ATTR_RW(vfront_porch);
711 
712 static DEVICE_ATTR_RW(fpdl3_output_width);
713 
714 struct attribute *mgb4_fpdl3_out_attrs[] = {
715 	&dev_attr_output_id.attr,
716 	&dev_attr_video_source.attr,
717 	&dev_attr_display_width.attr,
718 	&dev_attr_display_height.attr,
719 	&dev_attr_frame_rate.attr,
720 	&dev_attr_hsync_polarity.attr,
721 	&dev_attr_vsync_polarity.attr,
722 	&dev_attr_de_polarity.attr,
723 	&dev_attr_pclk_frequency.attr,
724 	&dev_attr_hsync_width.attr,
725 	&dev_attr_vsync_width.attr,
726 	&dev_attr_hback_porch.attr,
727 	&dev_attr_hfront_porch.attr,
728 	&dev_attr_vback_porch.attr,
729 	&dev_attr_vfront_porch.attr,
730 	&dev_attr_fpdl3_output_width.attr,
731 	NULL
732 };
733 
734 struct attribute *mgb4_gmsl_out_attrs[] = {
735 	&dev_attr_output_id.attr,
736 	&dev_attr_video_source.attr,
737 	&dev_attr_display_width.attr,
738 	&dev_attr_display_height.attr,
739 	&dev_attr_frame_rate.attr,
740 	NULL
741 };
742