diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-05 20:34:57 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-05 20:34:57 -0400 |
commit | e87d51ac61f88ae44fe14b34abe08566032d726b (patch) | |
tree | fc418d2e29fbf8a06f1ed0b6eaff8ba03e0543d7 /drivers/media | |
parent | bdc713bf5674bc6a881bd05c85e2a0f811b409b3 (diff) | |
parent | 3622d3e77ecef090b5111e3c5423313f11711dfa (diff) |
Merge tag 'media/v4.12-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
"Media updates for v4.12-rc1:
- new driver to support mediatek jpeg in hardware codec
- rc-lirc, s5p-cec and st-cec staging drivers got promoted
- hardware histogram support for vsp1 driver
- added Virtual Media Controller driver, to make easier to test the
media controller
- added a new CEC driver (rainshadow-cec)
- removed two staging LIRC drivers for obscure hardware that are too
obsolete
- added support for Intel SR300 Depth camera
- some improvements at CEC and RC core
- lots of driver cleanups, improvements all over the tree
With this series, we're finally getting rid of the LIRC staging
driver. There's just one left (lirc_zilog), with require more care,
as part of its functionality (IR RX) is already provided by another
driver. Work in progress to convert it on the proper way"
* tag 'media/v4.12-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (304 commits)
[media] ov2640: print error if devm_*_optional*() fails
[media] atmel-isc: Fix the static checker warning
[media] ov2640: add support for MEDIA_BUS_FMT_YVYU8_2X8 and MEDIA_BUS_FMT_VYUY8_2X8
[media] ov2640: fix vflip control
[media] ov2640: fix duplicate width+height returning from ov2640_select_win()
[media] ov2640: add missing write to size change preamble
[media] ov2640: add information about DSP register 0xc7
[media] ov2640: improve banding filter register definitions/documentation
[media] ov2640: fix init sequence alignment
[media] ov2640: make GPIOLIB an optional dependency
[media] xc5000: fix spelling mistake: "calibration"
[media] vidioc-queryctrl.rst: fix menu/int menu references
[media] media-entity: only call dev_dbg_obj if mdev is not NULL
[media] pixfmt-meta-vsp1-hgo.rst: remove spurious '-'
[media] mtk-vcodec: avoid warnings because of empty macros
[media] coda: bump maximum number of internal framebuffers to 17
[media] media: mtk-vcodec: remove informative log
[media] subdev-formats.rst: remove spurious '-'
[media] dw2102: limit messages to buffer size
[media] ttusb2: limit messages to buffer size
...
Diffstat (limited to 'drivers/media')
260 files changed, 14372 insertions, 2947 deletions
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 3512316e7a46..b72edd27f880 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig | |||
@@ -81,23 +81,15 @@ config MEDIA_RC_SUPPORT | |||
81 | Say Y when you have a TV or an IR device. | 81 | Say Y when you have a TV or an IR device. |
82 | 82 | ||
83 | config MEDIA_CEC_SUPPORT | 83 | config MEDIA_CEC_SUPPORT |
84 | bool "HDMI CEC support" | 84 | bool "HDMI CEC support" |
85 | select MEDIA_CEC_EDID | 85 | ---help--- |
86 | ---help--- | 86 | Enable support for HDMI CEC (Consumer Electronics Control), |
87 | Enable support for HDMI CEC (Consumer Electronics Control), | 87 | which is an optional HDMI feature. |
88 | which is an optional HDMI feature. | ||
89 | |||
90 | Say Y when you have an HDMI receiver, transmitter or a USB CEC | ||
91 | adapter that supports HDMI CEC. | ||
92 | 88 | ||
93 | config MEDIA_CEC_DEBUG | 89 | Say Y when you have an HDMI receiver, transmitter or a USB CEC |
94 | bool "HDMI CEC debugfs interface" | 90 | adapter that supports HDMI CEC. |
95 | depends on MEDIA_CEC_SUPPORT && DEBUG_FS | ||
96 | ---help--- | ||
97 | Turns on the DebugFS interface for CEC devices. | ||
98 | 91 | ||
99 | config MEDIA_CEC_EDID | 92 | source "drivers/media/cec/Kconfig" |
100 | bool | ||
101 | 93 | ||
102 | # | 94 | # |
103 | # Media controller | 95 | # Media controller |
diff --git a/drivers/media/Makefile b/drivers/media/Makefile index d87ccb8eeabe..523fea3648ad 100644 --- a/drivers/media/Makefile +++ b/drivers/media/Makefile | |||
@@ -2,16 +2,10 @@ | |||
2 | # Makefile for the kernel multimedia device drivers. | 2 | # Makefile for the kernel multimedia device drivers. |
3 | # | 3 | # |
4 | 4 | ||
5 | ifeq ($(CONFIG_MEDIA_CEC_EDID),y) | ||
6 | obj-$(CONFIG_MEDIA_SUPPORT) += cec-edid.o | ||
7 | endif | ||
8 | |||
9 | ifeq ($(CONFIG_MEDIA_CEC_SUPPORT),y) | ||
10 | obj-$(CONFIG_MEDIA_SUPPORT) += cec/ | ||
11 | endif | ||
12 | |||
13 | media-objs := media-device.o media-devnode.o media-entity.o | 5 | media-objs := media-device.o media-devnode.o media-entity.o |
14 | 6 | ||
7 | obj-$(CONFIG_CEC_CORE) += cec/ | ||
8 | |||
15 | # | 9 | # |
16 | # I2C drivers should come before other drivers, otherwise they'll fail | 10 | # I2C drivers should come before other drivers, otherwise they'll fail |
17 | # when compiled as builtin drivers | 11 | # when compiled as builtin drivers |
diff --git a/drivers/media/cec/Kconfig b/drivers/media/cec/Kconfig new file mode 100644 index 000000000000..f944d93e3167 --- /dev/null +++ b/drivers/media/cec/Kconfig | |||
@@ -0,0 +1,19 @@ | |||
1 | config CEC_CORE | ||
2 | tristate | ||
3 | depends on MEDIA_CEC_SUPPORT | ||
4 | default y | ||
5 | |||
6 | config MEDIA_CEC_NOTIFIER | ||
7 | bool | ||
8 | |||
9 | config MEDIA_CEC_RC | ||
10 | bool "HDMI CEC RC integration" | ||
11 | depends on CEC_CORE && RC_CORE | ||
12 | ---help--- | ||
13 | Pass on CEC remote control messages to the RC framework. | ||
14 | |||
15 | config MEDIA_CEC_DEBUG | ||
16 | bool "HDMI CEC debugfs interface" | ||
17 | depends on CEC_CORE && DEBUG_FS | ||
18 | ---help--- | ||
19 | Turns on the DebugFS interface for CEC devices. | ||
diff --git a/drivers/media/cec/Makefile b/drivers/media/cec/Makefile index d6686337275f..402a6c62a3e8 100644 --- a/drivers/media/cec/Makefile +++ b/drivers/media/cec/Makefile | |||
@@ -1,5 +1,7 @@ | |||
1 | cec-objs := cec-core.o cec-adap.o cec-api.o | 1 | cec-objs := cec-core.o cec-adap.o cec-api.o cec-edid.o |
2 | 2 | ||
3 | ifeq ($(CONFIG_MEDIA_CEC_SUPPORT),y) | 3 | ifeq ($(CONFIG_MEDIA_CEC_NOTIFIER),y) |
4 | obj-$(CONFIG_MEDIA_SUPPORT) += cec.o | 4 | cec-objs += cec-notifier.o |
5 | endif | 5 | endif |
6 | |||
7 | obj-$(CONFIG_CEC_CORE) += cec.o | ||
diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c index ccda41c2c9e4..f5fe01c9da8a 100644 --- a/drivers/media/cec/cec-adap.c +++ b/drivers/media/cec/cec-adap.c | |||
@@ -300,6 +300,40 @@ static void cec_data_cancel(struct cec_data *data) | |||
300 | } | 300 | } |
301 | 301 | ||
302 | /* | 302 | /* |
303 | * Flush all pending transmits and cancel any pending timeout work. | ||
304 | * | ||
305 | * This function is called with adap->lock held. | ||
306 | */ | ||
307 | static void cec_flush(struct cec_adapter *adap) | ||
308 | { | ||
309 | struct cec_data *data, *n; | ||
310 | |||
311 | /* | ||
312 | * If the adapter is disabled, or we're asked to stop, | ||
313 | * then cancel any pending transmits. | ||
314 | */ | ||
315 | while (!list_empty(&adap->transmit_queue)) { | ||
316 | data = list_first_entry(&adap->transmit_queue, | ||
317 | struct cec_data, list); | ||
318 | cec_data_cancel(data); | ||
319 | } | ||
320 | if (adap->transmitting) | ||
321 | cec_data_cancel(adap->transmitting); | ||
322 | |||
323 | /* Cancel the pending timeout work. */ | ||
324 | list_for_each_entry_safe(data, n, &adap->wait_queue, list) { | ||
325 | if (cancel_delayed_work(&data->work)) | ||
326 | cec_data_cancel(data); | ||
327 | /* | ||
328 | * If cancel_delayed_work returned false, then | ||
329 | * the cec_wait_timeout function is running, | ||
330 | * which will call cec_data_completed. So no | ||
331 | * need to do anything special in that case. | ||
332 | */ | ||
333 | } | ||
334 | } | ||
335 | |||
336 | /* | ||
303 | * Main CEC state machine | 337 | * Main CEC state machine |
304 | * | 338 | * |
305 | * Wait until the thread should be stopped, or we are not transmitting and | 339 | * Wait until the thread should be stopped, or we are not transmitting and |
@@ -333,7 +367,6 @@ int cec_thread_func(void *_adap) | |||
333 | */ | 367 | */ |
334 | err = wait_event_interruptible_timeout(adap->kthread_waitq, | 368 | err = wait_event_interruptible_timeout(adap->kthread_waitq, |
335 | kthread_should_stop() || | 369 | kthread_should_stop() || |
336 | (!adap->is_configured && !adap->is_configuring) || | ||
337 | (!adap->transmitting && | 370 | (!adap->transmitting && |
338 | !list_empty(&adap->transmit_queue)), | 371 | !list_empty(&adap->transmit_queue)), |
339 | msecs_to_jiffies(CEC_XFER_TIMEOUT_MS)); | 372 | msecs_to_jiffies(CEC_XFER_TIMEOUT_MS)); |
@@ -348,39 +381,8 @@ int cec_thread_func(void *_adap) | |||
348 | 381 | ||
349 | mutex_lock(&adap->lock); | 382 | mutex_lock(&adap->lock); |
350 | 383 | ||
351 | if ((!adap->is_configured && !adap->is_configuring) || | 384 | if (kthread_should_stop()) { |
352 | kthread_should_stop()) { | 385 | cec_flush(adap); |
353 | /* | ||
354 | * If the adapter is disabled, or we're asked to stop, | ||
355 | * then cancel any pending transmits. | ||
356 | */ | ||
357 | while (!list_empty(&adap->transmit_queue)) { | ||
358 | data = list_first_entry(&adap->transmit_queue, | ||
359 | struct cec_data, list); | ||
360 | cec_data_cancel(data); | ||
361 | } | ||
362 | if (adap->transmitting) | ||
363 | cec_data_cancel(adap->transmitting); | ||
364 | |||
365 | /* | ||
366 | * Cancel the pending timeout work. We have to unlock | ||
367 | * the mutex when flushing the work since | ||
368 | * cec_wait_timeout() will take it. This is OK since | ||
369 | * no new entries can be added to wait_queue as long | ||
370 | * as adap->transmitting is NULL, which it is due to | ||
371 | * the cec_data_cancel() above. | ||
372 | */ | ||
373 | while (!list_empty(&adap->wait_queue)) { | ||
374 | data = list_first_entry(&adap->wait_queue, | ||
375 | struct cec_data, list); | ||
376 | |||
377 | if (!cancel_delayed_work(&data->work)) { | ||
378 | mutex_unlock(&adap->lock); | ||
379 | flush_scheduled_work(); | ||
380 | mutex_lock(&adap->lock); | ||
381 | } | ||
382 | cec_data_cancel(data); | ||
383 | } | ||
384 | goto unlock; | 386 | goto unlock; |
385 | } | 387 | } |
386 | 388 | ||
@@ -410,6 +412,7 @@ int cec_thread_func(void *_adap) | |||
410 | struct cec_data, list); | 412 | struct cec_data, list); |
411 | list_del_init(&data->list); | 413 | list_del_init(&data->list); |
412 | adap->transmit_queue_sz--; | 414 | adap->transmit_queue_sz--; |
415 | |||
413 | /* Make this the current transmitting message */ | 416 | /* Make this the current transmitting message */ |
414 | adap->transmitting = data; | 417 | adap->transmitting = data; |
415 | 418 | ||
@@ -603,17 +606,17 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, | |||
603 | 606 | ||
604 | /* Sanity checks */ | 607 | /* Sanity checks */ |
605 | if (msg->len == 0 || msg->len > CEC_MAX_MSG_SIZE) { | 608 | if (msg->len == 0 || msg->len > CEC_MAX_MSG_SIZE) { |
606 | dprintk(1, "cec_transmit_msg: invalid length %d\n", msg->len); | 609 | dprintk(1, "%s: invalid length %d\n", __func__, msg->len); |
607 | return -EINVAL; | 610 | return -EINVAL; |
608 | } | 611 | } |
609 | if (msg->timeout && msg->len == 1) { | 612 | if (msg->timeout && msg->len == 1) { |
610 | dprintk(1, "cec_transmit_msg: can't reply for poll msg\n"); | 613 | dprintk(1, "%s: can't reply for poll msg\n", __func__); |
611 | return -EINVAL; | 614 | return -EINVAL; |
612 | } | 615 | } |
613 | memset(msg->msg + msg->len, 0, sizeof(msg->msg) - msg->len); | 616 | memset(msg->msg + msg->len, 0, sizeof(msg->msg) - msg->len); |
614 | if (msg->len == 1) { | 617 | if (msg->len == 1) { |
615 | if (cec_msg_destination(msg) == 0xf) { | 618 | if (cec_msg_destination(msg) == 0xf) { |
616 | dprintk(1, "cec_transmit_msg: invalid poll message\n"); | 619 | dprintk(1, "%s: invalid poll message\n", __func__); |
617 | return -EINVAL; | 620 | return -EINVAL; |
618 | } | 621 | } |
619 | if (cec_has_log_addr(adap, cec_msg_destination(msg))) { | 622 | if (cec_has_log_addr(adap, cec_msg_destination(msg))) { |
@@ -634,20 +637,30 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, | |||
634 | } | 637 | } |
635 | if (msg->len > 1 && !cec_msg_is_broadcast(msg) && | 638 | if (msg->len > 1 && !cec_msg_is_broadcast(msg) && |
636 | cec_has_log_addr(adap, cec_msg_destination(msg))) { | 639 | cec_has_log_addr(adap, cec_msg_destination(msg))) { |
637 | dprintk(1, "cec_transmit_msg: destination is the adapter itself\n"); | 640 | dprintk(1, "%s: destination is the adapter itself\n", __func__); |
638 | return -EINVAL; | 641 | return -EINVAL; |
639 | } | 642 | } |
640 | if (msg->len > 1 && adap->is_configured && | 643 | if (msg->len > 1 && adap->is_configured && |
641 | !cec_has_log_addr(adap, cec_msg_initiator(msg))) { | 644 | !cec_has_log_addr(adap, cec_msg_initiator(msg))) { |
642 | dprintk(1, "cec_transmit_msg: initiator has unknown logical address %d\n", | 645 | dprintk(1, "%s: initiator has unknown logical address %d\n", |
643 | cec_msg_initiator(msg)); | 646 | __func__, cec_msg_initiator(msg)); |
644 | return -EINVAL; | 647 | return -EINVAL; |
645 | } | 648 | } |
646 | if (!adap->is_configured && !adap->is_configuring) | 649 | if (!adap->is_configured && !adap->is_configuring) { |
647 | return -ENONET; | 650 | if (msg->msg[0] != 0xf0) { |
651 | dprintk(1, "%s: adapter is unconfigured\n", __func__); | ||
652 | return -ENONET; | ||
653 | } | ||
654 | if (msg->reply) { | ||
655 | dprintk(1, "%s: invalid msg->reply\n", __func__); | ||
656 | return -EINVAL; | ||
657 | } | ||
658 | } | ||
648 | 659 | ||
649 | if (adap->transmit_queue_sz >= CEC_MAX_MSG_TX_QUEUE_SZ) | 660 | if (adap->transmit_queue_sz >= CEC_MAX_MSG_TX_QUEUE_SZ) { |
661 | dprintk(1, "%s: transmit queue full\n", __func__); | ||
650 | return -EBUSY; | 662 | return -EBUSY; |
663 | } | ||
651 | 664 | ||
652 | data = kzalloc(sizeof(*data), GFP_KERNEL); | 665 | data = kzalloc(sizeof(*data), GFP_KERNEL); |
653 | if (!data) | 666 | if (!data) |
@@ -659,11 +672,11 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, | |||
659 | } | 672 | } |
660 | 673 | ||
661 | if (msg->timeout) | 674 | if (msg->timeout) |
662 | dprintk(2, "cec_transmit_msg: %*ph (wait for 0x%02x%s)\n", | 675 | dprintk(2, "%s: %*ph (wait for 0x%02x%s)\n", |
663 | msg->len, msg->msg, msg->reply, !block ? ", nb" : ""); | 676 | __func__, msg->len, msg->msg, msg->reply, !block ? ", nb" : ""); |
664 | else | 677 | else |
665 | dprintk(2, "cec_transmit_msg: %*ph%s\n", | 678 | dprintk(2, "%s: %*ph%s\n", |
666 | msg->len, msg->msg, !block ? " (nb)" : ""); | 679 | __func__, msg->len, msg->msg, !block ? " (nb)" : ""); |
667 | 680 | ||
668 | data->msg = *msg; | 681 | data->msg = *msg; |
669 | data->fh = fh; | 682 | data->fh = fh; |
@@ -692,6 +705,7 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, | |||
692 | 705 | ||
693 | if (fh) | 706 | if (fh) |
694 | list_add_tail(&data->xfer_list, &fh->xfer_list); | 707 | list_add_tail(&data->xfer_list, &fh->xfer_list); |
708 | |||
695 | list_add_tail(&data->list, &adap->transmit_queue); | 709 | list_add_tail(&data->list, &adap->transmit_queue); |
696 | adap->transmit_queue_sz++; | 710 | adap->transmit_queue_sz++; |
697 | if (!adap->transmitting) | 711 | if (!adap->transmitting) |
@@ -1117,6 +1131,7 @@ static void cec_adap_unconfigure(struct cec_adapter *adap) | |||
1117 | adap->is_configuring = false; | 1131 | adap->is_configuring = false; |
1118 | adap->is_configured = false; | 1132 | adap->is_configured = false; |
1119 | memset(adap->phys_addrs, 0xff, sizeof(adap->phys_addrs)); | 1133 | memset(adap->phys_addrs, 0xff, sizeof(adap->phys_addrs)); |
1134 | cec_flush(adap); | ||
1120 | wake_up_interruptible(&adap->kthread_waitq); | 1135 | wake_up_interruptible(&adap->kthread_waitq); |
1121 | cec_post_state_event(adap); | 1136 | cec_post_state_event(adap); |
1122 | } | 1137 | } |
@@ -1348,19 +1363,30 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block) | |||
1348 | /* Disabling monitor all mode should always succeed */ | 1363 | /* Disabling monitor all mode should always succeed */ |
1349 | if (adap->monitor_all_cnt) | 1364 | if (adap->monitor_all_cnt) |
1350 | WARN_ON(call_op(adap, adap_monitor_all_enable, false)); | 1365 | WARN_ON(call_op(adap, adap_monitor_all_enable, false)); |
1351 | WARN_ON(adap->ops->adap_enable(adap, false)); | 1366 | mutex_lock(&adap->devnode.lock); |
1367 | if (list_empty(&adap->devnode.fhs)) | ||
1368 | WARN_ON(adap->ops->adap_enable(adap, false)); | ||
1369 | mutex_unlock(&adap->devnode.lock); | ||
1352 | if (phys_addr == CEC_PHYS_ADDR_INVALID) | 1370 | if (phys_addr == CEC_PHYS_ADDR_INVALID) |
1353 | return; | 1371 | return; |
1354 | } | 1372 | } |
1355 | 1373 | ||
1356 | if (adap->ops->adap_enable(adap, true)) | 1374 | mutex_lock(&adap->devnode.lock); |
1375 | if (list_empty(&adap->devnode.fhs) && | ||
1376 | adap->ops->adap_enable(adap, true)) { | ||
1377 | mutex_unlock(&adap->devnode.lock); | ||
1357 | return; | 1378 | return; |
1379 | } | ||
1358 | 1380 | ||
1359 | if (adap->monitor_all_cnt && | 1381 | if (adap->monitor_all_cnt && |
1360 | call_op(adap, adap_monitor_all_enable, true)) { | 1382 | call_op(adap, adap_monitor_all_enable, true)) { |
1361 | WARN_ON(adap->ops->adap_enable(adap, false)); | 1383 | if (list_empty(&adap->devnode.fhs)) |
1384 | WARN_ON(adap->ops->adap_enable(adap, false)); | ||
1385 | mutex_unlock(&adap->devnode.lock); | ||
1362 | return; | 1386 | return; |
1363 | } | 1387 | } |
1388 | mutex_unlock(&adap->devnode.lock); | ||
1389 | |||
1364 | adap->phys_addr = phys_addr; | 1390 | adap->phys_addr = phys_addr; |
1365 | cec_post_state_event(adap); | 1391 | cec_post_state_event(adap); |
1366 | if (adap->log_addrs.num_log_addrs) | 1392 | if (adap->log_addrs.num_log_addrs) |
@@ -1435,12 +1461,16 @@ int __cec_s_log_addrs(struct cec_adapter *adap, | |||
1435 | * within the correct range. | 1461 | * within the correct range. |
1436 | */ | 1462 | */ |
1437 | if (log_addrs->vendor_id != CEC_VENDOR_ID_NONE && | 1463 | if (log_addrs->vendor_id != CEC_VENDOR_ID_NONE && |
1438 | (log_addrs->vendor_id & 0xff000000) != 0) | 1464 | (log_addrs->vendor_id & 0xff000000) != 0) { |
1465 | dprintk(1, "invalid vendor ID\n"); | ||
1439 | return -EINVAL; | 1466 | return -EINVAL; |
1467 | } | ||
1440 | 1468 | ||
1441 | if (log_addrs->cec_version != CEC_OP_CEC_VERSION_1_4 && | 1469 | if (log_addrs->cec_version != CEC_OP_CEC_VERSION_1_4 && |
1442 | log_addrs->cec_version != CEC_OP_CEC_VERSION_2_0) | 1470 | log_addrs->cec_version != CEC_OP_CEC_VERSION_2_0) { |
1471 | dprintk(1, "invalid CEC version\n"); | ||
1443 | return -EINVAL; | 1472 | return -EINVAL; |
1473 | } | ||
1444 | 1474 | ||
1445 | if (log_addrs->num_log_addrs > 1) | 1475 | if (log_addrs->num_log_addrs > 1) |
1446 | for (i = 0; i < log_addrs->num_log_addrs; i++) | 1476 | for (i = 0; i < log_addrs->num_log_addrs; i++) |
@@ -1585,6 +1615,9 @@ static int cec_feature_abort_reason(struct cec_adapter *adap, | |||
1585 | */ | 1615 | */ |
1586 | if (msg->msg[1] == CEC_MSG_FEATURE_ABORT) | 1616 | if (msg->msg[1] == CEC_MSG_FEATURE_ABORT) |
1587 | return 0; | 1617 | return 0; |
1618 | /* Don't Feature Abort messages from 'Unregistered' */ | ||
1619 | if (cec_msg_initiator(msg) == CEC_LOG_ADDR_UNREGISTERED) | ||
1620 | return 0; | ||
1588 | cec_msg_set_reply_to(&tx_msg, msg); | 1621 | cec_msg_set_reply_to(&tx_msg, msg); |
1589 | cec_msg_feature_abort(&tx_msg, msg->msg[1], reason); | 1622 | cec_msg_feature_abort(&tx_msg, msg->msg[1], reason); |
1590 | return cec_transmit_msg(adap, &tx_msg, false); | 1623 | return cec_transmit_msg(adap, &tx_msg, false); |
@@ -1699,7 +1732,7 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, | |||
1699 | !(adap->log_addrs.flags & CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU)) | 1732 | !(adap->log_addrs.flags & CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU)) |
1700 | break; | 1733 | break; |
1701 | 1734 | ||
1702 | #if IS_REACHABLE(CONFIG_RC_CORE) | 1735 | #ifdef CONFIG_MEDIA_CEC_RC |
1703 | switch (msg->msg[2]) { | 1736 | switch (msg->msg[2]) { |
1704 | /* | 1737 | /* |
1705 | * Play function, this message can have variable length | 1738 | * Play function, this message can have variable length |
@@ -1736,7 +1769,7 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, | |||
1736 | if (!(adap->capabilities & CEC_CAP_RC) || | 1769 | if (!(adap->capabilities & CEC_CAP_RC) || |
1737 | !(adap->log_addrs.flags & CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU)) | 1770 | !(adap->log_addrs.flags & CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU)) |
1738 | break; | 1771 | break; |
1739 | #if IS_REACHABLE(CONFIG_RC_CORE) | 1772 | #ifdef CONFIG_MEDIA_CEC_RC |
1740 | rc_keyup(adap->rc); | 1773 | rc_keyup(adap->rc); |
1741 | #endif | 1774 | #endif |
1742 | break; | 1775 | break; |
diff --git a/drivers/media/cec/cec-api.c b/drivers/media/cec/cec-api.c index 8950b6c9d6a9..0860fb458757 100644 --- a/drivers/media/cec/cec-api.c +++ b/drivers/media/cec/cec-api.c | |||
@@ -198,7 +198,11 @@ static long cec_transmit(struct cec_adapter *adap, struct cec_fh *fh, | |||
198 | return -EINVAL; | 198 | return -EINVAL; |
199 | 199 | ||
200 | mutex_lock(&adap->lock); | 200 | mutex_lock(&adap->lock); |
201 | if (!adap->is_configured) | 201 | if (adap->log_addrs.num_log_addrs == 0) |
202 | err = -EPERM; | ||
203 | else if (adap->is_configuring) | ||
204 | err = -ENONET; | ||
205 | else if (!adap->is_configured && msg.msg[0] != 0xf0) | ||
202 | err = -ENONET; | 206 | err = -ENONET; |
203 | else if (cec_is_busy(adap, fh)) | 207 | else if (cec_is_busy(adap, fh)) |
204 | err = -EBUSY; | 208 | err = -EBUSY; |
@@ -515,9 +519,18 @@ static int cec_open(struct inode *inode, struct file *filp) | |||
515 | return err; | 519 | return err; |
516 | } | 520 | } |
517 | 521 | ||
522 | mutex_lock(&devnode->lock); | ||
523 | if (list_empty(&devnode->fhs) && | ||
524 | adap->phys_addr == CEC_PHYS_ADDR_INVALID) { | ||
525 | err = adap->ops->adap_enable(adap, true); | ||
526 | if (err) { | ||
527 | mutex_unlock(&devnode->lock); | ||
528 | kfree(fh); | ||
529 | return err; | ||
530 | } | ||
531 | } | ||
518 | filp->private_data = fh; | 532 | filp->private_data = fh; |
519 | 533 | ||
520 | mutex_lock(&devnode->lock); | ||
521 | /* Queue up initial state events */ | 534 | /* Queue up initial state events */ |
522 | ev_state.state_change.phys_addr = adap->phys_addr; | 535 | ev_state.state_change.phys_addr = adap->phys_addr; |
523 | ev_state.state_change.log_addr_mask = adap->log_addrs.log_addr_mask; | 536 | ev_state.state_change.log_addr_mask = adap->log_addrs.log_addr_mask; |
@@ -551,6 +564,10 @@ static int cec_release(struct inode *inode, struct file *filp) | |||
551 | 564 | ||
552 | mutex_lock(&devnode->lock); | 565 | mutex_lock(&devnode->lock); |
553 | list_del(&fh->list); | 566 | list_del(&fh->list); |
567 | if (list_empty(&devnode->fhs) && | ||
568 | adap->phys_addr == CEC_PHYS_ADDR_INVALID) { | ||
569 | WARN_ON(adap->ops->adap_enable(adap, false)); | ||
570 | } | ||
554 | mutex_unlock(&devnode->lock); | 571 | mutex_unlock(&devnode->lock); |
555 | 572 | ||
556 | /* Unhook pending transmits from this filehandle. */ | 573 | /* Unhook pending transmits from this filehandle. */ |
diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c index 3163e038a364..f9ebff90f8eb 100644 --- a/drivers/media/cec/cec-core.c +++ b/drivers/media/cec/cec-core.c | |||
@@ -187,6 +187,24 @@ static void cec_devnode_unregister(struct cec_devnode *devnode) | |||
187 | put_device(&devnode->dev); | 187 | put_device(&devnode->dev); |
188 | } | 188 | } |
189 | 189 | ||
190 | #ifdef CONFIG_MEDIA_CEC_NOTIFIER | ||
191 | static void cec_cec_notify(struct cec_adapter *adap, u16 pa) | ||
192 | { | ||
193 | cec_s_phys_addr(adap, pa, false); | ||
194 | } | ||
195 | |||
196 | void cec_register_cec_notifier(struct cec_adapter *adap, | ||
197 | struct cec_notifier *notifier) | ||
198 | { | ||
199 | if (WARN_ON(!adap->devnode.registered)) | ||
200 | return; | ||
201 | |||
202 | adap->notifier = notifier; | ||
203 | cec_notifier_register(adap->notifier, adap, cec_cec_notify); | ||
204 | } | ||
205 | EXPORT_SYMBOL_GPL(cec_register_cec_notifier); | ||
206 | #endif | ||
207 | |||
190 | struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, | 208 | struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, |
191 | void *priv, const char *name, u32 caps, | 209 | void *priv, const char *name, u32 caps, |
192 | u8 available_las) | 210 | u8 available_las) |
@@ -194,6 +212,10 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, | |||
194 | struct cec_adapter *adap; | 212 | struct cec_adapter *adap; |
195 | int res; | 213 | int res; |
196 | 214 | ||
215 | #ifndef CONFIG_MEDIA_CEC_RC | ||
216 | caps &= ~CEC_CAP_RC; | ||
217 | #endif | ||
218 | |||
197 | if (WARN_ON(!caps)) | 219 | if (WARN_ON(!caps)) |
198 | return ERR_PTR(-EINVAL); | 220 | return ERR_PTR(-EINVAL); |
199 | if (WARN_ON(!ops)) | 221 | if (WARN_ON(!ops)) |
@@ -226,10 +248,10 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, | |||
226 | return ERR_PTR(res); | 248 | return ERR_PTR(res); |
227 | } | 249 | } |
228 | 250 | ||
251 | #ifdef CONFIG_MEDIA_CEC_RC | ||
229 | if (!(caps & CEC_CAP_RC)) | 252 | if (!(caps & CEC_CAP_RC)) |
230 | return adap; | 253 | return adap; |
231 | 254 | ||
232 | #if IS_REACHABLE(CONFIG_RC_CORE) | ||
233 | /* Prepare the RC input device */ | 255 | /* Prepare the RC input device */ |
234 | adap->rc = rc_allocate_device(RC_DRIVER_SCANCODE); | 256 | adap->rc = rc_allocate_device(RC_DRIVER_SCANCODE); |
235 | if (!adap->rc) { | 257 | if (!adap->rc) { |
@@ -256,8 +278,6 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, | |||
256 | adap->rc->priv = adap; | 278 | adap->rc->priv = adap; |
257 | adap->rc->map_name = RC_MAP_CEC; | 279 | adap->rc->map_name = RC_MAP_CEC; |
258 | adap->rc->timeout = MS_TO_NS(100); | 280 | adap->rc->timeout = MS_TO_NS(100); |
259 | #else | ||
260 | adap->capabilities &= ~CEC_CAP_RC; | ||
261 | #endif | 281 | #endif |
262 | return adap; | 282 | return adap; |
263 | } | 283 | } |
@@ -277,9 +297,9 @@ int cec_register_adapter(struct cec_adapter *adap, | |||
277 | adap->owner = parent->driver->owner; | 297 | adap->owner = parent->driver->owner; |
278 | adap->devnode.dev.parent = parent; | 298 | adap->devnode.dev.parent = parent; |
279 | 299 | ||
280 | #if IS_REACHABLE(CONFIG_RC_CORE) | 300 | #ifdef CONFIG_MEDIA_CEC_RC |
281 | adap->rc->dev.parent = parent; | ||
282 | if (adap->capabilities & CEC_CAP_RC) { | 301 | if (adap->capabilities & CEC_CAP_RC) { |
302 | adap->rc->dev.parent = parent; | ||
283 | res = rc_register_device(adap->rc); | 303 | res = rc_register_device(adap->rc); |
284 | 304 | ||
285 | if (res) { | 305 | if (res) { |
@@ -294,7 +314,7 @@ int cec_register_adapter(struct cec_adapter *adap, | |||
294 | 314 | ||
295 | res = cec_devnode_register(&adap->devnode, adap->owner); | 315 | res = cec_devnode_register(&adap->devnode, adap->owner); |
296 | if (res) { | 316 | if (res) { |
297 | #if IS_REACHABLE(CONFIG_RC_CORE) | 317 | #ifdef CONFIG_MEDIA_CEC_RC |
298 | /* Note: rc_unregister also calls rc_free */ | 318 | /* Note: rc_unregister also calls rc_free */ |
299 | rc_unregister_device(adap->rc); | 319 | rc_unregister_device(adap->rc); |
300 | adap->rc = NULL; | 320 | adap->rc = NULL; |
@@ -329,12 +349,16 @@ void cec_unregister_adapter(struct cec_adapter *adap) | |||
329 | if (IS_ERR_OR_NULL(adap)) | 349 | if (IS_ERR_OR_NULL(adap)) |
330 | return; | 350 | return; |
331 | 351 | ||
332 | #if IS_REACHABLE(CONFIG_RC_CORE) | 352 | #ifdef CONFIG_MEDIA_CEC_RC |
333 | /* Note: rc_unregister also calls rc_free */ | 353 | /* Note: rc_unregister also calls rc_free */ |
334 | rc_unregister_device(adap->rc); | 354 | rc_unregister_device(adap->rc); |
335 | adap->rc = NULL; | 355 | adap->rc = NULL; |
336 | #endif | 356 | #endif |
337 | debugfs_remove_recursive(adap->cec_dir); | 357 | debugfs_remove_recursive(adap->cec_dir); |
358 | #ifdef CONFIG_MEDIA_CEC_NOTIFIER | ||
359 | if (adap->notifier) | ||
360 | cec_notifier_unregister(adap->notifier); | ||
361 | #endif | ||
338 | cec_devnode_unregister(&adap->devnode); | 362 | cec_devnode_unregister(&adap->devnode); |
339 | } | 363 | } |
340 | EXPORT_SYMBOL_GPL(cec_unregister_adapter); | 364 | EXPORT_SYMBOL_GPL(cec_unregister_adapter); |
@@ -349,7 +373,7 @@ void cec_delete_adapter(struct cec_adapter *adap) | |||
349 | kthread_stop(adap->kthread); | 373 | kthread_stop(adap->kthread); |
350 | if (adap->kthread_config) | 374 | if (adap->kthread_config) |
351 | kthread_stop(adap->kthread_config); | 375 | kthread_stop(adap->kthread_config); |
352 | #if IS_REACHABLE(CONFIG_RC_CORE) | 376 | #ifdef CONFIG_MEDIA_CEC_RC |
353 | rc_free_device(adap->rc); | 377 | rc_free_device(adap->rc); |
354 | #endif | 378 | #endif |
355 | kfree(adap); | 379 | kfree(adap); |
diff --git a/drivers/media/cec-edid.c b/drivers/media/cec/cec-edid.c index 5719b991e340..38e3fec6152b 100644 --- a/drivers/media/cec-edid.c +++ b/drivers/media/cec/cec-edid.c | |||
@@ -20,7 +20,7 @@ | |||
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
22 | #include <linux/types.h> | 22 | #include <linux/types.h> |
23 | #include <media/cec-edid.h> | 23 | #include <media/cec.h> |
24 | 24 | ||
25 | /* | 25 | /* |
26 | * This EDID is expected to be a CEA-861 compliant, which means that there are | 26 | * This EDID is expected to be a CEA-861 compliant, which means that there are |
@@ -165,7 +165,3 @@ int cec_phys_addr_validate(u16 phys_addr, u16 *parent, u16 *port) | |||
165 | return 0; | 165 | return 0; |
166 | } | 166 | } |
167 | EXPORT_SYMBOL_GPL(cec_phys_addr_validate); | 167 | EXPORT_SYMBOL_GPL(cec_phys_addr_validate); |
168 | |||
169 | MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com>"); | ||
170 | MODULE_DESCRIPTION("CEC EDID helper functions"); | ||
171 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/cec/cec-notifier.c b/drivers/media/cec/cec-notifier.c new file mode 100644 index 000000000000..74dc1c32080e --- /dev/null +++ b/drivers/media/cec/cec-notifier.c | |||
@@ -0,0 +1,130 @@ | |||
1 | /* | ||
2 | * cec-notifier.c - notify CEC drivers of physical address changes | ||
3 | * | ||
4 | * Copyright 2016 Russell King <rmk+kernel@arm.linux.org.uk> | ||
5 | * Copyright 2016-2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved. | ||
6 | * | ||
7 | * This program is free software; you may redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; version 2 of the License. | ||
10 | * | ||
11 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
12 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
13 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
14 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
15 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
16 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
17 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
18 | * SOFTWARE. | ||
19 | */ | ||
20 | |||
21 | #include <linux/export.h> | ||
22 | #include <linux/string.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/list.h> | ||
25 | #include <linux/kref.h> | ||
26 | |||
27 | #include <media/cec.h> | ||
28 | #include <media/cec-notifier.h> | ||
29 | #include <drm/drm_edid.h> | ||
30 | |||
31 | struct cec_notifier { | ||
32 | struct mutex lock; | ||
33 | struct list_head head; | ||
34 | struct kref kref; | ||
35 | struct device *dev; | ||
36 | struct cec_adapter *cec_adap; | ||
37 | void (*callback)(struct cec_adapter *adap, u16 pa); | ||
38 | |||
39 | u16 phys_addr; | ||
40 | }; | ||
41 | |||
42 | static LIST_HEAD(cec_notifiers); | ||
43 | static DEFINE_MUTEX(cec_notifiers_lock); | ||
44 | |||
45 | struct cec_notifier *cec_notifier_get(struct device *dev) | ||
46 | { | ||
47 | struct cec_notifier *n; | ||
48 | |||
49 | mutex_lock(&cec_notifiers_lock); | ||
50 | list_for_each_entry(n, &cec_notifiers, head) { | ||
51 | if (n->dev == dev) { | ||
52 | kref_get(&n->kref); | ||
53 | mutex_unlock(&cec_notifiers_lock); | ||
54 | return n; | ||
55 | } | ||
56 | } | ||
57 | n = kzalloc(sizeof(*n), GFP_KERNEL); | ||
58 | if (!n) | ||
59 | goto unlock; | ||
60 | n->dev = dev; | ||
61 | n->phys_addr = CEC_PHYS_ADDR_INVALID; | ||
62 | mutex_init(&n->lock); | ||
63 | kref_init(&n->kref); | ||
64 | list_add_tail(&n->head, &cec_notifiers); | ||
65 | unlock: | ||
66 | mutex_unlock(&cec_notifiers_lock); | ||
67 | return n; | ||
68 | } | ||
69 | EXPORT_SYMBOL_GPL(cec_notifier_get); | ||
70 | |||
71 | static void cec_notifier_release(struct kref *kref) | ||
72 | { | ||
73 | struct cec_notifier *n = | ||
74 | container_of(kref, struct cec_notifier, kref); | ||
75 | |||
76 | list_del(&n->head); | ||
77 | kfree(n); | ||
78 | } | ||
79 | |||
80 | void cec_notifier_put(struct cec_notifier *n) | ||
81 | { | ||
82 | mutex_lock(&cec_notifiers_lock); | ||
83 | kref_put(&n->kref, cec_notifier_release); | ||
84 | mutex_unlock(&cec_notifiers_lock); | ||
85 | } | ||
86 | EXPORT_SYMBOL_GPL(cec_notifier_put); | ||
87 | |||
88 | void cec_notifier_set_phys_addr(struct cec_notifier *n, u16 pa) | ||
89 | { | ||
90 | mutex_lock(&n->lock); | ||
91 | n->phys_addr = pa; | ||
92 | if (n->callback) | ||
93 | n->callback(n->cec_adap, n->phys_addr); | ||
94 | mutex_unlock(&n->lock); | ||
95 | } | ||
96 | EXPORT_SYMBOL_GPL(cec_notifier_set_phys_addr); | ||
97 | |||
98 | void cec_notifier_set_phys_addr_from_edid(struct cec_notifier *n, | ||
99 | const struct edid *edid) | ||
100 | { | ||
101 | u16 pa = CEC_PHYS_ADDR_INVALID; | ||
102 | |||
103 | if (edid && edid->extensions) | ||
104 | pa = cec_get_edid_phys_addr((const u8 *)edid, | ||
105 | EDID_LENGTH * (edid->extensions + 1), NULL); | ||
106 | cec_notifier_set_phys_addr(n, pa); | ||
107 | } | ||
108 | EXPORT_SYMBOL_GPL(cec_notifier_set_phys_addr_from_edid); | ||
109 | |||
110 | void cec_notifier_register(struct cec_notifier *n, | ||
111 | struct cec_adapter *adap, | ||
112 | void (*callback)(struct cec_adapter *adap, u16 pa)) | ||
113 | { | ||
114 | kref_get(&n->kref); | ||
115 | mutex_lock(&n->lock); | ||
116 | n->cec_adap = adap; | ||
117 | n->callback = callback; | ||
118 | n->callback(adap, n->phys_addr); | ||
119 | mutex_unlock(&n->lock); | ||
120 | } | ||
121 | EXPORT_SYMBOL_GPL(cec_notifier_register); | ||
122 | |||
123 | void cec_notifier_unregister(struct cec_notifier *n) | ||
124 | { | ||
125 | mutex_lock(&n->lock); | ||
126 | n->callback = NULL; | ||
127 | mutex_unlock(&n->lock); | ||
128 | cec_notifier_put(n); | ||
129 | } | ||
130 | EXPORT_SYMBOL_GPL(cec_notifier_unregister); | ||
diff --git a/drivers/media/common/b2c2/flexcop-fe-tuner.c b/drivers/media/common/b2c2/flexcop-fe-tuner.c index 5f10151ecec9..7636606f0be5 100644 --- a/drivers/media/common/b2c2/flexcop-fe-tuner.c +++ b/drivers/media/common/b2c2/flexcop-fe-tuner.c | |||
@@ -473,7 +473,7 @@ static int airstar_atsc1_attach(struct flexcop_device *fc, | |||
473 | 473 | ||
474 | /* AirStar ATSC 2nd generation */ | 474 | /* AirStar ATSC 2nd generation */ |
475 | #if FE_SUPPORTED(NXT200X) && FE_SUPPORTED(PLL) | 475 | #if FE_SUPPORTED(NXT200X) && FE_SUPPORTED(PLL) |
476 | static struct nxt200x_config samsung_tbmv_config = { | 476 | static const struct nxt200x_config samsung_tbmv_config = { |
477 | .demod_address = 0x0a, | 477 | .demod_address = 0x0a, |
478 | }; | 478 | }; |
479 | 479 | ||
diff --git a/drivers/media/common/saa7146/saa7146_vbi.c b/drivers/media/common/saa7146/saa7146_vbi.c index 49237518d65f..3553ac4cba5c 100644 --- a/drivers/media/common/saa7146/saa7146_vbi.c +++ b/drivers/media/common/saa7146/saa7146_vbi.c | |||
@@ -365,9 +365,8 @@ static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv) | |||
365 | 365 | ||
366 | INIT_LIST_HEAD(&vv->vbi_dmaq.queue); | 366 | INIT_LIST_HEAD(&vv->vbi_dmaq.queue); |
367 | 367 | ||
368 | init_timer(&vv->vbi_dmaq.timeout); | 368 | setup_timer(&vv->vbi_dmaq.timeout, saa7146_buffer_timeout, |
369 | vv->vbi_dmaq.timeout.function = saa7146_buffer_timeout; | 369 | (unsigned long)(&vv->vbi_dmaq)); |
370 | vv->vbi_dmaq.timeout.data = (unsigned long)(&vv->vbi_dmaq); | ||
371 | vv->vbi_dmaq.dev = dev; | 370 | vv->vbi_dmaq.dev = dev; |
372 | 371 | ||
373 | init_waitqueue_head(&vv->vbi_wq); | 372 | init_waitqueue_head(&vv->vbi_wq); |
diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c index e034bcfcf757..b3b29d4f36ed 100644 --- a/drivers/media/common/saa7146/saa7146_video.c +++ b/drivers/media/common/saa7146/saa7146_video.c | |||
@@ -1201,9 +1201,8 @@ static void video_init(struct saa7146_dev *dev, struct saa7146_vv *vv) | |||
1201 | { | 1201 | { |
1202 | INIT_LIST_HEAD(&vv->video_dmaq.queue); | 1202 | INIT_LIST_HEAD(&vv->video_dmaq.queue); |
1203 | 1203 | ||
1204 | init_timer(&vv->video_dmaq.timeout); | 1204 | setup_timer(&vv->video_dmaq.timeout, saa7146_buffer_timeout, |
1205 | vv->video_dmaq.timeout.function = saa7146_buffer_timeout; | 1205 | (unsigned long)(&vv->video_dmaq)); |
1206 | vv->video_dmaq.timeout.data = (unsigned long)(&vv->video_dmaq); | ||
1207 | vv->video_dmaq.dev = dev; | 1206 | vv->video_dmaq.dev = dev; |
1208 | 1207 | ||
1209 | /* set some default values */ | 1208 | /* set some default values */ |
diff --git a/drivers/media/common/tveeprom.c b/drivers/media/common/tveeprom.c index 6e1020227f9f..ccf2d3b12aec 100644 --- a/drivers/media/common/tveeprom.c +++ b/drivers/media/common/tveeprom.c | |||
@@ -420,8 +420,8 @@ static int hasRadioTuner(int tunerType) | |||
420 | return 0; | 420 | return 0; |
421 | } | 421 | } |
422 | 422 | ||
423 | void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, | 423 | void tveeprom_hauppauge_analog(struct tveeprom *tvee, |
424 | unsigned char *eeprom_data) | 424 | unsigned char *eeprom_data) |
425 | { | 425 | { |
426 | /* ---------------------------------------------- | 426 | /* ---------------------------------------------- |
427 | ** The hauppauge eeprom format is tagged | 427 | ** The hauppauge eeprom format is tagged |
diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c index e47b46e2d26c..3dd22da7e17d 100644 --- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c +++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c | |||
@@ -927,7 +927,14 @@ static void precalculate_color(struct tpg_data *tpg, int k) | |||
927 | y >>= 4; | 927 | y >>= 4; |
928 | cb >>= 4; | 928 | cb >>= 4; |
929 | cr >>= 4; | 929 | cr >>= 4; |
930 | if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) { | 930 | /* |
931 | * XV601/709 use the header/footer margins to encode R', G' | ||
932 | * and B' values outside the range [0-1]. So do not clamp | ||
933 | * XV601/709 values. | ||
934 | */ | ||
935 | if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE && | ||
936 | tpg->real_ycbcr_enc != V4L2_YCBCR_ENC_XV601 && | ||
937 | tpg->real_ycbcr_enc != V4L2_YCBCR_ENC_XV709) { | ||
931 | y = clamp(y, 16, 235); | 938 | y = clamp(y, 16, 235); |
932 | cb = clamp(cb, 16, 240); | 939 | cb = clamp(cb, 16, 240); |
933 | cr = clamp(cr, 16, 240); | 940 | cr = clamp(cr, 16, 240); |
diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c index 8d65028c7a74..d38bf9bce480 100644 --- a/drivers/media/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb-core/dvb_ca_en50221.c | |||
@@ -785,6 +785,29 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * b | |||
785 | goto exit; | 785 | goto exit; |
786 | } | 786 | } |
787 | 787 | ||
788 | /* | ||
789 | * It may need some time for the CAM to settle down, or there might | ||
790 | * be a race condition between the CAM, writing HC and our last | ||
791 | * check for DA. This happens, if the CAM asserts DA, just after | ||
792 | * checking DA before we are setting HC. In this case it might be | ||
793 | * a bug in the CAM to keep the FR bit, the lower layer/HW | ||
794 | * communication requires a longer timeout or the CAM needs more | ||
795 | * time internally. But this happens in reality! | ||
796 | * We need to read the status from the HW again and do the same | ||
797 | * we did for the previous check for DA | ||
798 | */ | ||
799 | status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS); | ||
800 | if (status < 0) | ||
801 | goto exit; | ||
802 | |||
803 | if (status & (STATUSREG_DA | STATUSREG_RE)) { | ||
804 | if (status & STATUSREG_DA) | ||
805 | dvb_ca_en50221_thread_wakeup(ca); | ||
806 | |||
807 | status = -EAGAIN; | ||
808 | goto exit; | ||
809 | } | ||
810 | |||
788 | /* send the amount of data */ | 811 | /* send the amount of data */ |
789 | if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH, bytes_write >> 8)) != 0) | 812 | if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH, bytes_write >> 8)) != 0) |
790 | goto exit; | 813 | goto exit; |
diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h index 482912d3b77a..907a05bde162 100644 --- a/drivers/media/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb-core/dvb_frontend.h | |||
@@ -643,6 +643,8 @@ struct dtv_frontend_properties { | |||
643 | /** | 643 | /** |
644 | * struct dvb_frontend - Frontend structure to be used on drivers. | 644 | * struct dvb_frontend - Frontend structure to be used on drivers. |
645 | * | 645 | * |
646 | * @refcount: refcount to keep track of struct dvb_frontend | ||
647 | * references | ||
646 | * @ops: embedded struct dvb_frontend_ops | 648 | * @ops: embedded struct dvb_frontend_ops |
647 | * @dvb: pointer to struct dvb_adapter | 649 | * @dvb: pointer to struct dvb_adapter |
648 | * @demodulator_priv: demod private data | 650 | * @demodulator_priv: demod private data |
diff --git a/drivers/media/dvb-frontends/cxd2841er.c b/drivers/media/dvb-frontends/cxd2841er.c index 614bfb3740f1..ce37dc2e89c7 100644 --- a/drivers/media/dvb-frontends/cxd2841er.c +++ b/drivers/media/dvb-frontends/cxd2841er.c | |||
@@ -3852,7 +3852,9 @@ static struct dvb_frontend_ops cxd2841er_t_c_ops = { | |||
3852 | FE_CAN_MUTE_TS | | 3852 | FE_CAN_MUTE_TS | |
3853 | FE_CAN_2G_MODULATION, | 3853 | FE_CAN_2G_MODULATION, |
3854 | .frequency_min = 42000000, | 3854 | .frequency_min = 42000000, |
3855 | .frequency_max = 1002000000 | 3855 | .frequency_max = 1002000000, |
3856 | .symbol_rate_min = 870000, | ||
3857 | .symbol_rate_max = 11700000 | ||
3856 | }, | 3858 | }, |
3857 | .init = cxd2841er_init_tc, | 3859 | .init = cxd2841er_init_tc, |
3858 | .sleep = cxd2841er_sleep_tc, | 3860 | .sleep = cxd2841er_sleep_tc, |
diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c index 7e1bbbaad625..b5ea9192a341 100644 --- a/drivers/media/dvb-frontends/drxk_hard.c +++ b/drivers/media/dvb-frontends/drxk_hard.c | |||
@@ -1904,7 +1904,9 @@ static int get_lock_status(struct drxk_state *state, u32 *p_lock_status) | |||
1904 | status = get_dvbt_lock_status(state, p_lock_status); | 1904 | status = get_dvbt_lock_status(state, p_lock_status); |
1905 | break; | 1905 | break; |
1906 | default: | 1906 | default: |
1907 | break; | 1907 | pr_debug("Unsupported operation mode %d in %s\n", |
1908 | state->m_operation_mode, __func__); | ||
1909 | return 0; | ||
1908 | } | 1910 | } |
1909 | error: | 1911 | error: |
1910 | if (status < 0) | 1912 | if (status < 0) |
diff --git a/drivers/media/dvb-frontends/mn88472.c b/drivers/media/dvb-frontends/mn88472.c index 29dd13b36c28..f6938f9607ac 100644 --- a/drivers/media/dvb-frontends/mn88472.c +++ b/drivers/media/dvb-frontends/mn88472.c | |||
@@ -28,8 +28,9 @@ static int mn88472_read_status(struct dvb_frontend *fe, enum fe_status *status) | |||
28 | struct i2c_client *client = fe->demodulator_priv; | 28 | struct i2c_client *client = fe->demodulator_priv; |
29 | struct mn88472_dev *dev = i2c_get_clientdata(client); | 29 | struct mn88472_dev *dev = i2c_get_clientdata(client); |
30 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | 30 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
31 | int ret; | 31 | int ret, i, stmp; |
32 | unsigned int utmp; | 32 | unsigned int utmp, utmp1, utmp2; |
33 | u8 buf[5]; | ||
33 | 34 | ||
34 | if (!dev->active) { | 35 | if (!dev->active) { |
35 | ret = -EAGAIN; | 36 | ret = -EAGAIN; |
@@ -77,6 +78,127 @@ static int mn88472_read_status(struct dvb_frontend *fe, enum fe_status *status) | |||
77 | goto err; | 78 | goto err; |
78 | } | 79 | } |
79 | 80 | ||
81 | /* Signal strength */ | ||
82 | if (*status & FE_HAS_SIGNAL) { | ||
83 | for (i = 0; i < 2; i++) { | ||
84 | ret = regmap_bulk_read(dev->regmap[2], 0x8e + i, | ||
85 | &buf[i], 1); | ||
86 | if (ret) | ||
87 | goto err; | ||
88 | } | ||
89 | |||
90 | utmp1 = buf[0] << 8 | buf[1] << 0 | buf[0] >> 2; | ||
91 | dev_dbg(&client->dev, "strength=%u\n", utmp1); | ||
92 | |||
93 | c->strength.stat[0].scale = FE_SCALE_RELATIVE; | ||
94 | c->strength.stat[0].uvalue = utmp1; | ||
95 | } else { | ||
96 | c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
97 | } | ||
98 | |||
99 | /* CNR */ | ||
100 | if (*status & FE_HAS_VITERBI && c->delivery_system == SYS_DVBT) { | ||
101 | /* DVB-T CNR */ | ||
102 | ret = regmap_bulk_read(dev->regmap[0], 0x9c, buf, 2); | ||
103 | if (ret) | ||
104 | goto err; | ||
105 | |||
106 | utmp = buf[0] << 8 | buf[1] << 0; | ||
107 | if (utmp) { | ||
108 | /* CNR[dB]: 10 * log10(65536 / value) + 2 */ | ||
109 | /* log10(65536) = 80807124, 0.2 = 3355443 */ | ||
110 | stmp = ((u64)80807124 - intlog10(utmp) + 3355443) | ||
111 | * 10000 >> 24; | ||
112 | |||
113 | dev_dbg(&client->dev, "cnr=%d value=%u\n", stmp, utmp); | ||
114 | } else { | ||
115 | stmp = 0; | ||
116 | } | ||
117 | |||
118 | c->cnr.stat[0].svalue = stmp; | ||
119 | c->cnr.stat[0].scale = FE_SCALE_DECIBEL; | ||
120 | } else if (*status & FE_HAS_VITERBI && | ||
121 | c->delivery_system == SYS_DVBT2) { | ||
122 | /* DVB-T2 CNR */ | ||
123 | for (i = 0; i < 3; i++) { | ||
124 | ret = regmap_bulk_read(dev->regmap[2], 0xbc + i, | ||
125 | &buf[i], 1); | ||
126 | if (ret) | ||
127 | goto err; | ||
128 | } | ||
129 | |||
130 | utmp = buf[1] << 8 | buf[2] << 0; | ||
131 | utmp1 = (buf[0] >> 2) & 0x01; /* 0=SISO, 1=MISO */ | ||
132 | if (utmp) { | ||
133 | if (utmp1) { | ||
134 | /* CNR[dB]: 10 * log10(16384 / value) - 6 */ | ||
135 | /* log10(16384) = 70706234, 0.6 = 10066330 */ | ||
136 | stmp = ((u64)70706234 - intlog10(utmp) | ||
137 | - 10066330) * 10000 >> 24; | ||
138 | dev_dbg(&client->dev, "cnr=%d value=%u MISO\n", | ||
139 | stmp, utmp); | ||
140 | } else { | ||
141 | /* CNR[dB]: 10 * log10(65536 / value) + 2 */ | ||
142 | /* log10(65536) = 80807124, 0.2 = 3355443 */ | ||
143 | stmp = ((u64)80807124 - intlog10(utmp) | ||
144 | + 3355443) * 10000 >> 24; | ||
145 | |||
146 | dev_dbg(&client->dev, "cnr=%d value=%u SISO\n", | ||
147 | stmp, utmp); | ||
148 | } | ||
149 | } else { | ||
150 | stmp = 0; | ||
151 | } | ||
152 | |||
153 | c->cnr.stat[0].svalue = stmp; | ||
154 | c->cnr.stat[0].scale = FE_SCALE_DECIBEL; | ||
155 | } else if (*status & FE_HAS_VITERBI && | ||
156 | c->delivery_system == SYS_DVBC_ANNEX_A) { | ||
157 | /* DVB-C CNR */ | ||
158 | ret = regmap_bulk_read(dev->regmap[1], 0xa1, buf, 4); | ||
159 | if (ret) | ||
160 | goto err; | ||
161 | |||
162 | utmp1 = buf[0] << 8 | buf[1] << 0; /* signal */ | ||
163 | utmp2 = buf[2] << 8 | buf[3] << 0; /* noise */ | ||
164 | if (utmp1 && utmp2) { | ||
165 | /* CNR[dB]: 10 * log10(8 * (signal / noise)) */ | ||
166 | /* log10(8) = 15151336 */ | ||
167 | stmp = ((u64)15151336 + intlog10(utmp1) | ||
168 | - intlog10(utmp2)) * 10000 >> 24; | ||
169 | |||
170 | dev_dbg(&client->dev, "cnr=%d signal=%u noise=%u\n", | ||
171 | stmp, utmp1, utmp2); | ||
172 | } else { | ||
173 | stmp = 0; | ||
174 | } | ||
175 | |||
176 | c->cnr.stat[0].svalue = stmp; | ||
177 | c->cnr.stat[0].scale = FE_SCALE_DECIBEL; | ||
178 | } else { | ||
179 | c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
180 | } | ||
181 | |||
182 | /* PER */ | ||
183 | if (*status & FE_HAS_SYNC) { | ||
184 | ret = regmap_bulk_read(dev->regmap[0], 0xe1, buf, 4); | ||
185 | if (ret) | ||
186 | goto err; | ||
187 | |||
188 | utmp1 = buf[0] << 8 | buf[1] << 0; | ||
189 | utmp2 = buf[2] << 8 | buf[3] << 0; | ||
190 | dev_dbg(&client->dev, "block_error=%u block_count=%u\n", | ||
191 | utmp1, utmp2); | ||
192 | |||
193 | c->block_error.stat[0].scale = FE_SCALE_COUNTER; | ||
194 | c->block_error.stat[0].uvalue += utmp1; | ||
195 | c->block_count.stat[0].scale = FE_SCALE_COUNTER; | ||
196 | c->block_count.stat[0].uvalue += utmp2; | ||
197 | } else { | ||
198 | c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
199 | c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; | ||
200 | } | ||
201 | |||
80 | return 0; | 202 | return 0; |
81 | err: | 203 | err: |
82 | dev_dbg(&client->dev, "failed=%d\n", ret); | 204 | dev_dbg(&client->dev, "failed=%d\n", ret); |
@@ -462,6 +584,7 @@ static int mn88472_probe(struct i2c_client *client, | |||
462 | { | 584 | { |
463 | struct mn88472_config *pdata = client->dev.platform_data; | 585 | struct mn88472_config *pdata = client->dev.platform_data; |
464 | struct mn88472_dev *dev; | 586 | struct mn88472_dev *dev; |
587 | struct dtv_frontend_properties *c; | ||
465 | int ret; | 588 | int ret; |
466 | unsigned int utmp; | 589 | unsigned int utmp; |
467 | static const struct regmap_config regmap_config = { | 590 | static const struct regmap_config regmap_config = { |
@@ -547,6 +670,13 @@ static int mn88472_probe(struct i2c_client *client, | |||
547 | *pdata->fe = &dev->fe; | 670 | *pdata->fe = &dev->fe; |
548 | i2c_set_clientdata(client, dev); | 671 | i2c_set_clientdata(client, dev); |
549 | 672 | ||
673 | /* Init stats to indicate which stats are supported */ | ||
674 | c = &dev->fe.dtv_property_cache; | ||
675 | c->strength.len = 1; | ||
676 | c->cnr.len = 1; | ||
677 | c->block_error.len = 1; | ||
678 | c->block_count.len = 1; | ||
679 | |||
550 | /* Setup callbacks */ | 680 | /* Setup callbacks */ |
551 | pdata->get_dvb_frontend = mn88472_get_dvb_frontend; | 681 | pdata->get_dvb_frontend = mn88472_get_dvb_frontend; |
552 | 682 | ||
diff --git a/drivers/media/dvb-frontends/mn88472_priv.h b/drivers/media/dvb-frontends/mn88472_priv.h index cdf2597a25d1..fb50f56ba30b 100644 --- a/drivers/media/dvb-frontends/mn88472_priv.h +++ b/drivers/media/dvb-frontends/mn88472_priv.h | |||
@@ -18,6 +18,7 @@ | |||
18 | #define MN88472_PRIV_H | 18 | #define MN88472_PRIV_H |
19 | 19 | ||
20 | #include "dvb_frontend.h" | 20 | #include "dvb_frontend.h" |
21 | #include "dvb_math.h" | ||
21 | #include "mn88472.h" | 22 | #include "mn88472.h" |
22 | #include <linux/firmware.h> | 23 | #include <linux/firmware.h> |
23 | #include <linux/regmap.h> | 24 | #include <linux/regmap.h> |
diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index 680ba06c29fb..172fc367ccaa 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c | |||
@@ -740,6 +740,9 @@ static int si2168_probe(struct i2c_client *client, | |||
740 | case SI2168_CHIP_ID_B40: | 740 | case SI2168_CHIP_ID_B40: |
741 | dev->firmware_name = SI2168_B40_FIRMWARE; | 741 | dev->firmware_name = SI2168_B40_FIRMWARE; |
742 | break; | 742 | break; |
743 | case SI2168_CHIP_ID_D60: | ||
744 | dev->firmware_name = SI2168_D60_FIRMWARE; | ||
745 | break; | ||
743 | default: | 746 | default: |
744 | dev_dbg(&client->dev, "unknown chip version Si21%d-%c%c%c\n", | 747 | dev_dbg(&client->dev, "unknown chip version Si21%d-%c%c%c\n", |
745 | cmd.args[2], cmd.args[1], cmd.args[3], cmd.args[4]); | 748 | cmd.args[2], cmd.args[1], cmd.args[3], cmd.args[4]); |
@@ -827,3 +830,4 @@ MODULE_LICENSE("GPL"); | |||
827 | MODULE_FIRMWARE(SI2168_A20_FIRMWARE); | 830 | MODULE_FIRMWARE(SI2168_A20_FIRMWARE); |
828 | MODULE_FIRMWARE(SI2168_A30_FIRMWARE); | 831 | MODULE_FIRMWARE(SI2168_A30_FIRMWARE); |
829 | MODULE_FIRMWARE(SI2168_B40_FIRMWARE); | 832 | MODULE_FIRMWARE(SI2168_B40_FIRMWARE); |
833 | MODULE_FIRMWARE(SI2168_D60_FIRMWARE); | ||
diff --git a/drivers/media/dvb-frontends/si2168_priv.h b/drivers/media/dvb-frontends/si2168_priv.h index 2fecac6231ff..737cf416fbb2 100644 --- a/drivers/media/dvb-frontends/si2168_priv.h +++ b/drivers/media/dvb-frontends/si2168_priv.h | |||
@@ -26,6 +26,7 @@ | |||
26 | #define SI2168_A20_FIRMWARE "dvb-demod-si2168-a20-01.fw" | 26 | #define SI2168_A20_FIRMWARE "dvb-demod-si2168-a20-01.fw" |
27 | #define SI2168_A30_FIRMWARE "dvb-demod-si2168-a30-01.fw" | 27 | #define SI2168_A30_FIRMWARE "dvb-demod-si2168-a30-01.fw" |
28 | #define SI2168_B40_FIRMWARE "dvb-demod-si2168-b40-01.fw" | 28 | #define SI2168_B40_FIRMWARE "dvb-demod-si2168-b40-01.fw" |
29 | #define SI2168_D60_FIRMWARE "dvb-demod-si2168-d60-01.fw" | ||
29 | #define SI2168_B40_FIRMWARE_FALLBACK "dvb-demod-si2168-02.fw" | 30 | #define SI2168_B40_FIRMWARE_FALLBACK "dvb-demod-si2168-02.fw" |
30 | 31 | ||
31 | /* state struct */ | 32 | /* state struct */ |
@@ -38,6 +39,7 @@ struct si2168_dev { | |||
38 | #define SI2168_CHIP_ID_A20 ('A' << 24 | 68 << 16 | '2' << 8 | '0' << 0) | 39 | #define SI2168_CHIP_ID_A20 ('A' << 24 | 68 << 16 | '2' << 8 | '0' << 0) |
39 | #define SI2168_CHIP_ID_A30 ('A' << 24 | 68 << 16 | '3' << 8 | '0' << 0) | 40 | #define SI2168_CHIP_ID_A30 ('A' << 24 | 68 << 16 | '3' << 8 | '0' << 0) |
40 | #define SI2168_CHIP_ID_B40 ('B' << 24 | 68 << 16 | '4' << 8 | '0' << 0) | 41 | #define SI2168_CHIP_ID_B40 ('B' << 24 | 68 << 16 | '4' << 8 | '0' << 0) |
42 | #define SI2168_CHIP_ID_D60 ('D' << 24 | 68 << 16 | '6' << 8 | '0' << 0) | ||
41 | unsigned int chip_id; | 43 | unsigned int chip_id; |
42 | unsigned int version; | 44 | unsigned int version; |
43 | const char *firmware_name; | 45 | const char *firmware_name; |
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index cee1dae6e014..fd181c99ce11 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig | |||
@@ -209,7 +209,6 @@ config VIDEO_ADV7604 | |||
209 | depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API | 209 | depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API |
210 | depends on GPIOLIB || COMPILE_TEST | 210 | depends on GPIOLIB || COMPILE_TEST |
211 | select HDMI | 211 | select HDMI |
212 | select MEDIA_CEC_EDID | ||
213 | ---help--- | 212 | ---help--- |
214 | Support for the Analog Devices ADV7604 video decoder. | 213 | Support for the Analog Devices ADV7604 video decoder. |
215 | 214 | ||
@@ -221,7 +220,7 @@ config VIDEO_ADV7604 | |||
221 | 220 | ||
222 | config VIDEO_ADV7604_CEC | 221 | config VIDEO_ADV7604_CEC |
223 | bool "Enable Analog Devices ADV7604 CEC support" | 222 | bool "Enable Analog Devices ADV7604 CEC support" |
224 | depends on VIDEO_ADV7604 && MEDIA_CEC_SUPPORT | 223 | depends on VIDEO_ADV7604 && CEC_CORE |
225 | ---help--- | 224 | ---help--- |
226 | When selected the adv7604 will support the optional | 225 | When selected the adv7604 will support the optional |
227 | HDMI CEC feature. | 226 | HDMI CEC feature. |
@@ -230,7 +229,6 @@ config VIDEO_ADV7842 | |||
230 | tristate "Analog Devices ADV7842 decoder" | 229 | tristate "Analog Devices ADV7842 decoder" |
231 | depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API | 230 | depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API |
232 | select HDMI | 231 | select HDMI |
233 | select MEDIA_CEC_EDID | ||
234 | ---help--- | 232 | ---help--- |
235 | Support for the Analog Devices ADV7842 video decoder. | 233 | Support for the Analog Devices ADV7842 video decoder. |
236 | 234 | ||
@@ -242,7 +240,7 @@ config VIDEO_ADV7842 | |||
242 | 240 | ||
243 | config VIDEO_ADV7842_CEC | 241 | config VIDEO_ADV7842_CEC |
244 | bool "Enable Analog Devices ADV7842 CEC support" | 242 | bool "Enable Analog Devices ADV7842 CEC support" |
245 | depends on VIDEO_ADV7842 && MEDIA_CEC_SUPPORT | 243 | depends on VIDEO_ADV7842 && CEC_CORE |
246 | ---help--- | 244 | ---help--- |
247 | When selected the adv7842 will support the optional | 245 | When selected the adv7842 will support the optional |
248 | HDMI CEC feature. | 246 | HDMI CEC feature. |
@@ -470,7 +468,6 @@ config VIDEO_ADV7511 | |||
470 | tristate "Analog Devices ADV7511 encoder" | 468 | tristate "Analog Devices ADV7511 encoder" |
471 | depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API | 469 | depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API |
472 | select HDMI | 470 | select HDMI |
473 | select MEDIA_CEC_EDID | ||
474 | ---help--- | 471 | ---help--- |
475 | Support for the Analog Devices ADV7511 video encoder. | 472 | Support for the Analog Devices ADV7511 video encoder. |
476 | 473 | ||
@@ -481,7 +478,7 @@ config VIDEO_ADV7511 | |||
481 | 478 | ||
482 | config VIDEO_ADV7511_CEC | 479 | config VIDEO_ADV7511_CEC |
483 | bool "Enable Analog Devices ADV7511 CEC support" | 480 | bool "Enable Analog Devices ADV7511 CEC support" |
484 | depends on VIDEO_ADV7511 && MEDIA_CEC_SUPPORT | 481 | depends on VIDEO_ADV7511 && CEC_CORE |
485 | ---help--- | 482 | ---help--- |
486 | When selected the adv7511 will support the optional | 483 | When selected the adv7511 will support the optional |
487 | HDMI CEC feature. | 484 | HDMI CEC feature. |
@@ -520,6 +517,17 @@ config VIDEO_APTINA_PLL | |||
520 | config VIDEO_SMIAPP_PLL | 517 | config VIDEO_SMIAPP_PLL |
521 | tristate | 518 | tristate |
522 | 519 | ||
520 | config VIDEO_OV2640 | ||
521 | tristate "OmniVision OV2640 sensor support" | ||
522 | depends on VIDEO_V4L2 && I2C | ||
523 | depends on MEDIA_CAMERA_SUPPORT | ||
524 | help | ||
525 | This is a Video4Linux2 sensor-level driver for the OmniVision | ||
526 | OV2640 camera. | ||
527 | |||
528 | To compile this driver as a module, choose M here: the | ||
529 | module will be called ov2640. | ||
530 | |||
523 | config VIDEO_OV2659 | 531 | config VIDEO_OV2659 |
524 | tristate "OmniVision OV2659 sensor support" | 532 | tristate "OmniVision OV2659 sensor support" |
525 | depends on VIDEO_V4L2 && I2C | 533 | depends on VIDEO_V4L2 && I2C |
@@ -531,6 +539,29 @@ config VIDEO_OV2659 | |||
531 | To compile this driver as a module, choose M here: the | 539 | To compile this driver as a module, choose M here: the |
532 | module will be called ov2659. | 540 | module will be called ov2659. |
533 | 541 | ||
542 | config VIDEO_OV5645 | ||
543 | tristate "OmniVision OV5645 sensor support" | ||
544 | depends on OF | ||
545 | depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API | ||
546 | depends on MEDIA_CAMERA_SUPPORT | ||
547 | ---help--- | ||
548 | This is a Video4Linux2 sensor-level driver for the OmniVision | ||
549 | OV5645 camera. | ||
550 | |||
551 | To compile this driver as a module, choose M here: the | ||
552 | module will be called ov5645. | ||
553 | |||
554 | config VIDEO_OV5647 | ||
555 | tristate "OmniVision OV5647 sensor support" | ||
556 | depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API | ||
557 | depends on MEDIA_CAMERA_SUPPORT | ||
558 | ---help--- | ||
559 | This is a Video4Linux2 sensor-level driver for the OmniVision | ||
560 | OV5647 camera. | ||
561 | |||
562 | To compile this driver as a module, choose M here: the | ||
563 | module will be called ov5647. | ||
564 | |||
534 | config VIDEO_OV7640 | 565 | config VIDEO_OV7640 |
535 | tristate "OmniVision OV7640 sensor support" | 566 | tristate "OmniVision OV7640 sensor support" |
536 | depends on I2C && VIDEO_V4L2 | 567 | depends on I2C && VIDEO_V4L2 |
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 5bc7bbeb5499..62323ec66be8 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile | |||
@@ -57,6 +57,9 @@ obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o | |||
57 | obj-$(CONFIG_VIDEO_SONY_BTF_MPX) += sony-btf-mpx.o | 57 | obj-$(CONFIG_VIDEO_SONY_BTF_MPX) += sony-btf-mpx.o |
58 | obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o | 58 | obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o |
59 | obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o | 59 | obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o |
60 | obj-$(CONFIG_VIDEO_OV2640) += ov2640.o | ||
61 | obj-$(CONFIG_VIDEO_OV5645) += ov5645.o | ||
62 | obj-$(CONFIG_VIDEO_OV5647) += ov5647.o | ||
60 | obj-$(CONFIG_VIDEO_OV7640) += ov7640.o | 63 | obj-$(CONFIG_VIDEO_OV7640) += ov7640.o |
61 | obj-$(CONFIG_VIDEO_OV7670) += ov7670.o | 64 | obj-$(CONFIG_VIDEO_OV7670) += ov7670.o |
62 | obj-$(CONFIG_VIDEO_OV9650) += ov9650.o | 65 | obj-$(CONFIG_VIDEO_OV9650) += ov9650.o |
diff --git a/drivers/media/i2c/ad5820.c b/drivers/media/i2c/ad5820.c index a9026a91855e..3d2a3c6b67d8 100644 --- a/drivers/media/i2c/ad5820.c +++ b/drivers/media/i2c/ad5820.c | |||
@@ -336,7 +336,7 @@ cleanup: | |||
336 | return ret; | 336 | return ret; |
337 | } | 337 | } |
338 | 338 | ||
339 | static int __exit ad5820_remove(struct i2c_client *client) | 339 | static int ad5820_remove(struct i2c_client *client) |
340 | { | 340 | { |
341 | struct v4l2_subdev *subdev = i2c_get_clientdata(client); | 341 | struct v4l2_subdev *subdev = i2c_get_clientdata(client); |
342 | struct ad5820_device *coil = to_ad5820_device(subdev); | 342 | struct ad5820_device *coil = to_ad5820_device(subdev); |
@@ -362,7 +362,7 @@ static struct i2c_driver ad5820_i2c_driver = { | |||
362 | .pm = &ad5820_pm, | 362 | .pm = &ad5820_pm, |
363 | }, | 363 | }, |
364 | .probe = ad5820_probe, | 364 | .probe = ad5820_probe, |
365 | .remove = __exit_p(ad5820_remove), | 365 | .remove = ad5820_remove, |
366 | .id_table = ad5820_id_table, | 366 | .id_table = ad5820_id_table, |
367 | }; | 367 | }; |
368 | 368 | ||
diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c index 8c9e28949ab1..ccc478605643 100644 --- a/drivers/media/i2c/adv7511.c +++ b/drivers/media/i2c/adv7511.c | |||
@@ -734,7 +734,7 @@ static int adv7511_s_power(struct v4l2_subdev *sd, int on) | |||
734 | #if IS_ENABLED(CONFIG_VIDEO_ADV7511_CEC) | 734 | #if IS_ENABLED(CONFIG_VIDEO_ADV7511_CEC) |
735 | static int adv7511_cec_adap_enable(struct cec_adapter *adap, bool enable) | 735 | static int adv7511_cec_adap_enable(struct cec_adapter *adap, bool enable) |
736 | { | 736 | { |
737 | struct adv7511_state *state = adap->priv; | 737 | struct adv7511_state *state = cec_get_drvdata(adap); |
738 | struct v4l2_subdev *sd = &state->sd; | 738 | struct v4l2_subdev *sd = &state->sd; |
739 | 739 | ||
740 | if (state->i2c_cec == NULL) | 740 | if (state->i2c_cec == NULL) |
@@ -769,7 +769,7 @@ static int adv7511_cec_adap_enable(struct cec_adapter *adap, bool enable) | |||
769 | 769 | ||
770 | static int adv7511_cec_adap_log_addr(struct cec_adapter *adap, u8 addr) | 770 | static int adv7511_cec_adap_log_addr(struct cec_adapter *adap, u8 addr) |
771 | { | 771 | { |
772 | struct adv7511_state *state = adap->priv; | 772 | struct adv7511_state *state = cec_get_drvdata(adap); |
773 | struct v4l2_subdev *sd = &state->sd; | 773 | struct v4l2_subdev *sd = &state->sd; |
774 | unsigned int i, free_idx = ADV7511_MAX_ADDRS; | 774 | unsigned int i, free_idx = ADV7511_MAX_ADDRS; |
775 | 775 | ||
@@ -824,7 +824,7 @@ static int adv7511_cec_adap_log_addr(struct cec_adapter *adap, u8 addr) | |||
824 | static int adv7511_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, | 824 | static int adv7511_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, |
825 | u32 signal_free_time, struct cec_msg *msg) | 825 | u32 signal_free_time, struct cec_msg *msg) |
826 | { | 826 | { |
827 | struct adv7511_state *state = adap->priv; | 827 | struct adv7511_state *state = cec_get_drvdata(adap); |
828 | struct v4l2_subdev *sd = &state->sd; | 828 | struct v4l2_subdev *sd = &state->sd; |
829 | u8 len = msg->len; | 829 | u8 len = msg->len; |
830 | unsigned int i; | 830 | unsigned int i; |
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index d8bf435db86d..f1fa9cec489f 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c | |||
@@ -2050,7 +2050,7 @@ static void adv76xx_cec_isr(struct v4l2_subdev *sd, bool *handled) | |||
2050 | 2050 | ||
2051 | static int adv76xx_cec_adap_enable(struct cec_adapter *adap, bool enable) | 2051 | static int adv76xx_cec_adap_enable(struct cec_adapter *adap, bool enable) |
2052 | { | 2052 | { |
2053 | struct adv76xx_state *state = adap->priv; | 2053 | struct adv76xx_state *state = cec_get_drvdata(adap); |
2054 | struct v4l2_subdev *sd = &state->sd; | 2054 | struct v4l2_subdev *sd = &state->sd; |
2055 | 2055 | ||
2056 | if (!state->cec_enabled_adap && enable) { | 2056 | if (!state->cec_enabled_adap && enable) { |
@@ -2080,7 +2080,7 @@ static int adv76xx_cec_adap_enable(struct cec_adapter *adap, bool enable) | |||
2080 | 2080 | ||
2081 | static int adv76xx_cec_adap_log_addr(struct cec_adapter *adap, u8 addr) | 2081 | static int adv76xx_cec_adap_log_addr(struct cec_adapter *adap, u8 addr) |
2082 | { | 2082 | { |
2083 | struct adv76xx_state *state = adap->priv; | 2083 | struct adv76xx_state *state = cec_get_drvdata(adap); |
2084 | struct v4l2_subdev *sd = &state->sd; | 2084 | struct v4l2_subdev *sd = &state->sd; |
2085 | unsigned int i, free_idx = ADV76XX_MAX_ADDRS; | 2085 | unsigned int i, free_idx = ADV76XX_MAX_ADDRS; |
2086 | 2086 | ||
@@ -2135,7 +2135,7 @@ static int adv76xx_cec_adap_log_addr(struct cec_adapter *adap, u8 addr) | |||
2135 | static int adv76xx_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, | 2135 | static int adv76xx_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, |
2136 | u32 signal_free_time, struct cec_msg *msg) | 2136 | u32 signal_free_time, struct cec_msg *msg) |
2137 | { | 2137 | { |
2138 | struct adv76xx_state *state = adap->priv; | 2138 | struct adv76xx_state *state = cec_get_drvdata(adap); |
2139 | struct v4l2_subdev *sd = &state->sd; | 2139 | struct v4l2_subdev *sd = &state->sd; |
2140 | u8 len = msg->len; | 2140 | u8 len = msg->len; |
2141 | unsigned int i; | 2141 | unsigned int i; |
diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 2d61f0cc2b5b..303effda1a2e 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c | |||
@@ -2250,7 +2250,7 @@ static void adv7842_cec_isr(struct v4l2_subdev *sd, bool *handled) | |||
2250 | 2250 | ||
2251 | static int adv7842_cec_adap_enable(struct cec_adapter *adap, bool enable) | 2251 | static int adv7842_cec_adap_enable(struct cec_adapter *adap, bool enable) |
2252 | { | 2252 | { |
2253 | struct adv7842_state *state = adap->priv; | 2253 | struct adv7842_state *state = cec_get_drvdata(adap); |
2254 | struct v4l2_subdev *sd = &state->sd; | 2254 | struct v4l2_subdev *sd = &state->sd; |
2255 | 2255 | ||
2256 | if (!state->cec_enabled_adap && enable) { | 2256 | if (!state->cec_enabled_adap && enable) { |
@@ -2279,7 +2279,7 @@ static int adv7842_cec_adap_enable(struct cec_adapter *adap, bool enable) | |||
2279 | 2279 | ||
2280 | static int adv7842_cec_adap_log_addr(struct cec_adapter *adap, u8 addr) | 2280 | static int adv7842_cec_adap_log_addr(struct cec_adapter *adap, u8 addr) |
2281 | { | 2281 | { |
2282 | struct adv7842_state *state = adap->priv; | 2282 | struct adv7842_state *state = cec_get_drvdata(adap); |
2283 | struct v4l2_subdev *sd = &state->sd; | 2283 | struct v4l2_subdev *sd = &state->sd; |
2284 | unsigned int i, free_idx = ADV7842_MAX_ADDRS; | 2284 | unsigned int i, free_idx = ADV7842_MAX_ADDRS; |
2285 | 2285 | ||
@@ -2334,7 +2334,7 @@ static int adv7842_cec_adap_log_addr(struct cec_adapter *adap, u8 addr) | |||
2334 | static int adv7842_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, | 2334 | static int adv7842_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, |
2335 | u32 signal_free_time, struct cec_msg *msg) | 2335 | u32 signal_free_time, struct cec_msg *msg) |
2336 | { | 2336 | { |
2337 | struct adv7842_state *state = adap->priv; | 2337 | struct adv7842_state *state = cec_get_drvdata(adap); |
2338 | struct v4l2_subdev *sd = &state->sd; | 2338 | struct v4l2_subdev *sd = &state->sd; |
2339 | u8 len = msg->len; | 2339 | u8 len = msg->len; |
2340 | unsigned int i; | 2340 | unsigned int i; |
diff --git a/drivers/media/i2c/et8ek8/et8ek8_driver.c b/drivers/media/i2c/et8ek8/et8ek8_driver.c index bec4a563a09c..6e313d5243a0 100644 --- a/drivers/media/i2c/et8ek8/et8ek8_driver.c +++ b/drivers/media/i2c/et8ek8/et8ek8_driver.c | |||
@@ -1485,6 +1485,7 @@ static const struct of_device_id et8ek8_of_table[] = { | |||
1485 | { .compatible = "toshiba,et8ek8" }, | 1485 | { .compatible = "toshiba,et8ek8" }, |
1486 | { }, | 1486 | { }, |
1487 | }; | 1487 | }; |
1488 | MODULE_DEVICE_TABLE(of, et8ek8_of_table); | ||
1488 | 1489 | ||
1489 | static const struct i2c_device_id et8ek8_id_table[] = { | 1490 | static const struct i2c_device_id et8ek8_id_table[] = { |
1490 | { ET8EK8_NAME, 0 }, | 1491 | { ET8EK8_NAME, 0 }, |
@@ -1495,6 +1496,7 @@ MODULE_DEVICE_TABLE(i2c, et8ek8_id_table); | |||
1495 | static const struct dev_pm_ops et8ek8_pm_ops = { | 1496 | static const struct dev_pm_ops et8ek8_pm_ops = { |
1496 | SET_SYSTEM_SLEEP_PM_OPS(et8ek8_suspend, et8ek8_resume) | 1497 | SET_SYSTEM_SLEEP_PM_OPS(et8ek8_suspend, et8ek8_resume) |
1497 | }; | 1498 | }; |
1499 | MODULE_DEVICE_TABLE(of, et8ek8_of_table); | ||
1498 | 1500 | ||
1499 | static struct i2c_driver et8ek8_i2c_driver = { | 1501 | static struct i2c_driver et8ek8_i2c_driver = { |
1500 | .driver = { | 1502 | .driver = { |
diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/ov2640.c index 56de18263359..e6d0c1f64f0b 100644 --- a/drivers/media/i2c/soc_camera/ov2640.c +++ b/drivers/media/i2c/ov2640.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/i2c.h> | 18 | #include <linux/i2c.h> |
19 | #include <linux/clk.h> | ||
19 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
20 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
21 | #include <linux/gpio.h> | 22 | #include <linux/gpio.h> |
@@ -24,8 +25,7 @@ | |||
24 | #include <linux/v4l2-mediabus.h> | 25 | #include <linux/v4l2-mediabus.h> |
25 | #include <linux/videodev2.h> | 26 | #include <linux/videodev2.h> |
26 | 27 | ||
27 | #include <media/soc_camera.h> | 28 | #include <media/v4l2-device.h> |
28 | #include <media/v4l2-clk.h> | ||
29 | #include <media/v4l2-subdev.h> | 29 | #include <media/v4l2-subdev.h> |
30 | #include <media/v4l2-ctrls.h> | 30 | #include <media/v4l2-ctrls.h> |
31 | #include <media/v4l2-image-sizes.h> | 31 | #include <media/v4l2-image-sizes.h> |
@@ -106,6 +106,10 @@ | |||
106 | #define CTRL1_AWB_GAIN 0x04 | 106 | #define CTRL1_AWB_GAIN 0x04 |
107 | #define CTRL1_LENC 0x02 | 107 | #define CTRL1_LENC 0x02 |
108 | #define CTRL1_PRE 0x01 | 108 | #define CTRL1_PRE 0x01 |
109 | /* REG 0xC7 (unknown name): affects Auto White Balance (AWB) | ||
110 | * AWB_OFF 0x40 | ||
111 | * AWB_SIMPLE 0x10 | ||
112 | * AWB_ON 0x00 (Advanced AWB ?) */ | ||
109 | #define R_DVP_SP 0xD3 /* DVP output speed control */ | 113 | #define R_DVP_SP 0xD3 /* DVP output speed control */ |
110 | #define R_DVP_SP_AUTO_MODE 0x80 | 114 | #define R_DVP_SP_AUTO_MODE 0x80 |
111 | #define R_DVP_SP_DVP_MASK 0x3F /* DVP PCLK = sysclk (48)/[6:0] (YUV0); | 115 | #define R_DVP_SP_DVP_MASK 0x3F /* DVP PCLK = sysclk (48)/[6:0] (YUV0); |
@@ -199,7 +203,7 @@ | |||
199 | #define COM7_ZOOM_EN 0x04 /* Enable Zoom mode */ | 203 | #define COM7_ZOOM_EN 0x04 /* Enable Zoom mode */ |
200 | #define COM7_COLOR_BAR_TEST 0x02 /* Enable Color Bar Test Pattern */ | 204 | #define COM7_COLOR_BAR_TEST 0x02 /* Enable Color Bar Test Pattern */ |
201 | #define COM8 0x13 /* Common control 8 */ | 205 | #define COM8 0x13 /* Common control 8 */ |
202 | #define COM8_DEF 0xC0 /* Banding filter ON/OFF */ | 206 | #define COM8_DEF 0xC0 |
203 | #define COM8_BNDF_EN 0x20 /* Banding filter ON/OFF */ | 207 | #define COM8_BNDF_EN 0x20 /* Banding filter ON/OFF */ |
204 | #define COM8_AGC_EN 0x04 /* AGC Auto/Manual control selection */ | 208 | #define COM8_AGC_EN 0x04 /* AGC Auto/Manual control selection */ |
205 | #define COM8_AEC_EN 0x01 /* Auto/Manual Exposure control */ | 209 | #define COM8_AEC_EN 0x01 /* Auto/Manual Exposure control */ |
@@ -248,8 +252,19 @@ | |||
248 | #define ZOOMS 0x49 /* Zoom: Vertical start point */ | 252 | #define ZOOMS 0x49 /* Zoom: Vertical start point */ |
249 | #define COM22 0x4B /* Flash light control */ | 253 | #define COM22 0x4B /* Flash light control */ |
250 | #define COM25 0x4E /* For Banding operations */ | 254 | #define COM25 0x4E /* For Banding operations */ |
255 | #define COM25_50HZ_BANDING_AEC_MSBS_MASK 0xC0 /* 50Hz Bd. AEC 2 MSBs */ | ||
256 | #define COM25_60HZ_BANDING_AEC_MSBS_MASK 0x30 /* 60Hz Bd. AEC 2 MSBs */ | ||
257 | #define COM25_50HZ_BANDING_AEC_MSBS_SET(x) VAL_SET(x, 0x3, 8, 6) | ||
258 | #define COM25_60HZ_BANDING_AEC_MSBS_SET(x) VAL_SET(x, 0x3, 8, 4) | ||
251 | #define BD50 0x4F /* 50Hz Banding AEC 8 LSBs */ | 259 | #define BD50 0x4F /* 50Hz Banding AEC 8 LSBs */ |
260 | #define BD50_50HZ_BANDING_AEC_LSBS_SET(x) VAL_SET(x, 0xFF, 0, 0) | ||
252 | #define BD60 0x50 /* 60Hz Banding AEC 8 LSBs */ | 261 | #define BD60 0x50 /* 60Hz Banding AEC 8 LSBs */ |
262 | #define BD60_60HZ_BANDING_AEC_LSBS_SET(x) VAL_SET(x, 0xFF, 0, 0) | ||
263 | #define REG5A 0x5A /* 50/60Hz Banding Maximum AEC Step */ | ||
264 | #define BD50_MAX_AEC_STEP_MASK 0xF0 /* 50Hz Banding Max. AEC Step */ | ||
265 | #define BD60_MAX_AEC_STEP_MASK 0x0F /* 60Hz Banding Max. AEC Step */ | ||
266 | #define BD50_MAX_AEC_STEP_SET(x) VAL_SET((x - 1), 0x0F, 0, 4) | ||
267 | #define BD60_MAX_AEC_STEP_SET(x) VAL_SET((x - 1), 0x0F, 0, 0) | ||
253 | #define REG5D 0x5D /* AVGsel[7:0], 16-zone average weight option */ | 268 | #define REG5D 0x5D /* AVGsel[7:0], 16-zone average weight option */ |
254 | #define REG5E 0x5E /* AVGsel[15:8], 16-zone average weight option */ | 269 | #define REG5E 0x5E /* AVGsel[15:8], 16-zone average weight option */ |
255 | #define REG5F 0x5F /* AVGsel[23:16], 16-zone average weight option */ | 270 | #define REG5F 0x5F /* AVGsel[23:16], 16-zone average weight option */ |
@@ -282,12 +297,14 @@ struct ov2640_win_size { | |||
282 | 297 | ||
283 | struct ov2640_priv { | 298 | struct ov2640_priv { |
284 | struct v4l2_subdev subdev; | 299 | struct v4l2_subdev subdev; |
300 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
301 | struct media_pad pad; | ||
302 | #endif | ||
285 | struct v4l2_ctrl_handler hdl; | 303 | struct v4l2_ctrl_handler hdl; |
286 | u32 cfmt_code; | 304 | u32 cfmt_code; |
287 | struct v4l2_clk *clk; | 305 | struct clk *clk; |
288 | const struct ov2640_win_size *win; | 306 | const struct ov2640_win_size *win; |
289 | 307 | ||
290 | struct soc_camera_subdev_desc ssdd_dt; | ||
291 | struct gpio_desc *resetb_gpio; | 308 | struct gpio_desc *resetb_gpio; |
292 | struct gpio_desc *pwdn_gpio; | 309 | struct gpio_desc *pwdn_gpio; |
293 | }; | 310 | }; |
@@ -304,11 +321,11 @@ static const struct regval_list ov2640_init_regs[] = { | |||
304 | { 0x2e, 0xdf }, | 321 | { 0x2e, 0xdf }, |
305 | { BANK_SEL, BANK_SEL_SENS }, | 322 | { BANK_SEL, BANK_SEL_SENS }, |
306 | { 0x3c, 0x32 }, | 323 | { 0x3c, 0x32 }, |
307 | { CLKRC, CLKRC_DIV_SET(1) }, | 324 | { CLKRC, CLKRC_DIV_SET(1) }, |
308 | { COM2, COM2_OCAP_Nx_SET(3) }, | 325 | { COM2, COM2_OCAP_Nx_SET(3) }, |
309 | { REG04, REG04_DEF | REG04_HREF_EN }, | 326 | { REG04, REG04_DEF | REG04_HREF_EN }, |
310 | { COM8, COM8_DEF | COM8_BNDF_EN | COM8_AGC_EN | COM8_AEC_EN }, | 327 | { COM8, COM8_DEF | COM8_BNDF_EN | COM8_AGC_EN | COM8_AEC_EN }, |
311 | { COM9, COM9_AGC_GAIN_8x | 0x08}, | 328 | { COM9, COM9_AGC_GAIN_8x | 0x08}, |
312 | { 0x2c, 0x0c }, | 329 | { 0x2c, 0x0c }, |
313 | { 0x33, 0x78 }, | 330 | { 0x33, 0x78 }, |
314 | { 0x3a, 0x33 }, | 331 | { 0x3a, 0x33 }, |
@@ -353,25 +370,28 @@ static const struct regval_list ov2640_init_regs[] = { | |||
353 | { 0x71, 0x94 }, | 370 | { 0x71, 0x94 }, |
354 | { 0x73, 0xc1 }, | 371 | { 0x73, 0xc1 }, |
355 | { 0x3d, 0x34 }, | 372 | { 0x3d, 0x34 }, |
356 | { COM7, COM7_RES_UXGA | COM7_ZOOM_EN }, | 373 | { COM7, COM7_RES_UXGA | COM7_ZOOM_EN }, |
357 | { 0x5a, 0x57 }, | 374 | { REG5A, BD50_MAX_AEC_STEP_SET(6) |
358 | { BD50, 0xbb }, | 375 | | BD60_MAX_AEC_STEP_SET(8) }, /* 0x57 */ |
359 | { BD60, 0x9c }, | 376 | { COM25, COM25_50HZ_BANDING_AEC_MSBS_SET(0x0bb) |
360 | { BANK_SEL, BANK_SEL_DSP }, | 377 | | COM25_60HZ_BANDING_AEC_MSBS_SET(0x09c) }, /* 0x00 */ |
378 | { BD50, BD50_50HZ_BANDING_AEC_LSBS_SET(0x0bb) }, /* 0xbb */ | ||
379 | { BD60, BD60_60HZ_BANDING_AEC_LSBS_SET(0x09c) }, /* 0x9c */ | ||
380 | { BANK_SEL, BANK_SEL_DSP }, | ||
361 | { 0xe5, 0x7f }, | 381 | { 0xe5, 0x7f }, |
362 | { MC_BIST, MC_BIST_RESET | MC_BIST_BOOT_ROM_SEL }, | 382 | { MC_BIST, MC_BIST_RESET | MC_BIST_BOOT_ROM_SEL }, |
363 | { 0x41, 0x24 }, | 383 | { 0x41, 0x24 }, |
364 | { RESET, RESET_JPEG | RESET_DVP }, | 384 | { RESET, RESET_JPEG | RESET_DVP }, |
365 | { 0x76, 0xff }, | 385 | { 0x76, 0xff }, |
366 | { 0x33, 0xa0 }, | 386 | { 0x33, 0xa0 }, |
367 | { 0x42, 0x20 }, | 387 | { 0x42, 0x20 }, |
368 | { 0x43, 0x18 }, | 388 | { 0x43, 0x18 }, |
369 | { 0x4c, 0x00 }, | 389 | { 0x4c, 0x00 }, |
370 | { CTRL3, CTRL3_BPC_EN | CTRL3_WPC_EN | 0x10 }, | 390 | { CTRL3, CTRL3_BPC_EN | CTRL3_WPC_EN | 0x10 }, |
371 | { 0x88, 0x3f }, | 391 | { 0x88, 0x3f }, |
372 | { 0xd7, 0x03 }, | 392 | { 0xd7, 0x03 }, |
373 | { 0xd9, 0x10 }, | 393 | { 0xd9, 0x10 }, |
374 | { R_DVP_SP , R_DVP_SP_AUTO_MODE | 0x2 }, | 394 | { R_DVP_SP, R_DVP_SP_AUTO_MODE | 0x2 }, |
375 | { 0xc8, 0x08 }, | 395 | { 0xc8, 0x08 }, |
376 | { 0xc9, 0x80 }, | 396 | { 0xc9, 0x80 }, |
377 | { BPADDR, 0x00 }, | 397 | { BPADDR, 0x00 }, |
@@ -433,7 +453,7 @@ static const struct regval_list ov2640_init_regs[] = { | |||
433 | { 0xc5, 0x11 }, | 453 | { 0xc5, 0x11 }, |
434 | { 0xc6, 0x51 }, | 454 | { 0xc6, 0x51 }, |
435 | { 0xbf, 0x80 }, | 455 | { 0xbf, 0x80 }, |
436 | { 0xc7, 0x10 }, | 456 | { 0xc7, 0x10 }, /* simple AWB */ |
437 | { 0xb6, 0x66 }, | 457 | { 0xb6, 0x66 }, |
438 | { 0xb8, 0xA5 }, | 458 | { 0xb8, 0xA5 }, |
439 | { 0xb7, 0x64 }, | 459 | { 0xb7, 0x64 }, |
@@ -480,6 +500,9 @@ static const struct regval_list ov2640_init_regs[] = { | |||
480 | static const struct regval_list ov2640_size_change_preamble_regs[] = { | 500 | static const struct regval_list ov2640_size_change_preamble_regs[] = { |
481 | { BANK_SEL, BANK_SEL_DSP }, | 501 | { BANK_SEL, BANK_SEL_DSP }, |
482 | { RESET, RESET_DVP }, | 502 | { RESET, RESET_DVP }, |
503 | { SIZEL, SIZEL_HSIZE8_11_SET(UXGA_WIDTH) | | ||
504 | SIZEL_HSIZE8_SET(UXGA_WIDTH) | | ||
505 | SIZEL_VSIZE8_SET(UXGA_HEIGHT) }, | ||
483 | { HSIZE8, HSIZE8_SET(UXGA_WIDTH) }, | 506 | { HSIZE8, HSIZE8_SET(UXGA_WIDTH) }, |
484 | { VSIZE8, VSIZE8_SET(UXGA_HEIGHT) }, | 507 | { VSIZE8, VSIZE8_SET(UXGA_HEIGHT) }, |
485 | { CTRL2, CTRL2_DCW_EN | CTRL2_SDE_EN | | 508 | { CTRL2, CTRL2_DCW_EN | CTRL2_SDE_EN | |
@@ -611,6 +634,8 @@ static const struct regval_list ov2640_rgb565_le_regs[] = { | |||
611 | static u32 ov2640_codes[] = { | 634 | static u32 ov2640_codes[] = { |
612 | MEDIA_BUS_FMT_YUYV8_2X8, | 635 | MEDIA_BUS_FMT_YUYV8_2X8, |
613 | MEDIA_BUS_FMT_UYVY8_2X8, | 636 | MEDIA_BUS_FMT_UYVY8_2X8, |
637 | MEDIA_BUS_FMT_YVYU8_2X8, | ||
638 | MEDIA_BUS_FMT_VYUY8_2X8, | ||
614 | MEDIA_BUS_FMT_RGB565_2X8_BE, | 639 | MEDIA_BUS_FMT_RGB565_2X8_BE, |
615 | MEDIA_BUS_FMT_RGB565_2X8_LE, | 640 | MEDIA_BUS_FMT_RGB565_2X8_LE, |
616 | }; | 641 | }; |
@@ -677,13 +702,8 @@ err: | |||
677 | } | 702 | } |
678 | 703 | ||
679 | /* | 704 | /* |
680 | * soc_camera_ops functions | 705 | * functions |
681 | */ | 706 | */ |
682 | static int ov2640_s_stream(struct v4l2_subdev *sd, int enable) | ||
683 | { | ||
684 | return 0; | ||
685 | } | ||
686 | |||
687 | static int ov2640_s_ctrl(struct v4l2_ctrl *ctrl) | 707 | static int ov2640_s_ctrl(struct v4l2_ctrl *ctrl) |
688 | { | 708 | { |
689 | struct v4l2_subdev *sd = | 709 | struct v4l2_subdev *sd = |
@@ -698,8 +718,10 @@ static int ov2640_s_ctrl(struct v4l2_ctrl *ctrl) | |||
698 | 718 | ||
699 | switch (ctrl->id) { | 719 | switch (ctrl->id) { |
700 | case V4L2_CID_VFLIP: | 720 | case V4L2_CID_VFLIP: |
701 | val = ctrl->val ? REG04_VFLIP_IMG : 0x00; | 721 | val = ctrl->val ? REG04_VFLIP_IMG | REG04_VREF_EN : 0x00; |
702 | return ov2640_mask_set(client, REG04, REG04_VFLIP_IMG, val); | 722 | return ov2640_mask_set(client, REG04, |
723 | REG04_VFLIP_IMG | REG04_VREF_EN, val); | ||
724 | /* NOTE: REG04_VREF_EN: 1 line shift / even/odd line swap */ | ||
703 | case V4L2_CID_HFLIP: | 725 | case V4L2_CID_HFLIP: |
704 | val = ctrl->val ? REG04_HFLIP_IMG : 0x00; | 726 | val = ctrl->val ? REG04_HFLIP_IMG : 0x00; |
705 | return ov2640_mask_set(client, REG04, REG04_HFLIP_IMG, val); | 727 | return ov2640_mask_set(client, REG04, REG04_HFLIP_IMG, val); |
@@ -743,41 +765,46 @@ static int ov2640_s_register(struct v4l2_subdev *sd, | |||
743 | 765 | ||
744 | static int ov2640_s_power(struct v4l2_subdev *sd, int on) | 766 | static int ov2640_s_power(struct v4l2_subdev *sd, int on) |
745 | { | 767 | { |
768 | #ifdef CONFIG_GPIOLIB | ||
746 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 769 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
747 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); | ||
748 | struct ov2640_priv *priv = to_ov2640(client); | 770 | struct ov2640_priv *priv = to_ov2640(client); |
749 | 771 | ||
750 | return soc_camera_set_power(&client->dev, ssdd, priv->clk, on); | 772 | if (priv->pwdn_gpio) |
773 | gpiod_direction_output(priv->pwdn_gpio, !on); | ||
774 | if (on && priv->resetb_gpio) { | ||
775 | /* Active the resetb pin to perform a reset pulse */ | ||
776 | gpiod_direction_output(priv->resetb_gpio, 1); | ||
777 | usleep_range(3000, 5000); | ||
778 | gpiod_set_value(priv->resetb_gpio, 0); | ||
779 | } | ||
780 | #endif | ||
781 | return 0; | ||
751 | } | 782 | } |
752 | 783 | ||
753 | /* Select the nearest higher resolution for capture */ | 784 | /* Select the nearest higher resolution for capture */ |
754 | static const struct ov2640_win_size *ov2640_select_win(u32 *width, u32 *height) | 785 | static const struct ov2640_win_size *ov2640_select_win(u32 width, u32 height) |
755 | { | 786 | { |
756 | int i, default_size = ARRAY_SIZE(ov2640_supported_win_sizes) - 1; | 787 | int i, default_size = ARRAY_SIZE(ov2640_supported_win_sizes) - 1; |
757 | 788 | ||
758 | for (i = 0; i < ARRAY_SIZE(ov2640_supported_win_sizes); i++) { | 789 | for (i = 0; i < ARRAY_SIZE(ov2640_supported_win_sizes); i++) { |
759 | if (ov2640_supported_win_sizes[i].width >= *width && | 790 | if (ov2640_supported_win_sizes[i].width >= width && |
760 | ov2640_supported_win_sizes[i].height >= *height) { | 791 | ov2640_supported_win_sizes[i].height >= height) |
761 | *width = ov2640_supported_win_sizes[i].width; | ||
762 | *height = ov2640_supported_win_sizes[i].height; | ||
763 | return &ov2640_supported_win_sizes[i]; | 792 | return &ov2640_supported_win_sizes[i]; |
764 | } | ||
765 | } | 793 | } |
766 | 794 | ||
767 | *width = ov2640_supported_win_sizes[default_size].width; | ||
768 | *height = ov2640_supported_win_sizes[default_size].height; | ||
769 | return &ov2640_supported_win_sizes[default_size]; | 795 | return &ov2640_supported_win_sizes[default_size]; |
770 | } | 796 | } |
771 | 797 | ||
772 | static int ov2640_set_params(struct i2c_client *client, u32 *width, u32 *height, | 798 | static int ov2640_set_params(struct i2c_client *client, |
773 | u32 code) | 799 | const struct ov2640_win_size *win, u32 code) |
774 | { | 800 | { |
775 | struct ov2640_priv *priv = to_ov2640(client); | 801 | struct ov2640_priv *priv = to_ov2640(client); |
776 | const struct regval_list *selected_cfmt_regs; | 802 | const struct regval_list *selected_cfmt_regs; |
803 | u8 val; | ||
777 | int ret; | 804 | int ret; |
778 | 805 | ||
779 | /* select win */ | 806 | /* select win */ |
780 | priv->win = ov2640_select_win(width, height); | 807 | priv->win = win; |
781 | 808 | ||
782 | /* select format */ | 809 | /* select format */ |
783 | priv->cfmt_code = 0; | 810 | priv->cfmt_code = 0; |
@@ -794,10 +821,19 @@ static int ov2640_set_params(struct i2c_client *client, u32 *width, u32 *height, | |||
794 | dev_dbg(&client->dev, "%s: Selected cfmt YUYV (YUV422)", __func__); | 821 | dev_dbg(&client->dev, "%s: Selected cfmt YUYV (YUV422)", __func__); |
795 | selected_cfmt_regs = ov2640_yuyv_regs; | 822 | selected_cfmt_regs = ov2640_yuyv_regs; |
796 | break; | 823 | break; |
797 | default: | ||
798 | case MEDIA_BUS_FMT_UYVY8_2X8: | 824 | case MEDIA_BUS_FMT_UYVY8_2X8: |
825 | default: | ||
799 | dev_dbg(&client->dev, "%s: Selected cfmt UYVY", __func__); | 826 | dev_dbg(&client->dev, "%s: Selected cfmt UYVY", __func__); |
800 | selected_cfmt_regs = ov2640_uyvy_regs; | 827 | selected_cfmt_regs = ov2640_uyvy_regs; |
828 | break; | ||
829 | case MEDIA_BUS_FMT_YVYU8_2X8: | ||
830 | dev_dbg(&client->dev, "%s: Selected cfmt YVYU", __func__); | ||
831 | selected_cfmt_regs = ov2640_yuyv_regs; | ||
832 | break; | ||
833 | case MEDIA_BUS_FMT_VYUY8_2X8: | ||
834 | dev_dbg(&client->dev, "%s: Selected cfmt VYUY", __func__); | ||
835 | selected_cfmt_regs = ov2640_uyvy_regs; | ||
836 | break; | ||
801 | } | 837 | } |
802 | 838 | ||
803 | /* reset hardware */ | 839 | /* reset hardware */ |
@@ -830,10 +866,13 @@ static int ov2640_set_params(struct i2c_client *client, u32 *width, u32 *height, | |||
830 | ret = ov2640_write_array(client, selected_cfmt_regs); | 866 | ret = ov2640_write_array(client, selected_cfmt_regs); |
831 | if (ret < 0) | 867 | if (ret < 0) |
832 | goto err; | 868 | goto err; |
869 | val = (code == MEDIA_BUS_FMT_YVYU8_2X8) | ||
870 | || (code == MEDIA_BUS_FMT_VYUY8_2X8) ? CTRL0_VFIRST : 0x00; | ||
871 | ret = ov2640_mask_set(client, CTRL0, CTRL0_VFIRST, val); | ||
872 | if (ret < 0) | ||
873 | goto err; | ||
833 | 874 | ||
834 | priv->cfmt_code = code; | 875 | priv->cfmt_code = code; |
835 | *width = priv->win->width; | ||
836 | *height = priv->win->height; | ||
837 | 876 | ||
838 | return 0; | 877 | return 0; |
839 | 878 | ||
@@ -857,25 +896,14 @@ static int ov2640_get_fmt(struct v4l2_subdev *sd, | |||
857 | return -EINVAL; | 896 | return -EINVAL; |
858 | 897 | ||
859 | if (!priv->win) { | 898 | if (!priv->win) { |
860 | u32 width = SVGA_WIDTH, height = SVGA_HEIGHT; | 899 | priv->win = ov2640_select_win(SVGA_WIDTH, SVGA_HEIGHT); |
861 | priv->win = ov2640_select_win(&width, &height); | ||
862 | priv->cfmt_code = MEDIA_BUS_FMT_UYVY8_2X8; | 900 | priv->cfmt_code = MEDIA_BUS_FMT_UYVY8_2X8; |
863 | } | 901 | } |
864 | 902 | ||
865 | mf->width = priv->win->width; | 903 | mf->width = priv->win->width; |
866 | mf->height = priv->win->height; | 904 | mf->height = priv->win->height; |
867 | mf->code = priv->cfmt_code; | 905 | mf->code = priv->cfmt_code; |
868 | 906 | mf->colorspace = V4L2_COLORSPACE_SRGB; | |
869 | switch (mf->code) { | ||
870 | case MEDIA_BUS_FMT_RGB565_2X8_BE: | ||
871 | case MEDIA_BUS_FMT_RGB565_2X8_LE: | ||
872 | mf->colorspace = V4L2_COLORSPACE_SRGB; | ||
873 | break; | ||
874 | default: | ||
875 | case MEDIA_BUS_FMT_YUYV8_2X8: | ||
876 | case MEDIA_BUS_FMT_UYVY8_2X8: | ||
877 | mf->colorspace = V4L2_COLORSPACE_JPEG; | ||
878 | } | ||
879 | mf->field = V4L2_FIELD_NONE; | 907 | mf->field = V4L2_FIELD_NONE; |
880 | 908 | ||
881 | return 0; | 909 | return 0; |
@@ -887,32 +915,34 @@ static int ov2640_set_fmt(struct v4l2_subdev *sd, | |||
887 | { | 915 | { |
888 | struct v4l2_mbus_framefmt *mf = &format->format; | 916 | struct v4l2_mbus_framefmt *mf = &format->format; |
889 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 917 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
918 | const struct ov2640_win_size *win; | ||
890 | 919 | ||
891 | if (format->pad) | 920 | if (format->pad) |
892 | return -EINVAL; | 921 | return -EINVAL; |
893 | 922 | ||
894 | /* | 923 | /* select suitable win */ |
895 | * select suitable win, but don't store it | 924 | win = ov2640_select_win(mf->width, mf->height); |
896 | */ | 925 | mf->width = win->width; |
897 | ov2640_select_win(&mf->width, &mf->height); | 926 | mf->height = win->height; |
898 | 927 | ||
899 | mf->field = V4L2_FIELD_NONE; | 928 | mf->field = V4L2_FIELD_NONE; |
929 | mf->colorspace = V4L2_COLORSPACE_SRGB; | ||
900 | 930 | ||
901 | switch (mf->code) { | 931 | switch (mf->code) { |
902 | case MEDIA_BUS_FMT_RGB565_2X8_BE: | 932 | case MEDIA_BUS_FMT_RGB565_2X8_BE: |
903 | case MEDIA_BUS_FMT_RGB565_2X8_LE: | 933 | case MEDIA_BUS_FMT_RGB565_2X8_LE: |
904 | mf->colorspace = V4L2_COLORSPACE_SRGB; | 934 | case MEDIA_BUS_FMT_YUYV8_2X8: |
935 | case MEDIA_BUS_FMT_UYVY8_2X8: | ||
936 | case MEDIA_BUS_FMT_YVYU8_2X8: | ||
937 | case MEDIA_BUS_FMT_VYUY8_2X8: | ||
905 | break; | 938 | break; |
906 | default: | 939 | default: |
907 | mf->code = MEDIA_BUS_FMT_UYVY8_2X8; | 940 | mf->code = MEDIA_BUS_FMT_UYVY8_2X8; |
908 | case MEDIA_BUS_FMT_YUYV8_2X8: | 941 | break; |
909 | case MEDIA_BUS_FMT_UYVY8_2X8: | ||
910 | mf->colorspace = V4L2_COLORSPACE_JPEG; | ||
911 | } | 942 | } |
912 | 943 | ||
913 | if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) | 944 | if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) |
914 | return ov2640_set_params(client, &mf->width, | 945 | return ov2640_set_params(client, win, mf->code); |
915 | &mf->height, mf->code); | ||
916 | cfg->try_fmt = *mf; | 946 | cfg->try_fmt = *mf; |
917 | return 0; | 947 | return 0; |
918 | } | 948 | } |
@@ -995,7 +1025,7 @@ static const struct v4l2_ctrl_ops ov2640_ctrl_ops = { | |||
995 | .s_ctrl = ov2640_s_ctrl, | 1025 | .s_ctrl = ov2640_s_ctrl, |
996 | }; | 1026 | }; |
997 | 1027 | ||
998 | static struct v4l2_subdev_core_ops ov2640_subdev_core_ops = { | 1028 | static const struct v4l2_subdev_core_ops ov2640_subdev_core_ops = { |
999 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 1029 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
1000 | .g_register = ov2640_g_register, | 1030 | .g_register = ov2640_g_register, |
1001 | .s_register = ov2640_s_register, | 1031 | .s_register = ov2640_s_register, |
@@ -1003,26 +1033,6 @@ static struct v4l2_subdev_core_ops ov2640_subdev_core_ops = { | |||
1003 | .s_power = ov2640_s_power, | 1033 | .s_power = ov2640_s_power, |
1004 | }; | 1034 | }; |
1005 | 1035 | ||
1006 | static int ov2640_g_mbus_config(struct v4l2_subdev *sd, | ||
1007 | struct v4l2_mbus_config *cfg) | ||
1008 | { | ||
1009 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1010 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); | ||
1011 | |||
1012 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | | ||
1013 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | | ||
1014 | V4L2_MBUS_DATA_ACTIVE_HIGH; | ||
1015 | cfg->type = V4L2_MBUS_PARALLEL; | ||
1016 | cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); | ||
1017 | |||
1018 | return 0; | ||
1019 | } | ||
1020 | |||
1021 | static struct v4l2_subdev_video_ops ov2640_subdev_video_ops = { | ||
1022 | .s_stream = ov2640_s_stream, | ||
1023 | .g_mbus_config = ov2640_g_mbus_config, | ||
1024 | }; | ||
1025 | |||
1026 | static const struct v4l2_subdev_pad_ops ov2640_subdev_pad_ops = { | 1036 | static const struct v4l2_subdev_pad_ops ov2640_subdev_pad_ops = { |
1027 | .enum_mbus_code = ov2640_enum_mbus_code, | 1037 | .enum_mbus_code = ov2640_enum_mbus_code, |
1028 | .get_selection = ov2640_get_selection, | 1038 | .get_selection = ov2640_get_selection, |
@@ -1030,65 +1040,43 @@ static const struct v4l2_subdev_pad_ops ov2640_subdev_pad_ops = { | |||
1030 | .set_fmt = ov2640_set_fmt, | 1040 | .set_fmt = ov2640_set_fmt, |
1031 | }; | 1041 | }; |
1032 | 1042 | ||
1033 | static struct v4l2_subdev_ops ov2640_subdev_ops = { | 1043 | static const struct v4l2_subdev_ops ov2640_subdev_ops = { |
1034 | .core = &ov2640_subdev_core_ops, | 1044 | .core = &ov2640_subdev_core_ops, |
1035 | .video = &ov2640_subdev_video_ops, | ||
1036 | .pad = &ov2640_subdev_pad_ops, | 1045 | .pad = &ov2640_subdev_pad_ops, |
1037 | }; | 1046 | }; |
1038 | 1047 | ||
1039 | /* OF probe functions */ | ||
1040 | static int ov2640_hw_power(struct device *dev, int on) | ||
1041 | { | ||
1042 | struct i2c_client *client = to_i2c_client(dev); | ||
1043 | struct ov2640_priv *priv = to_ov2640(client); | ||
1044 | |||
1045 | dev_dbg(&client->dev, "%s: %s the camera\n", | ||
1046 | __func__, on ? "ENABLE" : "DISABLE"); | ||
1047 | |||
1048 | if (priv->pwdn_gpio) | ||
1049 | gpiod_direction_output(priv->pwdn_gpio, !on); | ||
1050 | |||
1051 | return 0; | ||
1052 | } | ||
1053 | |||
1054 | static int ov2640_hw_reset(struct device *dev) | ||
1055 | { | ||
1056 | struct i2c_client *client = to_i2c_client(dev); | ||
1057 | struct ov2640_priv *priv = to_ov2640(client); | ||
1058 | |||
1059 | if (priv->resetb_gpio) { | ||
1060 | /* Active the resetb pin to perform a reset pulse */ | ||
1061 | gpiod_direction_output(priv->resetb_gpio, 1); | ||
1062 | usleep_range(3000, 5000); | ||
1063 | gpiod_direction_output(priv->resetb_gpio, 0); | ||
1064 | } | ||
1065 | |||
1066 | return 0; | ||
1067 | } | ||
1068 | |||
1069 | static int ov2640_probe_dt(struct i2c_client *client, | 1048 | static int ov2640_probe_dt(struct i2c_client *client, |
1070 | struct ov2640_priv *priv) | 1049 | struct ov2640_priv *priv) |
1071 | { | 1050 | { |
1051 | int ret; | ||
1052 | |||
1072 | /* Request the reset GPIO deasserted */ | 1053 | /* Request the reset GPIO deasserted */ |
1073 | priv->resetb_gpio = devm_gpiod_get_optional(&client->dev, "resetb", | 1054 | priv->resetb_gpio = devm_gpiod_get_optional(&client->dev, "resetb", |
1074 | GPIOD_OUT_LOW); | 1055 | GPIOD_OUT_LOW); |
1056 | |||
1075 | if (!priv->resetb_gpio) | 1057 | if (!priv->resetb_gpio) |
1076 | dev_dbg(&client->dev, "resetb gpio is not assigned!\n"); | 1058 | dev_dbg(&client->dev, "resetb gpio is not assigned!\n"); |
1077 | else if (IS_ERR(priv->resetb_gpio)) | 1059 | |
1078 | return PTR_ERR(priv->resetb_gpio); | 1060 | ret = PTR_ERR_OR_ZERO(priv->resetb_gpio); |
1061 | if (ret && ret != -ENOSYS) { | ||
1062 | dev_dbg(&client->dev, | ||
1063 | "Error %d while getting resetb gpio\n", ret); | ||
1064 | return ret; | ||
1065 | } | ||
1079 | 1066 | ||
1080 | /* Request the power down GPIO asserted */ | 1067 | /* Request the power down GPIO asserted */ |
1081 | priv->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "pwdn", | 1068 | priv->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "pwdn", |
1082 | GPIOD_OUT_HIGH); | 1069 | GPIOD_OUT_HIGH); |
1070 | |||
1083 | if (!priv->pwdn_gpio) | 1071 | if (!priv->pwdn_gpio) |
1084 | dev_dbg(&client->dev, "pwdn gpio is not assigned!\n"); | 1072 | dev_dbg(&client->dev, "pwdn gpio is not assigned!\n"); |
1085 | else if (IS_ERR(priv->pwdn_gpio)) | ||
1086 | return PTR_ERR(priv->pwdn_gpio); | ||
1087 | 1073 | ||
1088 | /* Initialize the soc_camera_subdev_desc */ | 1074 | ret = PTR_ERR_OR_ZERO(priv->pwdn_gpio); |
1089 | priv->ssdd_dt.power = ov2640_hw_power; | 1075 | if (ret && ret != -ENOSYS) { |
1090 | priv->ssdd_dt.reset = ov2640_hw_reset; | 1076 | dev_dbg(&client->dev, |
1091 | client->dev.platform_data = &priv->ssdd_dt; | 1077 | "Error %d while getting pwdn gpio\n", ret); |
1078 | return ret; | ||
1079 | } | ||
1092 | 1080 | ||
1093 | return 0; | 1081 | return 0; |
1094 | } | 1082 | } |
@@ -1100,7 +1088,6 @@ static int ov2640_probe(struct i2c_client *client, | |||
1100 | const struct i2c_device_id *did) | 1088 | const struct i2c_device_id *did) |
1101 | { | 1089 | { |
1102 | struct ov2640_priv *priv; | 1090 | struct ov2640_priv *priv; |
1103 | struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); | ||
1104 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 1091 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
1105 | int ret; | 1092 | int ret; |
1106 | 1093 | ||
@@ -1117,23 +1104,19 @@ static int ov2640_probe(struct i2c_client *client, | |||
1117 | return -ENOMEM; | 1104 | return -ENOMEM; |
1118 | } | 1105 | } |
1119 | 1106 | ||
1120 | priv->clk = v4l2_clk_get(&client->dev, "xvclk"); | 1107 | if (client->dev.of_node) { |
1121 | if (IS_ERR(priv->clk)) | 1108 | priv->clk = devm_clk_get(&client->dev, "xvclk"); |
1122 | return -EPROBE_DEFER; | 1109 | if (IS_ERR(priv->clk)) |
1123 | 1110 | return -EPROBE_DEFER; | |
1124 | if (!ssdd && !client->dev.of_node) { | 1111 | clk_prepare_enable(priv->clk); |
1125 | dev_err(&client->dev, "Missing platform_data for driver\n"); | ||
1126 | ret = -EINVAL; | ||
1127 | goto err_clk; | ||
1128 | } | 1112 | } |
1129 | 1113 | ||
1130 | if (!ssdd) { | 1114 | ret = ov2640_probe_dt(client, priv); |
1131 | ret = ov2640_probe_dt(client, priv); | 1115 | if (ret) |
1132 | if (ret) | 1116 | goto err_clk; |
1133 | goto err_clk; | ||
1134 | } | ||
1135 | 1117 | ||
1136 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov2640_subdev_ops); | 1118 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov2640_subdev_ops); |
1119 | priv->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
1137 | v4l2_ctrl_handler_init(&priv->hdl, 2); | 1120 | v4l2_ctrl_handler_init(&priv->hdl, 2); |
1138 | v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops, | 1121 | v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops, |
1139 | V4L2_CID_VFLIP, 0, 1, 1, 0); | 1122 | V4L2_CID_VFLIP, 0, 1, 1, 0); |
@@ -1142,8 +1125,15 @@ static int ov2640_probe(struct i2c_client *client, | |||
1142 | priv->subdev.ctrl_handler = &priv->hdl; | 1125 | priv->subdev.ctrl_handler = &priv->hdl; |
1143 | if (priv->hdl.error) { | 1126 | if (priv->hdl.error) { |
1144 | ret = priv->hdl.error; | 1127 | ret = priv->hdl.error; |
1145 | goto err_clk; | 1128 | goto err_hdl; |
1146 | } | 1129 | } |
1130 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
1131 | priv->pad.flags = MEDIA_PAD_FL_SOURCE; | ||
1132 | priv->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR; | ||
1133 | ret = media_entity_pads_init(&priv->subdev.entity, 1, &priv->pad); | ||
1134 | if (ret < 0) | ||
1135 | goto err_hdl; | ||
1136 | #endif | ||
1147 | 1137 | ||
1148 | ret = ov2640_video_probe(client); | 1138 | ret = ov2640_video_probe(client); |
1149 | if (ret < 0) | 1139 | if (ret < 0) |
@@ -1158,9 +1148,13 @@ static int ov2640_probe(struct i2c_client *client, | |||
1158 | return 0; | 1148 | return 0; |
1159 | 1149 | ||
1160 | err_videoprobe: | 1150 | err_videoprobe: |
1151 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
1152 | media_entity_cleanup(&priv->subdev.entity); | ||
1153 | #endif | ||
1154 | err_hdl: | ||
1161 | v4l2_ctrl_handler_free(&priv->hdl); | 1155 | v4l2_ctrl_handler_free(&priv->hdl); |
1162 | err_clk: | 1156 | err_clk: |
1163 | v4l2_clk_put(priv->clk); | 1157 | clk_disable_unprepare(priv->clk); |
1164 | return ret; | 1158 | return ret; |
1165 | } | 1159 | } |
1166 | 1160 | ||
@@ -1169,9 +1163,12 @@ static int ov2640_remove(struct i2c_client *client) | |||
1169 | struct ov2640_priv *priv = to_ov2640(client); | 1163 | struct ov2640_priv *priv = to_ov2640(client); |
1170 | 1164 | ||
1171 | v4l2_async_unregister_subdev(&priv->subdev); | 1165 | v4l2_async_unregister_subdev(&priv->subdev); |
1172 | v4l2_clk_put(priv->clk); | ||
1173 | v4l2_device_unregister_subdev(&priv->subdev); | ||
1174 | v4l2_ctrl_handler_free(&priv->hdl); | 1166 | v4l2_ctrl_handler_free(&priv->hdl); |
1167 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
1168 | media_entity_cleanup(&priv->subdev.entity); | ||
1169 | #endif | ||
1170 | v4l2_device_unregister_subdev(&priv->subdev); | ||
1171 | clk_disable_unprepare(priv->clk); | ||
1175 | return 0; | 1172 | return 0; |
1176 | } | 1173 | } |
1177 | 1174 | ||
@@ -1199,6 +1196,6 @@ static struct i2c_driver ov2640_i2c_driver = { | |||
1199 | 1196 | ||
1200 | module_i2c_driver(ov2640_i2c_driver); | 1197 | module_i2c_driver(ov2640_i2c_driver); |
1201 | 1198 | ||
1202 | MODULE_DESCRIPTION("SoC Camera driver for Omni Vision 2640 sensor"); | 1199 | MODULE_DESCRIPTION("Driver for Omni Vision 2640 sensor"); |
1203 | MODULE_AUTHOR("Alberto Panizzo"); | 1200 | MODULE_AUTHOR("Alberto Panizzo"); |
1204 | MODULE_LICENSE("GPL v2"); | 1201 | MODULE_LICENSE("GPL v2"); |
diff --git a/drivers/media/i2c/ov5645.c b/drivers/media/i2c/ov5645.c new file mode 100644 index 000000000000..57bd591ea54b --- /dev/null +++ b/drivers/media/i2c/ov5645.c | |||
@@ -0,0 +1,1345 @@ | |||
1 | /* | ||
2 | * Driver for the OV5645 camera sensor. | ||
3 | * | ||
4 | * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. | ||
5 | * Copyright (C) 2015 By Tech Design S.L. All Rights Reserved. | ||
6 | * Copyright (C) 2012-2013 Freescale Semiconductor, Inc. All Rights Reserved. | ||
7 | * | ||
8 | * Based on: | ||
9 | * - the OV5645 driver from QC msm-3.10 kernel on codeaurora.org: | ||
10 | * https://us.codeaurora.org/cgit/quic/la/kernel/msm-3.10/tree/drivers/ | ||
11 | * media/platform/msm/camera_v2/sensor/ov5645.c?h=LA.BR.1.2.4_rb1.41 | ||
12 | * - the OV5640 driver posted on linux-media: | ||
13 | * https://www.mail-archive.com/linux-media%40vger.kernel.org/msg92671.html | ||
14 | */ | ||
15 | |||
16 | /* | ||
17 | * This program is free software; you can redistribute it and/or modify | ||
18 | * it under the terms of the GNU General Public License as published by | ||
19 | * the Free Software Foundation; either version 2 of the License, or | ||
20 | * (at your option) any later version. | ||
21 | |||
22 | * This program is distributed in the hope that it will be useful, | ||
23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
25 | * GNU General Public License for more details. | ||
26 | */ | ||
27 | |||
28 | #include <linux/bitops.h> | ||
29 | #include <linux/clk.h> | ||
30 | #include <linux/delay.h> | ||
31 | #include <linux/device.h> | ||
32 | #include <linux/gpio/consumer.h> | ||
33 | #include <linux/i2c.h> | ||
34 | #include <linux/init.h> | ||
35 | #include <linux/module.h> | ||
36 | #include <linux/of.h> | ||
37 | #include <linux/of_graph.h> | ||
38 | #include <linux/regulator/consumer.h> | ||
39 | #include <linux/slab.h> | ||
40 | #include <linux/types.h> | ||
41 | #include <media/v4l2-ctrls.h> | ||
42 | #include <media/v4l2-of.h> | ||
43 | #include <media/v4l2-subdev.h> | ||
44 | |||
45 | #define OV5645_VOLTAGE_ANALOG 2800000 | ||
46 | #define OV5645_VOLTAGE_DIGITAL_CORE 1500000 | ||
47 | #define OV5645_VOLTAGE_DIGITAL_IO 1800000 | ||
48 | |||
49 | #define OV5645_SYSTEM_CTRL0 0x3008 | ||
50 | #define OV5645_SYSTEM_CTRL0_START 0x02 | ||
51 | #define OV5645_SYSTEM_CTRL0_STOP 0x42 | ||
52 | #define OV5645_CHIP_ID_HIGH 0x300a | ||
53 | #define OV5645_CHIP_ID_HIGH_BYTE 0x56 | ||
54 | #define OV5645_CHIP_ID_LOW 0x300b | ||
55 | #define OV5645_CHIP_ID_LOW_BYTE 0x45 | ||
56 | #define OV5645_AWB_MANUAL_CONTROL 0x3406 | ||
57 | #define OV5645_AWB_MANUAL_ENABLE BIT(0) | ||
58 | #define OV5645_AEC_PK_MANUAL 0x3503 | ||
59 | #define OV5645_AEC_MANUAL_ENABLE BIT(0) | ||
60 | #define OV5645_AGC_MANUAL_ENABLE BIT(1) | ||
61 | #define OV5645_TIMING_TC_REG20 0x3820 | ||
62 | #define OV5645_SENSOR_VFLIP BIT(1) | ||
63 | #define OV5645_ISP_VFLIP BIT(2) | ||
64 | #define OV5645_TIMING_TC_REG21 0x3821 | ||
65 | #define OV5645_SENSOR_MIRROR BIT(1) | ||
66 | #define OV5645_PRE_ISP_TEST_SETTING_1 0x503d | ||
67 | #define OV5645_TEST_PATTERN_MASK 0x3 | ||
68 | #define OV5645_SET_TEST_PATTERN(x) ((x) & OV5645_TEST_PATTERN_MASK) | ||
69 | #define OV5645_TEST_PATTERN_ENABLE BIT(7) | ||
70 | #define OV5645_SDE_SAT_U 0x5583 | ||
71 | #define OV5645_SDE_SAT_V 0x5584 | ||
72 | |||
73 | struct reg_value { | ||
74 | u16 reg; | ||
75 | u8 val; | ||
76 | }; | ||
77 | |||
78 | struct ov5645_mode_info { | ||
79 | u32 width; | ||
80 | u32 height; | ||
81 | const struct reg_value *data; | ||
82 | u32 data_size; | ||
83 | }; | ||
84 | |||
85 | struct ov5645 { | ||
86 | struct i2c_client *i2c_client; | ||
87 | struct device *dev; | ||
88 | struct v4l2_subdev sd; | ||
89 | struct media_pad pad; | ||
90 | struct v4l2_of_endpoint ep; | ||
91 | struct v4l2_mbus_framefmt fmt; | ||
92 | struct v4l2_rect crop; | ||
93 | struct clk *xclk; | ||
94 | |||
95 | struct regulator *io_regulator; | ||
96 | struct regulator *core_regulator; | ||
97 | struct regulator *analog_regulator; | ||
98 | |||
99 | const struct ov5645_mode_info *current_mode; | ||
100 | |||
101 | struct v4l2_ctrl_handler ctrls; | ||
102 | |||
103 | /* Cached register values */ | ||
104 | u8 aec_pk_manual; | ||
105 | u8 timing_tc_reg20; | ||
106 | u8 timing_tc_reg21; | ||
107 | |||
108 | struct mutex power_lock; /* lock to protect power state */ | ||
109 | int power_count; | ||
110 | |||
111 | struct gpio_desc *enable_gpio; | ||
112 | struct gpio_desc *rst_gpio; | ||
113 | }; | ||
114 | |||
115 | static inline struct ov5645 *to_ov5645(struct v4l2_subdev *sd) | ||
116 | { | ||
117 | return container_of(sd, struct ov5645, sd); | ||
118 | } | ||
119 | |||
120 | static const struct reg_value ov5645_global_init_setting[] = { | ||
121 | { 0x3103, 0x11 }, | ||
122 | { 0x3008, 0x82 }, | ||
123 | { 0x3008, 0x42 }, | ||
124 | { 0x3103, 0x03 }, | ||
125 | { 0x3503, 0x07 }, | ||
126 | { 0x3002, 0x1c }, | ||
127 | { 0x3006, 0xc3 }, | ||
128 | { 0x300e, 0x45 }, | ||
129 | { 0x3017, 0x00 }, | ||
130 | { 0x3018, 0x00 }, | ||
131 | { 0x302e, 0x0b }, | ||
132 | { 0x3037, 0x13 }, | ||
133 | { 0x3108, 0x01 }, | ||
134 | { 0x3611, 0x06 }, | ||
135 | { 0x3500, 0x00 }, | ||
136 | { 0x3501, 0x01 }, | ||
137 | { 0x3502, 0x00 }, | ||
138 | { 0x350a, 0x00 }, | ||
139 | { 0x350b, 0x3f }, | ||
140 | { 0x3620, 0x33 }, | ||
141 | { 0x3621, 0xe0 }, | ||
142 | { 0x3622, 0x01 }, | ||
143 | { 0x3630, 0x2e }, | ||
144 | { 0x3631, 0x00 }, | ||
145 | { 0x3632, 0x32 }, | ||
146 | { 0x3633, 0x52 }, | ||
147 | { 0x3634, 0x70 }, | ||
148 | { 0x3635, 0x13 }, | ||
149 | { 0x3636, 0x03 }, | ||
150 | { 0x3703, 0x5a }, | ||
151 | { 0x3704, 0xa0 }, | ||
152 | { 0x3705, 0x1a }, | ||
153 | { 0x3709, 0x12 }, | ||
154 | { 0x370b, 0x61 }, | ||
155 | { 0x370f, 0x10 }, | ||
156 | { 0x3715, 0x78 }, | ||
157 | { 0x3717, 0x01 }, | ||
158 | { 0x371b, 0x20 }, | ||
159 | { 0x3731, 0x12 }, | ||
160 | { 0x3901, 0x0a }, | ||
161 | { 0x3905, 0x02 }, | ||
162 | { 0x3906, 0x10 }, | ||
163 | { 0x3719, 0x86 }, | ||
164 | { 0x3810, 0x00 }, | ||
165 | { 0x3811, 0x10 }, | ||
166 | { 0x3812, 0x00 }, | ||
167 | { 0x3821, 0x01 }, | ||
168 | { 0x3824, 0x01 }, | ||
169 | { 0x3826, 0x03 }, | ||
170 | { 0x3828, 0x08 }, | ||
171 | { 0x3a19, 0xf8 }, | ||
172 | { 0x3c01, 0x34 }, | ||
173 | { 0x3c04, 0x28 }, | ||
174 | { 0x3c05, 0x98 }, | ||
175 | { 0x3c07, 0x07 }, | ||
176 | { 0x3c09, 0xc2 }, | ||
177 | { 0x3c0a, 0x9c }, | ||
178 | { 0x3c0b, 0x40 }, | ||
179 | { 0x3c01, 0x34 }, | ||
180 | { 0x4001, 0x02 }, | ||
181 | { 0x4514, 0x00 }, | ||
182 | { 0x4520, 0xb0 }, | ||
183 | { 0x460b, 0x37 }, | ||
184 | { 0x460c, 0x20 }, | ||
185 | { 0x4818, 0x01 }, | ||
186 | { 0x481d, 0xf0 }, | ||
187 | { 0x481f, 0x50 }, | ||
188 | { 0x4823, 0x70 }, | ||
189 | { 0x4831, 0x14 }, | ||
190 | { 0x5000, 0xa7 }, | ||
191 | { 0x5001, 0x83 }, | ||
192 | { 0x501d, 0x00 }, | ||
193 | { 0x501f, 0x00 }, | ||
194 | { 0x503d, 0x00 }, | ||
195 | { 0x505c, 0x30 }, | ||
196 | { 0x5181, 0x59 }, | ||
197 | { 0x5183, 0x00 }, | ||
198 | { 0x5191, 0xf0 }, | ||
199 | { 0x5192, 0x03 }, | ||
200 | { 0x5684, 0x10 }, | ||
201 | { 0x5685, 0xa0 }, | ||
202 | { 0x5686, 0x0c }, | ||
203 | { 0x5687, 0x78 }, | ||
204 | { 0x5a00, 0x08 }, | ||
205 | { 0x5a21, 0x00 }, | ||
206 | { 0x5a24, 0x00 }, | ||
207 | { 0x3008, 0x02 }, | ||
208 | { 0x3503, 0x00 }, | ||
209 | { 0x5180, 0xff }, | ||
210 | { 0x5181, 0xf2 }, | ||
211 | { 0x5182, 0x00 }, | ||
212 | { 0x5183, 0x14 }, | ||
213 | { 0x5184, 0x25 }, | ||
214 | { 0x5185, 0x24 }, | ||
215 | { 0x5186, 0x09 }, | ||
216 | { 0x5187, 0x09 }, | ||
217 | { 0x5188, 0x0a }, | ||
218 | { 0x5189, 0x75 }, | ||
219 | { 0x518a, 0x52 }, | ||
220 | { 0x518b, 0xea }, | ||
221 | { 0x518c, 0xa8 }, | ||
222 | { 0x518d, 0x42 }, | ||
223 | { 0x518e, 0x38 }, | ||
224 | { 0x518f, 0x56 }, | ||
225 | { 0x5190, 0x42 }, | ||
226 | { 0x5191, 0xf8 }, | ||
227 | { 0x5192, 0x04 }, | ||
228 | { 0x5193, 0x70 }, | ||
229 | { 0x5194, 0xf0 }, | ||
230 | { 0x5195, 0xf0 }, | ||
231 | { 0x5196, 0x03 }, | ||
232 | { 0x5197, 0x01 }, | ||
233 | { 0x5198, 0x04 }, | ||
234 | { 0x5199, 0x12 }, | ||
235 | { 0x519a, 0x04 }, | ||
236 | { 0x519b, 0x00 }, | ||
237 | { 0x519c, 0x06 }, | ||
238 | { 0x519d, 0x82 }, | ||
239 | { 0x519e, 0x38 }, | ||
240 | { 0x5381, 0x1e }, | ||
241 | { 0x5382, 0x5b }, | ||
242 | { 0x5383, 0x08 }, | ||
243 | { 0x5384, 0x0a }, | ||
244 | { 0x5385, 0x7e }, | ||
245 | { 0x5386, 0x88 }, | ||
246 | { 0x5387, 0x7c }, | ||
247 | { 0x5388, 0x6c }, | ||
248 | { 0x5389, 0x10 }, | ||
249 | { 0x538a, 0x01 }, | ||
250 | { 0x538b, 0x98 }, | ||
251 | { 0x5300, 0x08 }, | ||
252 | { 0x5301, 0x30 }, | ||
253 | { 0x5302, 0x10 }, | ||
254 | { 0x5303, 0x00 }, | ||
255 | { 0x5304, 0x08 }, | ||
256 | { 0x5305, 0x30 }, | ||
257 | { 0x5306, 0x08 }, | ||
258 | { 0x5307, 0x16 }, | ||
259 | { 0x5309, 0x08 }, | ||
260 | { 0x530a, 0x30 }, | ||
261 | { 0x530b, 0x04 }, | ||
262 | { 0x530c, 0x06 }, | ||
263 | { 0x5480, 0x01 }, | ||
264 | { 0x5481, 0x08 }, | ||
265 | { 0x5482, 0x14 }, | ||
266 | { 0x5483, 0x28 }, | ||
267 | { 0x5484, 0x51 }, | ||
268 | { 0x5485, 0x65 }, | ||
269 | { 0x5486, 0x71 }, | ||
270 | { 0x5487, 0x7d }, | ||
271 | { 0x5488, 0x87 }, | ||
272 | { 0x5489, 0x91 }, | ||
273 | { 0x548a, 0x9a }, | ||
274 | { 0x548b, 0xaa }, | ||
275 | { 0x548c, 0xb8 }, | ||
276 | { 0x548d, 0xcd }, | ||
277 | { 0x548e, 0xdd }, | ||
278 | { 0x548f, 0xea }, | ||
279 | { 0x5490, 0x1d }, | ||
280 | { 0x5580, 0x02 }, | ||
281 | { 0x5583, 0x40 }, | ||
282 | { 0x5584, 0x10 }, | ||
283 | { 0x5589, 0x10 }, | ||
284 | { 0x558a, 0x00 }, | ||
285 | { 0x558b, 0xf8 }, | ||
286 | { 0x5800, 0x3f }, | ||
287 | { 0x5801, 0x16 }, | ||
288 | { 0x5802, 0x0e }, | ||
289 | { 0x5803, 0x0d }, | ||
290 | { 0x5804, 0x17 }, | ||
291 | { 0x5805, 0x3f }, | ||
292 | { 0x5806, 0x0b }, | ||
293 | { 0x5807, 0x06 }, | ||
294 | { 0x5808, 0x04 }, | ||
295 | { 0x5809, 0x04 }, | ||
296 | { 0x580a, 0x06 }, | ||
297 | { 0x580b, 0x0b }, | ||
298 | { 0x580c, 0x09 }, | ||
299 | { 0x580d, 0x03 }, | ||
300 | { 0x580e, 0x00 }, | ||
301 | { 0x580f, 0x00 }, | ||
302 | { 0x5810, 0x03 }, | ||
303 | { 0x5811, 0x08 }, | ||
304 | { 0x5812, 0x0a }, | ||
305 | { 0x5813, 0x03 }, | ||
306 | { 0x5814, 0x00 }, | ||
307 | { 0x5815, 0x00 }, | ||
308 | { 0x5816, 0x04 }, | ||
309 | { 0x5817, 0x09 }, | ||
310 | { 0x5818, 0x0f }, | ||
311 | { 0x5819, 0x08 }, | ||
312 | { 0x581a, 0x06 }, | ||
313 | { 0x581b, 0x06 }, | ||
314 | { 0x581c, 0x08 }, | ||
315 | { 0x581d, 0x0c }, | ||
316 | { 0x581e, 0x3f }, | ||
317 | { 0x581f, 0x1e }, | ||
318 | { 0x5820, 0x12 }, | ||
319 | { 0x5821, 0x13 }, | ||
320 | { 0x5822, 0x21 }, | ||
321 | { 0x5823, 0x3f }, | ||
322 | { 0x5824, 0x68 }, | ||
323 | { 0x5825, 0x28 }, | ||
324 | { 0x5826, 0x2c }, | ||
325 | { 0x5827, 0x28 }, | ||
326 | { 0x5828, 0x08 }, | ||
327 | { 0x5829, 0x48 }, | ||
328 | { 0x582a, 0x64 }, | ||
329 | { 0x582b, 0x62 }, | ||
330 | { 0x582c, 0x64 }, | ||
331 | { 0x582d, 0x28 }, | ||
332 | { 0x582e, 0x46 }, | ||
333 | { 0x582f, 0x62 }, | ||
334 | { 0x5830, 0x60 }, | ||
335 | { 0x5831, 0x62 }, | ||
336 | { 0x5832, 0x26 }, | ||
337 | { 0x5833, 0x48 }, | ||
338 | { 0x5834, 0x66 }, | ||
339 | { 0x5835, 0x44 }, | ||
340 | { 0x5836, 0x64 }, | ||
341 | { 0x5837, 0x28 }, | ||
342 | { 0x5838, 0x66 }, | ||
343 | { 0x5839, 0x48 }, | ||
344 | { 0x583a, 0x2c }, | ||
345 | { 0x583b, 0x28 }, | ||
346 | { 0x583c, 0x26 }, | ||
347 | { 0x583d, 0xae }, | ||
348 | { 0x5025, 0x00 }, | ||
349 | { 0x3a0f, 0x30 }, | ||
350 | { 0x3a10, 0x28 }, | ||
351 | { 0x3a1b, 0x30 }, | ||
352 | { 0x3a1e, 0x26 }, | ||
353 | { 0x3a11, 0x60 }, | ||
354 | { 0x3a1f, 0x14 }, | ||
355 | { 0x0601, 0x02 }, | ||
356 | { 0x3008, 0x42 }, | ||
357 | { 0x3008, 0x02 } | ||
358 | }; | ||
359 | |||
360 | static const struct reg_value ov5645_setting_sxga[] = { | ||
361 | { 0x3612, 0xa9 }, | ||
362 | { 0x3614, 0x50 }, | ||
363 | { 0x3618, 0x00 }, | ||
364 | { 0x3034, 0x18 }, | ||
365 | { 0x3035, 0x21 }, | ||
366 | { 0x3036, 0x70 }, | ||
367 | { 0x3600, 0x09 }, | ||
368 | { 0x3601, 0x43 }, | ||
369 | { 0x3708, 0x66 }, | ||
370 | { 0x370c, 0xc3 }, | ||
371 | { 0x3800, 0x00 }, | ||
372 | { 0x3801, 0x00 }, | ||
373 | { 0x3802, 0x00 }, | ||
374 | { 0x3803, 0x06 }, | ||
375 | { 0x3804, 0x0a }, | ||
376 | { 0x3805, 0x3f }, | ||
377 | { 0x3806, 0x07 }, | ||
378 | { 0x3807, 0x9d }, | ||
379 | { 0x3808, 0x05 }, | ||
380 | { 0x3809, 0x00 }, | ||
381 | { 0x380a, 0x03 }, | ||
382 | { 0x380b, 0xc0 }, | ||
383 | { 0x380c, 0x07 }, | ||
384 | { 0x380d, 0x68 }, | ||
385 | { 0x380e, 0x03 }, | ||
386 | { 0x380f, 0xd8 }, | ||
387 | { 0x3813, 0x06 }, | ||
388 | { 0x3814, 0x31 }, | ||
389 | { 0x3815, 0x31 }, | ||
390 | { 0x3820, 0x47 }, | ||
391 | { 0x3a02, 0x03 }, | ||
392 | { 0x3a03, 0xd8 }, | ||
393 | { 0x3a08, 0x01 }, | ||
394 | { 0x3a09, 0xf8 }, | ||
395 | { 0x3a0a, 0x01 }, | ||
396 | { 0x3a0b, 0xa4 }, | ||
397 | { 0x3a0e, 0x02 }, | ||
398 | { 0x3a0d, 0x02 }, | ||
399 | { 0x3a14, 0x03 }, | ||
400 | { 0x3a15, 0xd8 }, | ||
401 | { 0x3a18, 0x00 }, | ||
402 | { 0x4004, 0x02 }, | ||
403 | { 0x4005, 0x18 }, | ||
404 | { 0x4300, 0x32 }, | ||
405 | { 0x4202, 0x00 } | ||
406 | }; | ||
407 | |||
408 | static const struct reg_value ov5645_setting_1080p[] = { | ||
409 | { 0x3612, 0xab }, | ||
410 | { 0x3614, 0x50 }, | ||
411 | { 0x3618, 0x04 }, | ||
412 | { 0x3034, 0x18 }, | ||
413 | { 0x3035, 0x11 }, | ||
414 | { 0x3036, 0x54 }, | ||
415 | { 0x3600, 0x08 }, | ||
416 | { 0x3601, 0x33 }, | ||
417 | { 0x3708, 0x63 }, | ||
418 | { 0x370c, 0xc0 }, | ||
419 | { 0x3800, 0x01 }, | ||
420 | { 0x3801, 0x50 }, | ||
421 | { 0x3802, 0x01 }, | ||
422 | { 0x3803, 0xb2 }, | ||
423 | { 0x3804, 0x08 }, | ||
424 | { 0x3805, 0xef }, | ||
425 | { 0x3806, 0x05 }, | ||
426 | { 0x3807, 0xf1 }, | ||
427 | { 0x3808, 0x07 }, | ||
428 | { 0x3809, 0x80 }, | ||
429 | { 0x380a, 0x04 }, | ||
430 | { 0x380b, 0x38 }, | ||
431 | { 0x380c, 0x09 }, | ||
432 | { 0x380d, 0xc4 }, | ||
433 | { 0x380e, 0x04 }, | ||
434 | { 0x380f, 0x60 }, | ||
435 | { 0x3813, 0x04 }, | ||
436 | { 0x3814, 0x11 }, | ||
437 | { 0x3815, 0x11 }, | ||
438 | { 0x3820, 0x47 }, | ||
439 | { 0x4514, 0x88 }, | ||
440 | { 0x3a02, 0x04 }, | ||
441 | { 0x3a03, 0x60 }, | ||
442 | { 0x3a08, 0x01 }, | ||
443 | { 0x3a09, 0x50 }, | ||
444 | { 0x3a0a, 0x01 }, | ||
445 | { 0x3a0b, 0x18 }, | ||
446 | { 0x3a0e, 0x03 }, | ||
447 | { 0x3a0d, 0x04 }, | ||
448 | { 0x3a14, 0x04 }, | ||
449 | { 0x3a15, 0x60 }, | ||
450 | { 0x3a18, 0x00 }, | ||
451 | { 0x4004, 0x06 }, | ||
452 | { 0x4005, 0x18 }, | ||
453 | { 0x4300, 0x32 }, | ||
454 | { 0x4202, 0x00 }, | ||
455 | { 0x4837, 0x0b } | ||
456 | }; | ||
457 | |||
458 | static const struct reg_value ov5645_setting_full[] = { | ||
459 | { 0x3612, 0xab }, | ||
460 | { 0x3614, 0x50 }, | ||
461 | { 0x3618, 0x04 }, | ||
462 | { 0x3034, 0x18 }, | ||
463 | { 0x3035, 0x11 }, | ||
464 | { 0x3036, 0x54 }, | ||
465 | { 0x3600, 0x08 }, | ||
466 | { 0x3601, 0x33 }, | ||
467 | { 0x3708, 0x63 }, | ||
468 | { 0x370c, 0xc0 }, | ||
469 | { 0x3800, 0x00 }, | ||
470 | { 0x3801, 0x00 }, | ||
471 | { 0x3802, 0x00 }, | ||
472 | { 0x3803, 0x00 }, | ||
473 | { 0x3804, 0x0a }, | ||
474 | { 0x3805, 0x3f }, | ||
475 | { 0x3806, 0x07 }, | ||
476 | { 0x3807, 0x9f }, | ||
477 | { 0x3808, 0x0a }, | ||
478 | { 0x3809, 0x20 }, | ||
479 | { 0x380a, 0x07 }, | ||
480 | { 0x380b, 0x98 }, | ||
481 | { 0x380c, 0x0b }, | ||
482 | { 0x380d, 0x1c }, | ||
483 | { 0x380e, 0x07 }, | ||
484 | { 0x380f, 0xb0 }, | ||
485 | { 0x3813, 0x06 }, | ||
486 | { 0x3814, 0x11 }, | ||
487 | { 0x3815, 0x11 }, | ||
488 | { 0x3820, 0x47 }, | ||
489 | { 0x4514, 0x88 }, | ||
490 | { 0x3a02, 0x07 }, | ||
491 | { 0x3a03, 0xb0 }, | ||
492 | { 0x3a08, 0x01 }, | ||
493 | { 0x3a09, 0x27 }, | ||
494 | { 0x3a0a, 0x00 }, | ||
495 | { 0x3a0b, 0xf6 }, | ||
496 | { 0x3a0e, 0x06 }, | ||
497 | { 0x3a0d, 0x08 }, | ||
498 | { 0x3a14, 0x07 }, | ||
499 | { 0x3a15, 0xb0 }, | ||
500 | { 0x3a18, 0x01 }, | ||
501 | { 0x4004, 0x06 }, | ||
502 | { 0x4005, 0x18 }, | ||
503 | { 0x4300, 0x32 }, | ||
504 | { 0x4837, 0x0b }, | ||
505 | { 0x4202, 0x00 } | ||
506 | }; | ||
507 | |||
508 | static const struct ov5645_mode_info ov5645_mode_info_data[] = { | ||
509 | { | ||
510 | .width = 1280, | ||
511 | .height = 960, | ||
512 | .data = ov5645_setting_sxga, | ||
513 | .data_size = ARRAY_SIZE(ov5645_setting_sxga) | ||
514 | }, | ||
515 | { | ||
516 | .width = 1920, | ||
517 | .height = 1080, | ||
518 | .data = ov5645_setting_1080p, | ||
519 | .data_size = ARRAY_SIZE(ov5645_setting_1080p) | ||
520 | }, | ||
521 | { | ||
522 | .width = 2592, | ||
523 | .height = 1944, | ||
524 | .data = ov5645_setting_full, | ||
525 | .data_size = ARRAY_SIZE(ov5645_setting_full) | ||
526 | }, | ||
527 | }; | ||
528 | |||
529 | static int ov5645_regulators_enable(struct ov5645 *ov5645) | ||
530 | { | ||
531 | int ret; | ||
532 | |||
533 | ret = regulator_enable(ov5645->io_regulator); | ||
534 | if (ret < 0) { | ||
535 | dev_err(ov5645->dev, "set io voltage failed\n"); | ||
536 | return ret; | ||
537 | } | ||
538 | |||
539 | ret = regulator_enable(ov5645->analog_regulator); | ||
540 | if (ret) { | ||
541 | dev_err(ov5645->dev, "set analog voltage failed\n"); | ||
542 | goto err_disable_io; | ||
543 | } | ||
544 | |||
545 | ret = regulator_enable(ov5645->core_regulator); | ||
546 | if (ret) { | ||
547 | dev_err(ov5645->dev, "set core voltage failed\n"); | ||
548 | goto err_disable_analog; | ||
549 | } | ||
550 | |||
551 | return 0; | ||
552 | |||
553 | err_disable_analog: | ||
554 | regulator_disable(ov5645->analog_regulator); | ||
555 | err_disable_io: | ||
556 | regulator_disable(ov5645->io_regulator); | ||
557 | |||
558 | return ret; | ||
559 | } | ||
560 | |||
561 | static void ov5645_regulators_disable(struct ov5645 *ov5645) | ||
562 | { | ||
563 | int ret; | ||
564 | |||
565 | ret = regulator_disable(ov5645->core_regulator); | ||
566 | if (ret < 0) | ||
567 | dev_err(ov5645->dev, "core regulator disable failed\n"); | ||
568 | |||
569 | ret = regulator_disable(ov5645->analog_regulator); | ||
570 | if (ret < 0) | ||
571 | dev_err(ov5645->dev, "analog regulator disable failed\n"); | ||
572 | |||
573 | ret = regulator_disable(ov5645->io_regulator); | ||
574 | if (ret < 0) | ||
575 | dev_err(ov5645->dev, "io regulator disable failed\n"); | ||
576 | } | ||
577 | |||
578 | static int ov5645_write_reg(struct ov5645 *ov5645, u16 reg, u8 val) | ||
579 | { | ||
580 | u8 regbuf[3]; | ||
581 | int ret; | ||
582 | |||
583 | regbuf[0] = reg >> 8; | ||
584 | regbuf[1] = reg & 0xff; | ||
585 | regbuf[2] = val; | ||
586 | |||
587 | ret = i2c_master_send(ov5645->i2c_client, regbuf, 3); | ||
588 | if (ret < 0) | ||
589 | dev_err(ov5645->dev, "%s: write reg error %d: reg=%x, val=%x\n", | ||
590 | __func__, ret, reg, val); | ||
591 | |||
592 | return ret; | ||
593 | } | ||
594 | |||
595 | static int ov5645_read_reg(struct ov5645 *ov5645, u16 reg, u8 *val) | ||
596 | { | ||
597 | u8 regbuf[2]; | ||
598 | int ret; | ||
599 | |||
600 | regbuf[0] = reg >> 8; | ||
601 | regbuf[1] = reg & 0xff; | ||
602 | |||
603 | ret = i2c_master_send(ov5645->i2c_client, regbuf, 2); | ||
604 | if (ret < 0) { | ||
605 | dev_err(ov5645->dev, "%s: write reg error %d: reg=%x\n", | ||
606 | __func__, ret, reg); | ||
607 | return ret; | ||
608 | } | ||
609 | |||
610 | ret = i2c_master_recv(ov5645->i2c_client, val, 1); | ||
611 | if (ret < 0) { | ||
612 | dev_err(ov5645->dev, "%s: read reg error %d: reg=%x\n", | ||
613 | __func__, ret, reg); | ||
614 | return ret; | ||
615 | } | ||
616 | |||
617 | return 0; | ||
618 | } | ||
619 | |||
620 | static int ov5645_set_aec_mode(struct ov5645 *ov5645, u32 mode) | ||
621 | { | ||
622 | u8 val = ov5645->aec_pk_manual; | ||
623 | int ret; | ||
624 | |||
625 | if (mode == V4L2_EXPOSURE_AUTO) | ||
626 | val &= ~OV5645_AEC_MANUAL_ENABLE; | ||
627 | else /* V4L2_EXPOSURE_MANUAL */ | ||
628 | val |= OV5645_AEC_MANUAL_ENABLE; | ||
629 | |||
630 | ret = ov5645_write_reg(ov5645, OV5645_AEC_PK_MANUAL, val); | ||
631 | if (!ret) | ||
632 | ov5645->aec_pk_manual = val; | ||
633 | |||
634 | return ret; | ||
635 | } | ||
636 | |||
637 | static int ov5645_set_agc_mode(struct ov5645 *ov5645, u32 enable) | ||
638 | { | ||
639 | u8 val = ov5645->aec_pk_manual; | ||
640 | int ret; | ||
641 | |||
642 | if (enable) | ||
643 | val &= ~OV5645_AGC_MANUAL_ENABLE; | ||
644 | else | ||
645 | val |= OV5645_AGC_MANUAL_ENABLE; | ||
646 | |||
647 | ret = ov5645_write_reg(ov5645, OV5645_AEC_PK_MANUAL, val); | ||
648 | if (!ret) | ||
649 | ov5645->aec_pk_manual = val; | ||
650 | |||
651 | return ret; | ||
652 | } | ||
653 | |||
654 | static int ov5645_set_register_array(struct ov5645 *ov5645, | ||
655 | const struct reg_value *settings, | ||
656 | unsigned int num_settings) | ||
657 | { | ||
658 | unsigned int i; | ||
659 | int ret; | ||
660 | |||
661 | for (i = 0; i < num_settings; ++i, ++settings) { | ||
662 | ret = ov5645_write_reg(ov5645, settings->reg, settings->val); | ||
663 | if (ret < 0) | ||
664 | return ret; | ||
665 | } | ||
666 | |||
667 | return 0; | ||
668 | } | ||
669 | |||
670 | static int ov5645_set_power_on(struct ov5645 *ov5645) | ||
671 | { | ||
672 | int ret; | ||
673 | |||
674 | ret = ov5645_regulators_enable(ov5645); | ||
675 | if (ret < 0) { | ||
676 | return ret; | ||
677 | } | ||
678 | |||
679 | ret = clk_prepare_enable(ov5645->xclk); | ||
680 | if (ret < 0) { | ||
681 | dev_err(ov5645->dev, "clk prepare enable failed\n"); | ||
682 | ov5645_regulators_disable(ov5645); | ||
683 | return ret; | ||
684 | } | ||
685 | |||
686 | usleep_range(5000, 15000); | ||
687 | gpiod_set_value_cansleep(ov5645->enable_gpio, 1); | ||
688 | |||
689 | usleep_range(1000, 2000); | ||
690 | gpiod_set_value_cansleep(ov5645->rst_gpio, 0); | ||
691 | |||
692 | msleep(20); | ||
693 | |||
694 | return 0; | ||
695 | } | ||
696 | |||
697 | static void ov5645_set_power_off(struct ov5645 *ov5645) | ||
698 | { | ||
699 | gpiod_set_value_cansleep(ov5645->rst_gpio, 1); | ||
700 | gpiod_set_value_cansleep(ov5645->enable_gpio, 0); | ||
701 | clk_disable_unprepare(ov5645->xclk); | ||
702 | ov5645_regulators_disable(ov5645); | ||
703 | } | ||
704 | |||
705 | static int ov5645_s_power(struct v4l2_subdev *sd, int on) | ||
706 | { | ||
707 | struct ov5645 *ov5645 = to_ov5645(sd); | ||
708 | int ret = 0; | ||
709 | |||
710 | mutex_lock(&ov5645->power_lock); | ||
711 | |||
712 | /* If the power count is modified from 0 to != 0 or from != 0 to 0, | ||
713 | * update the power state. | ||
714 | */ | ||
715 | if (ov5645->power_count == !on) { | ||
716 | if (on) { | ||
717 | ret = ov5645_set_power_on(ov5645); | ||
718 | if (ret < 0) | ||
719 | goto exit; | ||
720 | |||
721 | ret = ov5645_set_register_array(ov5645, | ||
722 | ov5645_global_init_setting, | ||
723 | ARRAY_SIZE(ov5645_global_init_setting)); | ||
724 | if (ret < 0) { | ||
725 | dev_err(ov5645->dev, | ||
726 | "could not set init registers\n"); | ||
727 | ov5645_set_power_off(ov5645); | ||
728 | goto exit; | ||
729 | } | ||
730 | |||
731 | ret = ov5645_write_reg(ov5645, OV5645_SYSTEM_CTRL0, | ||
732 | OV5645_SYSTEM_CTRL0_STOP); | ||
733 | if (ret < 0) { | ||
734 | ov5645_set_power_off(ov5645); | ||
735 | goto exit; | ||
736 | } | ||
737 | } else { | ||
738 | ov5645_set_power_off(ov5645); | ||
739 | } | ||
740 | } | ||
741 | |||
742 | /* Update the power count. */ | ||
743 | ov5645->power_count += on ? 1 : -1; | ||
744 | WARN_ON(ov5645->power_count < 0); | ||
745 | |||
746 | exit: | ||
747 | mutex_unlock(&ov5645->power_lock); | ||
748 | |||
749 | return ret; | ||
750 | } | ||
751 | |||
752 | static int ov5645_set_saturation(struct ov5645 *ov5645, s32 value) | ||
753 | { | ||
754 | u32 reg_value = (value * 0x10) + 0x40; | ||
755 | int ret; | ||
756 | |||
757 | ret = ov5645_write_reg(ov5645, OV5645_SDE_SAT_U, reg_value); | ||
758 | if (ret < 0) | ||
759 | return ret; | ||
760 | |||
761 | return ov5645_write_reg(ov5645, OV5645_SDE_SAT_V, reg_value); | ||
762 | } | ||
763 | |||
764 | static int ov5645_set_hflip(struct ov5645 *ov5645, s32 value) | ||
765 | { | ||
766 | u8 val = ov5645->timing_tc_reg21; | ||
767 | int ret; | ||
768 | |||
769 | if (value == 0) | ||
770 | val &= ~(OV5645_SENSOR_MIRROR); | ||
771 | else | ||
772 | val |= (OV5645_SENSOR_MIRROR); | ||
773 | |||
774 | ret = ov5645_write_reg(ov5645, OV5645_TIMING_TC_REG21, val); | ||
775 | if (!ret) | ||
776 | ov5645->timing_tc_reg21 = val; | ||
777 | |||
778 | return ret; | ||
779 | } | ||
780 | |||
781 | static int ov5645_set_vflip(struct ov5645 *ov5645, s32 value) | ||
782 | { | ||
783 | u8 val = ov5645->timing_tc_reg20; | ||
784 | int ret; | ||
785 | |||
786 | if (value == 0) | ||
787 | val |= (OV5645_SENSOR_VFLIP | OV5645_ISP_VFLIP); | ||
788 | else | ||
789 | val &= ~(OV5645_SENSOR_VFLIP | OV5645_ISP_VFLIP); | ||
790 | |||
791 | ret = ov5645_write_reg(ov5645, OV5645_TIMING_TC_REG20, val); | ||
792 | if (!ret) | ||
793 | ov5645->timing_tc_reg20 = val; | ||
794 | |||
795 | return ret; | ||
796 | } | ||
797 | |||
798 | static int ov5645_set_test_pattern(struct ov5645 *ov5645, s32 value) | ||
799 | { | ||
800 | u8 val = 0; | ||
801 | |||
802 | if (value) { | ||
803 | val = OV5645_SET_TEST_PATTERN(value - 1); | ||
804 | val |= OV5645_TEST_PATTERN_ENABLE; | ||
805 | } | ||
806 | |||
807 | return ov5645_write_reg(ov5645, OV5645_PRE_ISP_TEST_SETTING_1, val); | ||
808 | } | ||
809 | |||
810 | static const char * const ov5645_test_pattern_menu[] = { | ||
811 | "Disabled", | ||
812 | "Vertical Color Bars", | ||
813 | "Pseudo-Random Data", | ||
814 | "Color Square", | ||
815 | "Black Image", | ||
816 | }; | ||
817 | |||
818 | static int ov5645_set_awb(struct ov5645 *ov5645, s32 enable_auto) | ||
819 | { | ||
820 | u8 val = 0; | ||
821 | |||
822 | if (!enable_auto) | ||
823 | val = OV5645_AWB_MANUAL_ENABLE; | ||
824 | |||
825 | return ov5645_write_reg(ov5645, OV5645_AWB_MANUAL_CONTROL, val); | ||
826 | } | ||
827 | |||
828 | static int ov5645_s_ctrl(struct v4l2_ctrl *ctrl) | ||
829 | { | ||
830 | struct ov5645 *ov5645 = container_of(ctrl->handler, | ||
831 | struct ov5645, ctrls); | ||
832 | int ret; | ||
833 | |||
834 | mutex_lock(&ov5645->power_lock); | ||
835 | if (!ov5645->power_count) { | ||
836 | mutex_unlock(&ov5645->power_lock); | ||
837 | return 0; | ||
838 | } | ||
839 | |||
840 | switch (ctrl->id) { | ||
841 | case V4L2_CID_SATURATION: | ||
842 | ret = ov5645_set_saturation(ov5645, ctrl->val); | ||
843 | break; | ||
844 | case V4L2_CID_AUTO_WHITE_BALANCE: | ||
845 | ret = ov5645_set_awb(ov5645, ctrl->val); | ||
846 | break; | ||
847 | case V4L2_CID_AUTOGAIN: | ||
848 | ret = ov5645_set_agc_mode(ov5645, ctrl->val); | ||
849 | break; | ||
850 | case V4L2_CID_EXPOSURE_AUTO: | ||
851 | ret = ov5645_set_aec_mode(ov5645, ctrl->val); | ||
852 | break; | ||
853 | case V4L2_CID_TEST_PATTERN: | ||
854 | ret = ov5645_set_test_pattern(ov5645, ctrl->val); | ||
855 | break; | ||
856 | case V4L2_CID_HFLIP: | ||
857 | ret = ov5645_set_hflip(ov5645, ctrl->val); | ||
858 | break; | ||
859 | case V4L2_CID_VFLIP: | ||
860 | ret = ov5645_set_vflip(ov5645, ctrl->val); | ||
861 | break; | ||
862 | default: | ||
863 | ret = -EINVAL; | ||
864 | break; | ||
865 | } | ||
866 | |||
867 | mutex_unlock(&ov5645->power_lock); | ||
868 | |||
869 | return ret; | ||
870 | } | ||
871 | |||
872 | static struct v4l2_ctrl_ops ov5645_ctrl_ops = { | ||
873 | .s_ctrl = ov5645_s_ctrl, | ||
874 | }; | ||
875 | |||
876 | static int ov5645_enum_mbus_code(struct v4l2_subdev *sd, | ||
877 | struct v4l2_subdev_pad_config *cfg, | ||
878 | struct v4l2_subdev_mbus_code_enum *code) | ||
879 | { | ||
880 | if (code->index > 0) | ||
881 | return -EINVAL; | ||
882 | |||
883 | code->code = MEDIA_BUS_FMT_UYVY8_2X8; | ||
884 | |||
885 | return 0; | ||
886 | } | ||
887 | |||
888 | static int ov5645_enum_frame_size(struct v4l2_subdev *subdev, | ||
889 | struct v4l2_subdev_pad_config *cfg, | ||
890 | struct v4l2_subdev_frame_size_enum *fse) | ||
891 | { | ||
892 | if (fse->code != MEDIA_BUS_FMT_UYVY8_2X8) | ||
893 | return -EINVAL; | ||
894 | |||
895 | if (fse->index >= ARRAY_SIZE(ov5645_mode_info_data)) | ||
896 | return -EINVAL; | ||
897 | |||
898 | fse->min_width = ov5645_mode_info_data[fse->index].width; | ||
899 | fse->max_width = ov5645_mode_info_data[fse->index].width; | ||
900 | fse->min_height = ov5645_mode_info_data[fse->index].height; | ||
901 | fse->max_height = ov5645_mode_info_data[fse->index].height; | ||
902 | |||
903 | return 0; | ||
904 | } | ||
905 | |||
906 | static struct v4l2_mbus_framefmt * | ||
907 | __ov5645_get_pad_format(struct ov5645 *ov5645, | ||
908 | struct v4l2_subdev_pad_config *cfg, | ||
909 | unsigned int pad, | ||
910 | enum v4l2_subdev_format_whence which) | ||
911 | { | ||
912 | switch (which) { | ||
913 | case V4L2_SUBDEV_FORMAT_TRY: | ||
914 | return v4l2_subdev_get_try_format(&ov5645->sd, cfg, pad); | ||
915 | case V4L2_SUBDEV_FORMAT_ACTIVE: | ||
916 | return &ov5645->fmt; | ||
917 | default: | ||
918 | return NULL; | ||
919 | } | ||
920 | } | ||
921 | |||
922 | static int ov5645_get_format(struct v4l2_subdev *sd, | ||
923 | struct v4l2_subdev_pad_config *cfg, | ||
924 | struct v4l2_subdev_format *format) | ||
925 | { | ||
926 | struct ov5645 *ov5645 = to_ov5645(sd); | ||
927 | |||
928 | format->format = *__ov5645_get_pad_format(ov5645, cfg, format->pad, | ||
929 | format->which); | ||
930 | return 0; | ||
931 | } | ||
932 | |||
933 | static struct v4l2_rect * | ||
934 | __ov5645_get_pad_crop(struct ov5645 *ov5645, struct v4l2_subdev_pad_config *cfg, | ||
935 | unsigned int pad, enum v4l2_subdev_format_whence which) | ||
936 | { | ||
937 | switch (which) { | ||
938 | case V4L2_SUBDEV_FORMAT_TRY: | ||
939 | return v4l2_subdev_get_try_crop(&ov5645->sd, cfg, pad); | ||
940 | case V4L2_SUBDEV_FORMAT_ACTIVE: | ||
941 | return &ov5645->crop; | ||
942 | default: | ||
943 | return NULL; | ||
944 | } | ||
945 | } | ||
946 | |||
947 | static const struct ov5645_mode_info * | ||
948 | ov5645_find_nearest_mode(unsigned int width, unsigned int height) | ||
949 | { | ||
950 | int i; | ||
951 | |||
952 | for (i = ARRAY_SIZE(ov5645_mode_info_data) - 1; i >= 0; i--) { | ||
953 | if (ov5645_mode_info_data[i].width <= width && | ||
954 | ov5645_mode_info_data[i].height <= height) | ||
955 | break; | ||
956 | } | ||
957 | |||
958 | if (i < 0) | ||
959 | i = 0; | ||
960 | |||
961 | return &ov5645_mode_info_data[i]; | ||
962 | } | ||
963 | |||
964 | static int ov5645_set_format(struct v4l2_subdev *sd, | ||
965 | struct v4l2_subdev_pad_config *cfg, | ||
966 | struct v4l2_subdev_format *format) | ||
967 | { | ||
968 | struct ov5645 *ov5645 = to_ov5645(sd); | ||
969 | struct v4l2_mbus_framefmt *__format; | ||
970 | struct v4l2_rect *__crop; | ||
971 | const struct ov5645_mode_info *new_mode; | ||
972 | |||
973 | __crop = __ov5645_get_pad_crop(ov5645, cfg, format->pad, | ||
974 | format->which); | ||
975 | |||
976 | new_mode = ov5645_find_nearest_mode(format->format.width, | ||
977 | format->format.height); | ||
978 | __crop->width = new_mode->width; | ||
979 | __crop->height = new_mode->height; | ||
980 | |||
981 | if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) | ||
982 | ov5645->current_mode = new_mode; | ||
983 | |||
984 | __format = __ov5645_get_pad_format(ov5645, cfg, format->pad, | ||
985 | format->which); | ||
986 | __format->width = __crop->width; | ||
987 | __format->height = __crop->height; | ||
988 | __format->code = MEDIA_BUS_FMT_UYVY8_2X8; | ||
989 | __format->field = V4L2_FIELD_NONE; | ||
990 | __format->colorspace = V4L2_COLORSPACE_SRGB; | ||
991 | |||
992 | format->format = *__format; | ||
993 | |||
994 | return 0; | ||
995 | } | ||
996 | |||
997 | static int ov5645_entity_init_cfg(struct v4l2_subdev *subdev, | ||
998 | struct v4l2_subdev_pad_config *cfg) | ||
999 | { | ||
1000 | struct v4l2_subdev_format fmt = { 0 }; | ||
1001 | |||
1002 | fmt.which = cfg ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; | ||
1003 | fmt.format.width = 1920; | ||
1004 | fmt.format.height = 1080; | ||
1005 | |||
1006 | ov5645_set_format(subdev, cfg, &fmt); | ||
1007 | |||
1008 | return 0; | ||
1009 | } | ||
1010 | |||
1011 | static int ov5645_get_selection(struct v4l2_subdev *sd, | ||
1012 | struct v4l2_subdev_pad_config *cfg, | ||
1013 | struct v4l2_subdev_selection *sel) | ||
1014 | { | ||
1015 | struct ov5645 *ov5645 = to_ov5645(sd); | ||
1016 | |||
1017 | if (sel->target != V4L2_SEL_TGT_CROP) | ||
1018 | return -EINVAL; | ||
1019 | |||
1020 | sel->r = *__ov5645_get_pad_crop(ov5645, cfg, sel->pad, | ||
1021 | sel->which); | ||
1022 | return 0; | ||
1023 | } | ||
1024 | |||
1025 | static int ov5645_s_stream(struct v4l2_subdev *subdev, int enable) | ||
1026 | { | ||
1027 | struct ov5645 *ov5645 = to_ov5645(subdev); | ||
1028 | int ret; | ||
1029 | |||
1030 | if (enable) { | ||
1031 | ret = ov5645_set_register_array(ov5645, | ||
1032 | ov5645->current_mode->data, | ||
1033 | ov5645->current_mode->data_size); | ||
1034 | if (ret < 0) { | ||
1035 | dev_err(ov5645->dev, "could not set mode %dx%d\n", | ||
1036 | ov5645->current_mode->width, | ||
1037 | ov5645->current_mode->height); | ||
1038 | return ret; | ||
1039 | } | ||
1040 | ret = v4l2_ctrl_handler_setup(&ov5645->ctrls); | ||
1041 | if (ret < 0) { | ||
1042 | dev_err(ov5645->dev, "could not sync v4l2 controls\n"); | ||
1043 | return ret; | ||
1044 | } | ||
1045 | ret = ov5645_write_reg(ov5645, OV5645_SYSTEM_CTRL0, | ||
1046 | OV5645_SYSTEM_CTRL0_START); | ||
1047 | if (ret < 0) | ||
1048 | return ret; | ||
1049 | } else { | ||
1050 | ret = ov5645_write_reg(ov5645, OV5645_SYSTEM_CTRL0, | ||
1051 | OV5645_SYSTEM_CTRL0_STOP); | ||
1052 | if (ret < 0) | ||
1053 | return ret; | ||
1054 | } | ||
1055 | |||
1056 | return 0; | ||
1057 | } | ||
1058 | |||
1059 | static const struct v4l2_subdev_core_ops ov5645_core_ops = { | ||
1060 | .s_power = ov5645_s_power, | ||
1061 | }; | ||
1062 | |||
1063 | static const struct v4l2_subdev_video_ops ov5645_video_ops = { | ||
1064 | .s_stream = ov5645_s_stream, | ||
1065 | }; | ||
1066 | |||
1067 | static const struct v4l2_subdev_pad_ops ov5645_subdev_pad_ops = { | ||
1068 | .init_cfg = ov5645_entity_init_cfg, | ||
1069 | .enum_mbus_code = ov5645_enum_mbus_code, | ||
1070 | .enum_frame_size = ov5645_enum_frame_size, | ||
1071 | .get_fmt = ov5645_get_format, | ||
1072 | .set_fmt = ov5645_set_format, | ||
1073 | .get_selection = ov5645_get_selection, | ||
1074 | }; | ||
1075 | |||
1076 | static const struct v4l2_subdev_ops ov5645_subdev_ops = { | ||
1077 | .core = &ov5645_core_ops, | ||
1078 | .video = &ov5645_video_ops, | ||
1079 | .pad = &ov5645_subdev_pad_ops, | ||
1080 | }; | ||
1081 | |||
1082 | static int ov5645_probe(struct i2c_client *client, | ||
1083 | const struct i2c_device_id *id) | ||
1084 | { | ||
1085 | struct device *dev = &client->dev; | ||
1086 | struct device_node *endpoint; | ||
1087 | struct ov5645 *ov5645; | ||
1088 | u8 chip_id_high, chip_id_low; | ||
1089 | u32 xclk_freq; | ||
1090 | int ret; | ||
1091 | |||
1092 | ov5645 = devm_kzalloc(dev, sizeof(struct ov5645), GFP_KERNEL); | ||
1093 | if (!ov5645) | ||
1094 | return -ENOMEM; | ||
1095 | |||
1096 | ov5645->i2c_client = client; | ||
1097 | ov5645->dev = dev; | ||
1098 | |||
1099 | endpoint = of_graph_get_next_endpoint(dev->of_node, NULL); | ||
1100 | if (!endpoint) { | ||
1101 | dev_err(dev, "endpoint node not found\n"); | ||
1102 | return -EINVAL; | ||
1103 | } | ||
1104 | |||
1105 | ret = v4l2_of_parse_endpoint(endpoint, &ov5645->ep); | ||
1106 | if (ret < 0) { | ||
1107 | dev_err(dev, "parsing endpoint node failed\n"); | ||
1108 | return ret; | ||
1109 | } | ||
1110 | |||
1111 | of_node_put(endpoint); | ||
1112 | |||
1113 | if (ov5645->ep.bus_type != V4L2_MBUS_CSI2) { | ||
1114 | dev_err(dev, "invalid bus type, must be CSI2\n"); | ||
1115 | return -EINVAL; | ||
1116 | } | ||
1117 | |||
1118 | /* get system clock (xclk) */ | ||
1119 | ov5645->xclk = devm_clk_get(dev, "xclk"); | ||
1120 | if (IS_ERR(ov5645->xclk)) { | ||
1121 | dev_err(dev, "could not get xclk"); | ||
1122 | return PTR_ERR(ov5645->xclk); | ||
1123 | } | ||
1124 | |||
1125 | ret = of_property_read_u32(dev->of_node, "clock-frequency", &xclk_freq); | ||
1126 | if (ret) { | ||
1127 | dev_err(dev, "could not get xclk frequency\n"); | ||
1128 | return ret; | ||
1129 | } | ||
1130 | |||
1131 | if (xclk_freq != 23880000) { | ||
1132 | dev_err(dev, "external clock frequency %u is not supported\n", | ||
1133 | xclk_freq); | ||
1134 | return -EINVAL; | ||
1135 | } | ||
1136 | |||
1137 | ret = clk_set_rate(ov5645->xclk, xclk_freq); | ||
1138 | if (ret) { | ||
1139 | dev_err(dev, "could not set xclk frequency\n"); | ||
1140 | return ret; | ||
1141 | } | ||
1142 | |||
1143 | ov5645->io_regulator = devm_regulator_get(dev, "vdddo"); | ||
1144 | if (IS_ERR(ov5645->io_regulator)) { | ||
1145 | dev_err(dev, "cannot get io regulator\n"); | ||
1146 | return PTR_ERR(ov5645->io_regulator); | ||
1147 | } | ||
1148 | |||
1149 | ret = regulator_set_voltage(ov5645->io_regulator, | ||
1150 | OV5645_VOLTAGE_DIGITAL_IO, | ||
1151 | OV5645_VOLTAGE_DIGITAL_IO); | ||
1152 | if (ret < 0) { | ||
1153 | dev_err(dev, "cannot set io voltage\n"); | ||
1154 | return ret; | ||
1155 | } | ||
1156 | |||
1157 | ov5645->core_regulator = devm_regulator_get(dev, "vddd"); | ||
1158 | if (IS_ERR(ov5645->core_regulator)) { | ||
1159 | dev_err(dev, "cannot get core regulator\n"); | ||
1160 | return PTR_ERR(ov5645->core_regulator); | ||
1161 | } | ||
1162 | |||
1163 | ret = regulator_set_voltage(ov5645->core_regulator, | ||
1164 | OV5645_VOLTAGE_DIGITAL_CORE, | ||
1165 | OV5645_VOLTAGE_DIGITAL_CORE); | ||
1166 | if (ret < 0) { | ||
1167 | dev_err(dev, "cannot set core voltage\n"); | ||
1168 | return ret; | ||
1169 | } | ||
1170 | |||
1171 | ov5645->analog_regulator = devm_regulator_get(dev, "vdda"); | ||
1172 | if (IS_ERR(ov5645->analog_regulator)) { | ||
1173 | dev_err(dev, "cannot get analog regulator\n"); | ||
1174 | return PTR_ERR(ov5645->analog_regulator); | ||
1175 | } | ||
1176 | |||
1177 | ret = regulator_set_voltage(ov5645->analog_regulator, | ||
1178 | OV5645_VOLTAGE_ANALOG, | ||
1179 | OV5645_VOLTAGE_ANALOG); | ||
1180 | if (ret < 0) { | ||
1181 | dev_err(dev, "cannot set analog voltage\n"); | ||
1182 | return ret; | ||
1183 | } | ||
1184 | |||
1185 | ov5645->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH); | ||
1186 | if (IS_ERR(ov5645->enable_gpio)) { | ||
1187 | dev_err(dev, "cannot get enable gpio\n"); | ||
1188 | return PTR_ERR(ov5645->enable_gpio); | ||
1189 | } | ||
1190 | |||
1191 | ov5645->rst_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); | ||
1192 | if (IS_ERR(ov5645->rst_gpio)) { | ||
1193 | dev_err(dev, "cannot get reset gpio\n"); | ||
1194 | return PTR_ERR(ov5645->rst_gpio); | ||
1195 | } | ||
1196 | |||
1197 | mutex_init(&ov5645->power_lock); | ||
1198 | |||
1199 | v4l2_ctrl_handler_init(&ov5645->ctrls, 7); | ||
1200 | v4l2_ctrl_new_std(&ov5645->ctrls, &ov5645_ctrl_ops, | ||
1201 | V4L2_CID_SATURATION, -4, 4, 1, 0); | ||
1202 | v4l2_ctrl_new_std(&ov5645->ctrls, &ov5645_ctrl_ops, | ||
1203 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
1204 | v4l2_ctrl_new_std(&ov5645->ctrls, &ov5645_ctrl_ops, | ||
1205 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
1206 | v4l2_ctrl_new_std(&ov5645->ctrls, &ov5645_ctrl_ops, | ||
1207 | V4L2_CID_AUTOGAIN, 0, 1, 1, 1); | ||
1208 | v4l2_ctrl_new_std(&ov5645->ctrls, &ov5645_ctrl_ops, | ||
1209 | V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); | ||
1210 | v4l2_ctrl_new_std_menu(&ov5645->ctrls, &ov5645_ctrl_ops, | ||
1211 | V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL, | ||
1212 | 0, V4L2_EXPOSURE_AUTO); | ||
1213 | v4l2_ctrl_new_std_menu_items(&ov5645->ctrls, &ov5645_ctrl_ops, | ||
1214 | V4L2_CID_TEST_PATTERN, | ||
1215 | ARRAY_SIZE(ov5645_test_pattern_menu) - 1, | ||
1216 | 0, 0, ov5645_test_pattern_menu); | ||
1217 | |||
1218 | ov5645->sd.ctrl_handler = &ov5645->ctrls; | ||
1219 | |||
1220 | if (ov5645->ctrls.error) { | ||
1221 | dev_err(dev, "%s: control initialization error %d\n", | ||
1222 | __func__, ov5645->ctrls.error); | ||
1223 | ret = ov5645->ctrls.error; | ||
1224 | goto free_ctrl; | ||
1225 | } | ||
1226 | |||
1227 | v4l2_i2c_subdev_init(&ov5645->sd, client, &ov5645_subdev_ops); | ||
1228 | ov5645->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
1229 | ov5645->pad.flags = MEDIA_PAD_FL_SOURCE; | ||
1230 | ov5645->sd.dev = &client->dev; | ||
1231 | |||
1232 | ret = media_entity_pads_init(&ov5645->sd.entity, 1, &ov5645->pad); | ||
1233 | if (ret < 0) { | ||
1234 | dev_err(dev, "could not register media entity\n"); | ||
1235 | goto free_ctrl; | ||
1236 | } | ||
1237 | |||
1238 | ret = ov5645_s_power(&ov5645->sd, true); | ||
1239 | if (ret < 0) { | ||
1240 | dev_err(dev, "could not power up OV5645\n"); | ||
1241 | goto free_entity; | ||
1242 | } | ||
1243 | |||
1244 | ret = ov5645_read_reg(ov5645, OV5645_CHIP_ID_HIGH, &chip_id_high); | ||
1245 | if (ret < 0 || chip_id_high != OV5645_CHIP_ID_HIGH_BYTE) { | ||
1246 | dev_err(dev, "could not read ID high\n"); | ||
1247 | ret = -ENODEV; | ||
1248 | goto power_down; | ||
1249 | } | ||
1250 | ret = ov5645_read_reg(ov5645, OV5645_CHIP_ID_LOW, &chip_id_low); | ||
1251 | if (ret < 0 || chip_id_low != OV5645_CHIP_ID_LOW_BYTE) { | ||
1252 | dev_err(dev, "could not read ID low\n"); | ||
1253 | ret = -ENODEV; | ||
1254 | goto power_down; | ||
1255 | } | ||
1256 | |||
1257 | dev_info(dev, "OV5645 detected at address 0x%02x\n", client->addr); | ||
1258 | |||
1259 | ret = ov5645_read_reg(ov5645, OV5645_AEC_PK_MANUAL, | ||
1260 | &ov5645->aec_pk_manual); | ||
1261 | if (ret < 0) { | ||
1262 | dev_err(dev, "could not read AEC/AGC mode\n"); | ||
1263 | ret = -ENODEV; | ||
1264 | goto power_down; | ||
1265 | } | ||
1266 | |||
1267 | ret = ov5645_read_reg(ov5645, OV5645_TIMING_TC_REG20, | ||
1268 | &ov5645->timing_tc_reg20); | ||
1269 | if (ret < 0) { | ||
1270 | dev_err(dev, "could not read vflip value\n"); | ||
1271 | ret = -ENODEV; | ||
1272 | goto power_down; | ||
1273 | } | ||
1274 | |||
1275 | ret = ov5645_read_reg(ov5645, OV5645_TIMING_TC_REG21, | ||
1276 | &ov5645->timing_tc_reg21); | ||
1277 | if (ret < 0) { | ||
1278 | dev_err(dev, "could not read hflip value\n"); | ||
1279 | ret = -ENODEV; | ||
1280 | goto power_down; | ||
1281 | } | ||
1282 | |||
1283 | ov5645_s_power(&ov5645->sd, false); | ||
1284 | |||
1285 | ret = v4l2_async_register_subdev(&ov5645->sd); | ||
1286 | if (ret < 0) { | ||
1287 | dev_err(dev, "could not register v4l2 device\n"); | ||
1288 | goto free_entity; | ||
1289 | } | ||
1290 | |||
1291 | ov5645_entity_init_cfg(&ov5645->sd, NULL); | ||
1292 | |||
1293 | return 0; | ||
1294 | |||
1295 | power_down: | ||
1296 | ov5645_s_power(&ov5645->sd, false); | ||
1297 | free_entity: | ||
1298 | media_entity_cleanup(&ov5645->sd.entity); | ||
1299 | free_ctrl: | ||
1300 | v4l2_ctrl_handler_free(&ov5645->ctrls); | ||
1301 | mutex_destroy(&ov5645->power_lock); | ||
1302 | |||
1303 | return ret; | ||
1304 | } | ||
1305 | |||
1306 | static int ov5645_remove(struct i2c_client *client) | ||
1307 | { | ||
1308 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | ||
1309 | struct ov5645 *ov5645 = to_ov5645(sd); | ||
1310 | |||
1311 | v4l2_async_unregister_subdev(&ov5645->sd); | ||
1312 | media_entity_cleanup(&ov5645->sd.entity); | ||
1313 | v4l2_ctrl_handler_free(&ov5645->ctrls); | ||
1314 | mutex_destroy(&ov5645->power_lock); | ||
1315 | |||
1316 | return 0; | ||
1317 | } | ||
1318 | |||
1319 | static const struct i2c_device_id ov5645_id[] = { | ||
1320 | { "ov5645", 0 }, | ||
1321 | {} | ||
1322 | }; | ||
1323 | MODULE_DEVICE_TABLE(i2c, ov5645_id); | ||
1324 | |||
1325 | static const struct of_device_id ov5645_of_match[] = { | ||
1326 | { .compatible = "ovti,ov5645" }, | ||
1327 | { /* sentinel */ } | ||
1328 | }; | ||
1329 | MODULE_DEVICE_TABLE(of, ov5645_of_match); | ||
1330 | |||
1331 | static struct i2c_driver ov5645_i2c_driver = { | ||
1332 | .driver = { | ||
1333 | .of_match_table = of_match_ptr(ov5645_of_match), | ||
1334 | .name = "ov5645", | ||
1335 | }, | ||
1336 | .probe = ov5645_probe, | ||
1337 | .remove = ov5645_remove, | ||
1338 | .id_table = ov5645_id, | ||
1339 | }; | ||
1340 | |||
1341 | module_i2c_driver(ov5645_i2c_driver); | ||
1342 | |||
1343 | MODULE_DESCRIPTION("Omnivision OV5645 Camera Driver"); | ||
1344 | MODULE_AUTHOR("Todor Tomov <todor.tomov@linaro.org>"); | ||
1345 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c new file mode 100644 index 000000000000..f57a0b354cf6 --- /dev/null +++ b/drivers/media/i2c/ov5647.c | |||
@@ -0,0 +1,634 @@ | |||
1 | /* | ||
2 | * A V4L2 driver for OmniVision OV5647 cameras. | ||
3 | * | ||
4 | * Based on Samsung S5K6AAFX SXGA 1/6" 1.3M CMOS Image Sensor driver | ||
5 | * Copyright (C) 2011 Sylwester Nawrocki <s.nawrocki@samsung.com> | ||
6 | * | ||
7 | * Based on Omnivision OV7670 Camera Driver | ||
8 | * Copyright (C) 2006-7 Jonathan Corbet <corbet@lwn.net> | ||
9 | * | ||
10 | * Copyright (C) 2016, Synopsys, Inc. | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License as | ||
14 | * published by the Free Software Foundation version 2. | ||
15 | * | ||
16 | * This program is distributed .as is. WITHOUT ANY WARRANTY of any | ||
17 | * kind, whether express or implied; without even the implied warranty | ||
18 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | */ | ||
21 | |||
22 | #include <linux/clk.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/i2c.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/io.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/videodev2.h> | ||
30 | #include <media/v4l2-device.h> | ||
31 | #include <media/v4l2-image-sizes.h> | ||
32 | #include <media/v4l2-mediabus.h> | ||
33 | #include <media/v4l2-of.h> | ||
34 | |||
35 | #define SENSOR_NAME "ov5647" | ||
36 | |||
37 | #define OV5647_SW_RESET 0x0103 | ||
38 | #define OV5647_REG_CHIPID_H 0x300A | ||
39 | #define OV5647_REG_CHIPID_L 0x300B | ||
40 | |||
41 | #define REG_TERM 0xfffe | ||
42 | #define VAL_TERM 0xfe | ||
43 | #define REG_DLY 0xffff | ||
44 | |||
45 | #define OV5647_ROW_START 0x01 | ||
46 | #define OV5647_ROW_START_MIN 0 | ||
47 | #define OV5647_ROW_START_MAX 2004 | ||
48 | #define OV5647_ROW_START_DEF 54 | ||
49 | |||
50 | #define OV5647_COLUMN_START 0x02 | ||
51 | #define OV5647_COLUMN_START_MIN 0 | ||
52 | #define OV5647_COLUMN_START_MAX 2750 | ||
53 | #define OV5647_COLUMN_START_DEF 16 | ||
54 | |||
55 | #define OV5647_WINDOW_HEIGHT 0x03 | ||
56 | #define OV5647_WINDOW_HEIGHT_MIN 2 | ||
57 | #define OV5647_WINDOW_HEIGHT_MAX 2006 | ||
58 | #define OV5647_WINDOW_HEIGHT_DEF 1944 | ||
59 | |||
60 | #define OV5647_WINDOW_WIDTH 0x04 | ||
61 | #define OV5647_WINDOW_WIDTH_MIN 2 | ||
62 | #define OV5647_WINDOW_WIDTH_MAX 2752 | ||
63 | #define OV5647_WINDOW_WIDTH_DEF 2592 | ||
64 | |||
65 | struct regval_list { | ||
66 | u16 addr; | ||
67 | u8 data; | ||
68 | }; | ||
69 | |||
70 | struct ov5647 { | ||
71 | struct v4l2_subdev sd; | ||
72 | struct media_pad pad; | ||
73 | struct mutex lock; | ||
74 | struct v4l2_mbus_framefmt format; | ||
75 | unsigned int width; | ||
76 | unsigned int height; | ||
77 | int power_count; | ||
78 | struct clk *xclk; | ||
79 | }; | ||
80 | |||
81 | static inline struct ov5647 *to_state(struct v4l2_subdev *sd) | ||
82 | { | ||
83 | return container_of(sd, struct ov5647, sd); | ||
84 | } | ||
85 | |||
86 | static struct regval_list sensor_oe_disable_regs[] = { | ||
87 | {0x3000, 0x00}, | ||
88 | {0x3001, 0x00}, | ||
89 | {0x3002, 0x00}, | ||
90 | }; | ||
91 | |||
92 | static struct regval_list sensor_oe_enable_regs[] = { | ||
93 | {0x3000, 0x0f}, | ||
94 | {0x3001, 0xff}, | ||
95 | {0x3002, 0xe4}, | ||
96 | }; | ||
97 | |||
98 | static struct regval_list ov5647_640x480[] = { | ||
99 | {0x0100, 0x00}, | ||
100 | {0x0103, 0x01}, | ||
101 | {0x3034, 0x08}, | ||
102 | {0x3035, 0x21}, | ||
103 | {0x3036, 0x46}, | ||
104 | {0x303c, 0x11}, | ||
105 | {0x3106, 0xf5}, | ||
106 | {0x3821, 0x07}, | ||
107 | {0x3820, 0x41}, | ||
108 | {0x3827, 0xec}, | ||
109 | {0x370c, 0x0f}, | ||
110 | {0x3612, 0x59}, | ||
111 | {0x3618, 0x00}, | ||
112 | {0x5000, 0x06}, | ||
113 | {0x5001, 0x01}, | ||
114 | {0x5002, 0x41}, | ||
115 | {0x5003, 0x08}, | ||
116 | {0x5a00, 0x08}, | ||
117 | {0x3000, 0x00}, | ||
118 | {0x3001, 0x00}, | ||
119 | {0x3002, 0x00}, | ||
120 | {0x3016, 0x08}, | ||
121 | {0x3017, 0xe0}, | ||
122 | {0x3018, 0x44}, | ||
123 | {0x301c, 0xf8}, | ||
124 | {0x301d, 0xf0}, | ||
125 | {0x3a18, 0x00}, | ||
126 | {0x3a19, 0xf8}, | ||
127 | {0x3c01, 0x80}, | ||
128 | {0x3b07, 0x0c}, | ||
129 | {0x380c, 0x07}, | ||
130 | {0x380d, 0x68}, | ||
131 | {0x380e, 0x03}, | ||
132 | {0x380f, 0xd8}, | ||
133 | {0x3814, 0x31}, | ||
134 | {0x3815, 0x31}, | ||
135 | {0x3708, 0x64}, | ||
136 | {0x3709, 0x52}, | ||
137 | {0x3808, 0x02}, | ||
138 | {0x3809, 0x80}, | ||
139 | {0x380a, 0x01}, | ||
140 | {0x380b, 0xE0}, | ||
141 | {0x3801, 0x00}, | ||
142 | {0x3802, 0x00}, | ||
143 | {0x3803, 0x00}, | ||
144 | {0x3804, 0x0a}, | ||
145 | {0x3805, 0x3f}, | ||
146 | {0x3806, 0x07}, | ||
147 | {0x3807, 0xa1}, | ||
148 | {0x3811, 0x08}, | ||
149 | {0x3813, 0x02}, | ||
150 | {0x3630, 0x2e}, | ||
151 | {0x3632, 0xe2}, | ||
152 | {0x3633, 0x23}, | ||
153 | {0x3634, 0x44}, | ||
154 | {0x3636, 0x06}, | ||
155 | {0x3620, 0x64}, | ||
156 | {0x3621, 0xe0}, | ||
157 | {0x3600, 0x37}, | ||
158 | {0x3704, 0xa0}, | ||
159 | {0x3703, 0x5a}, | ||
160 | {0x3715, 0x78}, | ||
161 | {0x3717, 0x01}, | ||
162 | {0x3731, 0x02}, | ||
163 | {0x370b, 0x60}, | ||
164 | {0x3705, 0x1a}, | ||
165 | {0x3f05, 0x02}, | ||
166 | {0x3f06, 0x10}, | ||
167 | {0x3f01, 0x0a}, | ||
168 | {0x3a08, 0x01}, | ||
169 | {0x3a09, 0x27}, | ||
170 | {0x3a0a, 0x00}, | ||
171 | {0x3a0b, 0xf6}, | ||
172 | {0x3a0d, 0x04}, | ||
173 | {0x3a0e, 0x03}, | ||
174 | {0x3a0f, 0x58}, | ||
175 | {0x3a10, 0x50}, | ||
176 | {0x3a1b, 0x58}, | ||
177 | {0x3a1e, 0x50}, | ||
178 | {0x3a11, 0x60}, | ||
179 | {0x3a1f, 0x28}, | ||
180 | {0x4001, 0x02}, | ||
181 | {0x4004, 0x02}, | ||
182 | {0x4000, 0x09}, | ||
183 | {0x4837, 0x24}, | ||
184 | {0x4050, 0x6e}, | ||
185 | {0x4051, 0x8f}, | ||
186 | {0x0100, 0x01}, | ||
187 | }; | ||
188 | |||
189 | static int ov5647_write(struct v4l2_subdev *sd, u16 reg, u8 val) | ||
190 | { | ||
191 | int ret; | ||
192 | unsigned char data[3] = { reg >> 8, reg & 0xff, val}; | ||
193 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
194 | |||
195 | ret = i2c_master_send(client, data, 3); | ||
196 | if (ret < 0) | ||
197 | dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n", | ||
198 | __func__, reg); | ||
199 | |||
200 | return ret; | ||
201 | } | ||
202 | |||
203 | static int ov5647_read(struct v4l2_subdev *sd, u16 reg, u8 *val) | ||
204 | { | ||
205 | int ret; | ||
206 | unsigned char data_w[2] = { reg >> 8, reg & 0xff }; | ||
207 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
208 | |||
209 | ret = i2c_master_send(client, data_w, 2); | ||
210 | if (ret < 0) { | ||
211 | dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n", | ||
212 | __func__, reg); | ||
213 | return ret; | ||
214 | } | ||
215 | |||
216 | ret = i2c_master_recv(client, val, 1); | ||
217 | if (ret < 0) | ||
218 | dev_dbg(&client->dev, "%s: i2c read error, reg: %x\n", | ||
219 | __func__, reg); | ||
220 | |||
221 | return ret; | ||
222 | } | ||
223 | |||
224 | static int ov5647_write_array(struct v4l2_subdev *sd, | ||
225 | struct regval_list *regs, int array_size) | ||
226 | { | ||
227 | int i, ret; | ||
228 | |||
229 | for (i = 0; i < array_size; i++) { | ||
230 | ret = ov5647_write(sd, regs[i].addr, regs[i].data); | ||
231 | if (ret < 0) | ||
232 | return ret; | ||
233 | } | ||
234 | |||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | static int ov5647_set_virtual_channel(struct v4l2_subdev *sd, int channel) | ||
239 | { | ||
240 | u8 channel_id; | ||
241 | int ret; | ||
242 | |||
243 | ret = ov5647_read(sd, 0x4814, &channel_id); | ||
244 | if (ret < 0) | ||
245 | return ret; | ||
246 | |||
247 | channel_id &= ~(3 << 6); | ||
248 | return ov5647_write(sd, 0x4814, channel_id | (channel << 6)); | ||
249 | } | ||
250 | |||
251 | static int ov5647_stream_on(struct v4l2_subdev *sd) | ||
252 | { | ||
253 | int ret; | ||
254 | |||
255 | ret = ov5647_write(sd, 0x4202, 0x00); | ||
256 | if (ret < 0) | ||
257 | return ret; | ||
258 | |||
259 | return ov5647_write(sd, 0x300D, 0x00); | ||
260 | } | ||
261 | |||
262 | static int ov5647_stream_off(struct v4l2_subdev *sd) | ||
263 | { | ||
264 | int ret; | ||
265 | |||
266 | ret = ov5647_write(sd, 0x4202, 0x0f); | ||
267 | if (ret < 0) | ||
268 | return ret; | ||
269 | |||
270 | return ov5647_write(sd, 0x300D, 0x01); | ||
271 | } | ||
272 | |||
273 | static int set_sw_standby(struct v4l2_subdev *sd, bool standby) | ||
274 | { | ||
275 | int ret; | ||
276 | u8 rdval; | ||
277 | |||
278 | ret = ov5647_read(sd, 0x0100, &rdval); | ||
279 | if (ret < 0) | ||
280 | return ret; | ||
281 | |||
282 | if (standby) | ||
283 | rdval &= ~0x01; | ||
284 | else | ||
285 | rdval |= 0x01; | ||
286 | |||
287 | return ov5647_write(sd, 0x0100, rdval); | ||
288 | } | ||
289 | |||
290 | static int __sensor_init(struct v4l2_subdev *sd) | ||
291 | { | ||
292 | int ret; | ||
293 | u8 resetval, rdval; | ||
294 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
295 | |||
296 | ret = ov5647_read(sd, 0x0100, &rdval); | ||
297 | if (ret < 0) | ||
298 | return ret; | ||
299 | |||
300 | ret = ov5647_write_array(sd, ov5647_640x480, | ||
301 | ARRAY_SIZE(ov5647_640x480)); | ||
302 | if (ret < 0) { | ||
303 | dev_err(&client->dev, "write sensor default regs error\n"); | ||
304 | return ret; | ||
305 | } | ||
306 | |||
307 | ret = ov5647_set_virtual_channel(sd, 0); | ||
308 | if (ret < 0) | ||
309 | return ret; | ||
310 | |||
311 | ret = ov5647_read(sd, 0x0100, &resetval); | ||
312 | if (ret < 0) | ||
313 | return ret; | ||
314 | |||
315 | if (!(resetval & 0x01)) { | ||
316 | dev_err(&client->dev, "Device was in SW standby"); | ||
317 | ret = ov5647_write(sd, 0x0100, 0x01); | ||
318 | if (ret < 0) | ||
319 | return ret; | ||
320 | } | ||
321 | |||
322 | return ov5647_write(sd, 0x4800, 0x04); | ||
323 | } | ||
324 | |||
325 | static int ov5647_sensor_power(struct v4l2_subdev *sd, int on) | ||
326 | { | ||
327 | int ret = 0; | ||
328 | struct ov5647 *ov5647 = to_state(sd); | ||
329 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
330 | |||
331 | mutex_lock(&ov5647->lock); | ||
332 | |||
333 | if (on && !ov5647->power_count) { | ||
334 | dev_dbg(&client->dev, "OV5647 power on\n"); | ||
335 | |||
336 | ret = clk_prepare_enable(ov5647->xclk); | ||
337 | if (ret < 0) { | ||
338 | dev_err(&client->dev, "clk prepare enable failed\n"); | ||
339 | goto out; | ||
340 | } | ||
341 | |||
342 | ret = ov5647_write_array(sd, sensor_oe_enable_regs, | ||
343 | ARRAY_SIZE(sensor_oe_enable_regs)); | ||
344 | if (ret < 0) { | ||
345 | clk_disable_unprepare(ov5647->xclk); | ||
346 | dev_err(&client->dev, | ||
347 | "write sensor_oe_enable_regs error\n"); | ||
348 | goto out; | ||
349 | } | ||
350 | |||
351 | ret = __sensor_init(sd); | ||
352 | if (ret < 0) { | ||
353 | clk_disable_unprepare(ov5647->xclk); | ||
354 | dev_err(&client->dev, | ||
355 | "Camera not available, check Power\n"); | ||
356 | goto out; | ||
357 | } | ||
358 | } else if (!on && ov5647->power_count == 1) { | ||
359 | dev_dbg(&client->dev, "OV5647 power off\n"); | ||
360 | |||
361 | ret = ov5647_write_array(sd, sensor_oe_disable_regs, | ||
362 | ARRAY_SIZE(sensor_oe_disable_regs)); | ||
363 | |||
364 | if (ret < 0) | ||
365 | dev_dbg(&client->dev, "disable oe failed\n"); | ||
366 | |||
367 | ret = set_sw_standby(sd, true); | ||
368 | |||
369 | if (ret < 0) | ||
370 | dev_dbg(&client->dev, "soft stby failed\n"); | ||
371 | |||
372 | clk_disable_unprepare(ov5647->xclk); | ||
373 | } | ||
374 | |||
375 | /* Update the power count. */ | ||
376 | ov5647->power_count += on ? 1 : -1; | ||
377 | WARN_ON(ov5647->power_count < 0); | ||
378 | |||
379 | out: | ||
380 | mutex_unlock(&ov5647->lock); | ||
381 | |||
382 | return ret; | ||
383 | } | ||
384 | |||
385 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
386 | static int ov5647_sensor_get_register(struct v4l2_subdev *sd, | ||
387 | struct v4l2_dbg_register *reg) | ||
388 | { | ||
389 | u8 val; | ||
390 | int ret; | ||
391 | |||
392 | ret = ov5647_read(sd, reg->reg & 0xff, &val); | ||
393 | if (ret < 0) | ||
394 | return ret; | ||
395 | |||
396 | reg->val = val; | ||
397 | reg->size = 1; | ||
398 | |||
399 | return 0; | ||
400 | } | ||
401 | |||
402 | static int ov5647_sensor_set_register(struct v4l2_subdev *sd, | ||
403 | const struct v4l2_dbg_register *reg) | ||
404 | { | ||
405 | return ov5647_write(sd, reg->reg & 0xff, reg->val & 0xff); | ||
406 | } | ||
407 | #endif | ||
408 | |||
409 | /** | ||
410 | * @short Subdev core operations registration | ||
411 | */ | ||
412 | static const struct v4l2_subdev_core_ops ov5647_subdev_core_ops = { | ||
413 | .s_power = ov5647_sensor_power, | ||
414 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
415 | .g_register = ov5647_sensor_get_register, | ||
416 | .s_register = ov5647_sensor_set_register, | ||
417 | #endif | ||
418 | }; | ||
419 | |||
420 | static int ov5647_s_stream(struct v4l2_subdev *sd, int enable) | ||
421 | { | ||
422 | if (enable) | ||
423 | return ov5647_stream_on(sd); | ||
424 | else | ||
425 | return ov5647_stream_off(sd); | ||
426 | } | ||
427 | |||
428 | static const struct v4l2_subdev_video_ops ov5647_subdev_video_ops = { | ||
429 | .s_stream = ov5647_s_stream, | ||
430 | }; | ||
431 | |||
432 | static int ov5647_enum_mbus_code(struct v4l2_subdev *sd, | ||
433 | struct v4l2_subdev_pad_config *cfg, | ||
434 | struct v4l2_subdev_mbus_code_enum *code) | ||
435 | { | ||
436 | if (code->index > 0) | ||
437 | return -EINVAL; | ||
438 | |||
439 | code->code = MEDIA_BUS_FMT_SBGGR8_1X8; | ||
440 | |||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | static const struct v4l2_subdev_pad_ops ov5647_subdev_pad_ops = { | ||
445 | .enum_mbus_code = ov5647_enum_mbus_code, | ||
446 | }; | ||
447 | |||
448 | static const struct v4l2_subdev_ops ov5647_subdev_ops = { | ||
449 | .core = &ov5647_subdev_core_ops, | ||
450 | .video = &ov5647_subdev_video_ops, | ||
451 | .pad = &ov5647_subdev_pad_ops, | ||
452 | }; | ||
453 | |||
454 | static int ov5647_detect(struct v4l2_subdev *sd) | ||
455 | { | ||
456 | u8 read; | ||
457 | int ret; | ||
458 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
459 | |||
460 | ret = ov5647_write(sd, OV5647_SW_RESET, 0x01); | ||
461 | if (ret < 0) | ||
462 | return ret; | ||
463 | |||
464 | ret = ov5647_read(sd, OV5647_REG_CHIPID_H, &read); | ||
465 | if (ret < 0) | ||
466 | return ret; | ||
467 | |||
468 | if (read != 0x56) { | ||
469 | dev_err(&client->dev, "ID High expected 0x56 got %x", read); | ||
470 | return -ENODEV; | ||
471 | } | ||
472 | |||
473 | ret = ov5647_read(sd, OV5647_REG_CHIPID_L, &read); | ||
474 | if (ret < 0) | ||
475 | return ret; | ||
476 | |||
477 | if (read != 0x47) { | ||
478 | dev_err(&client->dev, "ID Low expected 0x47 got %x", read); | ||
479 | return -ENODEV; | ||
480 | } | ||
481 | |||
482 | return ov5647_write(sd, OV5647_SW_RESET, 0x00); | ||
483 | } | ||
484 | |||
485 | static int ov5647_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | ||
486 | { | ||
487 | struct v4l2_mbus_framefmt *format = | ||
488 | v4l2_subdev_get_try_format(sd, fh->pad, 0); | ||
489 | struct v4l2_rect *crop = | ||
490 | v4l2_subdev_get_try_crop(sd, fh->pad, 0); | ||
491 | |||
492 | crop->left = OV5647_COLUMN_START_DEF; | ||
493 | crop->top = OV5647_ROW_START_DEF; | ||
494 | crop->width = OV5647_WINDOW_WIDTH_DEF; | ||
495 | crop->height = OV5647_WINDOW_HEIGHT_DEF; | ||
496 | |||
497 | format->code = MEDIA_BUS_FMT_SBGGR8_1X8; | ||
498 | |||
499 | format->width = OV5647_WINDOW_WIDTH_DEF; | ||
500 | format->height = OV5647_WINDOW_HEIGHT_DEF; | ||
501 | format->field = V4L2_FIELD_NONE; | ||
502 | format->colorspace = V4L2_COLORSPACE_SRGB; | ||
503 | |||
504 | return 0; | ||
505 | } | ||
506 | |||
507 | static const struct v4l2_subdev_internal_ops ov5647_subdev_internal_ops = { | ||
508 | .open = ov5647_open, | ||
509 | }; | ||
510 | |||
511 | static int ov5647_parse_dt(struct device_node *np) | ||
512 | { | ||
513 | struct v4l2_of_endpoint bus_cfg; | ||
514 | struct device_node *ep; | ||
515 | |||
516 | int ret; | ||
517 | |||
518 | ep = of_graph_get_next_endpoint(np, NULL); | ||
519 | if (!ep) | ||
520 | return -EINVAL; | ||
521 | |||
522 | ret = v4l2_of_parse_endpoint(ep, &bus_cfg); | ||
523 | |||
524 | of_node_put(ep); | ||
525 | return ret; | ||
526 | } | ||
527 | |||
528 | static int ov5647_probe(struct i2c_client *client, | ||
529 | const struct i2c_device_id *id) | ||
530 | { | ||
531 | struct device *dev = &client->dev; | ||
532 | struct ov5647 *sensor; | ||
533 | int ret; | ||
534 | struct v4l2_subdev *sd; | ||
535 | struct device_node *np = client->dev.of_node; | ||
536 | u32 xclk_freq; | ||
537 | |||
538 | sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); | ||
539 | if (!sensor) | ||
540 | return -ENOMEM; | ||
541 | |||
542 | if (IS_ENABLED(CONFIG_OF) && np) { | ||
543 | ret = ov5647_parse_dt(np); | ||
544 | if (ret) { | ||
545 | dev_err(dev, "DT parsing error: %d\n", ret); | ||
546 | return ret; | ||
547 | } | ||
548 | } | ||
549 | |||
550 | /* get system clock (xclk) */ | ||
551 | sensor->xclk = devm_clk_get(dev, NULL); | ||
552 | if (IS_ERR(sensor->xclk)) { | ||
553 | dev_err(dev, "could not get xclk"); | ||
554 | return PTR_ERR(sensor->xclk); | ||
555 | } | ||
556 | |||
557 | xclk_freq = clk_get_rate(sensor->xclk); | ||
558 | if (xclk_freq != 25000000) { | ||
559 | dev_err(dev, "Unsupported clock frequency: %u\n", xclk_freq); | ||
560 | return -EINVAL; | ||
561 | } | ||
562 | |||
563 | mutex_init(&sensor->lock); | ||
564 | |||
565 | sd = &sensor->sd; | ||
566 | v4l2_i2c_subdev_init(sd, client, &ov5647_subdev_ops); | ||
567 | sensor->sd.internal_ops = &ov5647_subdev_internal_ops; | ||
568 | sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
569 | |||
570 | sensor->pad.flags = MEDIA_PAD_FL_SOURCE; | ||
571 | sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; | ||
572 | ret = media_entity_pads_init(&sd->entity, 1, &sensor->pad); | ||
573 | if (ret < 0) | ||
574 | goto mutex_remove; | ||
575 | |||
576 | ret = ov5647_detect(sd); | ||
577 | if (ret < 0) | ||
578 | goto error; | ||
579 | |||
580 | ret = v4l2_async_register_subdev(sd); | ||
581 | if (ret < 0) | ||
582 | goto error; | ||
583 | |||
584 | dev_dbg(dev, "OmniVision OV5647 camera driver probed\n"); | ||
585 | return 0; | ||
586 | error: | ||
587 | media_entity_cleanup(&sd->entity); | ||
588 | mutex_remove: | ||
589 | mutex_destroy(&sensor->lock); | ||
590 | return ret; | ||
591 | } | ||
592 | |||
593 | static int ov5647_remove(struct i2c_client *client) | ||
594 | { | ||
595 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | ||
596 | struct ov5647 *ov5647 = to_state(sd); | ||
597 | |||
598 | v4l2_async_unregister_subdev(&ov5647->sd); | ||
599 | media_entity_cleanup(&ov5647->sd.entity); | ||
600 | v4l2_device_unregister_subdev(sd); | ||
601 | mutex_destroy(&ov5647->lock); | ||
602 | |||
603 | return 0; | ||
604 | } | ||
605 | |||
606 | static const struct i2c_device_id ov5647_id[] = { | ||
607 | { "ov5647", 0 }, | ||
608 | { } | ||
609 | }; | ||
610 | MODULE_DEVICE_TABLE(i2c, ov5647_id); | ||
611 | |||
612 | #if IS_ENABLED(CONFIG_OF) | ||
613 | static const struct of_device_id ov5647_of_match[] = { | ||
614 | { .compatible = "ovti,ov5647" }, | ||
615 | { /* sentinel */ }, | ||
616 | }; | ||
617 | MODULE_DEVICE_TABLE(of, ov5647_of_match); | ||
618 | #endif | ||
619 | |||
620 | static struct i2c_driver ov5647_driver = { | ||
621 | .driver = { | ||
622 | .of_match_table = of_match_ptr(ov5647_of_match), | ||
623 | .name = SENSOR_NAME, | ||
624 | }, | ||
625 | .probe = ov5647_probe, | ||
626 | .remove = ov5647_remove, | ||
627 | .id_table = ov5647_id, | ||
628 | }; | ||
629 | |||
630 | module_i2c_driver(ov5647_driver); | ||
631 | |||
632 | MODULE_AUTHOR("Ramiro Oliveira <roliveir@synopsys.com>"); | ||
633 | MODULE_DESCRIPTION("A low-level driver for OmniVision ov5647 sensors"); | ||
634 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index 56cfb5ca9c95..7270c68ed18a 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c | |||
@@ -10,12 +10,15 @@ | |||
10 | * This file may be distributed under the terms of the GNU General | 10 | * This file may be distributed under the terms of the GNU General |
11 | * Public License, version 2. | 11 | * Public License, version 2. |
12 | */ | 12 | */ |
13 | #include <linux/clk.h> | ||
13 | #include <linux/init.h> | 14 | #include <linux/init.h> |
14 | #include <linux/module.h> | 15 | #include <linux/module.h> |
15 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
16 | #include <linux/i2c.h> | 17 | #include <linux/i2c.h> |
17 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
18 | #include <linux/videodev2.h> | 19 | #include <linux/videodev2.h> |
20 | #include <linux/gpio.h> | ||
21 | #include <linux/gpio/consumer.h> | ||
19 | #include <media/v4l2-device.h> | 22 | #include <media/v4l2-device.h> |
20 | #include <media/v4l2-ctrls.h> | 23 | #include <media/v4l2-ctrls.h> |
21 | #include <media/v4l2-mediabus.h> | 24 | #include <media/v4l2-mediabus.h> |
@@ -227,6 +230,9 @@ struct ov7670_info { | |||
227 | struct v4l2_ctrl *hue; | 230 | struct v4l2_ctrl *hue; |
228 | }; | 231 | }; |
229 | struct ov7670_format_struct *fmt; /* Current format */ | 232 | struct ov7670_format_struct *fmt; /* Current format */ |
233 | struct clk *clk; | ||
234 | struct gpio_desc *resetb_gpio; | ||
235 | struct gpio_desc *pwdn_gpio; | ||
230 | int min_width; /* Filter out smaller sizes */ | 236 | int min_width; /* Filter out smaller sizes */ |
231 | int min_height; /* Filter out smaller sizes */ | 237 | int min_height; /* Filter out smaller sizes */ |
232 | int clock_speed; /* External clock speed (MHz) */ | 238 | int clock_speed; /* External clock speed (MHz) */ |
@@ -589,8 +595,6 @@ static int ov7670_init(struct v4l2_subdev *sd, u32 val) | |||
589 | return ov7670_write_array(sd, ov7670_default_regs); | 595 | return ov7670_write_array(sd, ov7670_default_regs); |
590 | } | 596 | } |
591 | 597 | ||
592 | |||
593 | |||
594 | static int ov7670_detect(struct v4l2_subdev *sd) | 598 | static int ov7670_detect(struct v4l2_subdev *sd) |
595 | { | 599 | { |
596 | unsigned char v; | 600 | unsigned char v; |
@@ -1046,7 +1050,6 @@ static int ov7670_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) | |||
1046 | if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 1050 | if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1047 | return -EINVAL; | 1051 | return -EINVAL; |
1048 | 1052 | ||
1049 | memset(cp, 0, sizeof(struct v4l2_captureparm)); | ||
1050 | cp->capability = V4L2_CAP_TIMEPERFRAME; | 1053 | cp->capability = V4L2_CAP_TIMEPERFRAME; |
1051 | info->devtype->get_framerate(sd, &cp->timeperframe); | 1054 | info->devtype->get_framerate(sd, &cp->timeperframe); |
1052 | 1055 | ||
@@ -1061,9 +1064,8 @@ static int ov7670_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) | |||
1061 | 1064 | ||
1062 | if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 1065 | if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1063 | return -EINVAL; | 1066 | return -EINVAL; |
1064 | if (cp->extendedmode != 0) | ||
1065 | return -EINVAL; | ||
1066 | 1067 | ||
1068 | cp->capability = V4L2_CAP_TIMEPERFRAME; | ||
1067 | return info->devtype->set_framerate(sd, tpf); | 1069 | return info->devtype->set_framerate(sd, tpf); |
1068 | } | 1070 | } |
1069 | 1071 | ||
@@ -1549,6 +1551,27 @@ static const struct ov7670_devtype ov7670_devdata[] = { | |||
1549 | }, | 1551 | }, |
1550 | }; | 1552 | }; |
1551 | 1553 | ||
1554 | static int ov7670_init_gpio(struct i2c_client *client, struct ov7670_info *info) | ||
1555 | { | ||
1556 | info->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown", | ||
1557 | GPIOD_OUT_LOW); | ||
1558 | if (IS_ERR(info->pwdn_gpio)) { | ||
1559 | dev_info(&client->dev, "can't get %s GPIO\n", "powerdown"); | ||
1560 | return PTR_ERR(info->pwdn_gpio); | ||
1561 | } | ||
1562 | |||
1563 | info->resetb_gpio = devm_gpiod_get_optional(&client->dev, "reset", | ||
1564 | GPIOD_OUT_LOW); | ||
1565 | if (IS_ERR(info->resetb_gpio)) { | ||
1566 | dev_info(&client->dev, "can't get %s GPIO\n", "reset"); | ||
1567 | return PTR_ERR(info->resetb_gpio); | ||
1568 | } | ||
1569 | |||
1570 | usleep_range(3000, 5000); | ||
1571 | |||
1572 | return 0; | ||
1573 | } | ||
1574 | |||
1552 | static int ov7670_probe(struct i2c_client *client, | 1575 | static int ov7670_probe(struct i2c_client *client, |
1553 | const struct i2c_device_id *id) | 1576 | const struct i2c_device_id *id) |
1554 | { | 1577 | { |
@@ -1589,13 +1612,28 @@ static int ov7670_probe(struct i2c_client *client, | |||
1589 | info->pclk_hb_disable = true; | 1612 | info->pclk_hb_disable = true; |
1590 | } | 1613 | } |
1591 | 1614 | ||
1615 | info->clk = devm_clk_get(&client->dev, "xclk"); | ||
1616 | if (IS_ERR(info->clk)) | ||
1617 | return -EPROBE_DEFER; | ||
1618 | clk_prepare_enable(info->clk); | ||
1619 | |||
1620 | ret = ov7670_init_gpio(client, info); | ||
1621 | if (ret) | ||
1622 | goto clk_disable; | ||
1623 | |||
1624 | info->clock_speed = clk_get_rate(info->clk) / 1000000; | ||
1625 | if (info->clock_speed < 10 || info->clock_speed > 48) { | ||
1626 | ret = -EINVAL; | ||
1627 | goto clk_disable; | ||
1628 | } | ||
1629 | |||
1592 | /* Make sure it's an ov7670 */ | 1630 | /* Make sure it's an ov7670 */ |
1593 | ret = ov7670_detect(sd); | 1631 | ret = ov7670_detect(sd); |
1594 | if (ret) { | 1632 | if (ret) { |
1595 | v4l_dbg(1, debug, client, | 1633 | v4l_dbg(1, debug, client, |
1596 | "chip found @ 0x%x (%s) is not an ov7670 chip.\n", | 1634 | "chip found @ 0x%x (%s) is not an ov7670 chip.\n", |
1597 | client->addr << 1, client->adapter->name); | 1635 | client->addr << 1, client->adapter->name); |
1598 | return ret; | 1636 | goto clk_disable; |
1599 | } | 1637 | } |
1600 | v4l_info(client, "chip found @ 0x%02x (%s)\n", | 1638 | v4l_info(client, "chip found @ 0x%02x (%s)\n", |
1601 | client->addr << 1, client->adapter->name); | 1639 | client->addr << 1, client->adapter->name); |
@@ -1636,10 +1674,9 @@ static int ov7670_probe(struct i2c_client *client, | |||
1636 | V4L2_EXPOSURE_AUTO); | 1674 | V4L2_EXPOSURE_AUTO); |
1637 | sd->ctrl_handler = &info->hdl; | 1675 | sd->ctrl_handler = &info->hdl; |
1638 | if (info->hdl.error) { | 1676 | if (info->hdl.error) { |
1639 | int err = info->hdl.error; | 1677 | ret = info->hdl.error; |
1640 | 1678 | ||
1641 | v4l2_ctrl_handler_free(&info->hdl); | 1679 | goto hdl_free; |
1642 | return err; | ||
1643 | } | 1680 | } |
1644 | /* | 1681 | /* |
1645 | * We have checked empirically that hw allows to read back the gain | 1682 | * We have checked empirically that hw allows to read back the gain |
@@ -1651,7 +1688,17 @@ static int ov7670_probe(struct i2c_client *client, | |||
1651 | v4l2_ctrl_cluster(2, &info->saturation); | 1688 | v4l2_ctrl_cluster(2, &info->saturation); |
1652 | v4l2_ctrl_handler_setup(&info->hdl); | 1689 | v4l2_ctrl_handler_setup(&info->hdl); |
1653 | 1690 | ||
1691 | ret = v4l2_async_register_subdev(&info->sd); | ||
1692 | if (ret < 0) | ||
1693 | goto hdl_free; | ||
1694 | |||
1654 | return 0; | 1695 | return 0; |
1696 | |||
1697 | hdl_free: | ||
1698 | v4l2_ctrl_handler_free(&info->hdl); | ||
1699 | clk_disable: | ||
1700 | clk_disable_unprepare(info->clk); | ||
1701 | return ret; | ||
1655 | } | 1702 | } |
1656 | 1703 | ||
1657 | 1704 | ||
@@ -1662,6 +1709,7 @@ static int ov7670_remove(struct i2c_client *client) | |||
1662 | 1709 | ||
1663 | v4l2_device_unregister_subdev(sd); | 1710 | v4l2_device_unregister_subdev(sd); |
1664 | v4l2_ctrl_handler_free(&info->hdl); | 1711 | v4l2_ctrl_handler_free(&info->hdl); |
1712 | clk_disable_unprepare(info->clk); | ||
1665 | return 0; | 1713 | return 0; |
1666 | } | 1714 | } |
1667 | 1715 | ||
@@ -1672,9 +1720,18 @@ static const struct i2c_device_id ov7670_id[] = { | |||
1672 | }; | 1720 | }; |
1673 | MODULE_DEVICE_TABLE(i2c, ov7670_id); | 1721 | MODULE_DEVICE_TABLE(i2c, ov7670_id); |
1674 | 1722 | ||
1723 | #if IS_ENABLED(CONFIG_OF) | ||
1724 | static const struct of_device_id ov7670_of_match[] = { | ||
1725 | { .compatible = "ovti,ov7670", }, | ||
1726 | { /* sentinel */ }, | ||
1727 | }; | ||
1728 | MODULE_DEVICE_TABLE(of, ov7670_of_match); | ||
1729 | #endif | ||
1730 | |||
1675 | static struct i2c_driver ov7670_driver = { | 1731 | static struct i2c_driver ov7670_driver = { |
1676 | .driver = { | 1732 | .driver = { |
1677 | .name = "ov7670", | 1733 | .name = "ov7670", |
1734 | .of_match_table = of_match_ptr(ov7670_of_match), | ||
1678 | }, | 1735 | }, |
1679 | .probe = ov7670_probe, | 1736 | .probe = ov7670_probe, |
1680 | .remove = ov7670_remove, | 1737 | .remove = ov7670_remove, |
diff --git a/drivers/media/i2c/soc_camera/Kconfig b/drivers/media/i2c/soc_camera/Kconfig index 7704bcf5cc25..96859f37cb1c 100644 --- a/drivers/media/i2c/soc_camera/Kconfig +++ b/drivers/media/i2c/soc_camera/Kconfig | |||
@@ -41,12 +41,6 @@ config SOC_CAMERA_MT9V022 | |||
41 | help | 41 | help |
42 | This driver supports MT9V022 cameras from Micron | 42 | This driver supports MT9V022 cameras from Micron |
43 | 43 | ||
44 | config SOC_CAMERA_OV2640 | ||
45 | tristate "ov2640 camera support" | ||
46 | depends on SOC_CAMERA && I2C | ||
47 | help | ||
48 | This is a ov2640 camera driver | ||
49 | |||
50 | config SOC_CAMERA_OV5642 | 44 | config SOC_CAMERA_OV5642 |
51 | tristate "ov5642 camera support" | 45 | tristate "ov5642 camera support" |
52 | depends on SOC_CAMERA && I2C | 46 | depends on SOC_CAMERA && I2C |
diff --git a/drivers/media/i2c/soc_camera/Makefile b/drivers/media/i2c/soc_camera/Makefile index 6f994f9353a0..974bdb721dbe 100644 --- a/drivers/media/i2c/soc_camera/Makefile +++ b/drivers/media/i2c/soc_camera/Makefile | |||
@@ -3,7 +3,6 @@ obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o | |||
3 | obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o | 3 | obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o |
4 | obj-$(CONFIG_SOC_CAMERA_MT9T112) += mt9t112.o | 4 | obj-$(CONFIG_SOC_CAMERA_MT9T112) += mt9t112.o |
5 | obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o | 5 | obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o |
6 | obj-$(CONFIG_SOC_CAMERA_OV2640) += ov2640.o | ||
7 | obj-$(CONFIG_SOC_CAMERA_OV5642) += ov5642.o | 6 | obj-$(CONFIG_SOC_CAMERA_OV5642) += ov5642.o |
8 | obj-$(CONFIG_SOC_CAMERA_OV6650) += ov6650.o | 7 | obj-$(CONFIG_SOC_CAMERA_OV6650) += ov6650.o |
9 | obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o | 8 | obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o |
diff --git a/drivers/media/i2c/soc_camera/imx074.c b/drivers/media/i2c/soc_camera/imx074.c index 05b55cfe8147..77f1e0243d6e 100644 --- a/drivers/media/i2c/soc_camera/imx074.c +++ b/drivers/media/i2c/soc_camera/imx074.c | |||
@@ -180,7 +180,7 @@ static int imx074_set_fmt(struct v4l2_subdev *sd, | |||
180 | mf->field = V4L2_FIELD_NONE; | 180 | mf->field = V4L2_FIELD_NONE; |
181 | 181 | ||
182 | if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) | 182 | if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) |
183 | priv->fmt = imx074_find_datafmt(mf->code); | 183 | priv->fmt = fmt; |
184 | else | 184 | else |
185 | cfg->try_fmt = *mf; | 185 | cfg->try_fmt = *mf; |
186 | 186 | ||
@@ -271,12 +271,12 @@ static int imx074_g_mbus_config(struct v4l2_subdev *sd, | |||
271 | return 0; | 271 | return 0; |
272 | } | 272 | } |
273 | 273 | ||
274 | static struct v4l2_subdev_video_ops imx074_subdev_video_ops = { | 274 | static const struct v4l2_subdev_video_ops imx074_subdev_video_ops = { |
275 | .s_stream = imx074_s_stream, | 275 | .s_stream = imx074_s_stream, |
276 | .g_mbus_config = imx074_g_mbus_config, | 276 | .g_mbus_config = imx074_g_mbus_config, |
277 | }; | 277 | }; |
278 | 278 | ||
279 | static struct v4l2_subdev_core_ops imx074_subdev_core_ops = { | 279 | static const struct v4l2_subdev_core_ops imx074_subdev_core_ops = { |
280 | .s_power = imx074_s_power, | 280 | .s_power = imx074_s_power, |
281 | }; | 281 | }; |
282 | 282 | ||
@@ -287,7 +287,7 @@ static const struct v4l2_subdev_pad_ops imx074_subdev_pad_ops = { | |||
287 | .set_fmt = imx074_set_fmt, | 287 | .set_fmt = imx074_set_fmt, |
288 | }; | 288 | }; |
289 | 289 | ||
290 | static struct v4l2_subdev_ops imx074_subdev_ops = { | 290 | static const struct v4l2_subdev_ops imx074_subdev_ops = { |
291 | .core = &imx074_subdev_core_ops, | 291 | .core = &imx074_subdev_core_ops, |
292 | .video = &imx074_subdev_video_ops, | 292 | .video = &imx074_subdev_video_ops, |
293 | .pad = &imx074_subdev_pad_ops, | 293 | .pad = &imx074_subdev_pad_ops, |
diff --git a/drivers/media/i2c/soc_camera/mt9m001.c b/drivers/media/i2c/soc_camera/mt9m001.c index 3d6378d4491c..1bfb0d53059e 100644 --- a/drivers/media/i2c/soc_camera/mt9m001.c +++ b/drivers/media/i2c/soc_camera/mt9m001.c | |||
@@ -278,6 +278,7 @@ static int mt9m001_get_fmt(struct v4l2_subdev *sd, | |||
278 | } | 278 | } |
279 | 279 | ||
280 | static int mt9m001_s_fmt(struct v4l2_subdev *sd, | 280 | static int mt9m001_s_fmt(struct v4l2_subdev *sd, |
281 | const struct mt9m001_datafmt *fmt, | ||
281 | struct v4l2_mbus_framefmt *mf) | 282 | struct v4l2_mbus_framefmt *mf) |
282 | { | 283 | { |
283 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 284 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
@@ -297,9 +298,8 @@ static int mt9m001_s_fmt(struct v4l2_subdev *sd, | |||
297 | if (!ret) { | 298 | if (!ret) { |
298 | mf->width = mt9m001->rect.width; | 299 | mf->width = mt9m001->rect.width; |
299 | mf->height = mt9m001->rect.height; | 300 | mf->height = mt9m001->rect.height; |
300 | mt9m001->fmt = mt9m001_find_datafmt(mf->code, | 301 | mt9m001->fmt = fmt; |
301 | mt9m001->fmts, mt9m001->num_fmts); | 302 | mf->colorspace = fmt->colorspace; |
302 | mf->colorspace = mt9m001->fmt->colorspace; | ||
303 | } | 303 | } |
304 | 304 | ||
305 | return ret; | 305 | return ret; |
@@ -335,7 +335,7 @@ static int mt9m001_set_fmt(struct v4l2_subdev *sd, | |||
335 | mf->colorspace = fmt->colorspace; | 335 | mf->colorspace = fmt->colorspace; |
336 | 336 | ||
337 | if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) | 337 | if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) |
338 | return mt9m001_s_fmt(sd, mf); | 338 | return mt9m001_s_fmt(sd, fmt, mf); |
339 | cfg->try_fmt = *mf; | 339 | cfg->try_fmt = *mf; |
340 | return 0; | 340 | return 0; |
341 | } | 341 | } |
@@ -574,7 +574,7 @@ static const struct v4l2_ctrl_ops mt9m001_ctrl_ops = { | |||
574 | .s_ctrl = mt9m001_s_ctrl, | 574 | .s_ctrl = mt9m001_s_ctrl, |
575 | }; | 575 | }; |
576 | 576 | ||
577 | static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = { | 577 | static const struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = { |
578 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 578 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
579 | .g_register = mt9m001_g_register, | 579 | .g_register = mt9m001_g_register, |
580 | .s_register = mt9m001_s_register, | 580 | .s_register = mt9m001_s_register, |
@@ -630,7 +630,7 @@ static int mt9m001_s_mbus_config(struct v4l2_subdev *sd, | |||
630 | return bps == 10 ? 0 : -EINVAL; | 630 | return bps == 10 ? 0 : -EINVAL; |
631 | } | 631 | } |
632 | 632 | ||
633 | static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = { | 633 | static const struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = { |
634 | .s_stream = mt9m001_s_stream, | 634 | .s_stream = mt9m001_s_stream, |
635 | .g_mbus_config = mt9m001_g_mbus_config, | 635 | .g_mbus_config = mt9m001_g_mbus_config, |
636 | .s_mbus_config = mt9m001_s_mbus_config, | 636 | .s_mbus_config = mt9m001_s_mbus_config, |
@@ -648,7 +648,7 @@ static const struct v4l2_subdev_pad_ops mt9m001_subdev_pad_ops = { | |||
648 | .set_fmt = mt9m001_set_fmt, | 648 | .set_fmt = mt9m001_set_fmt, |
649 | }; | 649 | }; |
650 | 650 | ||
651 | static struct v4l2_subdev_ops mt9m001_subdev_ops = { | 651 | static const struct v4l2_subdev_ops mt9m001_subdev_ops = { |
652 | .core = &mt9m001_subdev_core_ops, | 652 | .core = &mt9m001_subdev_core_ops, |
653 | .video = &mt9m001_subdev_video_ops, | 653 | .video = &mt9m001_subdev_video_ops, |
654 | .sensor = &mt9m001_subdev_sensor_ops, | 654 | .sensor = &mt9m001_subdev_sensor_ops, |
diff --git a/drivers/media/i2c/soc_camera/mt9t031.c b/drivers/media/i2c/soc_camera/mt9t031.c index 3aa5569065ad..714fb3555b34 100644 --- a/drivers/media/i2c/soc_camera/mt9t031.c +++ b/drivers/media/i2c/soc_camera/mt9t031.c | |||
@@ -679,7 +679,7 @@ static const struct v4l2_ctrl_ops mt9t031_ctrl_ops = { | |||
679 | .s_ctrl = mt9t031_s_ctrl, | 679 | .s_ctrl = mt9t031_s_ctrl, |
680 | }; | 680 | }; |
681 | 681 | ||
682 | static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = { | 682 | static const struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = { |
683 | .s_power = mt9t031_s_power, | 683 | .s_power = mt9t031_s_power, |
684 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 684 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
685 | .g_register = mt9t031_g_register, | 685 | .g_register = mt9t031_g_register, |
@@ -726,7 +726,7 @@ static int mt9t031_s_mbus_config(struct v4l2_subdev *sd, | |||
726 | return reg_set(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); | 726 | return reg_set(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); |
727 | } | 727 | } |
728 | 728 | ||
729 | static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = { | 729 | static const struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = { |
730 | .s_stream = mt9t031_s_stream, | 730 | .s_stream = mt9t031_s_stream, |
731 | .g_mbus_config = mt9t031_g_mbus_config, | 731 | .g_mbus_config = mt9t031_g_mbus_config, |
732 | .s_mbus_config = mt9t031_s_mbus_config, | 732 | .s_mbus_config = mt9t031_s_mbus_config, |
@@ -744,7 +744,7 @@ static const struct v4l2_subdev_pad_ops mt9t031_subdev_pad_ops = { | |||
744 | .set_fmt = mt9t031_set_fmt, | 744 | .set_fmt = mt9t031_set_fmt, |
745 | }; | 745 | }; |
746 | 746 | ||
747 | static struct v4l2_subdev_ops mt9t031_subdev_ops = { | 747 | static const struct v4l2_subdev_ops mt9t031_subdev_ops = { |
748 | .core = &mt9t031_subdev_core_ops, | 748 | .core = &mt9t031_subdev_core_ops, |
749 | .video = &mt9t031_subdev_video_ops, | 749 | .video = &mt9t031_subdev_video_ops, |
750 | .sensor = &mt9t031_subdev_sensor_ops, | 750 | .sensor = &mt9t031_subdev_sensor_ops, |
diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/mt9t112.c index 2ef22241ec14..297d22ebcb18 100644 --- a/drivers/media/i2c/soc_camera/mt9t112.c +++ b/drivers/media/i2c/soc_camera/mt9t112.c | |||
@@ -773,7 +773,7 @@ static int mt9t112_s_power(struct v4l2_subdev *sd, int on) | |||
773 | return soc_camera_set_power(&client->dev, ssdd, priv->clk, on); | 773 | return soc_camera_set_power(&client->dev, ssdd, priv->clk, on); |
774 | } | 774 | } |
775 | 775 | ||
776 | static struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = { | 776 | static const struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = { |
777 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 777 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
778 | .g_register = mt9t112_g_register, | 778 | .g_register = mt9t112_g_register, |
779 | .s_register = mt9t112_s_register, | 779 | .s_register = mt9t112_s_register, |
@@ -1031,7 +1031,7 @@ static int mt9t112_s_mbus_config(struct v4l2_subdev *sd, | |||
1031 | return 0; | 1031 | return 0; |
1032 | } | 1032 | } |
1033 | 1033 | ||
1034 | static struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = { | 1034 | static const struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = { |
1035 | .s_stream = mt9t112_s_stream, | 1035 | .s_stream = mt9t112_s_stream, |
1036 | .g_mbus_config = mt9t112_g_mbus_config, | 1036 | .g_mbus_config = mt9t112_g_mbus_config, |
1037 | .s_mbus_config = mt9t112_s_mbus_config, | 1037 | .s_mbus_config = mt9t112_s_mbus_config, |
@@ -1048,7 +1048,7 @@ static const struct v4l2_subdev_pad_ops mt9t112_subdev_pad_ops = { | |||
1048 | /************************************************************************ | 1048 | /************************************************************************ |
1049 | i2c driver | 1049 | i2c driver |
1050 | ************************************************************************/ | 1050 | ************************************************************************/ |
1051 | static struct v4l2_subdev_ops mt9t112_subdev_ops = { | 1051 | static const struct v4l2_subdev_ops mt9t112_subdev_ops = { |
1052 | .core = &mt9t112_subdev_core_ops, | 1052 | .core = &mt9t112_subdev_core_ops, |
1053 | .video = &mt9t112_subdev_video_ops, | 1053 | .video = &mt9t112_subdev_video_ops, |
1054 | .pad = &mt9t112_subdev_pad_ops, | 1054 | .pad = &mt9t112_subdev_pad_ops, |
diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c index 6a14ab5e4f2d..762f06919329 100644 --- a/drivers/media/i2c/soc_camera/mt9v022.c +++ b/drivers/media/i2c/soc_camera/mt9v022.c | |||
@@ -403,6 +403,7 @@ static int mt9v022_get_fmt(struct v4l2_subdev *sd, | |||
403 | } | 403 | } |
404 | 404 | ||
405 | static int mt9v022_s_fmt(struct v4l2_subdev *sd, | 405 | static int mt9v022_s_fmt(struct v4l2_subdev *sd, |
406 | const struct mt9v022_datafmt *fmt, | ||
406 | struct v4l2_mbus_framefmt *mf) | 407 | struct v4l2_mbus_framefmt *mf) |
407 | { | 408 | { |
408 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 409 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
@@ -441,9 +442,8 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd, | |||
441 | if (!ret) { | 442 | if (!ret) { |
442 | mf->width = mt9v022->rect.width; | 443 | mf->width = mt9v022->rect.width; |
443 | mf->height = mt9v022->rect.height; | 444 | mf->height = mt9v022->rect.height; |
444 | mt9v022->fmt = mt9v022_find_datafmt(mf->code, | 445 | mt9v022->fmt = fmt; |
445 | mt9v022->fmts, mt9v022->num_fmts); | 446 | mf->colorspace = fmt->colorspace; |
446 | mf->colorspace = mt9v022->fmt->colorspace; | ||
447 | } | 447 | } |
448 | 448 | ||
449 | return ret; | 449 | return ret; |
@@ -478,7 +478,7 @@ static int mt9v022_set_fmt(struct v4l2_subdev *sd, | |||
478 | mf->colorspace = fmt->colorspace; | 478 | mf->colorspace = fmt->colorspace; |
479 | 479 | ||
480 | if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) | 480 | if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) |
481 | return mt9v022_s_fmt(sd, mf); | 481 | return mt9v022_s_fmt(sd, fmt, mf); |
482 | cfg->try_fmt = *mf; | 482 | cfg->try_fmt = *mf; |
483 | return 0; | 483 | return 0; |
484 | } | 484 | } |
@@ -770,7 +770,7 @@ static const struct v4l2_ctrl_ops mt9v022_ctrl_ops = { | |||
770 | .s_ctrl = mt9v022_s_ctrl, | 770 | .s_ctrl = mt9v022_s_ctrl, |
771 | }; | 771 | }; |
772 | 772 | ||
773 | static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = { | 773 | static const struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = { |
774 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 774 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
775 | .g_register = mt9v022_g_register, | 775 | .g_register = mt9v022_g_register, |
776 | .s_register = mt9v022_s_register, | 776 | .s_register = mt9v022_s_register, |
@@ -858,7 +858,7 @@ static int mt9v022_s_mbus_config(struct v4l2_subdev *sd, | |||
858 | return 0; | 858 | return 0; |
859 | } | 859 | } |
860 | 860 | ||
861 | static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { | 861 | static const struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { |
862 | .s_stream = mt9v022_s_stream, | 862 | .s_stream = mt9v022_s_stream, |
863 | .g_mbus_config = mt9v022_g_mbus_config, | 863 | .g_mbus_config = mt9v022_g_mbus_config, |
864 | .s_mbus_config = mt9v022_s_mbus_config, | 864 | .s_mbus_config = mt9v022_s_mbus_config, |
@@ -876,7 +876,7 @@ static const struct v4l2_subdev_pad_ops mt9v022_subdev_pad_ops = { | |||
876 | .set_fmt = mt9v022_set_fmt, | 876 | .set_fmt = mt9v022_set_fmt, |
877 | }; | 877 | }; |
878 | 878 | ||
879 | static struct v4l2_subdev_ops mt9v022_subdev_ops = { | 879 | static const struct v4l2_subdev_ops mt9v022_subdev_ops = { |
880 | .core = &mt9v022_subdev_core_ops, | 880 | .core = &mt9v022_subdev_core_ops, |
881 | .video = &mt9v022_subdev_video_ops, | 881 | .video = &mt9v022_subdev_video_ops, |
882 | .sensor = &mt9v022_subdev_sensor_ops, | 882 | .sensor = &mt9v022_subdev_sensor_ops, |
diff --git a/drivers/media/i2c/soc_camera/ov5642.c b/drivers/media/i2c/soc_camera/ov5642.c index 3d185bd622a3..39f420db9c70 100644 --- a/drivers/media/i2c/soc_camera/ov5642.c +++ b/drivers/media/i2c/soc_camera/ov5642.c | |||
@@ -811,7 +811,7 @@ static int ov5642_set_fmt(struct v4l2_subdev *sd, | |||
811 | mf->field = V4L2_FIELD_NONE; | 811 | mf->field = V4L2_FIELD_NONE; |
812 | 812 | ||
813 | if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) | 813 | if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) |
814 | priv->fmt = ov5642_find_datafmt(mf->code); | 814 | priv->fmt = fmt; |
815 | else | 815 | else |
816 | cfg->try_fmt = *mf; | 816 | cfg->try_fmt = *mf; |
817 | return 0; | 817 | return 0; |
@@ -943,7 +943,7 @@ static int ov5642_s_power(struct v4l2_subdev *sd, int on) | |||
943 | return ret; | 943 | return ret; |
944 | } | 944 | } |
945 | 945 | ||
946 | static struct v4l2_subdev_video_ops ov5642_subdev_video_ops = { | 946 | static const struct v4l2_subdev_video_ops ov5642_subdev_video_ops = { |
947 | .g_mbus_config = ov5642_g_mbus_config, | 947 | .g_mbus_config = ov5642_g_mbus_config, |
948 | }; | 948 | }; |
949 | 949 | ||
@@ -955,7 +955,7 @@ static const struct v4l2_subdev_pad_ops ov5642_subdev_pad_ops = { | |||
955 | .set_fmt = ov5642_set_fmt, | 955 | .set_fmt = ov5642_set_fmt, |
956 | }; | 956 | }; |
957 | 957 | ||
958 | static struct v4l2_subdev_core_ops ov5642_subdev_core_ops = { | 958 | static const struct v4l2_subdev_core_ops ov5642_subdev_core_ops = { |
959 | .s_power = ov5642_s_power, | 959 | .s_power = ov5642_s_power, |
960 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 960 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
961 | .g_register = ov5642_get_register, | 961 | .g_register = ov5642_get_register, |
@@ -963,7 +963,7 @@ static struct v4l2_subdev_core_ops ov5642_subdev_core_ops = { | |||
963 | #endif | 963 | #endif |
964 | }; | 964 | }; |
965 | 965 | ||
966 | static struct v4l2_subdev_ops ov5642_subdev_ops = { | 966 | static const struct v4l2_subdev_ops ov5642_subdev_ops = { |
967 | .core = &ov5642_subdev_core_ops, | 967 | .core = &ov5642_subdev_core_ops, |
968 | .video = &ov5642_subdev_video_ops, | 968 | .video = &ov5642_subdev_video_ops, |
969 | .pad = &ov5642_subdev_pad_ops, | 969 | .pad = &ov5642_subdev_pad_ops, |
@@ -1063,9 +1063,18 @@ static const struct i2c_device_id ov5642_id[] = { | |||
1063 | }; | 1063 | }; |
1064 | MODULE_DEVICE_TABLE(i2c, ov5642_id); | 1064 | MODULE_DEVICE_TABLE(i2c, ov5642_id); |
1065 | 1065 | ||
1066 | #if IS_ENABLED(CONFIG_OF) | ||
1067 | static const struct of_device_id ov5642_of_match[] = { | ||
1068 | { .compatible = "ovti,ov5642" }, | ||
1069 | { }, | ||
1070 | }; | ||
1071 | MODULE_DEVICE_TABLE(of, ov5642_of_match); | ||
1072 | #endif | ||
1073 | |||
1066 | static struct i2c_driver ov5642_i2c_driver = { | 1074 | static struct i2c_driver ov5642_i2c_driver = { |
1067 | .driver = { | 1075 | .driver = { |
1068 | .name = "ov5642", | 1076 | .name = "ov5642", |
1077 | .of_match_table = of_match_ptr(ov5642_of_match), | ||
1069 | }, | 1078 | }, |
1070 | .probe = ov5642_probe, | 1079 | .probe = ov5642_probe, |
1071 | .remove = ov5642_remove, | 1080 | .remove = ov5642_remove, |
diff --git a/drivers/media/i2c/soc_camera/ov6650.c b/drivers/media/i2c/soc_camera/ov6650.c index 4bf2995e1cb8..dbd6d92c589f 100644 --- a/drivers/media/i2c/soc_camera/ov6650.c +++ b/drivers/media/i2c/soc_camera/ov6650.c | |||
@@ -885,7 +885,7 @@ static const struct v4l2_ctrl_ops ov6550_ctrl_ops = { | |||
885 | .s_ctrl = ov6550_s_ctrl, | 885 | .s_ctrl = ov6550_s_ctrl, |
886 | }; | 886 | }; |
887 | 887 | ||
888 | static struct v4l2_subdev_core_ops ov6650_core_ops = { | 888 | static const struct v4l2_subdev_core_ops ov6650_core_ops = { |
889 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 889 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
890 | .g_register = ov6650_get_register, | 890 | .g_register = ov6650_get_register, |
891 | .s_register = ov6650_set_register, | 891 | .s_register = ov6650_set_register, |
@@ -942,7 +942,7 @@ static int ov6650_s_mbus_config(struct v4l2_subdev *sd, | |||
942 | return ret; | 942 | return ret; |
943 | } | 943 | } |
944 | 944 | ||
945 | static struct v4l2_subdev_video_ops ov6650_video_ops = { | 945 | static const struct v4l2_subdev_video_ops ov6650_video_ops = { |
946 | .s_stream = ov6650_s_stream, | 946 | .s_stream = ov6650_s_stream, |
947 | .g_parm = ov6650_g_parm, | 947 | .g_parm = ov6650_g_parm, |
948 | .s_parm = ov6650_s_parm, | 948 | .s_parm = ov6650_s_parm, |
@@ -958,7 +958,7 @@ static const struct v4l2_subdev_pad_ops ov6650_pad_ops = { | |||
958 | .set_fmt = ov6650_set_fmt, | 958 | .set_fmt = ov6650_set_fmt, |
959 | }; | 959 | }; |
960 | 960 | ||
961 | static struct v4l2_subdev_ops ov6650_subdev_ops = { | 961 | static const struct v4l2_subdev_ops ov6650_subdev_ops = { |
962 | .core = &ov6650_core_ops, | 962 | .core = &ov6650_core_ops, |
963 | .video = &ov6650_video_ops, | 963 | .video = &ov6650_video_ops, |
964 | .pad = &ov6650_pad_ops, | 964 | .pad = &ov6650_pad_ops, |
@@ -1033,7 +1033,7 @@ static int ov6650_probe(struct i2c_client *client, | |||
1033 | priv->code = MEDIA_BUS_FMT_YUYV8_2X8; | 1033 | priv->code = MEDIA_BUS_FMT_YUYV8_2X8; |
1034 | priv->colorspace = V4L2_COLORSPACE_JPEG; | 1034 | priv->colorspace = V4L2_COLORSPACE_JPEG; |
1035 | 1035 | ||
1036 | priv->clk = v4l2_clk_get(&client->dev, "mclk"); | 1036 | priv->clk = v4l2_clk_get(&client->dev, NULL); |
1037 | if (IS_ERR(priv->clk)) { | 1037 | if (IS_ERR(priv->clk)) { |
1038 | ret = PTR_ERR(priv->clk); | 1038 | ret = PTR_ERR(priv->clk); |
1039 | goto eclkget; | 1039 | goto eclkget; |
diff --git a/drivers/media/i2c/soc_camera/ov772x.c b/drivers/media/i2c/soc_camera/ov772x.c index 985a3672b243..0f7b9d1b9c57 100644 --- a/drivers/media/i2c/soc_camera/ov772x.c +++ b/drivers/media/i2c/soc_camera/ov772x.c | |||
@@ -894,38 +894,15 @@ static int ov772x_get_fmt(struct v4l2_subdev *sd, | |||
894 | return 0; | 894 | return 0; |
895 | } | 895 | } |
896 | 896 | ||
897 | static int ov772x_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) | ||
898 | { | ||
899 | struct ov772x_priv *priv = to_ov772x(sd); | ||
900 | const struct ov772x_color_format *cfmt; | ||
901 | const struct ov772x_win_size *win; | ||
902 | int ret; | ||
903 | |||
904 | ov772x_select_params(mf, &cfmt, &win); | ||
905 | |||
906 | ret = ov772x_set_params(priv, cfmt, win); | ||
907 | if (ret < 0) | ||
908 | return ret; | ||
909 | |||
910 | priv->win = win; | ||
911 | priv->cfmt = cfmt; | ||
912 | |||
913 | mf->code = cfmt->code; | ||
914 | mf->width = win->rect.width; | ||
915 | mf->height = win->rect.height; | ||
916 | mf->field = V4L2_FIELD_NONE; | ||
917 | mf->colorspace = cfmt->colorspace; | ||
918 | |||
919 | return 0; | ||
920 | } | ||
921 | |||
922 | static int ov772x_set_fmt(struct v4l2_subdev *sd, | 897 | static int ov772x_set_fmt(struct v4l2_subdev *sd, |
923 | struct v4l2_subdev_pad_config *cfg, | 898 | struct v4l2_subdev_pad_config *cfg, |
924 | struct v4l2_subdev_format *format) | 899 | struct v4l2_subdev_format *format) |
925 | { | 900 | { |
901 | struct ov772x_priv *priv = to_ov772x(sd); | ||
926 | struct v4l2_mbus_framefmt *mf = &format->format; | 902 | struct v4l2_mbus_framefmt *mf = &format->format; |
927 | const struct ov772x_color_format *cfmt; | 903 | const struct ov772x_color_format *cfmt; |
928 | const struct ov772x_win_size *win; | 904 | const struct ov772x_win_size *win; |
905 | int ret; | ||
929 | 906 | ||
930 | if (format->pad) | 907 | if (format->pad) |
931 | return -EINVAL; | 908 | return -EINVAL; |
@@ -938,9 +915,17 @@ static int ov772x_set_fmt(struct v4l2_subdev *sd, | |||
938 | mf->field = V4L2_FIELD_NONE; | 915 | mf->field = V4L2_FIELD_NONE; |
939 | mf->colorspace = cfmt->colorspace; | 916 | mf->colorspace = cfmt->colorspace; |
940 | 917 | ||
941 | if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) | 918 | if (format->which == V4L2_SUBDEV_FORMAT_TRY) { |
942 | return ov772x_s_fmt(sd, mf); | 919 | cfg->try_fmt = *mf; |
943 | cfg->try_fmt = *mf; | 920 | return 0; |
921 | } | ||
922 | |||
923 | ret = ov772x_set_params(priv, cfmt, win); | ||
924 | if (ret < 0) | ||
925 | return ret; | ||
926 | |||
927 | priv->win = win; | ||
928 | priv->cfmt = cfmt; | ||
944 | return 0; | 929 | return 0; |
945 | } | 930 | } |
946 | 931 | ||
@@ -993,7 +978,7 @@ static const struct v4l2_ctrl_ops ov772x_ctrl_ops = { | |||
993 | .s_ctrl = ov772x_s_ctrl, | 978 | .s_ctrl = ov772x_s_ctrl, |
994 | }; | 979 | }; |
995 | 980 | ||
996 | static struct v4l2_subdev_core_ops ov772x_subdev_core_ops = { | 981 | static const struct v4l2_subdev_core_ops ov772x_subdev_core_ops = { |
997 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 982 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
998 | .g_register = ov772x_g_register, | 983 | .g_register = ov772x_g_register, |
999 | .s_register = ov772x_s_register, | 984 | .s_register = ov772x_s_register, |
@@ -1027,7 +1012,7 @@ static int ov772x_g_mbus_config(struct v4l2_subdev *sd, | |||
1027 | return 0; | 1012 | return 0; |
1028 | } | 1013 | } |
1029 | 1014 | ||
1030 | static struct v4l2_subdev_video_ops ov772x_subdev_video_ops = { | 1015 | static const struct v4l2_subdev_video_ops ov772x_subdev_video_ops = { |
1031 | .s_stream = ov772x_s_stream, | 1016 | .s_stream = ov772x_s_stream, |
1032 | .g_mbus_config = ov772x_g_mbus_config, | 1017 | .g_mbus_config = ov772x_g_mbus_config, |
1033 | }; | 1018 | }; |
@@ -1039,7 +1024,7 @@ static const struct v4l2_subdev_pad_ops ov772x_subdev_pad_ops = { | |||
1039 | .set_fmt = ov772x_set_fmt, | 1024 | .set_fmt = ov772x_set_fmt, |
1040 | }; | 1025 | }; |
1041 | 1026 | ||
1042 | static struct v4l2_subdev_ops ov772x_subdev_ops = { | 1027 | static const struct v4l2_subdev_ops ov772x_subdev_ops = { |
1043 | .core = &ov772x_subdev_core_ops, | 1028 | .core = &ov772x_subdev_core_ops, |
1044 | .video = &ov772x_subdev_video_ops, | 1029 | .video = &ov772x_subdev_video_ops, |
1045 | .pad = &ov772x_subdev_pad_ops, | 1030 | .pad = &ov772x_subdev_pad_ops, |
diff --git a/drivers/media/i2c/soc_camera/ov9640.c b/drivers/media/i2c/soc_camera/ov9640.c index 65085a235128..0146d1f7aacb 100644 --- a/drivers/media/i2c/soc_camera/ov9640.c +++ b/drivers/media/i2c/soc_camera/ov9640.c | |||
@@ -486,11 +486,8 @@ static int ov9640_s_fmt(struct v4l2_subdev *sd, | |||
486 | { | 486 | { |
487 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 487 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
488 | struct ov9640_reg_alt alts = {0}; | 488 | struct ov9640_reg_alt alts = {0}; |
489 | enum v4l2_colorspace cspace; | ||
490 | u32 code = mf->code; | ||
491 | int ret; | 489 | int ret; |
492 | 490 | ||
493 | ov9640_res_roundup(&mf->width, &mf->height); | ||
494 | ov9640_alter_regs(mf->code, &alts); | 491 | ov9640_alter_regs(mf->code, &alts); |
495 | 492 | ||
496 | ov9640_reset(client); | 493 | ov9640_reset(client); |
@@ -499,24 +496,7 @@ static int ov9640_s_fmt(struct v4l2_subdev *sd, | |||
499 | if (ret) | 496 | if (ret) |
500 | return ret; | 497 | return ret; |
501 | 498 | ||
502 | switch (code) { | 499 | return ov9640_write_regs(client, mf->width, mf->code, &alts); |
503 | case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE: | ||
504 | case MEDIA_BUS_FMT_RGB565_2X8_LE: | ||
505 | cspace = V4L2_COLORSPACE_SRGB; | ||
506 | break; | ||
507 | default: | ||
508 | code = MEDIA_BUS_FMT_UYVY8_2X8; | ||
509 | case MEDIA_BUS_FMT_UYVY8_2X8: | ||
510 | cspace = V4L2_COLORSPACE_JPEG; | ||
511 | } | ||
512 | |||
513 | ret = ov9640_write_regs(client, mf->width, code, &alts); | ||
514 | if (!ret) { | ||
515 | mf->code = code; | ||
516 | mf->colorspace = cspace; | ||
517 | } | ||
518 | |||
519 | return ret; | ||
520 | } | 500 | } |
521 | 501 | ||
522 | static int ov9640_set_fmt(struct v4l2_subdev *sd, | 502 | static int ov9640_set_fmt(struct v4l2_subdev *sd, |
@@ -539,8 +519,10 @@ static int ov9640_set_fmt(struct v4l2_subdev *sd, | |||
539 | break; | 519 | break; |
540 | default: | 520 | default: |
541 | mf->code = MEDIA_BUS_FMT_UYVY8_2X8; | 521 | mf->code = MEDIA_BUS_FMT_UYVY8_2X8; |
522 | /* fall through */ | ||
542 | case MEDIA_BUS_FMT_UYVY8_2X8: | 523 | case MEDIA_BUS_FMT_UYVY8_2X8: |
543 | mf->colorspace = V4L2_COLORSPACE_JPEG; | 524 | mf->colorspace = V4L2_COLORSPACE_JPEG; |
525 | break; | ||
544 | } | 526 | } |
545 | 527 | ||
546 | if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) | 528 | if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) |
@@ -637,7 +619,7 @@ static const struct v4l2_ctrl_ops ov9640_ctrl_ops = { | |||
637 | .s_ctrl = ov9640_s_ctrl, | 619 | .s_ctrl = ov9640_s_ctrl, |
638 | }; | 620 | }; |
639 | 621 | ||
640 | static struct v4l2_subdev_core_ops ov9640_core_ops = { | 622 | static const struct v4l2_subdev_core_ops ov9640_core_ops = { |
641 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 623 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
642 | .g_register = ov9640_get_register, | 624 | .g_register = ov9640_get_register, |
643 | .s_register = ov9640_set_register, | 625 | .s_register = ov9640_set_register, |
@@ -661,7 +643,7 @@ static int ov9640_g_mbus_config(struct v4l2_subdev *sd, | |||
661 | return 0; | 643 | return 0; |
662 | } | 644 | } |
663 | 645 | ||
664 | static struct v4l2_subdev_video_ops ov9640_video_ops = { | 646 | static const struct v4l2_subdev_video_ops ov9640_video_ops = { |
665 | .s_stream = ov9640_s_stream, | 647 | .s_stream = ov9640_s_stream, |
666 | .g_mbus_config = ov9640_g_mbus_config, | 648 | .g_mbus_config = ov9640_g_mbus_config, |
667 | }; | 649 | }; |
@@ -672,7 +654,7 @@ static const struct v4l2_subdev_pad_ops ov9640_pad_ops = { | |||
672 | .set_fmt = ov9640_set_fmt, | 654 | .set_fmt = ov9640_set_fmt, |
673 | }; | 655 | }; |
674 | 656 | ||
675 | static struct v4l2_subdev_ops ov9640_subdev_ops = { | 657 | static const struct v4l2_subdev_ops ov9640_subdev_ops = { |
676 | .core = &ov9640_core_ops, | 658 | .core = &ov9640_core_ops, |
677 | .video = &ov9640_video_ops, | 659 | .video = &ov9640_video_ops, |
678 | .pad = &ov9640_pad_ops, | 660 | .pad = &ov9640_pad_ops, |
diff --git a/drivers/media/i2c/soc_camera/ov9740.c b/drivers/media/i2c/soc_camera/ov9740.c index f11f76cdacad..cc07b7ae5407 100644 --- a/drivers/media/i2c/soc_camera/ov9740.c +++ b/drivers/media/i2c/soc_camera/ov9740.c | |||
@@ -673,20 +673,8 @@ static int ov9740_s_fmt(struct v4l2_subdev *sd, | |||
673 | { | 673 | { |
674 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 674 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
675 | struct ov9740_priv *priv = to_ov9740(sd); | 675 | struct ov9740_priv *priv = to_ov9740(sd); |
676 | enum v4l2_colorspace cspace; | ||
677 | u32 code = mf->code; | ||
678 | int ret; | 676 | int ret; |
679 | 677 | ||
680 | ov9740_res_roundup(&mf->width, &mf->height); | ||
681 | |||
682 | switch (code) { | ||
683 | case MEDIA_BUS_FMT_YUYV8_2X8: | ||
684 | cspace = V4L2_COLORSPACE_SRGB; | ||
685 | break; | ||
686 | default: | ||
687 | return -EINVAL; | ||
688 | } | ||
689 | |||
690 | ret = ov9740_reg_write_array(client, ov9740_defaults, | 678 | ret = ov9740_reg_write_array(client, ov9740_defaults, |
691 | ARRAY_SIZE(ov9740_defaults)); | 679 | ARRAY_SIZE(ov9740_defaults)); |
692 | if (ret < 0) | 680 | if (ret < 0) |
@@ -696,11 +684,7 @@ static int ov9740_s_fmt(struct v4l2_subdev *sd, | |||
696 | if (ret < 0) | 684 | if (ret < 0) |
697 | return ret; | 685 | return ret; |
698 | 686 | ||
699 | mf->code = code; | 687 | priv->current_mf = *mf; |
700 | mf->colorspace = cspace; | ||
701 | |||
702 | memcpy(&priv->current_mf, mf, sizeof(struct v4l2_mbus_framefmt)); | ||
703 | |||
704 | return ret; | 688 | return ret; |
705 | } | 689 | } |
706 | 690 | ||
@@ -907,12 +891,12 @@ static int ov9740_g_mbus_config(struct v4l2_subdev *sd, | |||
907 | return 0; | 891 | return 0; |
908 | } | 892 | } |
909 | 893 | ||
910 | static struct v4l2_subdev_video_ops ov9740_video_ops = { | 894 | static const struct v4l2_subdev_video_ops ov9740_video_ops = { |
911 | .s_stream = ov9740_s_stream, | 895 | .s_stream = ov9740_s_stream, |
912 | .g_mbus_config = ov9740_g_mbus_config, | 896 | .g_mbus_config = ov9740_g_mbus_config, |
913 | }; | 897 | }; |
914 | 898 | ||
915 | static struct v4l2_subdev_core_ops ov9740_core_ops = { | 899 | static const struct v4l2_subdev_core_ops ov9740_core_ops = { |
916 | .s_power = ov9740_s_power, | 900 | .s_power = ov9740_s_power, |
917 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 901 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
918 | .g_register = ov9740_get_register, | 902 | .g_register = ov9740_get_register, |
@@ -926,7 +910,7 @@ static const struct v4l2_subdev_pad_ops ov9740_pad_ops = { | |||
926 | .set_fmt = ov9740_set_fmt, | 910 | .set_fmt = ov9740_set_fmt, |
927 | }; | 911 | }; |
928 | 912 | ||
929 | static struct v4l2_subdev_ops ov9740_subdev_ops = { | 913 | static const struct v4l2_subdev_ops ov9740_subdev_ops = { |
930 | .core = &ov9740_core_ops, | 914 | .core = &ov9740_core_ops, |
931 | .video = &ov9740_video_ops, | 915 | .video = &ov9740_video_ops, |
932 | .pad = &ov9740_pad_ops, | 916 | .pad = &ov9740_pad_ops, |
diff --git a/drivers/media/i2c/soc_camera/rj54n1cb0c.c b/drivers/media/i2c/soc_camera/rj54n1cb0c.c index bc8ec59a3fbd..02398d0bc649 100644 --- a/drivers/media/i2c/soc_camera/rj54n1cb0c.c +++ b/drivers/media/i2c/soc_camera/rj54n1cb0c.c | |||
@@ -1213,7 +1213,7 @@ static const struct v4l2_ctrl_ops rj54n1_ctrl_ops = { | |||
1213 | .s_ctrl = rj54n1_s_ctrl, | 1213 | .s_ctrl = rj54n1_s_ctrl, |
1214 | }; | 1214 | }; |
1215 | 1215 | ||
1216 | static struct v4l2_subdev_core_ops rj54n1_subdev_core_ops = { | 1216 | static const struct v4l2_subdev_core_ops rj54n1_subdev_core_ops = { |
1217 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 1217 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
1218 | .g_register = rj54n1_g_register, | 1218 | .g_register = rj54n1_g_register, |
1219 | .s_register = rj54n1_s_register, | 1219 | .s_register = rj54n1_s_register, |
@@ -1251,7 +1251,7 @@ static int rj54n1_s_mbus_config(struct v4l2_subdev *sd, | |||
1251 | return reg_write(client, RJ54N1_OUT_SIGPO, 0); | 1251 | return reg_write(client, RJ54N1_OUT_SIGPO, 0); |
1252 | } | 1252 | } |
1253 | 1253 | ||
1254 | static struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = { | 1254 | static const struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = { |
1255 | .s_stream = rj54n1_s_stream, | 1255 | .s_stream = rj54n1_s_stream, |
1256 | .g_mbus_config = rj54n1_g_mbus_config, | 1256 | .g_mbus_config = rj54n1_g_mbus_config, |
1257 | .s_mbus_config = rj54n1_s_mbus_config, | 1257 | .s_mbus_config = rj54n1_s_mbus_config, |
@@ -1265,7 +1265,7 @@ static const struct v4l2_subdev_pad_ops rj54n1_subdev_pad_ops = { | |||
1265 | .set_fmt = rj54n1_set_fmt, | 1265 | .set_fmt = rj54n1_set_fmt, |
1266 | }; | 1266 | }; |
1267 | 1267 | ||
1268 | static struct v4l2_subdev_ops rj54n1_subdev_ops = { | 1268 | static const struct v4l2_subdev_ops rj54n1_subdev_ops = { |
1269 | .core = &rj54n1_subdev_core_ops, | 1269 | .core = &rj54n1_subdev_core_ops, |
1270 | .video = &rj54n1_subdev_video_ops, | 1270 | .video = &rj54n1_subdev_video_ops, |
1271 | .pad = &rj54n1_subdev_pad_ops, | 1271 | .pad = &rj54n1_subdev_pad_ops, |
diff --git a/drivers/media/i2c/soc_camera/tw9910.c b/drivers/media/i2c/soc_camera/tw9910.c index c9c49ed707b8..bdb5e0a431e9 100644 --- a/drivers/media/i2c/soc_camera/tw9910.c +++ b/drivers/media/i2c/soc_camera/tw9910.c | |||
@@ -837,7 +837,7 @@ done: | |||
837 | return ret; | 837 | return ret; |
838 | } | 838 | } |
839 | 839 | ||
840 | static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = { | 840 | static const struct v4l2_subdev_core_ops tw9910_subdev_core_ops = { |
841 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 841 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
842 | .g_register = tw9910_g_register, | 842 | .g_register = tw9910_g_register, |
843 | .s_register = tw9910_s_register, | 843 | .s_register = tw9910_s_register, |
@@ -901,7 +901,7 @@ static int tw9910_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *norm) | |||
901 | return 0; | 901 | return 0; |
902 | } | 902 | } |
903 | 903 | ||
904 | static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = { | 904 | static const struct v4l2_subdev_video_ops tw9910_subdev_video_ops = { |
905 | .s_std = tw9910_s_std, | 905 | .s_std = tw9910_s_std, |
906 | .g_std = tw9910_g_std, | 906 | .g_std = tw9910_g_std, |
907 | .s_stream = tw9910_s_stream, | 907 | .s_stream = tw9910_s_stream, |
@@ -917,7 +917,7 @@ static const struct v4l2_subdev_pad_ops tw9910_subdev_pad_ops = { | |||
917 | .set_fmt = tw9910_set_fmt, | 917 | .set_fmt = tw9910_set_fmt, |
918 | }; | 918 | }; |
919 | 919 | ||
920 | static struct v4l2_subdev_ops tw9910_subdev_ops = { | 920 | static const struct v4l2_subdev_ops tw9910_subdev_ops = { |
921 | .core = &tw9910_subdev_core_ops, | 921 | .core = &tw9910_subdev_core_ops, |
922 | .video = &tw9910_subdev_video_ops, | 922 | .video = &tw9910_subdev_video_ops, |
923 | .pad = &tw9910_subdev_pad_ops, | 923 | .pad = &tw9910_subdev_pad_ops, |
diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index f569a05fe105..acef4eca269f 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c | |||
@@ -194,57 +194,61 @@ static void i2c_wr(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) | |||
194 | } | 194 | } |
195 | } | 195 | } |
196 | 196 | ||
197 | static u8 i2c_rd8(struct v4l2_subdev *sd, u16 reg) | 197 | static noinline u32 i2c_rdreg(struct v4l2_subdev *sd, u16 reg, u32 n) |
198 | { | 198 | { |
199 | u8 val; | 199 | __le32 val = 0; |
200 | |||
201 | i2c_rd(sd, reg, (u8 __force *)&val, n); | ||
200 | 202 | ||
201 | i2c_rd(sd, reg, &val, 1); | 203 | return le32_to_cpu(val); |
204 | } | ||
205 | |||
206 | static noinline void i2c_wrreg(struct v4l2_subdev *sd, u16 reg, u32 val, u32 n) | ||
207 | { | ||
208 | __le32 raw = cpu_to_le32(val); | ||
202 | 209 | ||
203 | return val; | 210 | i2c_wr(sd, reg, (u8 __force *)&raw, n); |
211 | } | ||
212 | |||
213 | static u8 i2c_rd8(struct v4l2_subdev *sd, u16 reg) | ||
214 | { | ||
215 | return i2c_rdreg(sd, reg, 1); | ||
204 | } | 216 | } |
205 | 217 | ||
206 | static void i2c_wr8(struct v4l2_subdev *sd, u16 reg, u8 val) | 218 | static void i2c_wr8(struct v4l2_subdev *sd, u16 reg, u8 val) |
207 | { | 219 | { |
208 | i2c_wr(sd, reg, &val, 1); | 220 | i2c_wrreg(sd, reg, val, 1); |
209 | } | 221 | } |
210 | 222 | ||
211 | static void i2c_wr8_and_or(struct v4l2_subdev *sd, u16 reg, | 223 | static void i2c_wr8_and_or(struct v4l2_subdev *sd, u16 reg, |
212 | u8 mask, u8 val) | 224 | u8 mask, u8 val) |
213 | { | 225 | { |
214 | i2c_wr8(sd, reg, (i2c_rd8(sd, reg) & mask) | val); | 226 | i2c_wrreg(sd, reg, (i2c_rdreg(sd, reg, 2) & mask) | val, 2); |
215 | } | 227 | } |
216 | 228 | ||
217 | static u16 i2c_rd16(struct v4l2_subdev *sd, u16 reg) | 229 | static u16 i2c_rd16(struct v4l2_subdev *sd, u16 reg) |
218 | { | 230 | { |
219 | u16 val; | 231 | return i2c_rdreg(sd, reg, 2); |
220 | |||
221 | i2c_rd(sd, reg, (u8 *)&val, 2); | ||
222 | |||
223 | return val; | ||
224 | } | 232 | } |
225 | 233 | ||
226 | static void i2c_wr16(struct v4l2_subdev *sd, u16 reg, u16 val) | 234 | static void i2c_wr16(struct v4l2_subdev *sd, u16 reg, u16 val) |
227 | { | 235 | { |
228 | i2c_wr(sd, reg, (u8 *)&val, 2); | 236 | i2c_wrreg(sd, reg, val, 2); |
229 | } | 237 | } |
230 | 238 | ||
231 | static void i2c_wr16_and_or(struct v4l2_subdev *sd, u16 reg, u16 mask, u16 val) | 239 | static void i2c_wr16_and_or(struct v4l2_subdev *sd, u16 reg, u16 mask, u16 val) |
232 | { | 240 | { |
233 | i2c_wr16(sd, reg, (i2c_rd16(sd, reg) & mask) | val); | 241 | i2c_wrreg(sd, reg, (i2c_rdreg(sd, reg, 2) & mask) | val, 2); |
234 | } | 242 | } |
235 | 243 | ||
236 | static u32 i2c_rd32(struct v4l2_subdev *sd, u16 reg) | 244 | static u32 i2c_rd32(struct v4l2_subdev *sd, u16 reg) |
237 | { | 245 | { |
238 | u32 val; | 246 | return i2c_rdreg(sd, reg, 4); |
239 | |||
240 | i2c_rd(sd, reg, (u8 *)&val, 4); | ||
241 | |||
242 | return val; | ||
243 | } | 247 | } |
244 | 248 | ||
245 | static void i2c_wr32(struct v4l2_subdev *sd, u16 reg, u32 val) | 249 | static void i2c_wr32(struct v4l2_subdev *sd, u16 reg, u32 val) |
246 | { | 250 | { |
247 | i2c_wr(sd, reg, (u8 *)&val, 4); | 251 | i2c_wrreg(sd, reg, val, 4); |
248 | } | 252 | } |
249 | 253 | ||
250 | /* --------------- STATUS --------------- */ | 254 | /* --------------- STATUS --------------- */ |
@@ -1227,7 +1231,7 @@ static int tc358743_g_register(struct v4l2_subdev *sd, | |||
1227 | 1231 | ||
1228 | reg->size = tc358743_get_reg_size(reg->reg); | 1232 | reg->size = tc358743_get_reg_size(reg->reg); |
1229 | 1233 | ||
1230 | i2c_rd(sd, reg->reg, (u8 *)®->val, reg->size); | 1234 | reg->val = i2c_rdreg(sd, reg->reg, reg->size); |
1231 | 1235 | ||
1232 | return 0; | 1236 | return 0; |
1233 | } | 1237 | } |
@@ -1253,7 +1257,7 @@ static int tc358743_s_register(struct v4l2_subdev *sd, | |||
1253 | reg->reg == BCAPS) | 1257 | reg->reg == BCAPS) |
1254 | return 0; | 1258 | return 0; |
1255 | 1259 | ||
1256 | i2c_wr(sd, (u16)reg->reg, (u8 *)®->val, | 1260 | i2c_wrreg(sd, (u16)reg->reg, reg->val, |
1257 | tc358743_get_reg_size(reg->reg)); | 1261 | tc358743_get_reg_size(reg->reg)); |
1258 | 1262 | ||
1259 | return 0; | 1263 | return 0; |
@@ -1459,6 +1463,10 @@ static int tc358743_g_mbus_config(struct v4l2_subdev *sd, | |||
1459 | static int tc358743_s_stream(struct v4l2_subdev *sd, int enable) | 1463 | static int tc358743_s_stream(struct v4l2_subdev *sd, int enable) |
1460 | { | 1464 | { |
1461 | enable_stream(sd, enable); | 1465 | enable_stream(sd, enable); |
1466 | if (!enable) { | ||
1467 | /* Put all lanes in PL-11 state (STOPSTATE) */ | ||
1468 | tc358743_set_csi(sd); | ||
1469 | } | ||
1462 | 1470 | ||
1463 | return 0; | 1471 | return 0; |
1464 | } | 1472 | } |
@@ -1951,9 +1959,18 @@ static struct i2c_device_id tc358743_id[] = { | |||
1951 | 1959 | ||
1952 | MODULE_DEVICE_TABLE(i2c, tc358743_id); | 1960 | MODULE_DEVICE_TABLE(i2c, tc358743_id); |
1953 | 1961 | ||
1962 | #if IS_ENABLED(CONFIG_OF) | ||
1963 | static const struct of_device_id tc358743_of_match[] = { | ||
1964 | { .compatible = "toshiba,tc358743" }, | ||
1965 | {}, | ||
1966 | }; | ||
1967 | MODULE_DEVICE_TABLE(of, tc358743_of_match); | ||
1968 | #endif | ||
1969 | |||
1954 | static struct i2c_driver tc358743_driver = { | 1970 | static struct i2c_driver tc358743_driver = { |
1955 | .driver = { | 1971 | .driver = { |
1956 | .name = "tc358743", | 1972 | .name = "tc358743", |
1973 | .of_match_table = of_match_ptr(tc358743_of_match), | ||
1957 | }, | 1974 | }, |
1958 | .probe = tc358743_probe, | 1975 | .probe = tc358743_probe, |
1959 | .remove = tc358743_remove, | 1976 | .remove = tc358743_remove, |
diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index 48646a7f3fb0..04e96b3057bb 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c | |||
@@ -865,13 +865,13 @@ static int tvp5150_fill_fmt(struct v4l2_subdev *sd, | |||
865 | struct v4l2_mbus_framefmt *f; | 865 | struct v4l2_mbus_framefmt *f; |
866 | struct tvp5150 *decoder = to_tvp5150(sd); | 866 | struct tvp5150 *decoder = to_tvp5150(sd); |
867 | 867 | ||
868 | if (!format || format->pad) | 868 | if (!format || (format->pad != DEMOD_PAD_VID_OUT)) |
869 | return -EINVAL; | 869 | return -EINVAL; |
870 | 870 | ||
871 | f = &format->format; | 871 | f = &format->format; |
872 | 872 | ||
873 | f->width = decoder->rect.width; | 873 | f->width = decoder->rect.width; |
874 | f->height = decoder->rect.height / 2; | 874 | f->height = decoder->rect.height; |
875 | 875 | ||
876 | f->code = MEDIA_BUS_FMT_UYVY8_2X8; | 876 | f->code = MEDIA_BUS_FMT_UYVY8_2X8; |
877 | f->field = V4L2_FIELD_ALTERNATE; | 877 | f->field = V4L2_FIELD_ALTERNATE; |
diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c index 5640ca29da8c..bc44193efa47 100644 --- a/drivers/media/media-entity.c +++ b/drivers/media/media-entity.c | |||
@@ -199,12 +199,12 @@ void media_gobj_create(struct media_device *mdev, | |||
199 | 199 | ||
200 | void media_gobj_destroy(struct media_gobj *gobj) | 200 | void media_gobj_destroy(struct media_gobj *gobj) |
201 | { | 201 | { |
202 | dev_dbg_obj(__func__, gobj); | ||
203 | |||
204 | /* Do nothing if the object is not linked. */ | 202 | /* Do nothing if the object is not linked. */ |
205 | if (gobj->mdev == NULL) | 203 | if (gobj->mdev == NULL) |
206 | return; | 204 | return; |
207 | 205 | ||
206 | dev_dbg_obj(__func__, gobj); | ||
207 | |||
208 | gobj->mdev->topology_version++; | 208 | gobj->mdev->topology_version++; |
209 | 209 | ||
210 | /* Remove the object from mdev list */ | 210 | /* Remove the object from mdev list */ |
diff --git a/drivers/media/pci/bt8xx/bttv-cards.c b/drivers/media/pci/bt8xx/bttv-cards.c index a1b0f3193bc0..5cc42b426715 100644 --- a/drivers/media/pci/bt8xx/bttv-cards.c +++ b/drivers/media/pci/bt8xx/bttv-cards.c | |||
@@ -3717,7 +3717,7 @@ static void hauppauge_eeprom(struct bttv *btv) | |||
3717 | { | 3717 | { |
3718 | struct tveeprom tv; | 3718 | struct tveeprom tv; |
3719 | 3719 | ||
3720 | tveeprom_hauppauge_analog(&btv->i2c_client, &tv, eeprom_data); | 3720 | tveeprom_hauppauge_analog(&tv, eeprom_data); |
3721 | btv->tuner_type = tv.tuner_type; | 3721 | btv->tuner_type = tv.tuner_type; |
3722 | btv->has_radio = tv.has_radio; | 3722 | btv->has_radio = tv.has_radio; |
3723 | 3723 | ||
diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index fb4aefbcc8f8..ed319f18ba48 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c | |||
@@ -4043,9 +4043,7 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) | |||
4043 | INIT_LIST_HEAD(&btv->capture); | 4043 | INIT_LIST_HEAD(&btv->capture); |
4044 | INIT_LIST_HEAD(&btv->vcapture); | 4044 | INIT_LIST_HEAD(&btv->vcapture); |
4045 | 4045 | ||
4046 | init_timer(&btv->timeout); | 4046 | setup_timer(&btv->timeout, bttv_irq_timeout, (unsigned long)btv); |
4047 | btv->timeout.function = bttv_irq_timeout; | ||
4048 | btv->timeout.data = (unsigned long)btv; | ||
4049 | 4047 | ||
4050 | btv->i2c_rc = -1; | 4048 | btv->i2c_rc = -1; |
4051 | btv->tuner_type = UNSET; | 4049 | btv->tuner_type = UNSET; |
diff --git a/drivers/media/pci/cx18/cx18-driver.c b/drivers/media/pci/cx18/cx18-driver.c index 206db81ef78e..8bce49cdad46 100644 --- a/drivers/media/pci/cx18/cx18-driver.c +++ b/drivers/media/pci/cx18/cx18-driver.c | |||
@@ -339,7 +339,7 @@ void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv) | |||
339 | case CX18_CARD_HVR_1600_ESMT: | 339 | case CX18_CARD_HVR_1600_ESMT: |
340 | case CX18_CARD_HVR_1600_SAMSUNG: | 340 | case CX18_CARD_HVR_1600_SAMSUNG: |
341 | case CX18_CARD_HVR_1600_S5H1411: | 341 | case CX18_CARD_HVR_1600_S5H1411: |
342 | tveeprom_hauppauge_analog(c, tv, eedata); | 342 | tveeprom_hauppauge_analog(tv, eedata); |
343 | break; | 343 | break; |
344 | case CX18_CARD_YUAN_MPC718: | 344 | case CX18_CARD_YUAN_MPC718: |
345 | case CX18_CARD_GOTVIEW_PCI_DVD3: | 345 | case CX18_CARD_GOTVIEW_PCI_DVD3: |
diff --git a/drivers/media/pci/cx18/cx18-streams.c b/drivers/media/pci/cx18/cx18-streams.c index 7c9381448966..3c45e0071530 100644 --- a/drivers/media/pci/cx18/cx18-streams.c +++ b/drivers/media/pci/cx18/cx18-streams.c | |||
@@ -282,9 +282,7 @@ static void cx18_stream_init(struct cx18 *cx, int type) | |||
282 | INIT_WORK(&s->out_work_order, cx18_out_work_handler); | 282 | INIT_WORK(&s->out_work_order, cx18_out_work_handler); |
283 | 283 | ||
284 | INIT_LIST_HEAD(&s->vb_capture); | 284 | INIT_LIST_HEAD(&s->vb_capture); |
285 | s->vb_timeout.function = cx18_vb_timeout; | 285 | setup_timer(&s->vb_timeout, cx18_vb_timeout, (unsigned long)s); |
286 | s->vb_timeout.data = (unsigned long)s; | ||
287 | init_timer(&s->vb_timeout); | ||
288 | spin_lock_init(&s->vb_lock); | 286 | spin_lock_init(&s->vb_lock); |
289 | if (type == CX18_ENC_STREAM_TYPE_YUV) { | 287 | if (type == CX18_ENC_STREAM_TYPE_YUV) { |
290 | spin_lock_init(&s->vbuf_q_lock); | 288 | spin_lock_init(&s->vbuf_q_lock); |
diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index 0350f13c5a9f..9e39aea85df6 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c | |||
@@ -1143,8 +1143,7 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) | |||
1143 | { | 1143 | { |
1144 | struct tveeprom tv; | 1144 | struct tveeprom tv; |
1145 | 1145 | ||
1146 | tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv, | 1146 | tveeprom_hauppauge_analog(&tv, eeprom_data); |
1147 | eeprom_data); | ||
1148 | 1147 | ||
1149 | /* Make sure we support the board model */ | 1148 | /* Make sure we support the board model */ |
1150 | switch (tv.model) { | 1149 | switch (tv.model) { |
diff --git a/drivers/media/pci/cx88/cx88-cards.c b/drivers/media/pci/cx88/cx88-cards.c index cdfbde277b8b..73cc7a67a8bc 100644 --- a/drivers/media/pci/cx88/cx88-cards.c +++ b/drivers/media/pci/cx88/cx88-cards.c | |||
@@ -2854,7 +2854,7 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) | |||
2854 | { | 2854 | { |
2855 | struct tveeprom tv; | 2855 | struct tveeprom tv; |
2856 | 2856 | ||
2857 | tveeprom_hauppauge_analog(&core->i2c_client, &tv, eeprom_data); | 2857 | tveeprom_hauppauge_analog(&tv, eeprom_data); |
2858 | core->board.tuner_type = tv.tuner_type; | 2858 | core->board.tuner_type = tv.tuner_type; |
2859 | core->tuner_formats = tv.tuner_formats; | 2859 | core->tuner_formats = tv.tuner_formats; |
2860 | core->board.radio.type = tv.has_radio ? CX88_RADIO : 0; | 2860 | core->board.radio.type = tv.has_radio ? CX88_RADIO : 0; |
@@ -3670,7 +3670,7 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) | |||
3670 | if (!core) | 3670 | if (!core) |
3671 | return NULL; | 3671 | return NULL; |
3672 | 3672 | ||
3673 | atomic_inc(&core->refcount); | 3673 | refcount_set(&core->refcount, 1); |
3674 | core->pci_bus = pci->bus->number; | 3674 | core->pci_bus = pci->bus->number; |
3675 | core->pci_slot = PCI_SLOT(pci->devfn); | 3675 | core->pci_slot = PCI_SLOT(pci->devfn); |
3676 | core->pci_irqmask = PCI_INT_RISC_RD_BERRINT | PCI_INT_RISC_WR_BERRINT | | 3676 | core->pci_irqmask = PCI_INT_RISC_RD_BERRINT | PCI_INT_RISC_WR_BERRINT | |
diff --git a/drivers/media/pci/cx88/cx88-core.c b/drivers/media/pci/cx88/cx88-core.c index 973a9cd4c635..8bfa5b7ed91b 100644 --- a/drivers/media/pci/cx88/cx88-core.c +++ b/drivers/media/pci/cx88/cx88-core.c | |||
@@ -1052,7 +1052,7 @@ struct cx88_core *cx88_core_get(struct pci_dev *pci) | |||
1052 | mutex_unlock(&devlist); | 1052 | mutex_unlock(&devlist); |
1053 | return NULL; | 1053 | return NULL; |
1054 | } | 1054 | } |
1055 | atomic_inc(&core->refcount); | 1055 | refcount_inc(&core->refcount); |
1056 | mutex_unlock(&devlist); | 1056 | mutex_unlock(&devlist); |
1057 | return core; | 1057 | return core; |
1058 | } | 1058 | } |
@@ -1073,7 +1073,7 @@ void cx88_core_put(struct cx88_core *core, struct pci_dev *pci) | |||
1073 | release_mem_region(pci_resource_start(pci, 0), | 1073 | release_mem_region(pci_resource_start(pci, 0), |
1074 | pci_resource_len(pci, 0)); | 1074 | pci_resource_len(pci, 0)); |
1075 | 1075 | ||
1076 | if (!atomic_dec_and_test(&core->refcount)) | 1076 | if (!refcount_dec_and_test(&core->refcount)) |
1077 | return; | 1077 | return; |
1078 | 1078 | ||
1079 | mutex_lock(&devlist); | 1079 | mutex_lock(&devlist); |
diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c index ddf90678df34..49a335f4603e 100644 --- a/drivers/media/pci/cx88/cx88-dvb.c +++ b/drivers/media/pci/cx88/cx88-dvb.c | |||
@@ -306,7 +306,7 @@ static const struct zl10353_config cx88_terratec_cinergy_ht_pci_mkii_config = { | |||
306 | .if2 = 45600, | 306 | .if2 = 45600, |
307 | }; | 307 | }; |
308 | 308 | ||
309 | static struct mb86a16_config twinhan_vp1027 = { | 309 | static const struct mb86a16_config twinhan_vp1027 = { |
310 | .demod_address = 0x08, | 310 | .demod_address = 0x08, |
311 | }; | 311 | }; |
312 | 312 | ||
diff --git a/drivers/media/pci/cx88/cx88.h b/drivers/media/pci/cx88/cx88.h index 115414cf520f..6777926f20f2 100644 --- a/drivers/media/pci/cx88/cx88.h +++ b/drivers/media/pci/cx88/cx88.h | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/i2c-algo-bit.h> | 24 | #include <linux/i2c-algo-bit.h> |
25 | #include <linux/videodev2.h> | 25 | #include <linux/videodev2.h> |
26 | #include <linux/kdev_t.h> | 26 | #include <linux/kdev_t.h> |
27 | #include <linux/refcount.h> | ||
27 | 28 | ||
28 | #include <media/v4l2-device.h> | 29 | #include <media/v4l2-device.h> |
29 | #include <media/v4l2-fh.h> | 30 | #include <media/v4l2-fh.h> |
@@ -339,7 +340,7 @@ struct cx8802_dev; | |||
339 | 340 | ||
340 | struct cx88_core { | 341 | struct cx88_core { |
341 | struct list_head devlist; | 342 | struct list_head devlist; |
342 | atomic_t refcount; | 343 | refcount_t refcount; |
343 | 344 | ||
344 | /* board name */ | 345 | /* board name */ |
345 | int nr; | 346 | int nr; |
diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c index a7724b78fbb4..1d41934cfaf5 100644 --- a/drivers/media/pci/dm1105/dm1105.c +++ b/drivers/media/pci/dm1105/dm1105.c | |||
@@ -815,7 +815,7 @@ static void dm1105_hw_exit(struct dm1105_dev *dev) | |||
815 | dm1105_dma_unmap(dev); | 815 | dm1105_dma_unmap(dev); |
816 | } | 816 | } |
817 | 817 | ||
818 | static struct stv0299_config sharp_z0194a_config = { | 818 | static const struct stv0299_config sharp_z0194a_config = { |
819 | .demod_address = 0x68, | 819 | .demod_address = 0x68, |
820 | .inittab = sharp_z0194a_inittab, | 820 | .inittab = sharp_z0194a_inittab, |
821 | .mclk = 88000000UL, | 821 | .mclk = 88000000UL, |
diff --git a/drivers/media/pci/ivtv/ivtv-driver.c b/drivers/media/pci/ivtv/ivtv-driver.c index e73c153285f0..e8fa99b6c7b4 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.c +++ b/drivers/media/pci/ivtv/ivtv-driver.c | |||
@@ -409,7 +409,7 @@ void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv) | |||
409 | 409 | ||
410 | itv->i2c_client.addr = 0xA0 >> 1; | 410 | itv->i2c_client.addr = 0xA0 >> 1; |
411 | tveeprom_read(&itv->i2c_client, eedata, sizeof(eedata)); | 411 | tveeprom_read(&itv->i2c_client, eedata, sizeof(eedata)); |
412 | tveeprom_hauppauge_analog(&itv->i2c_client, tv, eedata); | 412 | tveeprom_hauppauge_analog(tv, eedata); |
413 | } | 413 | } |
414 | 414 | ||
415 | static void ivtv_process_eeprom(struct ivtv *itv) | 415 | static void ivtv_process_eeprom(struct ivtv *itv) |
@@ -770,9 +770,8 @@ static int ivtv_init_struct1(struct ivtv *itv) | |||
770 | init_waitqueue_head(&itv->event_waitq); | 770 | init_waitqueue_head(&itv->event_waitq); |
771 | init_waitqueue_head(&itv->vsync_waitq); | 771 | init_waitqueue_head(&itv->vsync_waitq); |
772 | init_waitqueue_head(&itv->dma_waitq); | 772 | init_waitqueue_head(&itv->dma_waitq); |
773 | init_timer(&itv->dma_timer); | 773 | setup_timer(&itv->dma_timer, ivtv_unfinished_dma, |
774 | itv->dma_timer.function = ivtv_unfinished_dma; | 774 | (unsigned long)itv); |
775 | itv->dma_timer.data = (unsigned long)itv; | ||
776 | 775 | ||
777 | itv->cur_dma_stream = -1; | 776 | itv->cur_dma_stream = -1; |
778 | itv->cur_pio_stream = -1; | 777 | itv->cur_pio_stream = -1; |
diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c index f956188f7f19..670462d195b5 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.c +++ b/drivers/media/pci/ivtv/ivtv-ioctl.c | |||
@@ -1506,10 +1506,8 @@ static int ivtv_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subs | |||
1506 | case V4L2_EVENT_VSYNC: | 1506 | case V4L2_EVENT_VSYNC: |
1507 | case V4L2_EVENT_EOS: | 1507 | case V4L2_EVENT_EOS: |
1508 | return v4l2_event_subscribe(fh, sub, 0, NULL); | 1508 | return v4l2_event_subscribe(fh, sub, 0, NULL); |
1509 | case V4L2_EVENT_CTRL: | ||
1510 | return v4l2_event_subscribe(fh, sub, 0, &v4l2_ctrl_sub_ev_ops); | ||
1511 | default: | 1509 | default: |
1512 | return -EINVAL; | 1510 | return v4l2_ctrl_subscribe_event(fh, sub); |
1513 | } | 1511 | } |
1514 | } | 1512 | } |
1515 | 1513 | ||
diff --git a/drivers/media/pci/ivtv/ivtv-udma.c b/drivers/media/pci/ivtv/ivtv-udma.c index 2c9232ef7baa..3b33e87ed73b 100644 --- a/drivers/media/pci/ivtv/ivtv-udma.c +++ b/drivers/media/pci/ivtv/ivtv-udma.c | |||
@@ -76,7 +76,7 @@ void ivtv_udma_fill_sg_array (struct ivtv_user_dma *dma, u32 buffer_offset, u32 | |||
76 | int i; | 76 | int i; |
77 | struct scatterlist *sg; | 77 | struct scatterlist *sg; |
78 | 78 | ||
79 | for (i = 0, sg = dma->SGlist; i < dma->SG_length; i++, sg = sg_next(sg)) { | 79 | for_each_sg(dma->SGlist, sg, dma->SG_length, i) { |
80 | dma->SGarray[i].size = cpu_to_le32(sg_dma_len(sg)); | 80 | dma->SGarray[i].size = cpu_to_le32(sg_dma_len(sg)); |
81 | dma->SGarray[i].src = cpu_to_le32(sg_dma_address(sg)); | 81 | dma->SGarray[i].src = cpu_to_le32(sg_dma_address(sg)); |
82 | dma->SGarray[i].dst = cpu_to_le32(buffer_offset); | 82 | dma->SGarray[i].dst = cpu_to_le32(buffer_offset); |
diff --git a/drivers/media/pci/mantis/mantis_vp1034.c b/drivers/media/pci/mantis/mantis_vp1034.c index 3b1928594b12..e4972ff823c2 100644 --- a/drivers/media/pci/mantis/mantis_vp1034.c +++ b/drivers/media/pci/mantis/mantis_vp1034.c | |||
@@ -36,7 +36,7 @@ | |||
36 | #include "mantis_vp1034.h" | 36 | #include "mantis_vp1034.h" |
37 | #include "mantis_reg.h" | 37 | #include "mantis_reg.h" |
38 | 38 | ||
39 | static struct mb86a16_config vp1034_mb86a16_config = { | 39 | static const struct mb86a16_config vp1034_mb86a16_config = { |
40 | .demod_address = 0x08, | 40 | .demod_address = 0x08, |
41 | .set_voltage = vp1034_set_voltage, | 41 | .set_voltage = vp1034_set_voltage, |
42 | }; | 42 | }; |
diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c index 191bd8299dc3..9444483fb942 100644 --- a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c +++ b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c | |||
@@ -663,9 +663,8 @@ static int netup_unidvb_dma_init(struct netup_unidvb_dev *ndev, int num) | |||
663 | spin_lock_init(&dma->lock); | 663 | spin_lock_init(&dma->lock); |
664 | INIT_WORK(&dma->work, netup_unidvb_dma_worker); | 664 | INIT_WORK(&dma->work, netup_unidvb_dma_worker); |
665 | INIT_LIST_HEAD(&dma->free_buffers); | 665 | INIT_LIST_HEAD(&dma->free_buffers); |
666 | dma->timeout.function = netup_unidvb_dma_timeout; | 666 | setup_timer(&dma->timeout, netup_unidvb_dma_timeout, |
667 | dma->timeout.data = (unsigned long)dma; | 667 | (unsigned long)dma); |
668 | init_timer(&dma->timeout); | ||
669 | dma->ring_buffer_size = ndev->dma_size / 2; | 668 | dma->ring_buffer_size = ndev->dma_size / 2; |
670 | dma->addr_virt = ndev->dma_virt + dma->ring_buffer_size * num; | 669 | dma->addr_virt = ndev->dma_virt + dma->ring_buffer_size * num; |
671 | dma->addr_phys = (dma_addr_t)((u64)ndev->dma_phys + | 670 | dma->addr_phys = (dma_addr_t)((u64)ndev->dma_phys + |
diff --git a/drivers/media/pci/saa7134/saa7134-cards.c b/drivers/media/pci/saa7134/saa7134-cards.c index 321253827997..f79380faf499 100644 --- a/drivers/media/pci/saa7134/saa7134-cards.c +++ b/drivers/media/pci/saa7134/saa7134-cards.c | |||
@@ -7319,7 +7319,7 @@ static void hauppauge_eeprom(struct saa7134_dev *dev, u8 *eeprom_data) | |||
7319 | { | 7319 | { |
7320 | struct tveeprom tv; | 7320 | struct tveeprom tv; |
7321 | 7321 | ||
7322 | tveeprom_hauppauge_analog(&dev->i2c_client, &tv, eeprom_data); | 7322 | tveeprom_hauppauge_analog(&tv, eeprom_data); |
7323 | 7323 | ||
7324 | /* Make sure we support the board model */ | 7324 | /* Make sure we support the board model */ |
7325 | switch (tv.model) { | 7325 | switch (tv.model) { |
diff --git a/drivers/media/pci/saa7134/saa7134-dvb.c b/drivers/media/pci/saa7134/saa7134-dvb.c index efdece5ab11c..731dee0a66e7 100644 --- a/drivers/media/pci/saa7134/saa7134-dvb.c +++ b/drivers/media/pci/saa7134/saa7134-dvb.c | |||
@@ -1042,11 +1042,11 @@ static int md8800_set_high_voltage2(struct dvb_frontend *fe, long arg) | |||
1042 | * nxt200x based ATSC cards, helper functions | 1042 | * nxt200x based ATSC cards, helper functions |
1043 | */ | 1043 | */ |
1044 | 1044 | ||
1045 | static struct nxt200x_config avertvhda180 = { | 1045 | static const struct nxt200x_config avertvhda180 = { |
1046 | .demod_address = 0x0a, | 1046 | .demod_address = 0x0a, |
1047 | }; | 1047 | }; |
1048 | 1048 | ||
1049 | static struct nxt200x_config kworldatsc110 = { | 1049 | static const struct nxt200x_config kworldatsc110 = { |
1050 | .demod_address = 0x0a, | 1050 | .demod_address = 0x0a, |
1051 | }; | 1051 | }; |
1052 | 1052 | ||
diff --git a/drivers/media/pci/saa7134/saa7134-ts.c b/drivers/media/pci/saa7134/saa7134-ts.c index 578e03f8c041..7414878af9e0 100644 --- a/drivers/media/pci/saa7134/saa7134-ts.c +++ b/drivers/media/pci/saa7134/saa7134-ts.c | |||
@@ -223,9 +223,8 @@ int saa7134_ts_init1(struct saa7134_dev *dev) | |||
223 | dev->ts.nr_packets = ts_nr_packets; | 223 | dev->ts.nr_packets = ts_nr_packets; |
224 | 224 | ||
225 | INIT_LIST_HEAD(&dev->ts_q.queue); | 225 | INIT_LIST_HEAD(&dev->ts_q.queue); |
226 | init_timer(&dev->ts_q.timeout); | 226 | setup_timer(&dev->ts_q.timeout, saa7134_buffer_timeout, |
227 | dev->ts_q.timeout.function = saa7134_buffer_timeout; | 227 | (unsigned long)(&dev->ts_q)); |
228 | dev->ts_q.timeout.data = (unsigned long)(&dev->ts_q); | ||
229 | dev->ts_q.dev = dev; | 228 | dev->ts_q.dev = dev; |
230 | dev->ts_q.need_two = 1; | 229 | dev->ts_q.need_two = 1; |
231 | dev->ts_started = 0; | 230 | dev->ts_started = 0; |
diff --git a/drivers/media/pci/saa7134/saa7134-vbi.c b/drivers/media/pci/saa7134/saa7134-vbi.c index 46193370e41a..bcad9b2d9bb3 100644 --- a/drivers/media/pci/saa7134/saa7134-vbi.c +++ b/drivers/media/pci/saa7134/saa7134-vbi.c | |||
@@ -181,9 +181,8 @@ struct vb2_ops saa7134_vbi_qops = { | |||
181 | int saa7134_vbi_init1(struct saa7134_dev *dev) | 181 | int saa7134_vbi_init1(struct saa7134_dev *dev) |
182 | { | 182 | { |
183 | INIT_LIST_HEAD(&dev->vbi_q.queue); | 183 | INIT_LIST_HEAD(&dev->vbi_q.queue); |
184 | init_timer(&dev->vbi_q.timeout); | 184 | setup_timer(&dev->vbi_q.timeout, saa7134_buffer_timeout, |
185 | dev->vbi_q.timeout.function = saa7134_buffer_timeout; | 185 | (unsigned long)(&dev->vbi_q)); |
186 | dev->vbi_q.timeout.data = (unsigned long)(&dev->vbi_q); | ||
187 | dev->vbi_q.dev = dev; | 186 | dev->vbi_q.dev = dev; |
188 | 187 | ||
189 | if (vbibufs < 2) | 188 | if (vbibufs < 2) |
diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 4b1c4327f112..51d42bbf969e 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c | |||
@@ -2145,9 +2145,8 @@ int saa7134_video_init1(struct saa7134_dev *dev) | |||
2145 | dev->automute = 0; | 2145 | dev->automute = 0; |
2146 | 2146 | ||
2147 | INIT_LIST_HEAD(&dev->video_q.queue); | 2147 | INIT_LIST_HEAD(&dev->video_q.queue); |
2148 | init_timer(&dev->video_q.timeout); | 2148 | setup_timer(&dev->video_q.timeout, saa7134_buffer_timeout, |
2149 | dev->video_q.timeout.function = saa7134_buffer_timeout; | 2149 | (unsigned long)(&dev->video_q)); |
2150 | dev->video_q.timeout.data = (unsigned long)(&dev->video_q); | ||
2151 | dev->video_q.dev = dev; | 2150 | dev->video_q.dev = dev; |
2152 | dev->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); | 2151 | dev->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); |
2153 | dev->width = 720; | 2152 | dev->width = 720; |
diff --git a/drivers/media/pci/saa7164/saa7164-cards.c b/drivers/media/pci/saa7164/saa7164-cards.c index 0e1cd7e153ca..3af16062e79d 100644 --- a/drivers/media/pci/saa7164/saa7164-cards.c +++ b/drivers/media/pci/saa7164/saa7164-cards.c | |||
@@ -780,9 +780,7 @@ static void hauppauge_eeprom(struct saa7164_dev *dev, u8 *eeprom_data) | |||
780 | { | 780 | { |
781 | struct tveeprom tv; | 781 | struct tveeprom tv; |
782 | 782 | ||
783 | /* TODO: Assumption: eeprom on bus 0 */ | 783 | tveeprom_hauppauge_analog(&tv, eeprom_data); |
784 | tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv, | ||
785 | eeprom_data); | ||
786 | 784 | ||
787 | /* Make sure we support the board model */ | 785 | /* Make sure we support the board model */ |
788 | switch (tv.model) { | 786 | switch (tv.model) { |
diff --git a/drivers/media/pci/saa7164/saa7164-cmd.c b/drivers/media/pci/saa7164/saa7164-cmd.c index f55c177fd1e4..175015ca79f2 100644 --- a/drivers/media/pci/saa7164/saa7164-cmd.c +++ b/drivers/media/pci/saa7164/saa7164-cmd.c | |||
@@ -130,14 +130,13 @@ int saa7164_irq_dequeue(struct saa7164_dev *dev) | |||
130 | * -bus/c running buffer. */ | 130 | * -bus/c running buffer. */ |
131 | static int saa7164_cmd_dequeue(struct saa7164_dev *dev) | 131 | static int saa7164_cmd_dequeue(struct saa7164_dev *dev) |
132 | { | 132 | { |
133 | int loop = 1; | ||
134 | int ret; | 133 | int ret; |
135 | u32 timeout; | 134 | u32 timeout; |
136 | wait_queue_head_t *q = NULL; | 135 | wait_queue_head_t *q = NULL; |
137 | u8 tmp[512]; | 136 | u8 tmp[512]; |
138 | dprintk(DBGLVL_CMD, "%s()\n", __func__); | 137 | dprintk(DBGLVL_CMD, "%s()\n", __func__); |
139 | 138 | ||
140 | while (loop) { | 139 | while (true) { |
141 | 140 | ||
142 | struct tmComResInfo tRsp = { 0, 0, 0, 0, 0, 0 }; | 141 | struct tmComResInfo tRsp = { 0, 0, 0, 0, 0, 0 }; |
143 | ret = saa7164_bus_get(dev, &tRsp, NULL, 1); | 142 | ret = saa7164_bus_get(dev, &tRsp, NULL, 1); |
@@ -178,8 +177,6 @@ static int saa7164_cmd_dequeue(struct saa7164_dev *dev) | |||
178 | wake_up(q); | 177 | wake_up(q); |
179 | return SAA_OK; | 178 | return SAA_OK; |
180 | } | 179 | } |
181 | |||
182 | return SAA_OK; | ||
183 | } | 180 | } |
184 | 181 | ||
185 | static int saa7164_cmd_set(struct saa7164_dev *dev, struct tmComResInfo *msg, | 182 | static int saa7164_cmd_set(struct saa7164_dev *dev, struct tmComResInfo *msg, |
diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c index 25a2137ab799..25f9f2ebff1d 100644 --- a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c +++ b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c | |||
@@ -1140,14 +1140,13 @@ static int solo_subscribe_event(struct v4l2_fh *fh, | |||
1140 | { | 1140 | { |
1141 | 1141 | ||
1142 | switch (sub->type) { | 1142 | switch (sub->type) { |
1143 | case V4L2_EVENT_CTRL: | ||
1144 | return v4l2_ctrl_subscribe_event(fh, sub); | ||
1145 | case V4L2_EVENT_MOTION_DET: | 1143 | case V4L2_EVENT_MOTION_DET: |
1146 | /* Allow for up to 30 events (1 second for NTSC) to be | 1144 | /* Allow for up to 30 events (1 second for NTSC) to be |
1147 | * stored. */ | 1145 | * stored. */ |
1148 | return v4l2_event_subscribe(fh, sub, 30, NULL); | 1146 | return v4l2_event_subscribe(fh, sub, 30, NULL); |
1147 | default: | ||
1148 | return v4l2_ctrl_subscribe_event(fh, sub); | ||
1149 | } | 1149 | } |
1150 | return -EINVAL; | ||
1151 | } | 1150 | } |
1152 | 1151 | ||
1153 | static const struct v4l2_file_operations solo_enc_fops = { | 1152 | static const struct v4l2_file_operations solo_enc_fops = { |
diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2.c b/drivers/media/pci/solo6x10/solo6x10-v4l2.c index 896bec6627aa..3266fc21825f 100644 --- a/drivers/media/pci/solo6x10/solo6x10-v4l2.c +++ b/drivers/media/pci/solo6x10/solo6x10-v4l2.c | |||
@@ -341,6 +341,17 @@ static void solo_stop_streaming(struct vb2_queue *q) | |||
341 | struct solo_dev *solo_dev = vb2_get_drv_priv(q); | 341 | struct solo_dev *solo_dev = vb2_get_drv_priv(q); |
342 | 342 | ||
343 | solo_stop_thread(solo_dev); | 343 | solo_stop_thread(solo_dev); |
344 | |||
345 | spin_lock(&solo_dev->slock); | ||
346 | while (!list_empty(&solo_dev->vidq_active)) { | ||
347 | struct solo_vb2_buf *buf = list_entry( | ||
348 | solo_dev->vidq_active.next, | ||
349 | struct solo_vb2_buf, list); | ||
350 | |||
351 | list_del(&buf->list); | ||
352 | vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); | ||
353 | } | ||
354 | spin_unlock(&solo_dev->slock); | ||
344 | INIT_LIST_HEAD(&solo_dev->vidq_active); | 355 | INIT_LIST_HEAD(&solo_dev->vidq_active); |
345 | } | 356 | } |
346 | 357 | ||
diff --git a/drivers/media/pci/ttpci/av7110_ir.c b/drivers/media/pci/ttpci/av7110_ir.c index 10e28f067b45..ca05198de2c2 100644 --- a/drivers/media/pci/ttpci/av7110_ir.c +++ b/drivers/media/pci/ttpci/av7110_ir.c | |||
@@ -333,9 +333,8 @@ int av7110_ir_init(struct av7110 *av7110) | |||
333 | av_list[av_cnt++] = av7110; | 333 | av_list[av_cnt++] = av7110; |
334 | av7110_check_ir_config(av7110, true); | 334 | av7110_check_ir_config(av7110, true); |
335 | 335 | ||
336 | init_timer(&av7110->ir.keyup_timer); | 336 | setup_timer(&av7110->ir.keyup_timer, av7110_emit_keyup, |
337 | av7110->ir.keyup_timer.function = av7110_emit_keyup; | 337 | (unsigned long)&av7110->ir); |
338 | av7110->ir.keyup_timer.data = (unsigned long) &av7110->ir; | ||
339 | 338 | ||
340 | input_dev = input_allocate_device(); | 339 | input_dev = input_allocate_device(); |
341 | if (!input_dev) | 340 | if (!input_dev) |
diff --git a/drivers/media/pci/ttpci/budget-av.c b/drivers/media/pci/ttpci/budget-av.c index 19f07d4aba6a..dc7be8fac9a3 100644 --- a/drivers/media/pci/ttpci/budget-av.c +++ b/drivers/media/pci/ttpci/budget-av.c | |||
@@ -577,7 +577,7 @@ static u8 typhoon_cinergy1200s_inittab[] = { | |||
577 | 0xff, 0xff | 577 | 0xff, 0xff |
578 | }; | 578 | }; |
579 | 579 | ||
580 | static struct stv0299_config typhoon_config = { | 580 | static const struct stv0299_config typhoon_config = { |
581 | .demod_address = 0x68, | 581 | .demod_address = 0x68, |
582 | .inittab = typhoon_cinergy1200s_inittab, | 582 | .inittab = typhoon_cinergy1200s_inittab, |
583 | .mclk = 88000000UL, | 583 | .mclk = 88000000UL, |
@@ -590,7 +590,7 @@ static struct stv0299_config typhoon_config = { | |||
590 | }; | 590 | }; |
591 | 591 | ||
592 | 592 | ||
593 | static struct stv0299_config cinergy_1200s_config = { | 593 | static const struct stv0299_config cinergy_1200s_config = { |
594 | .demod_address = 0x68, | 594 | .demod_address = 0x68, |
595 | .inittab = typhoon_cinergy1200s_inittab, | 595 | .inittab = typhoon_cinergy1200s_inittab, |
596 | .mclk = 88000000UL, | 596 | .mclk = 88000000UL, |
@@ -602,7 +602,7 @@ static struct stv0299_config cinergy_1200s_config = { | |||
602 | .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate, | 602 | .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate, |
603 | }; | 603 | }; |
604 | 604 | ||
605 | static struct stv0299_config cinergy_1200s_1894_0010_config = { | 605 | static const struct stv0299_config cinergy_1200s_1894_0010_config = { |
606 | .demod_address = 0x68, | 606 | .demod_address = 0x68, |
607 | .inittab = typhoon_cinergy1200s_inittab, | 607 | .inittab = typhoon_cinergy1200s_inittab, |
608 | .mclk = 88000000UL, | 608 | .mclk = 88000000UL, |
@@ -876,7 +876,7 @@ static int philips_sd1878_ci_set_symbol_rate(struct dvb_frontend *fe, | |||
876 | return 0; | 876 | return 0; |
877 | } | 877 | } |
878 | 878 | ||
879 | static struct stv0299_config philips_sd1878_config = { | 879 | static const struct stv0299_config philips_sd1878_config = { |
880 | .demod_address = 0x68, | 880 | .demod_address = 0x68, |
881 | .inittab = philips_sd1878_inittab, | 881 | .inittab = philips_sd1878_inittab, |
882 | .mclk = 88000000UL, | 882 | .mclk = 88000000UL, |
diff --git a/drivers/media/pci/ttpci/budget-ci.c b/drivers/media/pci/ttpci/budget-ci.c index 68355484ba7d..11b9227307bf 100644 --- a/drivers/media/pci/ttpci/budget-ci.c +++ b/drivers/media/pci/ttpci/budget-ci.c | |||
@@ -693,7 +693,7 @@ static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe) | |||
693 | return 0; | 693 | return 0; |
694 | } | 694 | } |
695 | 695 | ||
696 | static struct stv0299_config philips_su1278_tt_config = { | 696 | static const struct stv0299_config philips_su1278_tt_config = { |
697 | 697 | ||
698 | .demod_address = 0x68, | 698 | .demod_address = 0x68, |
699 | .inittab = philips_su1278_tt_inittab, | 699 | .inittab = philips_su1278_tt_inittab, |
diff --git a/drivers/media/pci/ttpci/budget.c b/drivers/media/pci/ttpci/budget.c index 5f17e1c9a207..81fe35cedd10 100644 --- a/drivers/media/pci/ttpci/budget.c +++ b/drivers/media/pci/ttpci/budget.c | |||
@@ -397,7 +397,7 @@ static struct tda10086_config tda10086_config = { | |||
397 | .xtal_freq = TDA10086_XTAL_16M, | 397 | .xtal_freq = TDA10086_XTAL_16M, |
398 | }; | 398 | }; |
399 | 399 | ||
400 | static struct stv0299_config alps_bsru6_config_activy = { | 400 | static const struct stv0299_config alps_bsru6_config_activy = { |
401 | .demod_address = 0x68, | 401 | .demod_address = 0x68, |
402 | .inittab = alps_bsru6_inittab, | 402 | .inittab = alps_bsru6_inittab, |
403 | .mclk = 88000000UL, | 403 | .mclk = 88000000UL, |
@@ -407,7 +407,7 @@ static struct stv0299_config alps_bsru6_config_activy = { | |||
407 | .set_symbol_rate = alps_bsru6_set_symbol_rate, | 407 | .set_symbol_rate = alps_bsru6_set_symbol_rate, |
408 | }; | 408 | }; |
409 | 409 | ||
410 | static struct stv0299_config alps_bsbe1_config_activy = { | 410 | static const struct stv0299_config alps_bsbe1_config_activy = { |
411 | .demod_address = 0x68, | 411 | .demod_address = 0x68, |
412 | .inittab = alps_bsbe1_inittab, | 412 | .inittab = alps_bsbe1_inittab, |
413 | .mclk = 88000000UL, | 413 | .mclk = 88000000UL, |
diff --git a/drivers/media/pci/tw5864/tw5864-video.c b/drivers/media/pci/tw5864/tw5864-video.c index 9421216bb942..2a044be729da 100644 --- a/drivers/media/pci/tw5864/tw5864-video.c +++ b/drivers/media/pci/tw5864/tw5864-video.c | |||
@@ -664,15 +664,14 @@ static int tw5864_subscribe_event(struct v4l2_fh *fh, | |||
664 | const struct v4l2_event_subscription *sub) | 664 | const struct v4l2_event_subscription *sub) |
665 | { | 665 | { |
666 | switch (sub->type) { | 666 | switch (sub->type) { |
667 | case V4L2_EVENT_CTRL: | ||
668 | return v4l2_ctrl_subscribe_event(fh, sub); | ||
669 | case V4L2_EVENT_MOTION_DET: | 667 | case V4L2_EVENT_MOTION_DET: |
670 | /* | 668 | /* |
671 | * Allow for up to 30 events (1 second for NTSC) to be stored. | 669 | * Allow for up to 30 events (1 second for NTSC) to be stored. |
672 | */ | 670 | */ |
673 | return v4l2_event_subscribe(fh, sub, 30, NULL); | 671 | return v4l2_event_subscribe(fh, sub, 30, NULL); |
672 | default: | ||
673 | return v4l2_ctrl_subscribe_event(fh, sub); | ||
674 | } | 674 | } |
675 | return -EINVAL; | ||
676 | } | 675 | } |
677 | 676 | ||
678 | static void tw5864_frame_interval_set(struct tw5864_input *input) | 677 | static void tw5864_frame_interval_set(struct tw5864_input *input) |
@@ -717,6 +716,8 @@ static void tw5864_frame_interval_set(struct tw5864_input *input) | |||
717 | static int tw5864_frameinterval_get(struct tw5864_input *input, | 716 | static int tw5864_frameinterval_get(struct tw5864_input *input, |
718 | struct v4l2_fract *frameinterval) | 717 | struct v4l2_fract *frameinterval) |
719 | { | 718 | { |
719 | struct tw5864_dev *dev = input->root; | ||
720 | |||
720 | switch (input->std) { | 721 | switch (input->std) { |
721 | case STD_NTSC: | 722 | case STD_NTSC: |
722 | frameinterval->numerator = 1001; | 723 | frameinterval->numerator = 1001; |
@@ -728,8 +729,8 @@ static int tw5864_frameinterval_get(struct tw5864_input *input, | |||
728 | frameinterval->denominator = 25; | 729 | frameinterval->denominator = 25; |
729 | break; | 730 | break; |
730 | default: | 731 | default: |
731 | WARN(1, "tw5864_frameinterval_get requested for unknown std %d\n", | 732 | dev_warn(&dev->pci->dev, "tw5864_frameinterval_get requested for unknown std %d\n", |
732 | input->std); | 733 | input->std); |
733 | return -EINVAL; | 734 | return -EINVAL; |
734 | } | 735 | } |
735 | 736 | ||
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index c9106e105bab..ac026ee1ca07 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig | |||
@@ -151,7 +151,7 @@ if V4L_MEM2MEM_DRIVERS | |||
151 | 151 | ||
152 | config VIDEO_CODA | 152 | config VIDEO_CODA |
153 | tristate "Chips&Media Coda multi-standard codec IP" | 153 | tristate "Chips&Media Coda multi-standard codec IP" |
154 | depends on VIDEO_DEV && VIDEO_V4L2 && ARCH_MXC | 154 | depends on VIDEO_DEV && VIDEO_V4L2 && (ARCH_MXC || COMPILE_TEST) |
155 | depends on HAS_DMA | 155 | depends on HAS_DMA |
156 | select SRAM | 156 | select SRAM |
157 | select VIDEOBUF2_DMA_CONTIG | 157 | select VIDEOBUF2_DMA_CONTIG |
@@ -165,6 +165,21 @@ config VIDEO_CODA | |||
165 | config VIDEO_IMX_VDOA | 165 | config VIDEO_IMX_VDOA |
166 | def_tristate VIDEO_CODA if SOC_IMX6Q || COMPILE_TEST | 166 | def_tristate VIDEO_CODA if SOC_IMX6Q || COMPILE_TEST |
167 | 167 | ||
168 | config VIDEO_MEDIATEK_JPEG | ||
169 | tristate "Mediatek JPEG Codec driver" | ||
170 | depends on MTK_IOMMU_V1 || COMPILE_TEST | ||
171 | depends on VIDEO_DEV && VIDEO_V4L2 | ||
172 | depends on ARCH_MEDIATEK || COMPILE_TEST | ||
173 | depends on HAS_DMA | ||
174 | select VIDEOBUF2_DMA_CONTIG | ||
175 | select V4L2_MEM2MEM_DEV | ||
176 | ---help--- | ||
177 | Mediatek jpeg codec driver provides HW capability to decode | ||
178 | JPEG format | ||
179 | |||
180 | To compile this driver as a module, choose M here: the | ||
181 | module will be called mtk-jpeg | ||
182 | |||
168 | config VIDEO_MEDIATEK_VPU | 183 | config VIDEO_MEDIATEK_VPU |
169 | tristate "Mediatek Video Processor Unit" | 184 | tristate "Mediatek Video Processor Unit" |
170 | depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA | 185 | depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA |
@@ -405,6 +420,7 @@ config VIDEO_RENESAS_VSP1 | |||
405 | depends on (ARCH_RENESAS && OF) || COMPILE_TEST | 420 | depends on (ARCH_RENESAS && OF) || COMPILE_TEST |
406 | depends on (!ARM64 && !VIDEO_RENESAS_FCP) || VIDEO_RENESAS_FCP | 421 | depends on (!ARM64 && !VIDEO_RENESAS_FCP) || VIDEO_RENESAS_FCP |
407 | select VIDEOBUF2_DMA_CONTIG | 422 | select VIDEOBUF2_DMA_CONTIG |
423 | select VIDEOBUF2_VMALLOC | ||
408 | ---help--- | 424 | ---help--- |
409 | This is a V4L2 driver for the Renesas VSP1 video processing engine. | 425 | This is a V4L2 driver for the Renesas VSP1 video processing engine. |
410 | 426 | ||
@@ -451,6 +467,8 @@ menuconfig V4L_TEST_DRIVERS | |||
451 | 467 | ||
452 | if V4L_TEST_DRIVERS | 468 | if V4L_TEST_DRIVERS |
453 | 469 | ||
470 | source "drivers/media/platform/vimc/Kconfig" | ||
471 | |||
454 | source "drivers/media/platform/vivid/Kconfig" | 472 | source "drivers/media/platform/vivid/Kconfig" |
455 | 473 | ||
456 | config VIDEO_VIM2M | 474 | config VIDEO_VIM2M |
@@ -474,3 +492,31 @@ menuconfig DVB_PLATFORM_DRIVERS | |||
474 | if DVB_PLATFORM_DRIVERS | 492 | if DVB_PLATFORM_DRIVERS |
475 | source "drivers/media/platform/sti/c8sectpfe/Kconfig" | 493 | source "drivers/media/platform/sti/c8sectpfe/Kconfig" |
476 | endif #DVB_PLATFORM_DRIVERS | 494 | endif #DVB_PLATFORM_DRIVERS |
495 | |||
496 | menuconfig CEC_PLATFORM_DRIVERS | ||
497 | bool "CEC platform devices" | ||
498 | depends on MEDIA_CEC_SUPPORT | ||
499 | |||
500 | if CEC_PLATFORM_DRIVERS | ||
501 | |||
502 | config VIDEO_SAMSUNG_S5P_CEC | ||
503 | tristate "Samsung S5P CEC driver" | ||
504 | depends on CEC_CORE && (PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST) | ||
505 | select MEDIA_CEC_NOTIFIER | ||
506 | ---help--- | ||
507 | This is a driver for Samsung S5P HDMI CEC interface. It uses the | ||
508 | generic CEC framework interface. | ||
509 | CEC bus is present in the HDMI connector and enables communication | ||
510 | between compatible devices. | ||
511 | |||
512 | config VIDEO_STI_HDMI_CEC | ||
513 | tristate "STMicroelectronics STiH4xx HDMI CEC driver" | ||
514 | depends on CEC_CORE && (ARCH_STI || COMPILE_TEST) | ||
515 | select MEDIA_CEC_NOTIFIER | ||
516 | ---help--- | ||
517 | This is a driver for STIH4xx HDMI CEC interface. It uses the | ||
518 | generic CEC framework interface. | ||
519 | CEC bus is present in the HDMI connector and enables communication | ||
520 | between compatible devices. | ||
521 | |||
522 | endif #CEC_PLATFORM_DRIVERS | ||
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 349ddf6a69da..63303d63c64c 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile | |||
@@ -13,6 +13,7 @@ obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o | |||
13 | 13 | ||
14 | obj-$(CONFIG_VIDEO_VIU) += fsl-viu.o | 14 | obj-$(CONFIG_VIDEO_VIU) += fsl-viu.o |
15 | 15 | ||
16 | obj-$(CONFIG_VIDEO_VIMC) += vimc/ | ||
16 | obj-$(CONFIG_VIDEO_VIVID) += vivid/ | 17 | obj-$(CONFIG_VIDEO_VIVID) += vivid/ |
17 | obj-$(CONFIG_VIDEO_VIM2M) += vim2m.o | 18 | obj-$(CONFIG_VIDEO_VIM2M) += vim2m.o |
18 | 19 | ||
@@ -33,11 +34,13 @@ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += s5p-jpeg/ | |||
33 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) += s5p-mfc/ | 34 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) += s5p-mfc/ |
34 | 35 | ||
35 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D) += s5p-g2d/ | 36 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D) += s5p-g2d/ |
37 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_CEC) += s5p-cec/ | ||
36 | obj-$(CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC) += exynos-gsc/ | 38 | obj-$(CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC) += exynos-gsc/ |
37 | 39 | ||
38 | obj-$(CONFIG_VIDEO_STI_BDISP) += sti/bdisp/ | 40 | obj-$(CONFIG_VIDEO_STI_BDISP) += sti/bdisp/ |
39 | obj-$(CONFIG_VIDEO_STI_HVA) += sti/hva/ | 41 | obj-$(CONFIG_VIDEO_STI_HVA) += sti/hva/ |
40 | obj-$(CONFIG_DVB_C8SECTPFE) += sti/c8sectpfe/ | 42 | obj-$(CONFIG_DVB_C8SECTPFE) += sti/c8sectpfe/ |
43 | obj-$(CONFIG_VIDEO_STI_HDMI_CEC) += sti/cec/ | ||
41 | 44 | ||
42 | obj-$(CONFIG_VIDEO_STI_DELTA) += sti/delta/ | 45 | obj-$(CONFIG_VIDEO_STI_DELTA) += sti/delta/ |
43 | 46 | ||
@@ -63,6 +66,7 @@ obj-$(CONFIG_VIDEO_XILINX) += xilinx/ | |||
63 | obj-$(CONFIG_VIDEO_RCAR_VIN) += rcar-vin/ | 66 | obj-$(CONFIG_VIDEO_RCAR_VIN) += rcar-vin/ |
64 | 67 | ||
65 | obj-$(CONFIG_VIDEO_ATMEL_ISC) += atmel/ | 68 | obj-$(CONFIG_VIDEO_ATMEL_ISC) += atmel/ |
69 | obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel/ | ||
66 | 70 | ||
67 | ccflags-y += -I$(srctree)/drivers/media/i2c | 71 | ccflags-y += -I$(srctree)/drivers/media/i2c |
68 | 72 | ||
@@ -71,3 +75,5 @@ obj-$(CONFIG_VIDEO_MEDIATEK_VPU) += mtk-vpu/ | |||
71 | obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec/ | 75 | obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec/ |
72 | 76 | ||
73 | obj-$(CONFIG_VIDEO_MEDIATEK_MDP) += mtk-mdp/ | 77 | obj-$(CONFIG_VIDEO_MEDIATEK_MDP) += mtk-mdp/ |
78 | |||
79 | obj-$(CONFIG_VIDEO_MEDIATEK_JPEG) += mtk-jpeg/ | ||
diff --git a/drivers/media/platform/atmel/Kconfig b/drivers/media/platform/atmel/Kconfig index 867dca22a473..9bd0f19b127f 100644 --- a/drivers/media/platform/atmel/Kconfig +++ b/drivers/media/platform/atmel/Kconfig | |||
@@ -6,4 +6,13 @@ config VIDEO_ATMEL_ISC | |||
6 | select REGMAP_MMIO | 6 | select REGMAP_MMIO |
7 | help | 7 | help |
8 | This module makes the ATMEL Image Sensor Controller available | 8 | This module makes the ATMEL Image Sensor Controller available |
9 | as a v4l2 device. \ No newline at end of file | 9 | as a v4l2 device. |
10 | |||
11 | config VIDEO_ATMEL_ISI | ||
12 | tristate "ATMEL Image Sensor Interface (ISI) support" | ||
13 | depends on VIDEO_V4L2 && OF && HAS_DMA | ||
14 | depends on ARCH_AT91 || COMPILE_TEST | ||
15 | select VIDEOBUF2_DMA_CONTIG | ||
16 | ---help--- | ||
17 | This module makes the ATMEL Image Sensor Interface available | ||
18 | as a v4l2 device. | ||
diff --git a/drivers/media/platform/atmel/Makefile b/drivers/media/platform/atmel/Makefile index 9d7c999d434d..27000d099a5e 100644 --- a/drivers/media/platform/atmel/Makefile +++ b/drivers/media/platform/atmel/Makefile | |||
@@ -1 +1,2 @@ | |||
1 | obj-$(CONFIG_VIDEO_ATMEL_ISC) += atmel-isc.o | 1 | obj-$(CONFIG_VIDEO_ATMEL_ISC) += atmel-isc.o |
2 | obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o | ||
diff --git a/drivers/media/platform/atmel/atmel-isc-regs.h b/drivers/media/platform/atmel/atmel-isc-regs.h index 00c449717cde..6936ac467609 100644 --- a/drivers/media/platform/atmel/atmel-isc-regs.h +++ b/drivers/media/platform/atmel/atmel-isc-regs.h | |||
@@ -65,6 +65,7 @@ | |||
65 | #define ISC_INTSR 0x00000034 | 65 | #define ISC_INTSR 0x00000034 |
66 | 66 | ||
67 | #define ISC_INT_DDONE BIT(8) | 67 | #define ISC_INT_DDONE BIT(8) |
68 | #define ISC_INT_HISDONE BIT(12) | ||
68 | 69 | ||
69 | /* ISC White Balance Control Register */ | 70 | /* ISC White Balance Control Register */ |
70 | #define ISC_WB_CTRL 0x00000058 | 71 | #define ISC_WB_CTRL 0x00000058 |
@@ -72,30 +73,98 @@ | |||
72 | /* ISC White Balance Configuration Register */ | 73 | /* ISC White Balance Configuration Register */ |
73 | #define ISC_WB_CFG 0x0000005c | 74 | #define ISC_WB_CFG 0x0000005c |
74 | 75 | ||
76 | /* ISC White Balance Offset for R, GR Register */ | ||
77 | #define ISC_WB_O_RGR 0x00000060 | ||
78 | |||
79 | /* ISC White Balance Offset for B, GB Register */ | ||
80 | #define ISC_WB_O_BGR 0x00000064 | ||
81 | |||
82 | /* ISC White Balance Gain for R, GR Register */ | ||
83 | #define ISC_WB_G_RGR 0x00000068 | ||
84 | |||
85 | /* ISC White Balance Gain for B, GB Register */ | ||
86 | #define ISC_WB_G_BGR 0x0000006c | ||
87 | |||
75 | /* ISC Color Filter Array Control Register */ | 88 | /* ISC Color Filter Array Control Register */ |
76 | #define ISC_CFA_CTRL 0x00000070 | 89 | #define ISC_CFA_CTRL 0x00000070 |
77 | 90 | ||
78 | /* ISC Color Filter Array Configuration Register */ | 91 | /* ISC Color Filter Array Configuration Register */ |
79 | #define ISC_CFA_CFG 0x00000074 | 92 | #define ISC_CFA_CFG 0x00000074 |
93 | #define ISC_CFA_CFG_EITPOL BIT(4) | ||
80 | 94 | ||
81 | #define ISC_BAY_CFG_GRGR 0x0 | 95 | #define ISC_BAY_CFG_GRGR 0x0 |
82 | #define ISC_BAY_CFG_RGRG 0x1 | 96 | #define ISC_BAY_CFG_RGRG 0x1 |
83 | #define ISC_BAY_CFG_GBGB 0x2 | 97 | #define ISC_BAY_CFG_GBGB 0x2 |
84 | #define ISC_BAY_CFG_BGBG 0x3 | 98 | #define ISC_BAY_CFG_BGBG 0x3 |
85 | #define ISC_BAY_CFG_MASK GENMASK(1, 0) | ||
86 | 99 | ||
87 | /* ISC Color Correction Control Register */ | 100 | /* ISC Color Correction Control Register */ |
88 | #define ISC_CC_CTRL 0x00000078 | 101 | #define ISC_CC_CTRL 0x00000078 |
89 | 102 | ||
103 | /* ISC Color Correction RR RG Register */ | ||
104 | #define ISC_CC_RR_RG 0x0000007c | ||
105 | |||
106 | /* ISC Color Correction RB OR Register */ | ||
107 | #define ISC_CC_RB_OR 0x00000080 | ||
108 | |||
109 | /* ISC Color Correction GR GG Register */ | ||
110 | #define ISC_CC_GR_GG 0x00000084 | ||
111 | |||
112 | /* ISC Color Correction GB OG Register */ | ||
113 | #define ISC_CC_GB_OG 0x00000088 | ||
114 | |||
115 | /* ISC Color Correction BR BG Register */ | ||
116 | #define ISC_CC_BR_BG 0x0000008c | ||
117 | |||
118 | /* ISC Color Correction BB OB Register */ | ||
119 | #define ISC_CC_BB_OB 0x00000090 | ||
120 | |||
90 | /* ISC Gamma Correction Control Register */ | 121 | /* ISC Gamma Correction Control Register */ |
91 | #define ISC_GAM_CTRL 0x00000094 | 122 | #define ISC_GAM_CTRL 0x00000094 |
92 | 123 | ||
124 | /* ISC_Gamma Correction Blue Entry Register */ | ||
125 | #define ISC_GAM_BENTRY 0x00000098 | ||
126 | |||
127 | /* ISC_Gamma Correction Green Entry Register */ | ||
128 | #define ISC_GAM_GENTRY 0x00000198 | ||
129 | |||
130 | /* ISC_Gamma Correction Green Entry Register */ | ||
131 | #define ISC_GAM_RENTRY 0x00000298 | ||
132 | |||
93 | /* Color Space Conversion Control Register */ | 133 | /* Color Space Conversion Control Register */ |
94 | #define ISC_CSC_CTRL 0x00000398 | 134 | #define ISC_CSC_CTRL 0x00000398 |
95 | 135 | ||
136 | /* Color Space Conversion YR YG Register */ | ||
137 | #define ISC_CSC_YR_YG 0x0000039c | ||
138 | |||
139 | /* Color Space Conversion YB OY Register */ | ||
140 | #define ISC_CSC_YB_OY 0x000003a0 | ||
141 | |||
142 | /* Color Space Conversion CBR CBG Register */ | ||
143 | #define ISC_CSC_CBR_CBG 0x000003a4 | ||
144 | |||
145 | /* Color Space Conversion CBB OCB Register */ | ||
146 | #define ISC_CSC_CBB_OCB 0x000003a8 | ||
147 | |||
148 | /* Color Space Conversion CRR CRG Register */ | ||
149 | #define ISC_CSC_CRR_CRG 0x000003ac | ||
150 | |||
151 | /* Color Space Conversion CRB OCR Register */ | ||
152 | #define ISC_CSC_CRB_OCR 0x000003b0 | ||
153 | |||
96 | /* Contrast And Brightness Control Register */ | 154 | /* Contrast And Brightness Control Register */ |
97 | #define ISC_CBC_CTRL 0x000003b4 | 155 | #define ISC_CBC_CTRL 0x000003b4 |
98 | 156 | ||
157 | /* Contrast And Brightness Configuration Register */ | ||
158 | #define ISC_CBC_CFG 0x000003b8 | ||
159 | |||
160 | /* Brightness Register */ | ||
161 | #define ISC_CBC_BRIGHT 0x000003bc | ||
162 | #define ISC_CBC_BRIGHT_MASK GENMASK(10, 0) | ||
163 | |||
164 | /* Contrast Register */ | ||
165 | #define ISC_CBC_CONTRAST 0x000003c0 | ||
166 | #define ISC_CBC_CONTRAST_MASK GENMASK(11, 0) | ||
167 | |||
99 | /* Subsampling 4:4:4 to 4:2:2 Control Register */ | 168 | /* Subsampling 4:4:4 to 4:2:2 Control Register */ |
100 | #define ISC_SUB422_CTRL 0x000003c4 | 169 | #define ISC_SUB422_CTRL 0x000003c4 |
101 | 170 | ||
@@ -120,6 +189,27 @@ | |||
120 | #define ISC_RLP_CFG_MODE_YYCC_LIMITED 0xc | 189 | #define ISC_RLP_CFG_MODE_YYCC_LIMITED 0xc |
121 | #define ISC_RLP_CFG_MODE_MASK GENMASK(3, 0) | 190 | #define ISC_RLP_CFG_MODE_MASK GENMASK(3, 0) |
122 | 191 | ||
192 | /* Histogram Control Register */ | ||
193 | #define ISC_HIS_CTRL 0x000003d4 | ||
194 | |||
195 | #define ISC_HIS_CTRL_EN BIT(0) | ||
196 | #define ISC_HIS_CTRL_DIS 0x0 | ||
197 | |||
198 | /* Histogram Configuration Register */ | ||
199 | #define ISC_HIS_CFG 0x000003d8 | ||
200 | |||
201 | #define ISC_HIS_CFG_MODE_GR 0x0 | ||
202 | #define ISC_HIS_CFG_MODE_R 0x1 | ||
203 | #define ISC_HIS_CFG_MODE_GB 0x2 | ||
204 | #define ISC_HIS_CFG_MODE_B 0x3 | ||
205 | #define ISC_HIS_CFG_MODE_Y 0x4 | ||
206 | #define ISC_HIS_CFG_MODE_RAW 0x5 | ||
207 | #define ISC_HIS_CFG_MODE_YCCIR656 0x6 | ||
208 | |||
209 | #define ISC_HIS_CFG_BAYSEL_SHIFT 4 | ||
210 | |||
211 | #define ISC_HIS_CFG_RAR BIT(8) | ||
212 | |||
123 | /* DMA Configuration Register */ | 213 | /* DMA Configuration Register */ |
124 | #define ISC_DCFG 0x000003e0 | 214 | #define ISC_DCFG 0x000003e0 |
125 | #define ISC_DCFG_IMODE_PACKED8 0x0 | 215 | #define ISC_DCFG_IMODE_PACKED8 0x0 |
@@ -159,7 +249,13 @@ | |||
159 | /* DMA Address 0 Register */ | 249 | /* DMA Address 0 Register */ |
160 | #define ISC_DAD0 0x000003ec | 250 | #define ISC_DAD0 0x000003ec |
161 | 251 | ||
162 | /* DMA Stride 0 Register */ | 252 | /* DMA Address 1 Register */ |
163 | #define ISC_DST0 0x000003f0 | 253 | #define ISC_DAD1 0x000003f4 |
254 | |||
255 | /* DMA Address 2 Register */ | ||
256 | #define ISC_DAD2 0x000003fc | ||
257 | |||
258 | /* Histogram Entry */ | ||
259 | #define ISC_HIS_ENTRY 0x00000410 | ||
164 | 260 | ||
165 | #endif | 261 | #endif |
diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index fa68fe912c95..c4b2115559a5 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/clk-provider.h> | 29 | #include <linux/clk-provider.h> |
30 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
31 | #include <linux/interrupt.h> | 31 | #include <linux/interrupt.h> |
32 | #include <linux/math64.h> | ||
32 | #include <linux/module.h> | 33 | #include <linux/module.h> |
33 | #include <linux/of.h> | 34 | #include <linux/of.h> |
34 | #include <linux/platform_device.h> | 35 | #include <linux/platform_device.h> |
@@ -36,7 +37,9 @@ | |||
36 | #include <linux/regmap.h> | 37 | #include <linux/regmap.h> |
37 | #include <linux/videodev2.h> | 38 | #include <linux/videodev2.h> |
38 | 39 | ||
40 | #include <media/v4l2-ctrls.h> | ||
39 | #include <media/v4l2-device.h> | 41 | #include <media/v4l2-device.h> |
42 | #include <media/v4l2-event.h> | ||
40 | #include <media/v4l2-image-sizes.h> | 43 | #include <media/v4l2-image-sizes.h> |
41 | #include <media/v4l2-ioctl.h> | 44 | #include <media/v4l2-ioctl.h> |
42 | #include <media/v4l2-of.h> | 45 | #include <media/v4l2-of.h> |
@@ -89,10 +92,12 @@ struct isc_subdev_entity { | |||
89 | * struct isc_format - ISC media bus format information | 92 | * struct isc_format - ISC media bus format information |
90 | * @fourcc: Fourcc code for this format | 93 | * @fourcc: Fourcc code for this format |
91 | * @mbus_code: V4L2 media bus format code. | 94 | * @mbus_code: V4L2 media bus format code. |
92 | * @bpp: Bytes per pixel (when stored in memory) | 95 | * @bpp: Bits per pixel (when stored in memory) |
93 | * @reg_bps: reg value for bits per sample | 96 | * @reg_bps: reg value for bits per sample |
94 | * (when transferred over a bus) | 97 | * (when transferred over a bus) |
95 | * @support: Indicates format supported by subdev | 98 | * @pipeline: pipeline switch |
99 | * @sd_support: Subdev supports this format | ||
100 | * @isc_support: ISC can convert raw format to this format | ||
96 | */ | 101 | */ |
97 | struct isc_format { | 102 | struct isc_format { |
98 | u32 fourcc; | 103 | u32 fourcc; |
@@ -100,11 +105,42 @@ struct isc_format { | |||
100 | u8 bpp; | 105 | u8 bpp; |
101 | 106 | ||
102 | u32 reg_bps; | 107 | u32 reg_bps; |
108 | u32 reg_bay_cfg; | ||
103 | u32 reg_rlp_mode; | 109 | u32 reg_rlp_mode; |
104 | u32 reg_dcfg_imode; | 110 | u32 reg_dcfg_imode; |
105 | u32 reg_dctrl_dview; | 111 | u32 reg_dctrl_dview; |
106 | 112 | ||
107 | bool support; | 113 | u32 pipeline; |
114 | |||
115 | bool sd_support; | ||
116 | bool isc_support; | ||
117 | }; | ||
118 | |||
119 | |||
120 | #define HIST_ENTRIES 512 | ||
121 | #define HIST_BAYER (ISC_HIS_CFG_MODE_B + 1) | ||
122 | |||
123 | enum{ | ||
124 | HIST_INIT = 0, | ||
125 | HIST_ENABLED, | ||
126 | HIST_DISABLED, | ||
127 | }; | ||
128 | |||
129 | struct isc_ctrls { | ||
130 | struct v4l2_ctrl_handler handler; | ||
131 | |||
132 | u32 brightness; | ||
133 | u32 contrast; | ||
134 | u8 gamma_index; | ||
135 | u8 awb; | ||
136 | |||
137 | u32 r_gain; | ||
138 | u32 b_gain; | ||
139 | |||
140 | u32 hist_entry[HIST_ENTRIES]; | ||
141 | u32 hist_count[HIST_BAYER]; | ||
142 | u8 hist_id; | ||
143 | u8 hist_stat; | ||
108 | }; | 144 | }; |
109 | 145 | ||
110 | #define ISC_PIPE_LINE_NODE_NUM 11 | 146 | #define ISC_PIPE_LINE_NODE_NUM 11 |
@@ -131,6 +167,10 @@ struct isc_device { | |||
131 | struct isc_format **user_formats; | 167 | struct isc_format **user_formats; |
132 | unsigned int num_user_formats; | 168 | unsigned int num_user_formats; |
133 | const struct isc_format *current_fmt; | 169 | const struct isc_format *current_fmt; |
170 | const struct isc_format *raw_fmt; | ||
171 | |||
172 | struct isc_ctrls ctrls; | ||
173 | struct work_struct awb_work; | ||
134 | 174 | ||
135 | struct mutex lock; | 175 | struct mutex lock; |
136 | 176 | ||
@@ -140,51 +180,134 @@ struct isc_device { | |||
140 | struct list_head subdev_entities; | 180 | struct list_head subdev_entities; |
141 | }; | 181 | }; |
142 | 182 | ||
183 | #define RAW_FMT_IND_START 0 | ||
184 | #define RAW_FMT_IND_END 11 | ||
185 | #define ISC_FMT_IND_START 12 | ||
186 | #define ISC_FMT_IND_END 14 | ||
187 | |||
143 | static struct isc_format isc_formats[] = { | 188 | static struct isc_format isc_formats[] = { |
144 | { V4L2_PIX_FMT_SBGGR8, MEDIA_BUS_FMT_SBGGR8_1X8, | 189 | { V4L2_PIX_FMT_SBGGR8, MEDIA_BUS_FMT_SBGGR8_1X8, 8, |
145 | 1, ISC_PFE_CFG0_BPS_EIGHT, ISC_RLP_CFG_MODE_DAT8, | 190 | ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_DAT8, |
146 | ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, false }, | 191 | ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, 0x0, |
147 | { V4L2_PIX_FMT_SGBRG8, MEDIA_BUS_FMT_SGBRG8_1X8, | 192 | false, false }, |
148 | 1, ISC_PFE_CFG0_BPS_EIGHT, ISC_RLP_CFG_MODE_DAT8, | 193 | { V4L2_PIX_FMT_SGBRG8, MEDIA_BUS_FMT_SGBRG8_1X8, 8, |
149 | ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, false }, | 194 | ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_GBGB, ISC_RLP_CFG_MODE_DAT8, |
150 | { V4L2_PIX_FMT_SGRBG8, MEDIA_BUS_FMT_SGRBG8_1X8, | 195 | ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, 0x0, |
151 | 1, ISC_PFE_CFG0_BPS_EIGHT, ISC_RLP_CFG_MODE_DAT8, | 196 | false, false }, |
152 | ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, false }, | 197 | { V4L2_PIX_FMT_SGRBG8, MEDIA_BUS_FMT_SGRBG8_1X8, 8, |
153 | { V4L2_PIX_FMT_SRGGB8, MEDIA_BUS_FMT_SRGGB8_1X8, | 198 | ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_GRGR, ISC_RLP_CFG_MODE_DAT8, |
154 | 1, ISC_PFE_CFG0_BPS_EIGHT, ISC_RLP_CFG_MODE_DAT8, | 199 | ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, 0x0, |
155 | ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, false }, | 200 | false, false }, |
156 | 201 | { V4L2_PIX_FMT_SRGGB8, MEDIA_BUS_FMT_SRGGB8_1X8, 8, | |
157 | { V4L2_PIX_FMT_SBGGR10, MEDIA_BUS_FMT_SBGGR10_1X10, | 202 | ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_RGRG, ISC_RLP_CFG_MODE_DAT8, |
158 | 2, ISC_PFG_CFG0_BPS_TEN, ISC_RLP_CFG_MODE_DAT10, | 203 | ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, 0x0, |
159 | ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false }, | 204 | false, false }, |
160 | { V4L2_PIX_FMT_SGBRG10, MEDIA_BUS_FMT_SGBRG10_1X10, | 205 | |
161 | 2, ISC_PFG_CFG0_BPS_TEN, ISC_RLP_CFG_MODE_DAT10, | 206 | { V4L2_PIX_FMT_SBGGR10, MEDIA_BUS_FMT_SBGGR10_1X10, 16, |
162 | ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false }, | 207 | ISC_PFG_CFG0_BPS_TEN, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_DAT10, |
163 | { V4L2_PIX_FMT_SGRBG10, MEDIA_BUS_FMT_SGRBG10_1X10, | 208 | ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, |
164 | 2, ISC_PFG_CFG0_BPS_TEN, ISC_RLP_CFG_MODE_DAT10, | 209 | false, false }, |
165 | ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false }, | 210 | { V4L2_PIX_FMT_SGBRG10, MEDIA_BUS_FMT_SGBRG10_1X10, 16, |
166 | { V4L2_PIX_FMT_SRGGB10, MEDIA_BUS_FMT_SRGGB10_1X10, | 211 | ISC_PFG_CFG0_BPS_TEN, ISC_BAY_CFG_GBGB, ISC_RLP_CFG_MODE_DAT10, |
167 | 2, ISC_PFG_CFG0_BPS_TEN, ISC_RLP_CFG_MODE_DAT10, | 212 | ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, |
168 | ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false }, | 213 | false, false }, |
169 | 214 | { V4L2_PIX_FMT_SGRBG10, MEDIA_BUS_FMT_SGRBG10_1X10, 16, | |
170 | { V4L2_PIX_FMT_SBGGR12, MEDIA_BUS_FMT_SBGGR12_1X12, | 215 | ISC_PFG_CFG0_BPS_TEN, ISC_BAY_CFG_GRGR, ISC_RLP_CFG_MODE_DAT10, |
171 | 2, ISC_PFG_CFG0_BPS_TWELVE, ISC_RLP_CFG_MODE_DAT12, | 216 | ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, |
172 | ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false }, | 217 | false, false }, |
173 | { V4L2_PIX_FMT_SGBRG12, MEDIA_BUS_FMT_SGBRG12_1X12, | 218 | { V4L2_PIX_FMT_SRGGB10, MEDIA_BUS_FMT_SRGGB10_1X10, 16, |
174 | 2, ISC_PFG_CFG0_BPS_TWELVE, ISC_RLP_CFG_MODE_DAT12, | 219 | ISC_PFG_CFG0_BPS_TEN, ISC_BAY_CFG_RGRG, ISC_RLP_CFG_MODE_DAT10, |
175 | ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false }, | 220 | ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, |
176 | { V4L2_PIX_FMT_SGRBG12, MEDIA_BUS_FMT_SGRBG12_1X12, | 221 | false, false }, |
177 | 2, ISC_PFG_CFG0_BPS_TWELVE, ISC_RLP_CFG_MODE_DAT12, | 222 | |
178 | ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false }, | 223 | { V4L2_PIX_FMT_SBGGR12, MEDIA_BUS_FMT_SBGGR12_1X12, 16, |
179 | { V4L2_PIX_FMT_SRGGB12, MEDIA_BUS_FMT_SRGGB12_1X12, | 224 | ISC_PFG_CFG0_BPS_TWELVE, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_DAT12, |
180 | 2, ISC_PFG_CFG0_BPS_TWELVE, ISC_RLP_CFG_MODE_DAT12, | 225 | ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, |
181 | ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, false }, | 226 | false, false }, |
182 | 227 | { V4L2_PIX_FMT_SGBRG12, MEDIA_BUS_FMT_SGBRG12_1X12, 16, | |
183 | { V4L2_PIX_FMT_YUYV, MEDIA_BUS_FMT_YUYV8_2X8, | 228 | ISC_PFG_CFG0_BPS_TWELVE, ISC_BAY_CFG_GBGB, ISC_RLP_CFG_MODE_DAT12, |
184 | 2, ISC_PFE_CFG0_BPS_EIGHT, ISC_RLP_CFG_MODE_DAT8, | 229 | ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, |
185 | ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, false }, | 230 | false, false }, |
231 | { V4L2_PIX_FMT_SGRBG12, MEDIA_BUS_FMT_SGRBG12_1X12, 16, | ||
232 | ISC_PFG_CFG0_BPS_TWELVE, ISC_BAY_CFG_GRGR, ISC_RLP_CFG_MODE_DAT12, | ||
233 | ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, | ||
234 | false, false }, | ||
235 | { V4L2_PIX_FMT_SRGGB12, MEDIA_BUS_FMT_SRGGB12_1X12, 16, | ||
236 | ISC_PFG_CFG0_BPS_TWELVE, ISC_BAY_CFG_RGRG, ISC_RLP_CFG_MODE_DAT12, | ||
237 | ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, | ||
238 | false, false }, | ||
239 | |||
240 | { V4L2_PIX_FMT_YUV420, 0x0, 12, | ||
241 | ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_YYCC, | ||
242 | ISC_DCFG_IMODE_YC420P | ISC_DCFG_YMBSIZE_BEATS8 | | ||
243 | ISC_DCFG_CMBSIZE_BEATS8, ISC_DCTRL_DVIEW_PLANAR, 0x7fb, | ||
244 | false, false }, | ||
245 | { V4L2_PIX_FMT_YUV422P, 0x0, 16, | ||
246 | ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_YYCC, | ||
247 | ISC_DCFG_IMODE_YC422P | ISC_DCFG_YMBSIZE_BEATS8 | | ||
248 | ISC_DCFG_CMBSIZE_BEATS8, ISC_DCTRL_DVIEW_PLANAR, 0x3fb, | ||
249 | false, false }, | ||
250 | { V4L2_PIX_FMT_RGB565, MEDIA_BUS_FMT_RGB565_2X8_LE, 16, | ||
251 | ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_RGB565, | ||
252 | ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x7b, | ||
253 | false, false }, | ||
254 | |||
255 | { V4L2_PIX_FMT_YUYV, MEDIA_BUS_FMT_YUYV8_2X8, 16, | ||
256 | ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_DAT8, | ||
257 | ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, 0x0, | ||
258 | false, false }, | ||
259 | }; | ||
260 | |||
261 | #define GAMMA_MAX 2 | ||
262 | #define GAMMA_ENTRIES 64 | ||
263 | |||
264 | /* Gamma table with gamma 1/2.2 */ | ||
265 | static const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES] = { | ||
266 | /* 0 --> gamma 1/1.8 */ | ||
267 | { 0x65, 0x66002F, 0x950025, 0xBB0020, 0xDB001D, 0xF8001A, | ||
268 | 0x1130018, 0x12B0017, 0x1420016, 0x1580014, 0x16D0013, 0x1810012, | ||
269 | 0x1940012, 0x1A60012, 0x1B80011, 0x1C90010, 0x1DA0010, 0x1EA000F, | ||
270 | 0x1FA000F, 0x209000F, 0x218000F, 0x227000E, 0x235000E, 0x243000E, | ||
271 | 0x251000E, 0x25F000D, 0x26C000D, 0x279000D, 0x286000D, 0x293000C, | ||
272 | 0x2A0000C, 0x2AC000C, 0x2B8000C, 0x2C4000C, 0x2D0000B, 0x2DC000B, | ||
273 | 0x2E7000B, 0x2F3000B, 0x2FE000B, 0x309000B, 0x314000B, 0x31F000A, | ||
274 | 0x32A000A, 0x334000B, 0x33F000A, 0x349000A, 0x354000A, 0x35E000A, | ||
275 | 0x368000A, 0x372000A, 0x37C000A, 0x386000A, 0x3900009, 0x399000A, | ||
276 | 0x3A30009, 0x3AD0009, 0x3B60009, 0x3BF000A, 0x3C90009, 0x3D20009, | ||
277 | 0x3DB0009, 0x3E40009, 0x3ED0009, 0x3F60009 }, | ||
278 | |||
279 | /* 1 --> gamma 1/2 */ | ||
280 | { 0x7F, 0x800034, 0xB50028, 0xDE0021, 0x100001E, 0x11E001B, | ||
281 | 0x1390019, 0x1520017, 0x16A0015, 0x1800014, 0x1940014, 0x1A80013, | ||
282 | 0x1BB0012, 0x1CD0011, 0x1DF0010, 0x1EF0010, 0x200000F, 0x20F000F, | ||
283 | 0x21F000E, 0x22D000F, 0x23C000E, 0x24A000E, 0x258000D, 0x265000D, | ||
284 | 0x273000C, 0x27F000D, 0x28C000C, 0x299000C, 0x2A5000C, 0x2B1000B, | ||
285 | 0x2BC000C, 0x2C8000B, 0x2D3000C, 0x2DF000B, 0x2EA000A, 0x2F5000A, | ||
286 | 0x2FF000B, 0x30A000A, 0x314000B, 0x31F000A, 0x329000A, 0x333000A, | ||
287 | 0x33D0009, 0x3470009, 0x350000A, 0x35A0009, 0x363000A, 0x36D0009, | ||
288 | 0x3760009, 0x37F0009, 0x3880009, 0x3910009, 0x39A0009, 0x3A30009, | ||
289 | 0x3AC0008, 0x3B40009, 0x3BD0008, 0x3C60008, 0x3CE0008, 0x3D60009, | ||
290 | 0x3DF0008, 0x3E70008, 0x3EF0008, 0x3F70008 }, | ||
291 | |||
292 | /* 2 --> gamma 1/2.2 */ | ||
293 | { 0x99, 0x9B0038, 0xD4002A, 0xFF0023, 0x122001F, 0x141001B, | ||
294 | 0x15D0019, 0x1760017, 0x18E0015, 0x1A30015, 0x1B80013, 0x1CC0012, | ||
295 | 0x1DE0011, 0x1F00010, 0x2010010, 0x2110010, 0x221000F, 0x230000F, | ||
296 | 0x23F000E, 0x24D000E, 0x25B000D, 0x269000C, 0x276000C, 0x283000C, | ||
297 | 0x28F000C, 0x29B000C, 0x2A7000C, 0x2B3000B, 0x2BF000B, 0x2CA000B, | ||
298 | 0x2D5000B, 0x2E0000A, 0x2EB000A, 0x2F5000A, 0x2FF000A, 0x30A000A, | ||
299 | 0x3140009, 0x31E0009, 0x327000A, 0x3310009, 0x33A0009, 0x3440009, | ||
300 | 0x34D0009, 0x3560009, 0x35F0009, 0x3680008, 0x3710008, 0x3790009, | ||
301 | 0x3820008, 0x38A0008, 0x3930008, 0x39B0008, 0x3A30008, 0x3AB0008, | ||
302 | 0x3B30008, 0x3BB0008, 0x3C30008, 0x3CB0007, 0x3D20008, 0x3DA0007, | ||
303 | 0x3E20007, 0x3E90007, 0x3F00008, 0x3F80007 }, | ||
186 | }; | 304 | }; |
187 | 305 | ||
306 | static unsigned int sensor_preferred = 1; | ||
307 | module_param(sensor_preferred, uint, 0644); | ||
308 | MODULE_PARM_DESC(sensor_preferred, | ||
309 | "Sensor is preferred to output the specified format (1-on 0-off), default 1"); | ||
310 | |||
188 | static int isc_clk_enable(struct clk_hw *hw) | 311 | static int isc_clk_enable(struct clk_hw *hw) |
189 | { | 312 | { |
190 | struct isc_clk *isc_clk = to_isc_clk(hw); | 313 | struct isc_clk *isc_clk = to_isc_clk(hw); |
@@ -447,27 +570,155 @@ static int isc_buffer_prepare(struct vb2_buffer *vb) | |||
447 | return 0; | 570 | return 0; |
448 | } | 571 | } |
449 | 572 | ||
450 | static inline void isc_start_dma(struct regmap *regmap, | 573 | static inline bool sensor_is_preferred(const struct isc_format *isc_fmt) |
451 | struct isc_buffer *frm, u32 dview) | 574 | { |
575 | return (sensor_preferred && isc_fmt->sd_support) || | ||
576 | !isc_fmt->isc_support; | ||
577 | } | ||
578 | |||
579 | static void isc_start_dma(struct isc_device *isc) | ||
452 | { | 580 | { |
453 | dma_addr_t addr; | 581 | struct regmap *regmap = isc->regmap; |
582 | struct v4l2_pix_format *pixfmt = &isc->fmt.fmt.pix; | ||
583 | u32 sizeimage = pixfmt->sizeimage; | ||
584 | u32 dctrl_dview; | ||
585 | dma_addr_t addr0; | ||
586 | |||
587 | addr0 = vb2_dma_contig_plane_dma_addr(&isc->cur_frm->vb.vb2_buf, 0); | ||
588 | regmap_write(regmap, ISC_DAD0, addr0); | ||
589 | |||
590 | switch (pixfmt->pixelformat) { | ||
591 | case V4L2_PIX_FMT_YUV420: | ||
592 | regmap_write(regmap, ISC_DAD1, addr0 + (sizeimage * 2) / 3); | ||
593 | regmap_write(regmap, ISC_DAD2, addr0 + (sizeimage * 5) / 6); | ||
594 | break; | ||
595 | case V4L2_PIX_FMT_YUV422P: | ||
596 | regmap_write(regmap, ISC_DAD1, addr0 + sizeimage / 2); | ||
597 | regmap_write(regmap, ISC_DAD2, addr0 + (sizeimage * 3) / 4); | ||
598 | break; | ||
599 | default: | ||
600 | break; | ||
601 | } | ||
454 | 602 | ||
455 | addr = vb2_dma_contig_plane_dma_addr(&frm->vb.vb2_buf, 0); | 603 | if (sensor_is_preferred(isc->current_fmt)) |
604 | dctrl_dview = ISC_DCTRL_DVIEW_PACKED; | ||
605 | else | ||
606 | dctrl_dview = isc->current_fmt->reg_dctrl_dview; | ||
456 | 607 | ||
457 | regmap_write(regmap, ISC_DCTRL, dview | ISC_DCTRL_IE_IS); | 608 | regmap_write(regmap, ISC_DCTRL, dctrl_dview | ISC_DCTRL_IE_IS); |
458 | regmap_write(regmap, ISC_DAD0, addr); | ||
459 | regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_CAPTURE); | 609 | regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_CAPTURE); |
460 | } | 610 | } |
461 | 611 | ||
462 | static void isc_set_pipeline(struct isc_device *isc, u32 pipeline) | 612 | static void isc_set_pipeline(struct isc_device *isc, u32 pipeline) |
463 | { | 613 | { |
464 | u32 val; | 614 | struct regmap *regmap = isc->regmap; |
615 | struct isc_ctrls *ctrls = &isc->ctrls; | ||
616 | u32 val, bay_cfg; | ||
617 | const u32 *gamma; | ||
465 | unsigned int i; | 618 | unsigned int i; |
466 | 619 | ||
620 | /* WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB422-->SUB420 */ | ||
467 | for (i = 0; i < ISC_PIPE_LINE_NODE_NUM; i++) { | 621 | for (i = 0; i < ISC_PIPE_LINE_NODE_NUM; i++) { |
468 | val = pipeline & BIT(i) ? 1 : 0; | 622 | val = pipeline & BIT(i) ? 1 : 0; |
469 | regmap_field_write(isc->pipeline[i], val); | 623 | regmap_field_write(isc->pipeline[i], val); |
470 | } | 624 | } |
625 | |||
626 | if (!pipeline) | ||
627 | return; | ||
628 | |||
629 | bay_cfg = isc->raw_fmt->reg_bay_cfg; | ||
630 | |||
631 | regmap_write(regmap, ISC_WB_CFG, bay_cfg); | ||
632 | regmap_write(regmap, ISC_WB_O_RGR, 0x0); | ||
633 | regmap_write(regmap, ISC_WB_O_BGR, 0x0); | ||
634 | regmap_write(regmap, ISC_WB_G_RGR, ctrls->r_gain | (0x1 << 25)); | ||
635 | regmap_write(regmap, ISC_WB_G_BGR, ctrls->b_gain | (0x1 << 25)); | ||
636 | |||
637 | regmap_write(regmap, ISC_CFA_CFG, bay_cfg | ISC_CFA_CFG_EITPOL); | ||
638 | |||
639 | gamma = &isc_gamma_table[ctrls->gamma_index][0]; | ||
640 | regmap_bulk_write(regmap, ISC_GAM_BENTRY, gamma, GAMMA_ENTRIES); | ||
641 | regmap_bulk_write(regmap, ISC_GAM_GENTRY, gamma, GAMMA_ENTRIES); | ||
642 | regmap_bulk_write(regmap, ISC_GAM_RENTRY, gamma, GAMMA_ENTRIES); | ||
643 | |||
644 | /* Convert RGB to YUV */ | ||
645 | regmap_write(regmap, ISC_CSC_YR_YG, 0x42 | (0x81 << 16)); | ||
646 | regmap_write(regmap, ISC_CSC_YB_OY, 0x19 | (0x10 << 16)); | ||
647 | regmap_write(regmap, ISC_CSC_CBR_CBG, 0xFDA | (0xFB6 << 16)); | ||
648 | regmap_write(regmap, ISC_CSC_CBB_OCB, 0x70 | (0x80 << 16)); | ||
649 | regmap_write(regmap, ISC_CSC_CRR_CRG, 0x70 | (0xFA2 << 16)); | ||
650 | regmap_write(regmap, ISC_CSC_CRB_OCR, 0xFEE | (0x80 << 16)); | ||
651 | |||
652 | regmap_write(regmap, ISC_CBC_BRIGHT, ctrls->brightness); | ||
653 | regmap_write(regmap, ISC_CBC_CONTRAST, ctrls->contrast); | ||
654 | } | ||
655 | |||
656 | static int isc_update_profile(struct isc_device *isc) | ||
657 | { | ||
658 | struct regmap *regmap = isc->regmap; | ||
659 | u32 sr; | ||
660 | int counter = 100; | ||
661 | |||
662 | regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_UPPRO); | ||
663 | |||
664 | regmap_read(regmap, ISC_CTRLSR, &sr); | ||
665 | while ((sr & ISC_CTRL_UPPRO) && counter--) { | ||
666 | usleep_range(1000, 2000); | ||
667 | regmap_read(regmap, ISC_CTRLSR, &sr); | ||
668 | } | ||
669 | |||
670 | if (counter < 0) { | ||
671 | v4l2_warn(&isc->v4l2_dev, "Time out to update profie\n"); | ||
672 | return -ETIMEDOUT; | ||
673 | } | ||
674 | |||
675 | return 0; | ||
676 | } | ||
677 | |||
678 | static void isc_set_histogram(struct isc_device *isc) | ||
679 | { | ||
680 | struct regmap *regmap = isc->regmap; | ||
681 | struct isc_ctrls *ctrls = &isc->ctrls; | ||
682 | |||
683 | if (ctrls->awb && (ctrls->hist_stat != HIST_ENABLED)) { | ||
684 | regmap_write(regmap, ISC_HIS_CFG, ISC_HIS_CFG_MODE_R | | ||
685 | (isc->raw_fmt->reg_bay_cfg << ISC_HIS_CFG_BAYSEL_SHIFT) | | ||
686 | ISC_HIS_CFG_RAR); | ||
687 | regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_EN); | ||
688 | regmap_write(regmap, ISC_INTEN, ISC_INT_HISDONE); | ||
689 | ctrls->hist_id = ISC_HIS_CFG_MODE_R; | ||
690 | isc_update_profile(isc); | ||
691 | regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ); | ||
692 | |||
693 | ctrls->hist_stat = HIST_ENABLED; | ||
694 | } else if (!ctrls->awb && (ctrls->hist_stat != HIST_DISABLED)) { | ||
695 | regmap_write(regmap, ISC_INTDIS, ISC_INT_HISDONE); | ||
696 | regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_DIS); | ||
697 | |||
698 | ctrls->hist_stat = HIST_DISABLED; | ||
699 | } | ||
700 | } | ||
701 | |||
702 | static inline void isc_get_param(const struct isc_format *fmt, | ||
703 | u32 *rlp_mode, u32 *dcfg_imode) | ||
704 | { | ||
705 | switch (fmt->fourcc) { | ||
706 | case V4L2_PIX_FMT_SBGGR10: | ||
707 | case V4L2_PIX_FMT_SGBRG10: | ||
708 | case V4L2_PIX_FMT_SGRBG10: | ||
709 | case V4L2_PIX_FMT_SRGGB10: | ||
710 | case V4L2_PIX_FMT_SBGGR12: | ||
711 | case V4L2_PIX_FMT_SGBRG12: | ||
712 | case V4L2_PIX_FMT_SGRBG12: | ||
713 | case V4L2_PIX_FMT_SRGGB12: | ||
714 | *rlp_mode = fmt->reg_rlp_mode; | ||
715 | *dcfg_imode = fmt->reg_dcfg_imode; | ||
716 | break; | ||
717 | default: | ||
718 | *rlp_mode = ISC_RLP_CFG_MODE_DAT8; | ||
719 | *dcfg_imode = ISC_DCFG_IMODE_PACKED8; | ||
720 | break; | ||
721 | } | ||
471 | } | 722 | } |
472 | 723 | ||
473 | static int isc_configure(struct isc_device *isc) | 724 | static int isc_configure(struct isc_device *isc) |
@@ -475,39 +726,40 @@ static int isc_configure(struct isc_device *isc) | |||
475 | struct regmap *regmap = isc->regmap; | 726 | struct regmap *regmap = isc->regmap; |
476 | const struct isc_format *current_fmt = isc->current_fmt; | 727 | const struct isc_format *current_fmt = isc->current_fmt; |
477 | struct isc_subdev_entity *subdev = isc->current_subdev; | 728 | struct isc_subdev_entity *subdev = isc->current_subdev; |
478 | u32 val, mask; | 729 | u32 pfe_cfg0, rlp_mode, dcfg_imode, mask, pipeline; |
479 | int counter = 10; | 730 | |
731 | if (sensor_is_preferred(current_fmt)) { | ||
732 | pfe_cfg0 = current_fmt->reg_bps; | ||
733 | pipeline = 0x0; | ||
734 | isc_get_param(current_fmt, &rlp_mode, &dcfg_imode); | ||
735 | isc->ctrls.hist_stat = HIST_INIT; | ||
736 | } else { | ||
737 | pfe_cfg0 = isc->raw_fmt->reg_bps; | ||
738 | pipeline = current_fmt->pipeline; | ||
739 | rlp_mode = current_fmt->reg_rlp_mode; | ||
740 | dcfg_imode = current_fmt->reg_dcfg_imode; | ||
741 | } | ||
480 | 742 | ||
481 | val = current_fmt->reg_bps | subdev->pfe_cfg0 | | 743 | pfe_cfg0 |= subdev->pfe_cfg0 | ISC_PFE_CFG0_MODE_PROGRESSIVE; |
482 | ISC_PFE_CFG0_MODE_PROGRESSIVE; | ||
483 | mask = ISC_PFE_CFG0_BPS_MASK | ISC_PFE_CFG0_HPOL_LOW | | 744 | mask = ISC_PFE_CFG0_BPS_MASK | ISC_PFE_CFG0_HPOL_LOW | |
484 | ISC_PFE_CFG0_VPOL_LOW | ISC_PFE_CFG0_PPOL_LOW | | 745 | ISC_PFE_CFG0_VPOL_LOW | ISC_PFE_CFG0_PPOL_LOW | |
485 | ISC_PFE_CFG0_MODE_MASK; | 746 | ISC_PFE_CFG0_MODE_MASK; |
486 | 747 | ||
487 | regmap_update_bits(regmap, ISC_PFE_CFG0, mask, val); | 748 | regmap_update_bits(regmap, ISC_PFE_CFG0, mask, pfe_cfg0); |
488 | 749 | ||
489 | regmap_update_bits(regmap, ISC_RLP_CFG, ISC_RLP_CFG_MODE_MASK, | 750 | regmap_update_bits(regmap, ISC_RLP_CFG, ISC_RLP_CFG_MODE_MASK, |
490 | current_fmt->reg_rlp_mode); | 751 | rlp_mode); |
491 | 752 | ||
492 | regmap_update_bits(regmap, ISC_DCFG, ISC_DCFG_IMODE_MASK, | 753 | regmap_update_bits(regmap, ISC_DCFG, ISC_DCFG_IMODE_MASK, dcfg_imode); |
493 | current_fmt->reg_dcfg_imode); | ||
494 | 754 | ||
495 | /* Disable the pipeline */ | 755 | /* Set the pipeline */ |
496 | isc_set_pipeline(isc, 0x0); | 756 | isc_set_pipeline(isc, pipeline); |
497 | 757 | ||
498 | /* Update profile */ | 758 | if (pipeline) |
499 | regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_UPPRO); | 759 | isc_set_histogram(isc); |
500 | |||
501 | regmap_read(regmap, ISC_CTRLSR, &val); | ||
502 | while ((val & ISC_CTRL_UPPRO) && counter--) { | ||
503 | usleep_range(1000, 2000); | ||
504 | regmap_read(regmap, ISC_CTRLSR, &val); | ||
505 | } | ||
506 | 760 | ||
507 | if (counter < 0) | 761 | /* Update profile */ |
508 | return -ETIMEDOUT; | 762 | return isc_update_profile(isc); |
509 | |||
510 | return 0; | ||
511 | } | 763 | } |
512 | 764 | ||
513 | static int isc_start_streaming(struct vb2_queue *vq, unsigned int count) | 765 | static int isc_start_streaming(struct vb2_queue *vq, unsigned int count) |
@@ -517,7 +769,6 @@ static int isc_start_streaming(struct vb2_queue *vq, unsigned int count) | |||
517 | struct isc_buffer *buf; | 769 | struct isc_buffer *buf; |
518 | unsigned long flags; | 770 | unsigned long flags; |
519 | int ret; | 771 | int ret; |
520 | u32 val; | ||
521 | 772 | ||
522 | /* Enable stream on the sub device */ | 773 | /* Enable stream on the sub device */ |
523 | ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 1); | 774 | ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 1); |
@@ -528,12 +779,6 @@ static int isc_start_streaming(struct vb2_queue *vq, unsigned int count) | |||
528 | 779 | ||
529 | pm_runtime_get_sync(isc->dev); | 780 | pm_runtime_get_sync(isc->dev); |
530 | 781 | ||
531 | /* Disable all the interrupts */ | ||
532 | regmap_write(isc->regmap, ISC_INTDIS, (u32)~0UL); | ||
533 | |||
534 | /* Clean the interrupt status register */ | ||
535 | regmap_read(regmap, ISC_INTSR, &val); | ||
536 | |||
537 | ret = isc_configure(isc); | 782 | ret = isc_configure(isc); |
538 | if (unlikely(ret)) | 783 | if (unlikely(ret)) |
539 | goto err_configure; | 784 | goto err_configure; |
@@ -551,7 +796,7 @@ static int isc_start_streaming(struct vb2_queue *vq, unsigned int count) | |||
551 | struct isc_buffer, list); | 796 | struct isc_buffer, list); |
552 | list_del(&isc->cur_frm->list); | 797 | list_del(&isc->cur_frm->list); |
553 | 798 | ||
554 | isc_start_dma(regmap, isc->cur_frm, isc->current_fmt->reg_dctrl_dview); | 799 | isc_start_dma(isc); |
555 | 800 | ||
556 | spin_unlock_irqrestore(&isc->dma_queue_lock, flags); | 801 | spin_unlock_irqrestore(&isc->dma_queue_lock, flags); |
557 | 802 | ||
@@ -620,8 +865,7 @@ static void isc_buffer_queue(struct vb2_buffer *vb) | |||
620 | if (!isc->cur_frm && list_empty(&isc->dma_queue) && | 865 | if (!isc->cur_frm && list_empty(&isc->dma_queue) && |
621 | vb2_is_streaming(vb->vb2_queue)) { | 866 | vb2_is_streaming(vb->vb2_queue)) { |
622 | isc->cur_frm = buf; | 867 | isc->cur_frm = buf; |
623 | isc_start_dma(isc->regmap, isc->cur_frm, | 868 | isc_start_dma(isc); |
624 | isc->current_fmt->reg_dctrl_dview); | ||
625 | } else | 869 | } else |
626 | list_add_tail(&buf->list, &isc->dma_queue); | 870 | list_add_tail(&buf->list, &isc->dma_queue); |
627 | spin_unlock_irqrestore(&isc->dma_queue_lock, flags); | 871 | spin_unlock_irqrestore(&isc->dma_queue_lock, flags); |
@@ -691,13 +935,14 @@ static struct isc_format *find_format_by_fourcc(struct isc_device *isc, | |||
691 | } | 935 | } |
692 | 936 | ||
693 | static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f, | 937 | static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f, |
694 | struct isc_format **current_fmt) | 938 | struct isc_format **current_fmt, u32 *code) |
695 | { | 939 | { |
696 | struct isc_format *isc_fmt; | 940 | struct isc_format *isc_fmt; |
697 | struct v4l2_pix_format *pixfmt = &f->fmt.pix; | 941 | struct v4l2_pix_format *pixfmt = &f->fmt.pix; |
698 | struct v4l2_subdev_format format = { | 942 | struct v4l2_subdev_format format = { |
699 | .which = V4L2_SUBDEV_FORMAT_TRY, | 943 | .which = V4L2_SUBDEV_FORMAT_TRY, |
700 | }; | 944 | }; |
945 | u32 mbus_code; | ||
701 | int ret; | 946 | int ret; |
702 | 947 | ||
703 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 948 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
@@ -717,7 +962,12 @@ static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f, | |||
717 | if (pixfmt->height > ISC_MAX_SUPPORT_HEIGHT) | 962 | if (pixfmt->height > ISC_MAX_SUPPORT_HEIGHT) |
718 | pixfmt->height = ISC_MAX_SUPPORT_HEIGHT; | 963 | pixfmt->height = ISC_MAX_SUPPORT_HEIGHT; |
719 | 964 | ||
720 | v4l2_fill_mbus_format(&format.format, pixfmt, isc_fmt->mbus_code); | 965 | if (sensor_is_preferred(isc_fmt)) |
966 | mbus_code = isc_fmt->mbus_code; | ||
967 | else | ||
968 | mbus_code = isc->raw_fmt->mbus_code; | ||
969 | |||
970 | v4l2_fill_mbus_format(&format.format, pixfmt, mbus_code); | ||
721 | ret = v4l2_subdev_call(isc->current_subdev->sd, pad, set_fmt, | 971 | ret = v4l2_subdev_call(isc->current_subdev->sd, pad, set_fmt, |
722 | isc->current_subdev->config, &format); | 972 | isc->current_subdev->config, &format); |
723 | if (ret < 0) | 973 | if (ret < 0) |
@@ -726,12 +976,15 @@ static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f, | |||
726 | v4l2_fill_pix_format(pixfmt, &format.format); | 976 | v4l2_fill_pix_format(pixfmt, &format.format); |
727 | 977 | ||
728 | pixfmt->field = V4L2_FIELD_NONE; | 978 | pixfmt->field = V4L2_FIELD_NONE; |
729 | pixfmt->bytesperline = pixfmt->width * isc_fmt->bpp; | 979 | pixfmt->bytesperline = (pixfmt->width * isc_fmt->bpp) >> 3; |
730 | pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; | 980 | pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; |
731 | 981 | ||
732 | if (current_fmt) | 982 | if (current_fmt) |
733 | *current_fmt = isc_fmt; | 983 | *current_fmt = isc_fmt; |
734 | 984 | ||
985 | if (code) | ||
986 | *code = mbus_code; | ||
987 | |||
735 | return 0; | 988 | return 0; |
736 | } | 989 | } |
737 | 990 | ||
@@ -741,14 +994,14 @@ static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f) | |||
741 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | 994 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, |
742 | }; | 995 | }; |
743 | struct isc_format *current_fmt; | 996 | struct isc_format *current_fmt; |
997 | u32 mbus_code; | ||
744 | int ret; | 998 | int ret; |
745 | 999 | ||
746 | ret = isc_try_fmt(isc, f, ¤t_fmt); | 1000 | ret = isc_try_fmt(isc, f, ¤t_fmt, &mbus_code); |
747 | if (ret) | 1001 | if (ret) |
748 | return ret; | 1002 | return ret; |
749 | 1003 | ||
750 | v4l2_fill_mbus_format(&format.format, &f->fmt.pix, | 1004 | v4l2_fill_mbus_format(&format.format, &f->fmt.pix, mbus_code); |
751 | current_fmt->mbus_code); | ||
752 | ret = v4l2_subdev_call(isc->current_subdev->sd, pad, | 1005 | ret = v4l2_subdev_call(isc->current_subdev->sd, pad, |
753 | set_fmt, NULL, &format); | 1006 | set_fmt, NULL, &format); |
754 | if (ret < 0) | 1007 | if (ret < 0) |
@@ -776,7 +1029,7 @@ static int isc_try_fmt_vid_cap(struct file *file, void *priv, | |||
776 | { | 1029 | { |
777 | struct isc_device *isc = video_drvdata(file); | 1030 | struct isc_device *isc = video_drvdata(file); |
778 | 1031 | ||
779 | return isc_try_fmt(isc, f, NULL); | 1032 | return isc_try_fmt(isc, f, NULL, NULL); |
780 | } | 1033 | } |
781 | 1034 | ||
782 | static int isc_enum_input(struct file *file, void *priv, | 1035 | static int isc_enum_input(struct file *file, void *priv, |
@@ -842,7 +1095,10 @@ static int isc_enum_framesizes(struct file *file, void *fh, | |||
842 | if (!isc_fmt) | 1095 | if (!isc_fmt) |
843 | return -EINVAL; | 1096 | return -EINVAL; |
844 | 1097 | ||
845 | fse.code = isc_fmt->mbus_code; | 1098 | if (sensor_is_preferred(isc_fmt)) |
1099 | fse.code = isc_fmt->mbus_code; | ||
1100 | else | ||
1101 | fse.code = isc->raw_fmt->mbus_code; | ||
846 | 1102 | ||
847 | ret = v4l2_subdev_call(isc->current_subdev->sd, pad, enum_frame_size, | 1103 | ret = v4l2_subdev_call(isc->current_subdev->sd, pad, enum_frame_size, |
848 | NULL, &fse); | 1104 | NULL, &fse); |
@@ -873,7 +1129,10 @@ static int isc_enum_frameintervals(struct file *file, void *fh, | |||
873 | if (!isc_fmt) | 1129 | if (!isc_fmt) |
874 | return -EINVAL; | 1130 | return -EINVAL; |
875 | 1131 | ||
876 | fie.code = isc_fmt->mbus_code; | 1132 | if (sensor_is_preferred(isc_fmt)) |
1133 | fie.code = isc_fmt->mbus_code; | ||
1134 | else | ||
1135 | fie.code = isc->raw_fmt->mbus_code; | ||
877 | 1136 | ||
878 | ret = v4l2_subdev_call(isc->current_subdev->sd, pad, | 1137 | ret = v4l2_subdev_call(isc->current_subdev->sd, pad, |
879 | enum_frame_interval, NULL, &fie); | 1138 | enum_frame_interval, NULL, &fie); |
@@ -911,6 +1170,10 @@ static const struct v4l2_ioctl_ops isc_ioctl_ops = { | |||
911 | .vidioc_s_parm = isc_s_parm, | 1170 | .vidioc_s_parm = isc_s_parm, |
912 | .vidioc_enum_framesizes = isc_enum_framesizes, | 1171 | .vidioc_enum_framesizes = isc_enum_framesizes, |
913 | .vidioc_enum_frameintervals = isc_enum_frameintervals, | 1172 | .vidioc_enum_frameintervals = isc_enum_frameintervals, |
1173 | |||
1174 | .vidioc_log_status = v4l2_ctrl_log_status, | ||
1175 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, | ||
1176 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | ||
914 | }; | 1177 | }; |
915 | 1178 | ||
916 | static int isc_open(struct file *file) | 1179 | static int isc_open(struct file *file) |
@@ -984,14 +1247,13 @@ static irqreturn_t isc_interrupt(int irq, void *dev_id) | |||
984 | u32 isc_intsr, isc_intmask, pending; | 1247 | u32 isc_intsr, isc_intmask, pending; |
985 | irqreturn_t ret = IRQ_NONE; | 1248 | irqreturn_t ret = IRQ_NONE; |
986 | 1249 | ||
987 | spin_lock(&isc->dma_queue_lock); | ||
988 | |||
989 | regmap_read(regmap, ISC_INTSR, &isc_intsr); | 1250 | regmap_read(regmap, ISC_INTSR, &isc_intsr); |
990 | regmap_read(regmap, ISC_INTMASK, &isc_intmask); | 1251 | regmap_read(regmap, ISC_INTMASK, &isc_intmask); |
991 | 1252 | ||
992 | pending = isc_intsr & isc_intmask; | 1253 | pending = isc_intsr & isc_intmask; |
993 | 1254 | ||
994 | if (likely(pending & ISC_INT_DDONE)) { | 1255 | if (likely(pending & ISC_INT_DDONE)) { |
1256 | spin_lock(&isc->dma_queue_lock); | ||
995 | if (isc->cur_frm) { | 1257 | if (isc->cur_frm) { |
996 | struct vb2_v4l2_buffer *vbuf = &isc->cur_frm->vb; | 1258 | struct vb2_v4l2_buffer *vbuf = &isc->cur_frm->vb; |
997 | struct vb2_buffer *vb = &vbuf->vb2_buf; | 1259 | struct vb2_buffer *vb = &vbuf->vb2_buf; |
@@ -1007,21 +1269,144 @@ static irqreturn_t isc_interrupt(int irq, void *dev_id) | |||
1007 | struct isc_buffer, list); | 1269 | struct isc_buffer, list); |
1008 | list_del(&isc->cur_frm->list); | 1270 | list_del(&isc->cur_frm->list); |
1009 | 1271 | ||
1010 | isc_start_dma(regmap, isc->cur_frm, | 1272 | isc_start_dma(isc); |
1011 | isc->current_fmt->reg_dctrl_dview); | ||
1012 | } | 1273 | } |
1013 | 1274 | ||
1014 | if (isc->stop) | 1275 | if (isc->stop) |
1015 | complete(&isc->comp); | 1276 | complete(&isc->comp); |
1016 | 1277 | ||
1017 | ret = IRQ_HANDLED; | 1278 | ret = IRQ_HANDLED; |
1279 | spin_unlock(&isc->dma_queue_lock); | ||
1018 | } | 1280 | } |
1019 | 1281 | ||
1020 | spin_unlock(&isc->dma_queue_lock); | 1282 | if (pending & ISC_INT_HISDONE) { |
1283 | schedule_work(&isc->awb_work); | ||
1284 | ret = IRQ_HANDLED; | ||
1285 | } | ||
1021 | 1286 | ||
1022 | return ret; | 1287 | return ret; |
1023 | } | 1288 | } |
1024 | 1289 | ||
1290 | static void isc_hist_count(struct isc_device *isc) | ||
1291 | { | ||
1292 | struct regmap *regmap = isc->regmap; | ||
1293 | struct isc_ctrls *ctrls = &isc->ctrls; | ||
1294 | u32 *hist_count = &ctrls->hist_count[ctrls->hist_id]; | ||
1295 | u32 *hist_entry = &ctrls->hist_entry[0]; | ||
1296 | u32 i; | ||
1297 | |||
1298 | regmap_bulk_read(regmap, ISC_HIS_ENTRY, hist_entry, HIST_ENTRIES); | ||
1299 | |||
1300 | *hist_count = 0; | ||
1301 | for (i = 0; i < HIST_ENTRIES; i++) | ||
1302 | *hist_count += i * (*hist_entry++); | ||
1303 | } | ||
1304 | |||
1305 | static void isc_wb_update(struct isc_ctrls *ctrls) | ||
1306 | { | ||
1307 | u32 *hist_count = &ctrls->hist_count[0]; | ||
1308 | u64 g_count = (u64)hist_count[ISC_HIS_CFG_MODE_GB] << 9; | ||
1309 | u32 hist_r = hist_count[ISC_HIS_CFG_MODE_R]; | ||
1310 | u32 hist_b = hist_count[ISC_HIS_CFG_MODE_B]; | ||
1311 | |||
1312 | if (hist_r) | ||
1313 | ctrls->r_gain = div_u64(g_count, hist_r); | ||
1314 | |||
1315 | if (hist_b) | ||
1316 | ctrls->b_gain = div_u64(g_count, hist_b); | ||
1317 | } | ||
1318 | |||
1319 | static void isc_awb_work(struct work_struct *w) | ||
1320 | { | ||
1321 | struct isc_device *isc = | ||
1322 | container_of(w, struct isc_device, awb_work); | ||
1323 | struct regmap *regmap = isc->regmap; | ||
1324 | struct isc_ctrls *ctrls = &isc->ctrls; | ||
1325 | u32 hist_id = ctrls->hist_id; | ||
1326 | u32 baysel; | ||
1327 | |||
1328 | if (ctrls->hist_stat != HIST_ENABLED) | ||
1329 | return; | ||
1330 | |||
1331 | isc_hist_count(isc); | ||
1332 | |||
1333 | if (hist_id != ISC_HIS_CFG_MODE_B) { | ||
1334 | hist_id++; | ||
1335 | } else { | ||
1336 | isc_wb_update(ctrls); | ||
1337 | hist_id = ISC_HIS_CFG_MODE_R; | ||
1338 | } | ||
1339 | |||
1340 | ctrls->hist_id = hist_id; | ||
1341 | baysel = isc->raw_fmt->reg_bay_cfg << ISC_HIS_CFG_BAYSEL_SHIFT; | ||
1342 | |||
1343 | pm_runtime_get_sync(isc->dev); | ||
1344 | |||
1345 | regmap_write(regmap, ISC_HIS_CFG, hist_id | baysel | ISC_HIS_CFG_RAR); | ||
1346 | isc_update_profile(isc); | ||
1347 | regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ); | ||
1348 | |||
1349 | pm_runtime_put_sync(isc->dev); | ||
1350 | } | ||
1351 | |||
1352 | static int isc_s_ctrl(struct v4l2_ctrl *ctrl) | ||
1353 | { | ||
1354 | struct isc_device *isc = container_of(ctrl->handler, | ||
1355 | struct isc_device, ctrls.handler); | ||
1356 | struct isc_ctrls *ctrls = &isc->ctrls; | ||
1357 | |||
1358 | switch (ctrl->id) { | ||
1359 | case V4L2_CID_BRIGHTNESS: | ||
1360 | ctrls->brightness = ctrl->val & ISC_CBC_BRIGHT_MASK; | ||
1361 | break; | ||
1362 | case V4L2_CID_CONTRAST: | ||
1363 | ctrls->contrast = ctrl->val & ISC_CBC_CONTRAST_MASK; | ||
1364 | break; | ||
1365 | case V4L2_CID_GAMMA: | ||
1366 | ctrls->gamma_index = ctrl->val; | ||
1367 | break; | ||
1368 | case V4L2_CID_AUTO_WHITE_BALANCE: | ||
1369 | ctrls->awb = ctrl->val; | ||
1370 | if (ctrls->hist_stat != HIST_ENABLED) { | ||
1371 | ctrls->r_gain = 0x1 << 9; | ||
1372 | ctrls->b_gain = 0x1 << 9; | ||
1373 | } | ||
1374 | break; | ||
1375 | default: | ||
1376 | return -EINVAL; | ||
1377 | } | ||
1378 | |||
1379 | return 0; | ||
1380 | } | ||
1381 | |||
1382 | static const struct v4l2_ctrl_ops isc_ctrl_ops = { | ||
1383 | .s_ctrl = isc_s_ctrl, | ||
1384 | }; | ||
1385 | |||
1386 | static int isc_ctrl_init(struct isc_device *isc) | ||
1387 | { | ||
1388 | const struct v4l2_ctrl_ops *ops = &isc_ctrl_ops; | ||
1389 | struct isc_ctrls *ctrls = &isc->ctrls; | ||
1390 | struct v4l2_ctrl_handler *hdl = &ctrls->handler; | ||
1391 | int ret; | ||
1392 | |||
1393 | ctrls->hist_stat = HIST_INIT; | ||
1394 | |||
1395 | ret = v4l2_ctrl_handler_init(hdl, 4); | ||
1396 | if (ret < 0) | ||
1397 | return ret; | ||
1398 | |||
1399 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -1024, 1023, 1, 0); | ||
1400 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 256); | ||
1401 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, GAMMA_MAX, 1, 2); | ||
1402 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); | ||
1403 | |||
1404 | v4l2_ctrl_handler_setup(hdl); | ||
1405 | |||
1406 | return 0; | ||
1407 | } | ||
1408 | |||
1409 | |||
1025 | static int isc_async_bound(struct v4l2_async_notifier *notifier, | 1410 | static int isc_async_bound(struct v4l2_async_notifier *notifier, |
1026 | struct v4l2_subdev *subdev, | 1411 | struct v4l2_subdev *subdev, |
1027 | struct v4l2_async_subdev *asd) | 1412 | struct v4l2_async_subdev *asd) |
@@ -1047,10 +1432,11 @@ static void isc_async_unbind(struct v4l2_async_notifier *notifier, | |||
1047 | { | 1432 | { |
1048 | struct isc_device *isc = container_of(notifier->v4l2_dev, | 1433 | struct isc_device *isc = container_of(notifier->v4l2_dev, |
1049 | struct isc_device, v4l2_dev); | 1434 | struct isc_device, v4l2_dev); |
1050 | 1435 | cancel_work_sync(&isc->awb_work); | |
1051 | video_unregister_device(&isc->video_dev); | 1436 | video_unregister_device(&isc->video_dev); |
1052 | if (isc->current_subdev->config) | 1437 | if (isc->current_subdev->config) |
1053 | v4l2_subdev_free_pad_config(isc->current_subdev->config); | 1438 | v4l2_subdev_free_pad_config(isc->current_subdev->config); |
1439 | v4l2_ctrl_handler_free(&isc->ctrls.handler); | ||
1054 | } | 1440 | } |
1055 | 1441 | ||
1056 | static struct isc_format *find_format_by_code(unsigned int code, int *index) | 1442 | static struct isc_format *find_format_by_code(unsigned int code, int *index) |
@@ -1074,14 +1460,16 @@ static int isc_formats_init(struct isc_device *isc) | |||
1074 | { | 1460 | { |
1075 | struct isc_format *fmt; | 1461 | struct isc_format *fmt; |
1076 | struct v4l2_subdev *subdev = isc->current_subdev->sd; | 1462 | struct v4l2_subdev *subdev = isc->current_subdev->sd; |
1077 | int num_fmts = 0, i, j; | 1463 | unsigned int num_fmts, i, j; |
1078 | struct v4l2_subdev_mbus_code_enum mbus_code = { | 1464 | struct v4l2_subdev_mbus_code_enum mbus_code = { |
1079 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | 1465 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, |
1080 | }; | 1466 | }; |
1081 | 1467 | ||
1082 | fmt = &isc_formats[0]; | 1468 | fmt = &isc_formats[0]; |
1083 | for (i = 0; i < ARRAY_SIZE(isc_formats); i++) { | 1469 | for (i = 0; i < ARRAY_SIZE(isc_formats); i++) { |
1084 | fmt->support = false; | 1470 | fmt->isc_support = false; |
1471 | fmt->sd_support = false; | ||
1472 | |||
1085 | fmt++; | 1473 | fmt++; |
1086 | } | 1474 | } |
1087 | 1475 | ||
@@ -1092,8 +1480,22 @@ static int isc_formats_init(struct isc_device *isc) | |||
1092 | if (!fmt) | 1480 | if (!fmt) |
1093 | continue; | 1481 | continue; |
1094 | 1482 | ||
1095 | fmt->support = true; | 1483 | fmt->sd_support = true; |
1096 | num_fmts++; | 1484 | |
1485 | if (i <= RAW_FMT_IND_END) { | ||
1486 | for (j = ISC_FMT_IND_START; j <= ISC_FMT_IND_END; j++) | ||
1487 | isc_formats[j].isc_support = true; | ||
1488 | |||
1489 | isc->raw_fmt = fmt; | ||
1490 | } | ||
1491 | } | ||
1492 | |||
1493 | fmt = &isc_formats[0]; | ||
1494 | for (i = 0, num_fmts = 0; i < ARRAY_SIZE(isc_formats); i++) { | ||
1495 | if (fmt->isc_support || fmt->sd_support) | ||
1496 | num_fmts++; | ||
1497 | |||
1498 | fmt++; | ||
1097 | } | 1499 | } |
1098 | 1500 | ||
1099 | if (!num_fmts) | 1501 | if (!num_fmts) |
@@ -1110,7 +1512,7 @@ static int isc_formats_init(struct isc_device *isc) | |||
1110 | 1512 | ||
1111 | fmt = &isc_formats[0]; | 1513 | fmt = &isc_formats[0]; |
1112 | for (i = 0, j = 0; i < ARRAY_SIZE(isc_formats); i++) { | 1514 | for (i = 0, j = 0; i < ARRAY_SIZE(isc_formats); i++) { |
1113 | if (fmt->support) | 1515 | if (fmt->isc_support || fmt->sd_support) |
1114 | isc->user_formats[j++] = fmt; | 1516 | isc->user_formats[j++] = fmt; |
1115 | 1517 | ||
1116 | fmt++; | 1518 | fmt++; |
@@ -1132,7 +1534,7 @@ static int isc_set_default_fmt(struct isc_device *isc) | |||
1132 | }; | 1534 | }; |
1133 | int ret; | 1535 | int ret; |
1134 | 1536 | ||
1135 | ret = isc_try_fmt(isc, &f, NULL); | 1537 | ret = isc_try_fmt(isc, &f, NULL, NULL); |
1136 | if (ret) | 1538 | if (ret) |
1137 | return ret; | 1539 | return ret; |
1138 | 1540 | ||
@@ -1151,6 +1553,12 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) | |||
1151 | struct vb2_queue *q = &isc->vb2_vidq; | 1553 | struct vb2_queue *q = &isc->vb2_vidq; |
1152 | int ret; | 1554 | int ret; |
1153 | 1555 | ||
1556 | ret = v4l2_device_register_subdev_nodes(&isc->v4l2_dev); | ||
1557 | if (ret < 0) { | ||
1558 | v4l2_err(&isc->v4l2_dev, "Failed to register subdev nodes\n"); | ||
1559 | return ret; | ||
1560 | } | ||
1561 | |||
1154 | isc->current_subdev = container_of(notifier, | 1562 | isc->current_subdev = container_of(notifier, |
1155 | struct isc_subdev_entity, notifier); | 1563 | struct isc_subdev_entity, notifier); |
1156 | sd_entity = isc->current_subdev; | 1564 | sd_entity = isc->current_subdev; |
@@ -1198,6 +1606,14 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) | |||
1198 | return ret; | 1606 | return ret; |
1199 | } | 1607 | } |
1200 | 1608 | ||
1609 | ret = isc_ctrl_init(isc); | ||
1610 | if (ret) { | ||
1611 | v4l2_err(&isc->v4l2_dev, "Init isc ctrols failed: %d\n", ret); | ||
1612 | return ret; | ||
1613 | } | ||
1614 | |||
1615 | INIT_WORK(&isc->awb_work, isc_awb_work); | ||
1616 | |||
1201 | /* Register video device */ | 1617 | /* Register video device */ |
1202 | strlcpy(vdev->name, ATMEL_ISC_NAME, sizeof(vdev->name)); | 1618 | strlcpy(vdev->name, ATMEL_ISC_NAME, sizeof(vdev->name)); |
1203 | vdev->release = video_device_release_empty; | 1619 | vdev->release = video_device_release_empty; |
@@ -1207,7 +1623,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) | |||
1207 | vdev->vfl_dir = VFL_DIR_RX; | 1623 | vdev->vfl_dir = VFL_DIR_RX; |
1208 | vdev->queue = q; | 1624 | vdev->queue = q; |
1209 | vdev->lock = &isc->lock; | 1625 | vdev->lock = &isc->lock; |
1210 | vdev->ctrl_handler = isc->current_subdev->sd->ctrl_handler; | 1626 | vdev->ctrl_handler = &isc->ctrls.handler; |
1211 | vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE; | 1627 | vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE; |
1212 | video_set_drvdata(vdev, isc); | 1628 | video_set_drvdata(vdev, isc); |
1213 | 1629 | ||
diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c new file mode 100644 index 000000000000..e4867f84514c --- /dev/null +++ b/drivers/media/platform/atmel/atmel-isi.c | |||
@@ -0,0 +1,1368 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2011 Atmel Corporation | ||
3 | * Josh Wu, <josh.wu@atmel.com> | ||
4 | * | ||
5 | * Based on previous work by Lars Haring, <lars.haring@atmel.com> | ||
6 | * and Sedji Gaouaou | ||
7 | * Based on the bttv driver for Bt848 with respective copyright holders | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/clk.h> | ||
15 | #include <linux/completion.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/fs.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/pm_runtime.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/of.h> | ||
26 | |||
27 | #include <linux/videodev2.h> | ||
28 | #include <media/v4l2-ctrls.h> | ||
29 | #include <media/v4l2-device.h> | ||
30 | #include <media/v4l2-dev.h> | ||
31 | #include <media/v4l2-ioctl.h> | ||
32 | #include <media/v4l2-event.h> | ||
33 | #include <media/v4l2-of.h> | ||
34 | #include <media/videobuf2-dma-contig.h> | ||
35 | #include <media/v4l2-image-sizes.h> | ||
36 | |||
37 | #include "atmel-isi.h" | ||
38 | |||
39 | #define MAX_SUPPORT_WIDTH 2048 | ||
40 | #define MAX_SUPPORT_HEIGHT 2048 | ||
41 | #define MIN_FRAME_RATE 15 | ||
42 | #define FRAME_INTERVAL_MILLI_SEC (1000 / MIN_FRAME_RATE) | ||
43 | |||
44 | /* Frame buffer descriptor */ | ||
45 | struct fbd { | ||
46 | /* Physical address of the frame buffer */ | ||
47 | u32 fb_address; | ||
48 | /* DMA Control Register(only in HISI2) */ | ||
49 | u32 dma_ctrl; | ||
50 | /* Physical address of the next fbd */ | ||
51 | u32 next_fbd_address; | ||
52 | }; | ||
53 | |||
54 | static void set_dma_ctrl(struct fbd *fb_desc, u32 ctrl) | ||
55 | { | ||
56 | fb_desc->dma_ctrl = ctrl; | ||
57 | } | ||
58 | |||
59 | struct isi_dma_desc { | ||
60 | struct list_head list; | ||
61 | struct fbd *p_fbd; | ||
62 | dma_addr_t fbd_phys; | ||
63 | }; | ||
64 | |||
65 | /* Frame buffer data */ | ||
66 | struct frame_buffer { | ||
67 | struct vb2_v4l2_buffer vb; | ||
68 | struct isi_dma_desc *p_dma_desc; | ||
69 | struct list_head list; | ||
70 | }; | ||
71 | |||
72 | struct isi_graph_entity { | ||
73 | struct device_node *node; | ||
74 | |||
75 | struct v4l2_async_subdev asd; | ||
76 | struct v4l2_subdev *subdev; | ||
77 | }; | ||
78 | |||
79 | /* | ||
80 | * struct isi_format - ISI media bus format information | ||
81 | * @fourcc: Fourcc code for this format | ||
82 | * @mbus_code: V4L2 media bus format code. | ||
83 | * @bpp: Bytes per pixel (when stored in memory) | ||
84 | * @swap: Byte swap configuration value | ||
85 | * @support: Indicates format supported by subdev | ||
86 | * @skip: Skip duplicate format supported by subdev | ||
87 | */ | ||
88 | struct isi_format { | ||
89 | u32 fourcc; | ||
90 | u32 mbus_code; | ||
91 | u8 bpp; | ||
92 | u32 swap; | ||
93 | }; | ||
94 | |||
95 | |||
96 | struct atmel_isi { | ||
97 | /* Protects the access of variables shared with the ISR */ | ||
98 | spinlock_t irqlock; | ||
99 | struct device *dev; | ||
100 | void __iomem *regs; | ||
101 | |||
102 | int sequence; | ||
103 | |||
104 | /* Allocate descriptors for dma buffer use */ | ||
105 | struct fbd *p_fb_descriptors; | ||
106 | dma_addr_t fb_descriptors_phys; | ||
107 | struct list_head dma_desc_head; | ||
108 | struct isi_dma_desc dma_desc[VIDEO_MAX_FRAME]; | ||
109 | bool enable_preview_path; | ||
110 | |||
111 | struct completion complete; | ||
112 | /* ISI peripherial clock */ | ||
113 | struct clk *pclk; | ||
114 | unsigned int irq; | ||
115 | |||
116 | struct isi_platform_data pdata; | ||
117 | u16 width_flags; /* max 12 bits */ | ||
118 | |||
119 | struct list_head video_buffer_list; | ||
120 | struct frame_buffer *active; | ||
121 | |||
122 | struct v4l2_device v4l2_dev; | ||
123 | struct video_device *vdev; | ||
124 | struct v4l2_async_notifier notifier; | ||
125 | struct isi_graph_entity entity; | ||
126 | struct v4l2_format fmt; | ||
127 | |||
128 | const struct isi_format **user_formats; | ||
129 | unsigned int num_user_formats; | ||
130 | const struct isi_format *current_fmt; | ||
131 | |||
132 | struct mutex lock; | ||
133 | struct vb2_queue queue; | ||
134 | }; | ||
135 | |||
136 | #define notifier_to_isi(n) container_of(n, struct atmel_isi, notifier) | ||
137 | |||
138 | static void isi_writel(struct atmel_isi *isi, u32 reg, u32 val) | ||
139 | { | ||
140 | writel(val, isi->regs + reg); | ||
141 | } | ||
142 | static u32 isi_readl(struct atmel_isi *isi, u32 reg) | ||
143 | { | ||
144 | return readl(isi->regs + reg); | ||
145 | } | ||
146 | |||
147 | static void configure_geometry(struct atmel_isi *isi) | ||
148 | { | ||
149 | u32 cfg2, psize; | ||
150 | u32 fourcc = isi->current_fmt->fourcc; | ||
151 | |||
152 | isi->enable_preview_path = fourcc == V4L2_PIX_FMT_RGB565 || | ||
153 | fourcc == V4L2_PIX_FMT_RGB32; | ||
154 | |||
155 | /* According to sensor's output format to set cfg2 */ | ||
156 | cfg2 = isi->current_fmt->swap; | ||
157 | |||
158 | isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); | ||
159 | /* Set width */ | ||
160 | cfg2 |= ((isi->fmt.fmt.pix.width - 1) << ISI_CFG2_IM_HSIZE_OFFSET) & | ||
161 | ISI_CFG2_IM_HSIZE_MASK; | ||
162 | /* Set height */ | ||
163 | cfg2 |= ((isi->fmt.fmt.pix.height - 1) << ISI_CFG2_IM_VSIZE_OFFSET) | ||
164 | & ISI_CFG2_IM_VSIZE_MASK; | ||
165 | isi_writel(isi, ISI_CFG2, cfg2); | ||
166 | |||
167 | /* No down sampling, preview size equal to sensor output size */ | ||
168 | psize = ((isi->fmt.fmt.pix.width - 1) << ISI_PSIZE_PREV_HSIZE_OFFSET) & | ||
169 | ISI_PSIZE_PREV_HSIZE_MASK; | ||
170 | psize |= ((isi->fmt.fmt.pix.height - 1) << ISI_PSIZE_PREV_VSIZE_OFFSET) & | ||
171 | ISI_PSIZE_PREV_VSIZE_MASK; | ||
172 | isi_writel(isi, ISI_PSIZE, psize); | ||
173 | isi_writel(isi, ISI_PDECF, ISI_PDECF_NO_SAMPLING); | ||
174 | } | ||
175 | |||
176 | static irqreturn_t atmel_isi_handle_streaming(struct atmel_isi *isi) | ||
177 | { | ||
178 | if (isi->active) { | ||
179 | struct vb2_v4l2_buffer *vbuf = &isi->active->vb; | ||
180 | struct frame_buffer *buf = isi->active; | ||
181 | |||
182 | list_del_init(&buf->list); | ||
183 | vbuf->vb2_buf.timestamp = ktime_get_ns(); | ||
184 | vbuf->sequence = isi->sequence++; | ||
185 | vbuf->field = V4L2_FIELD_NONE; | ||
186 | vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE); | ||
187 | } | ||
188 | |||
189 | if (list_empty(&isi->video_buffer_list)) { | ||
190 | isi->active = NULL; | ||
191 | } else { | ||
192 | /* start next dma frame. */ | ||
193 | isi->active = list_entry(isi->video_buffer_list.next, | ||
194 | struct frame_buffer, list); | ||
195 | if (!isi->enable_preview_path) { | ||
196 | isi_writel(isi, ISI_DMA_C_DSCR, | ||
197 | (u32)isi->active->p_dma_desc->fbd_phys); | ||
198 | isi_writel(isi, ISI_DMA_C_CTRL, | ||
199 | ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); | ||
200 | isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH); | ||
201 | } else { | ||
202 | isi_writel(isi, ISI_DMA_P_DSCR, | ||
203 | (u32)isi->active->p_dma_desc->fbd_phys); | ||
204 | isi_writel(isi, ISI_DMA_P_CTRL, | ||
205 | ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); | ||
206 | isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_P_CH); | ||
207 | } | ||
208 | } | ||
209 | return IRQ_HANDLED; | ||
210 | } | ||
211 | |||
212 | /* ISI interrupt service routine */ | ||
213 | static irqreturn_t isi_interrupt(int irq, void *dev_id) | ||
214 | { | ||
215 | struct atmel_isi *isi = dev_id; | ||
216 | u32 status, mask, pending; | ||
217 | irqreturn_t ret = IRQ_NONE; | ||
218 | |||
219 | spin_lock(&isi->irqlock); | ||
220 | |||
221 | status = isi_readl(isi, ISI_STATUS); | ||
222 | mask = isi_readl(isi, ISI_INTMASK); | ||
223 | pending = status & mask; | ||
224 | |||
225 | if (pending & ISI_CTRL_SRST) { | ||
226 | complete(&isi->complete); | ||
227 | isi_writel(isi, ISI_INTDIS, ISI_CTRL_SRST); | ||
228 | ret = IRQ_HANDLED; | ||
229 | } else if (pending & ISI_CTRL_DIS) { | ||
230 | complete(&isi->complete); | ||
231 | isi_writel(isi, ISI_INTDIS, ISI_CTRL_DIS); | ||
232 | ret = IRQ_HANDLED; | ||
233 | } else { | ||
234 | if (likely(pending & ISI_SR_CXFR_DONE) || | ||
235 | likely(pending & ISI_SR_PXFR_DONE)) | ||
236 | ret = atmel_isi_handle_streaming(isi); | ||
237 | } | ||
238 | |||
239 | spin_unlock(&isi->irqlock); | ||
240 | return ret; | ||
241 | } | ||
242 | |||
243 | #define WAIT_ISI_RESET 1 | ||
244 | #define WAIT_ISI_DISABLE 0 | ||
245 | static int atmel_isi_wait_status(struct atmel_isi *isi, int wait_reset) | ||
246 | { | ||
247 | unsigned long timeout; | ||
248 | /* | ||
249 | * The reset or disable will only succeed if we have a | ||
250 | * pixel clock from the camera. | ||
251 | */ | ||
252 | init_completion(&isi->complete); | ||
253 | |||
254 | if (wait_reset) { | ||
255 | isi_writel(isi, ISI_INTEN, ISI_CTRL_SRST); | ||
256 | isi_writel(isi, ISI_CTRL, ISI_CTRL_SRST); | ||
257 | } else { | ||
258 | isi_writel(isi, ISI_INTEN, ISI_CTRL_DIS); | ||
259 | isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); | ||
260 | } | ||
261 | |||
262 | timeout = wait_for_completion_timeout(&isi->complete, | ||
263 | msecs_to_jiffies(500)); | ||
264 | if (timeout == 0) | ||
265 | return -ETIMEDOUT; | ||
266 | |||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | /* ------------------------------------------------------------------ | ||
271 | Videobuf operations | ||
272 | ------------------------------------------------------------------*/ | ||
273 | static int queue_setup(struct vb2_queue *vq, | ||
274 | unsigned int *nbuffers, unsigned int *nplanes, | ||
275 | unsigned int sizes[], struct device *alloc_devs[]) | ||
276 | { | ||
277 | struct atmel_isi *isi = vb2_get_drv_priv(vq); | ||
278 | unsigned long size; | ||
279 | |||
280 | size = isi->fmt.fmt.pix.sizeimage; | ||
281 | |||
282 | /* Make sure the image size is large enough. */ | ||
283 | if (*nplanes) | ||
284 | return sizes[0] < size ? -EINVAL : 0; | ||
285 | |||
286 | *nplanes = 1; | ||
287 | sizes[0] = size; | ||
288 | |||
289 | isi->active = NULL; | ||
290 | |||
291 | dev_dbg(isi->dev, "%s, count=%d, size=%ld\n", __func__, | ||
292 | *nbuffers, size); | ||
293 | |||
294 | return 0; | ||
295 | } | ||
296 | |||
297 | static int buffer_init(struct vb2_buffer *vb) | ||
298 | { | ||
299 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | ||
300 | struct frame_buffer *buf = container_of(vbuf, struct frame_buffer, vb); | ||
301 | |||
302 | buf->p_dma_desc = NULL; | ||
303 | INIT_LIST_HEAD(&buf->list); | ||
304 | |||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | static int buffer_prepare(struct vb2_buffer *vb) | ||
309 | { | ||
310 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | ||
311 | struct frame_buffer *buf = container_of(vbuf, struct frame_buffer, vb); | ||
312 | struct atmel_isi *isi = vb2_get_drv_priv(vb->vb2_queue); | ||
313 | unsigned long size; | ||
314 | struct isi_dma_desc *desc; | ||
315 | |||
316 | size = isi->fmt.fmt.pix.sizeimage; | ||
317 | |||
318 | if (vb2_plane_size(vb, 0) < size) { | ||
319 | dev_err(isi->dev, "%s data will not fit into plane (%lu < %lu)\n", | ||
320 | __func__, vb2_plane_size(vb, 0), size); | ||
321 | return -EINVAL; | ||
322 | } | ||
323 | |||
324 | vb2_set_plane_payload(vb, 0, size); | ||
325 | |||
326 | if (!buf->p_dma_desc) { | ||
327 | if (list_empty(&isi->dma_desc_head)) { | ||
328 | dev_err(isi->dev, "Not enough dma descriptors.\n"); | ||
329 | return -EINVAL; | ||
330 | } else { | ||
331 | /* Get an available descriptor */ | ||
332 | desc = list_entry(isi->dma_desc_head.next, | ||
333 | struct isi_dma_desc, list); | ||
334 | /* Delete the descriptor since now it is used */ | ||
335 | list_del_init(&desc->list); | ||
336 | |||
337 | /* Initialize the dma descriptor */ | ||
338 | desc->p_fbd->fb_address = | ||
339 | vb2_dma_contig_plane_dma_addr(vb, 0); | ||
340 | desc->p_fbd->next_fbd_address = 0; | ||
341 | set_dma_ctrl(desc->p_fbd, ISI_DMA_CTRL_WB); | ||
342 | |||
343 | buf->p_dma_desc = desc; | ||
344 | } | ||
345 | } | ||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | static void buffer_cleanup(struct vb2_buffer *vb) | ||
350 | { | ||
351 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | ||
352 | struct atmel_isi *isi = vb2_get_drv_priv(vb->vb2_queue); | ||
353 | struct frame_buffer *buf = container_of(vbuf, struct frame_buffer, vb); | ||
354 | |||
355 | /* This descriptor is available now and we add to head list */ | ||
356 | if (buf->p_dma_desc) | ||
357 | list_add(&buf->p_dma_desc->list, &isi->dma_desc_head); | ||
358 | } | ||
359 | |||
360 | static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer) | ||
361 | { | ||
362 | u32 ctrl, cfg1; | ||
363 | |||
364 | cfg1 = isi_readl(isi, ISI_CFG1); | ||
365 | /* Enable irq: cxfr for the codec path, pxfr for the preview path */ | ||
366 | isi_writel(isi, ISI_INTEN, | ||
367 | ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE); | ||
368 | |||
369 | /* Check if already in a frame */ | ||
370 | if (!isi->enable_preview_path) { | ||
371 | if (isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) { | ||
372 | dev_err(isi->dev, "Already in frame handling.\n"); | ||
373 | return; | ||
374 | } | ||
375 | |||
376 | isi_writel(isi, ISI_DMA_C_DSCR, | ||
377 | (u32)buffer->p_dma_desc->fbd_phys); | ||
378 | isi_writel(isi, ISI_DMA_C_CTRL, | ||
379 | ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); | ||
380 | isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH); | ||
381 | } else { | ||
382 | isi_writel(isi, ISI_DMA_P_DSCR, | ||
383 | (u32)buffer->p_dma_desc->fbd_phys); | ||
384 | isi_writel(isi, ISI_DMA_P_CTRL, | ||
385 | ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); | ||
386 | isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_P_CH); | ||
387 | } | ||
388 | |||
389 | cfg1 &= ~ISI_CFG1_FRATE_DIV_MASK; | ||
390 | /* Enable linked list */ | ||
391 | cfg1 |= isi->pdata.frate | ISI_CFG1_DISCR; | ||
392 | |||
393 | /* Enable ISI */ | ||
394 | ctrl = ISI_CTRL_EN; | ||
395 | |||
396 | if (!isi->enable_preview_path) | ||
397 | ctrl |= ISI_CTRL_CDC; | ||
398 | |||
399 | isi_writel(isi, ISI_CTRL, ctrl); | ||
400 | isi_writel(isi, ISI_CFG1, cfg1); | ||
401 | } | ||
402 | |||
403 | static void buffer_queue(struct vb2_buffer *vb) | ||
404 | { | ||
405 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | ||
406 | struct atmel_isi *isi = vb2_get_drv_priv(vb->vb2_queue); | ||
407 | struct frame_buffer *buf = container_of(vbuf, struct frame_buffer, vb); | ||
408 | unsigned long flags = 0; | ||
409 | |||
410 | spin_lock_irqsave(&isi->irqlock, flags); | ||
411 | list_add_tail(&buf->list, &isi->video_buffer_list); | ||
412 | |||
413 | if (isi->active == NULL) { | ||
414 | isi->active = buf; | ||
415 | if (vb2_is_streaming(vb->vb2_queue)) | ||
416 | start_dma(isi, buf); | ||
417 | } | ||
418 | spin_unlock_irqrestore(&isi->irqlock, flags); | ||
419 | } | ||
420 | |||
421 | static int start_streaming(struct vb2_queue *vq, unsigned int count) | ||
422 | { | ||
423 | struct atmel_isi *isi = vb2_get_drv_priv(vq); | ||
424 | struct frame_buffer *buf, *node; | ||
425 | int ret; | ||
426 | |||
427 | /* Enable stream on the sub device */ | ||
428 | ret = v4l2_subdev_call(isi->entity.subdev, video, s_stream, 1); | ||
429 | if (ret && ret != -ENOIOCTLCMD) { | ||
430 | dev_err(isi->dev, "stream on failed in subdev\n"); | ||
431 | goto err_start_stream; | ||
432 | } | ||
433 | |||
434 | pm_runtime_get_sync(isi->dev); | ||
435 | |||
436 | /* Reset ISI */ | ||
437 | ret = atmel_isi_wait_status(isi, WAIT_ISI_RESET); | ||
438 | if (ret < 0) { | ||
439 | dev_err(isi->dev, "Reset ISI timed out\n"); | ||
440 | goto err_reset; | ||
441 | } | ||
442 | /* Disable all interrupts */ | ||
443 | isi_writel(isi, ISI_INTDIS, (u32)~0UL); | ||
444 | |||
445 | isi->sequence = 0; | ||
446 | configure_geometry(isi); | ||
447 | |||
448 | spin_lock_irq(&isi->irqlock); | ||
449 | /* Clear any pending interrupt */ | ||
450 | isi_readl(isi, ISI_STATUS); | ||
451 | |||
452 | start_dma(isi, isi->active); | ||
453 | spin_unlock_irq(&isi->irqlock); | ||
454 | |||
455 | return 0; | ||
456 | |||
457 | err_reset: | ||
458 | pm_runtime_put(isi->dev); | ||
459 | v4l2_subdev_call(isi->entity.subdev, video, s_stream, 0); | ||
460 | |||
461 | err_start_stream: | ||
462 | spin_lock_irq(&isi->irqlock); | ||
463 | isi->active = NULL; | ||
464 | /* Release all active buffers */ | ||
465 | list_for_each_entry_safe(buf, node, &isi->video_buffer_list, list) { | ||
466 | list_del_init(&buf->list); | ||
467 | vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED); | ||
468 | } | ||
469 | spin_unlock_irq(&isi->irqlock); | ||
470 | |||
471 | return ret; | ||
472 | } | ||
473 | |||
474 | /* abort streaming and wait for last buffer */ | ||
475 | static void stop_streaming(struct vb2_queue *vq) | ||
476 | { | ||
477 | struct atmel_isi *isi = vb2_get_drv_priv(vq); | ||
478 | struct frame_buffer *buf, *node; | ||
479 | int ret = 0; | ||
480 | unsigned long timeout; | ||
481 | |||
482 | /* Disable stream on the sub device */ | ||
483 | ret = v4l2_subdev_call(isi->entity.subdev, video, s_stream, 0); | ||
484 | if (ret && ret != -ENOIOCTLCMD) | ||
485 | dev_err(isi->dev, "stream off failed in subdev\n"); | ||
486 | |||
487 | spin_lock_irq(&isi->irqlock); | ||
488 | isi->active = NULL; | ||
489 | /* Release all active buffers */ | ||
490 | list_for_each_entry_safe(buf, node, &isi->video_buffer_list, list) { | ||
491 | list_del_init(&buf->list); | ||
492 | vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); | ||
493 | } | ||
494 | spin_unlock_irq(&isi->irqlock); | ||
495 | |||
496 | if (!isi->enable_preview_path) { | ||
497 | timeout = jiffies + FRAME_INTERVAL_MILLI_SEC * HZ; | ||
498 | /* Wait until the end of the current frame. */ | ||
499 | while ((isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) && | ||
500 | time_before(jiffies, timeout)) | ||
501 | msleep(1); | ||
502 | |||
503 | if (time_after(jiffies, timeout)) | ||
504 | dev_err(isi->dev, | ||
505 | "Timeout waiting for finishing codec request\n"); | ||
506 | } | ||
507 | |||
508 | /* Disable interrupts */ | ||
509 | isi_writel(isi, ISI_INTDIS, | ||
510 | ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE); | ||
511 | |||
512 | /* Disable ISI and wait for it is done */ | ||
513 | ret = atmel_isi_wait_status(isi, WAIT_ISI_DISABLE); | ||
514 | if (ret < 0) | ||
515 | dev_err(isi->dev, "Disable ISI timed out\n"); | ||
516 | |||
517 | pm_runtime_put(isi->dev); | ||
518 | } | ||
519 | |||
520 | static const struct vb2_ops isi_video_qops = { | ||
521 | .queue_setup = queue_setup, | ||
522 | .buf_init = buffer_init, | ||
523 | .buf_prepare = buffer_prepare, | ||
524 | .buf_cleanup = buffer_cleanup, | ||
525 | .buf_queue = buffer_queue, | ||
526 | .start_streaming = start_streaming, | ||
527 | .stop_streaming = stop_streaming, | ||
528 | .wait_prepare = vb2_ops_wait_prepare, | ||
529 | .wait_finish = vb2_ops_wait_finish, | ||
530 | }; | ||
531 | |||
532 | static int isi_g_fmt_vid_cap(struct file *file, void *priv, | ||
533 | struct v4l2_format *fmt) | ||
534 | { | ||
535 | struct atmel_isi *isi = video_drvdata(file); | ||
536 | |||
537 | *fmt = isi->fmt; | ||
538 | |||
539 | return 0; | ||
540 | } | ||
541 | |||
542 | static const struct isi_format *find_format_by_fourcc(struct atmel_isi *isi, | ||
543 | unsigned int fourcc) | ||
544 | { | ||
545 | unsigned int num_formats = isi->num_user_formats; | ||
546 | const struct isi_format *fmt; | ||
547 | unsigned int i; | ||
548 | |||
549 | for (i = 0; i < num_formats; i++) { | ||
550 | fmt = isi->user_formats[i]; | ||
551 | if (fmt->fourcc == fourcc) | ||
552 | return fmt; | ||
553 | } | ||
554 | |||
555 | return NULL; | ||
556 | } | ||
557 | |||
558 | static int isi_try_fmt(struct atmel_isi *isi, struct v4l2_format *f, | ||
559 | const struct isi_format **current_fmt) | ||
560 | { | ||
561 | const struct isi_format *isi_fmt; | ||
562 | struct v4l2_pix_format *pixfmt = &f->fmt.pix; | ||
563 | struct v4l2_subdev_pad_config pad_cfg; | ||
564 | struct v4l2_subdev_format format = { | ||
565 | .which = V4L2_SUBDEV_FORMAT_TRY, | ||
566 | }; | ||
567 | int ret; | ||
568 | |||
569 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
570 | return -EINVAL; | ||
571 | |||
572 | isi_fmt = find_format_by_fourcc(isi, pixfmt->pixelformat); | ||
573 | if (!isi_fmt) { | ||
574 | isi_fmt = isi->user_formats[isi->num_user_formats - 1]; | ||
575 | pixfmt->pixelformat = isi_fmt->fourcc; | ||
576 | } | ||
577 | |||
578 | /* Limit to Atmel ISC hardware capabilities */ | ||
579 | if (pixfmt->width > MAX_SUPPORT_WIDTH) | ||
580 | pixfmt->width = MAX_SUPPORT_WIDTH; | ||
581 | if (pixfmt->height > MAX_SUPPORT_HEIGHT) | ||
582 | pixfmt->height = MAX_SUPPORT_HEIGHT; | ||
583 | |||
584 | v4l2_fill_mbus_format(&format.format, pixfmt, isi_fmt->mbus_code); | ||
585 | ret = v4l2_subdev_call(isi->entity.subdev, pad, set_fmt, | ||
586 | &pad_cfg, &format); | ||
587 | if (ret < 0) | ||
588 | return ret; | ||
589 | |||
590 | v4l2_fill_pix_format(pixfmt, &format.format); | ||
591 | |||
592 | pixfmt->field = V4L2_FIELD_NONE; | ||
593 | pixfmt->bytesperline = pixfmt->width * isi_fmt->bpp; | ||
594 | pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; | ||
595 | |||
596 | if (current_fmt) | ||
597 | *current_fmt = isi_fmt; | ||
598 | |||
599 | return 0; | ||
600 | } | ||
601 | |||
602 | static int isi_set_fmt(struct atmel_isi *isi, struct v4l2_format *f) | ||
603 | { | ||
604 | struct v4l2_subdev_format format = { | ||
605 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
606 | }; | ||
607 | const struct isi_format *current_fmt; | ||
608 | int ret; | ||
609 | |||
610 | ret = isi_try_fmt(isi, f, ¤t_fmt); | ||
611 | if (ret) | ||
612 | return ret; | ||
613 | |||
614 | v4l2_fill_mbus_format(&format.format, &f->fmt.pix, | ||
615 | current_fmt->mbus_code); | ||
616 | ret = v4l2_subdev_call(isi->entity.subdev, pad, | ||
617 | set_fmt, NULL, &format); | ||
618 | if (ret < 0) | ||
619 | return ret; | ||
620 | |||
621 | isi->fmt = *f; | ||
622 | isi->current_fmt = current_fmt; | ||
623 | |||
624 | return 0; | ||
625 | } | ||
626 | |||
627 | static int isi_s_fmt_vid_cap(struct file *file, void *priv, | ||
628 | struct v4l2_format *f) | ||
629 | { | ||
630 | struct atmel_isi *isi = video_drvdata(file); | ||
631 | |||
632 | if (vb2_is_streaming(&isi->queue)) | ||
633 | return -EBUSY; | ||
634 | |||
635 | return isi_set_fmt(isi, f); | ||
636 | } | ||
637 | |||
638 | static int isi_try_fmt_vid_cap(struct file *file, void *priv, | ||
639 | struct v4l2_format *f) | ||
640 | { | ||
641 | struct atmel_isi *isi = video_drvdata(file); | ||
642 | |||
643 | return isi_try_fmt(isi, f, NULL); | ||
644 | } | ||
645 | |||
646 | static int isi_enum_fmt_vid_cap(struct file *file, void *priv, | ||
647 | struct v4l2_fmtdesc *f) | ||
648 | { | ||
649 | struct atmel_isi *isi = video_drvdata(file); | ||
650 | |||
651 | if (f->index >= isi->num_user_formats) | ||
652 | return -EINVAL; | ||
653 | |||
654 | f->pixelformat = isi->user_formats[f->index]->fourcc; | ||
655 | return 0; | ||
656 | } | ||
657 | |||
658 | static int isi_querycap(struct file *file, void *priv, | ||
659 | struct v4l2_capability *cap) | ||
660 | { | ||
661 | strlcpy(cap->driver, "atmel-isi", sizeof(cap->driver)); | ||
662 | strlcpy(cap->card, "Atmel Image Sensor Interface", sizeof(cap->card)); | ||
663 | strlcpy(cap->bus_info, "platform:isi", sizeof(cap->bus_info)); | ||
664 | return 0; | ||
665 | } | ||
666 | |||
667 | static int isi_enum_input(struct file *file, void *priv, | ||
668 | struct v4l2_input *i) | ||
669 | { | ||
670 | if (i->index != 0) | ||
671 | return -EINVAL; | ||
672 | |||
673 | i->type = V4L2_INPUT_TYPE_CAMERA; | ||
674 | strlcpy(i->name, "Camera", sizeof(i->name)); | ||
675 | return 0; | ||
676 | } | ||
677 | |||
678 | static int isi_g_input(struct file *file, void *priv, unsigned int *i) | ||
679 | { | ||
680 | *i = 0; | ||
681 | return 0; | ||
682 | } | ||
683 | |||
684 | static int isi_s_input(struct file *file, void *priv, unsigned int i) | ||
685 | { | ||
686 | if (i > 0) | ||
687 | return -EINVAL; | ||
688 | return 0; | ||
689 | } | ||
690 | |||
691 | static int isi_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) | ||
692 | { | ||
693 | struct atmel_isi *isi = video_drvdata(file); | ||
694 | |||
695 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
696 | return -EINVAL; | ||
697 | |||
698 | a->parm.capture.readbuffers = 2; | ||
699 | return v4l2_subdev_call(isi->entity.subdev, video, g_parm, a); | ||
700 | } | ||
701 | |||
702 | static int isi_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) | ||
703 | { | ||
704 | struct atmel_isi *isi = video_drvdata(file); | ||
705 | |||
706 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
707 | return -EINVAL; | ||
708 | |||
709 | a->parm.capture.readbuffers = 2; | ||
710 | return v4l2_subdev_call(isi->entity.subdev, video, s_parm, a); | ||
711 | } | ||
712 | |||
713 | static int isi_enum_framesizes(struct file *file, void *fh, | ||
714 | struct v4l2_frmsizeenum *fsize) | ||
715 | { | ||
716 | struct atmel_isi *isi = video_drvdata(file); | ||
717 | const struct isi_format *isi_fmt; | ||
718 | struct v4l2_subdev_frame_size_enum fse = { | ||
719 | .index = fsize->index, | ||
720 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
721 | }; | ||
722 | int ret; | ||
723 | |||
724 | isi_fmt = find_format_by_fourcc(isi, fsize->pixel_format); | ||
725 | if (!isi_fmt) | ||
726 | return -EINVAL; | ||
727 | |||
728 | fse.code = isi_fmt->mbus_code; | ||
729 | |||
730 | ret = v4l2_subdev_call(isi->entity.subdev, pad, enum_frame_size, | ||
731 | NULL, &fse); | ||
732 | if (ret) | ||
733 | return ret; | ||
734 | |||
735 | fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; | ||
736 | fsize->discrete.width = fse.max_width; | ||
737 | fsize->discrete.height = fse.max_height; | ||
738 | |||
739 | return 0; | ||
740 | } | ||
741 | |||
742 | static int isi_enum_frameintervals(struct file *file, void *fh, | ||
743 | struct v4l2_frmivalenum *fival) | ||
744 | { | ||
745 | struct atmel_isi *isi = video_drvdata(file); | ||
746 | const struct isi_format *isi_fmt; | ||
747 | struct v4l2_subdev_frame_interval_enum fie = { | ||
748 | .index = fival->index, | ||
749 | .width = fival->width, | ||
750 | .height = fival->height, | ||
751 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
752 | }; | ||
753 | int ret; | ||
754 | |||
755 | isi_fmt = find_format_by_fourcc(isi, fival->pixel_format); | ||
756 | if (!isi_fmt) | ||
757 | return -EINVAL; | ||
758 | |||
759 | fie.code = isi_fmt->mbus_code; | ||
760 | |||
761 | ret = v4l2_subdev_call(isi->entity.subdev, pad, | ||
762 | enum_frame_interval, NULL, &fie); | ||
763 | if (ret) | ||
764 | return ret; | ||
765 | |||
766 | fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; | ||
767 | fival->discrete = fie.interval; | ||
768 | |||
769 | return 0; | ||
770 | } | ||
771 | |||
772 | static void isi_camera_set_bus_param(struct atmel_isi *isi) | ||
773 | { | ||
774 | u32 cfg1 = 0; | ||
775 | |||
776 | /* set bus param for ISI */ | ||
777 | if (isi->pdata.hsync_act_low) | ||
778 | cfg1 |= ISI_CFG1_HSYNC_POL_ACTIVE_LOW; | ||
779 | if (isi->pdata.vsync_act_low) | ||
780 | cfg1 |= ISI_CFG1_VSYNC_POL_ACTIVE_LOW; | ||
781 | if (isi->pdata.pclk_act_falling) | ||
782 | cfg1 |= ISI_CFG1_PIXCLK_POL_ACTIVE_FALLING; | ||
783 | if (isi->pdata.has_emb_sync) | ||
784 | cfg1 |= ISI_CFG1_EMB_SYNC; | ||
785 | if (isi->pdata.full_mode) | ||
786 | cfg1 |= ISI_CFG1_FULL_MODE; | ||
787 | |||
788 | cfg1 |= ISI_CFG1_THMASK_BEATS_16; | ||
789 | |||
790 | /* Enable PM and peripheral clock before operate isi registers */ | ||
791 | pm_runtime_get_sync(isi->dev); | ||
792 | |||
793 | isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); | ||
794 | isi_writel(isi, ISI_CFG1, cfg1); | ||
795 | |||
796 | pm_runtime_put(isi->dev); | ||
797 | } | ||
798 | |||
799 | /* -----------------------------------------------------------------------*/ | ||
800 | static int atmel_isi_parse_dt(struct atmel_isi *isi, | ||
801 | struct platform_device *pdev) | ||
802 | { | ||
803 | struct device_node *np = pdev->dev.of_node; | ||
804 | struct v4l2_of_endpoint ep; | ||
805 | int err; | ||
806 | |||
807 | /* Default settings for ISI */ | ||
808 | isi->pdata.full_mode = 1; | ||
809 | isi->pdata.frate = ISI_CFG1_FRATE_CAPTURE_ALL; | ||
810 | |||
811 | np = of_graph_get_next_endpoint(np, NULL); | ||
812 | if (!np) { | ||
813 | dev_err(&pdev->dev, "Could not find the endpoint\n"); | ||
814 | return -EINVAL; | ||
815 | } | ||
816 | |||
817 | err = v4l2_of_parse_endpoint(np, &ep); | ||
818 | of_node_put(np); | ||
819 | if (err) { | ||
820 | dev_err(&pdev->dev, "Could not parse the endpoint\n"); | ||
821 | return err; | ||
822 | } | ||
823 | |||
824 | switch (ep.bus.parallel.bus_width) { | ||
825 | case 8: | ||
826 | isi->pdata.data_width_flags = ISI_DATAWIDTH_8; | ||
827 | break; | ||
828 | case 10: | ||
829 | isi->pdata.data_width_flags = | ||
830 | ISI_DATAWIDTH_8 | ISI_DATAWIDTH_10; | ||
831 | break; | ||
832 | default: | ||
833 | dev_err(&pdev->dev, "Unsupported bus width: %d\n", | ||
834 | ep.bus.parallel.bus_width); | ||
835 | return -EINVAL; | ||
836 | } | ||
837 | |||
838 | if (ep.bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) | ||
839 | isi->pdata.hsync_act_low = true; | ||
840 | if (ep.bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) | ||
841 | isi->pdata.vsync_act_low = true; | ||
842 | if (ep.bus.parallel.flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) | ||
843 | isi->pdata.pclk_act_falling = true; | ||
844 | |||
845 | if (ep.bus_type == V4L2_MBUS_BT656) | ||
846 | isi->pdata.has_emb_sync = true; | ||
847 | |||
848 | return 0; | ||
849 | } | ||
850 | |||
851 | static int isi_open(struct file *file) | ||
852 | { | ||
853 | struct atmel_isi *isi = video_drvdata(file); | ||
854 | struct v4l2_subdev *sd = isi->entity.subdev; | ||
855 | int ret; | ||
856 | |||
857 | if (mutex_lock_interruptible(&isi->lock)) | ||
858 | return -ERESTARTSYS; | ||
859 | |||
860 | ret = v4l2_fh_open(file); | ||
861 | if (ret < 0) | ||
862 | goto unlock; | ||
863 | |||
864 | if (!v4l2_fh_is_singular_file(file)) | ||
865 | goto fh_rel; | ||
866 | |||
867 | ret = v4l2_subdev_call(sd, core, s_power, 1); | ||
868 | if (ret < 0 && ret != -ENOIOCTLCMD) | ||
869 | goto fh_rel; | ||
870 | |||
871 | ret = isi_set_fmt(isi, &isi->fmt); | ||
872 | if (ret) | ||
873 | v4l2_subdev_call(sd, core, s_power, 0); | ||
874 | fh_rel: | ||
875 | if (ret) | ||
876 | v4l2_fh_release(file); | ||
877 | unlock: | ||
878 | mutex_unlock(&isi->lock); | ||
879 | return ret; | ||
880 | } | ||
881 | |||
882 | static int isi_release(struct file *file) | ||
883 | { | ||
884 | struct atmel_isi *isi = video_drvdata(file); | ||
885 | struct v4l2_subdev *sd = isi->entity.subdev; | ||
886 | bool fh_singular; | ||
887 | int ret; | ||
888 | |||
889 | mutex_lock(&isi->lock); | ||
890 | |||
891 | fh_singular = v4l2_fh_is_singular_file(file); | ||
892 | |||
893 | ret = _vb2_fop_release(file, NULL); | ||
894 | |||
895 | if (fh_singular) | ||
896 | v4l2_subdev_call(sd, core, s_power, 0); | ||
897 | |||
898 | mutex_unlock(&isi->lock); | ||
899 | |||
900 | return ret; | ||
901 | } | ||
902 | |||
903 | static const struct v4l2_ioctl_ops isi_ioctl_ops = { | ||
904 | .vidioc_querycap = isi_querycap, | ||
905 | |||
906 | .vidioc_try_fmt_vid_cap = isi_try_fmt_vid_cap, | ||
907 | .vidioc_g_fmt_vid_cap = isi_g_fmt_vid_cap, | ||
908 | .vidioc_s_fmt_vid_cap = isi_s_fmt_vid_cap, | ||
909 | .vidioc_enum_fmt_vid_cap = isi_enum_fmt_vid_cap, | ||
910 | |||
911 | .vidioc_enum_input = isi_enum_input, | ||
912 | .vidioc_g_input = isi_g_input, | ||
913 | .vidioc_s_input = isi_s_input, | ||
914 | |||
915 | .vidioc_g_parm = isi_g_parm, | ||
916 | .vidioc_s_parm = isi_s_parm, | ||
917 | .vidioc_enum_framesizes = isi_enum_framesizes, | ||
918 | .vidioc_enum_frameintervals = isi_enum_frameintervals, | ||
919 | |||
920 | .vidioc_reqbufs = vb2_ioctl_reqbufs, | ||
921 | .vidioc_create_bufs = vb2_ioctl_create_bufs, | ||
922 | .vidioc_querybuf = vb2_ioctl_querybuf, | ||
923 | .vidioc_qbuf = vb2_ioctl_qbuf, | ||
924 | .vidioc_dqbuf = vb2_ioctl_dqbuf, | ||
925 | .vidioc_expbuf = vb2_ioctl_expbuf, | ||
926 | .vidioc_prepare_buf = vb2_ioctl_prepare_buf, | ||
927 | .vidioc_streamon = vb2_ioctl_streamon, | ||
928 | .vidioc_streamoff = vb2_ioctl_streamoff, | ||
929 | |||
930 | .vidioc_log_status = v4l2_ctrl_log_status, | ||
931 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, | ||
932 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | ||
933 | }; | ||
934 | |||
935 | static const struct v4l2_file_operations isi_fops = { | ||
936 | .owner = THIS_MODULE, | ||
937 | .unlocked_ioctl = video_ioctl2, | ||
938 | .open = isi_open, | ||
939 | .release = isi_release, | ||
940 | .poll = vb2_fop_poll, | ||
941 | .mmap = vb2_fop_mmap, | ||
942 | .read = vb2_fop_read, | ||
943 | }; | ||
944 | |||
945 | static int isi_set_default_fmt(struct atmel_isi *isi) | ||
946 | { | ||
947 | struct v4l2_format f = { | ||
948 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
949 | .fmt.pix = { | ||
950 | .width = VGA_WIDTH, | ||
951 | .height = VGA_HEIGHT, | ||
952 | .field = V4L2_FIELD_NONE, | ||
953 | .pixelformat = isi->user_formats[0]->fourcc, | ||
954 | }, | ||
955 | }; | ||
956 | int ret; | ||
957 | |||
958 | ret = isi_try_fmt(isi, &f, NULL); | ||
959 | if (ret) | ||
960 | return ret; | ||
961 | isi->current_fmt = isi->user_formats[0]; | ||
962 | isi->fmt = f; | ||
963 | return 0; | ||
964 | } | ||
965 | |||
966 | static const struct isi_format isi_formats[] = { | ||
967 | { | ||
968 | .fourcc = V4L2_PIX_FMT_YUYV, | ||
969 | .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, | ||
970 | .bpp = 2, | ||
971 | .swap = ISI_CFG2_YCC_SWAP_DEFAULT, | ||
972 | }, { | ||
973 | .fourcc = V4L2_PIX_FMT_YUYV, | ||
974 | .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8, | ||
975 | .bpp = 2, | ||
976 | .swap = ISI_CFG2_YCC_SWAP_MODE_1, | ||
977 | }, { | ||
978 | .fourcc = V4L2_PIX_FMT_YUYV, | ||
979 | .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, | ||
980 | .bpp = 2, | ||
981 | .swap = ISI_CFG2_YCC_SWAP_MODE_2, | ||
982 | }, { | ||
983 | .fourcc = V4L2_PIX_FMT_YUYV, | ||
984 | .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8, | ||
985 | .bpp = 2, | ||
986 | .swap = ISI_CFG2_YCC_SWAP_MODE_3, | ||
987 | }, { | ||
988 | .fourcc = V4L2_PIX_FMT_RGB565, | ||
989 | .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, | ||
990 | .bpp = 2, | ||
991 | .swap = ISI_CFG2_YCC_SWAP_MODE_2, | ||
992 | }, { | ||
993 | .fourcc = V4L2_PIX_FMT_RGB565, | ||
994 | .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8, | ||
995 | .bpp = 2, | ||
996 | .swap = ISI_CFG2_YCC_SWAP_MODE_3, | ||
997 | }, { | ||
998 | .fourcc = V4L2_PIX_FMT_RGB565, | ||
999 | .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, | ||
1000 | .bpp = 2, | ||
1001 | .swap = ISI_CFG2_YCC_SWAP_DEFAULT, | ||
1002 | }, { | ||
1003 | .fourcc = V4L2_PIX_FMT_RGB565, | ||
1004 | .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8, | ||
1005 | .bpp = 2, | ||
1006 | .swap = ISI_CFG2_YCC_SWAP_MODE_1, | ||
1007 | }, | ||
1008 | }; | ||
1009 | |||
1010 | static int isi_formats_init(struct atmel_isi *isi) | ||
1011 | { | ||
1012 | const struct isi_format *isi_fmts[ARRAY_SIZE(isi_formats)]; | ||
1013 | unsigned int num_fmts = 0, i, j; | ||
1014 | struct v4l2_subdev *subdev = isi->entity.subdev; | ||
1015 | struct v4l2_subdev_mbus_code_enum mbus_code = { | ||
1016 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
1017 | }; | ||
1018 | |||
1019 | while (!v4l2_subdev_call(subdev, pad, enum_mbus_code, | ||
1020 | NULL, &mbus_code)) { | ||
1021 | for (i = 0; i < ARRAY_SIZE(isi_formats); i++) { | ||
1022 | if (isi_formats[i].mbus_code != mbus_code.code) | ||
1023 | continue; | ||
1024 | |||
1025 | /* Code supported, have we got this fourcc yet? */ | ||
1026 | for (j = 0; j < num_fmts; j++) | ||
1027 | if (isi_fmts[j]->fourcc == isi_formats[i].fourcc) | ||
1028 | /* Already available */ | ||
1029 | break; | ||
1030 | if (j == num_fmts) | ||
1031 | /* new */ | ||
1032 | isi_fmts[num_fmts++] = isi_formats + i; | ||
1033 | } | ||
1034 | mbus_code.index++; | ||
1035 | } | ||
1036 | |||
1037 | if (!num_fmts) | ||
1038 | return -ENXIO; | ||
1039 | |||
1040 | isi->num_user_formats = num_fmts; | ||
1041 | isi->user_formats = devm_kcalloc(isi->dev, | ||
1042 | num_fmts, sizeof(struct isi_format *), | ||
1043 | GFP_KERNEL); | ||
1044 | if (!isi->user_formats) { | ||
1045 | dev_err(isi->dev, "could not allocate memory\n"); | ||
1046 | return -ENOMEM; | ||
1047 | } | ||
1048 | |||
1049 | memcpy(isi->user_formats, isi_fmts, | ||
1050 | num_fmts * sizeof(struct isi_format *)); | ||
1051 | isi->current_fmt = isi->user_formats[0]; | ||
1052 | |||
1053 | return 0; | ||
1054 | } | ||
1055 | |||
1056 | static int isi_graph_notify_complete(struct v4l2_async_notifier *notifier) | ||
1057 | { | ||
1058 | struct atmel_isi *isi = notifier_to_isi(notifier); | ||
1059 | int ret; | ||
1060 | |||
1061 | isi->vdev->ctrl_handler = isi->entity.subdev->ctrl_handler; | ||
1062 | ret = isi_formats_init(isi); | ||
1063 | if (ret) { | ||
1064 | dev_err(isi->dev, "No supported mediabus format found\n"); | ||
1065 | return ret; | ||
1066 | } | ||
1067 | isi_camera_set_bus_param(isi); | ||
1068 | |||
1069 | ret = isi_set_default_fmt(isi); | ||
1070 | if (ret) { | ||
1071 | dev_err(isi->dev, "Could not set default format\n"); | ||
1072 | return ret; | ||
1073 | } | ||
1074 | |||
1075 | ret = video_register_device(isi->vdev, VFL_TYPE_GRABBER, -1); | ||
1076 | if (ret) { | ||
1077 | dev_err(isi->dev, "Failed to register video device\n"); | ||
1078 | return ret; | ||
1079 | } | ||
1080 | |||
1081 | dev_dbg(isi->dev, "Device registered as %s\n", | ||
1082 | video_device_node_name(isi->vdev)); | ||
1083 | return 0; | ||
1084 | } | ||
1085 | |||
1086 | static void isi_graph_notify_unbind(struct v4l2_async_notifier *notifier, | ||
1087 | struct v4l2_subdev *sd, | ||
1088 | struct v4l2_async_subdev *asd) | ||
1089 | { | ||
1090 | struct atmel_isi *isi = notifier_to_isi(notifier); | ||
1091 | |||
1092 | dev_dbg(isi->dev, "Removing %s\n", video_device_node_name(isi->vdev)); | ||
1093 | |||
1094 | /* Checks internaly if vdev have been init or not */ | ||
1095 | video_unregister_device(isi->vdev); | ||
1096 | } | ||
1097 | |||
1098 | static int isi_graph_notify_bound(struct v4l2_async_notifier *notifier, | ||
1099 | struct v4l2_subdev *subdev, | ||
1100 | struct v4l2_async_subdev *asd) | ||
1101 | { | ||
1102 | struct atmel_isi *isi = notifier_to_isi(notifier); | ||
1103 | |||
1104 | dev_dbg(isi->dev, "subdev %s bound\n", subdev->name); | ||
1105 | |||
1106 | isi->entity.subdev = subdev; | ||
1107 | |||
1108 | return 0; | ||
1109 | } | ||
1110 | |||
1111 | static int isi_graph_parse(struct atmel_isi *isi, struct device_node *node) | ||
1112 | { | ||
1113 | struct device_node *ep = NULL; | ||
1114 | struct device_node *remote; | ||
1115 | |||
1116 | while (1) { | ||
1117 | ep = of_graph_get_next_endpoint(node, ep); | ||
1118 | if (!ep) | ||
1119 | return -EINVAL; | ||
1120 | |||
1121 | remote = of_graph_get_remote_port_parent(ep); | ||
1122 | if (!remote) { | ||
1123 | of_node_put(ep); | ||
1124 | return -EINVAL; | ||
1125 | } | ||
1126 | |||
1127 | /* Remote node to connect */ | ||
1128 | isi->entity.node = remote; | ||
1129 | isi->entity.asd.match_type = V4L2_ASYNC_MATCH_OF; | ||
1130 | isi->entity.asd.match.of.node = remote; | ||
1131 | return 0; | ||
1132 | } | ||
1133 | } | ||
1134 | |||
1135 | static int isi_graph_init(struct atmel_isi *isi) | ||
1136 | { | ||
1137 | struct v4l2_async_subdev **subdevs = NULL; | ||
1138 | int ret; | ||
1139 | |||
1140 | /* Parse the graph to extract a list of subdevice DT nodes. */ | ||
1141 | ret = isi_graph_parse(isi, isi->dev->of_node); | ||
1142 | if (ret < 0) { | ||
1143 | dev_err(isi->dev, "Graph parsing failed\n"); | ||
1144 | return ret; | ||
1145 | } | ||
1146 | |||
1147 | /* Register the subdevices notifier. */ | ||
1148 | subdevs = devm_kzalloc(isi->dev, sizeof(*subdevs), GFP_KERNEL); | ||
1149 | if (subdevs == NULL) { | ||
1150 | of_node_put(isi->entity.node); | ||
1151 | return -ENOMEM; | ||
1152 | } | ||
1153 | |||
1154 | subdevs[0] = &isi->entity.asd; | ||
1155 | |||
1156 | isi->notifier.subdevs = subdevs; | ||
1157 | isi->notifier.num_subdevs = 1; | ||
1158 | isi->notifier.bound = isi_graph_notify_bound; | ||
1159 | isi->notifier.unbind = isi_graph_notify_unbind; | ||
1160 | isi->notifier.complete = isi_graph_notify_complete; | ||
1161 | |||
1162 | ret = v4l2_async_notifier_register(&isi->v4l2_dev, &isi->notifier); | ||
1163 | if (ret < 0) { | ||
1164 | dev_err(isi->dev, "Notifier registration failed\n"); | ||
1165 | of_node_put(isi->entity.node); | ||
1166 | return ret; | ||
1167 | } | ||
1168 | |||
1169 | return 0; | ||
1170 | } | ||
1171 | |||
1172 | |||
1173 | static int atmel_isi_probe(struct platform_device *pdev) | ||
1174 | { | ||
1175 | int irq; | ||
1176 | struct atmel_isi *isi; | ||
1177 | struct vb2_queue *q; | ||
1178 | struct resource *regs; | ||
1179 | int ret, i; | ||
1180 | |||
1181 | isi = devm_kzalloc(&pdev->dev, sizeof(struct atmel_isi), GFP_KERNEL); | ||
1182 | if (!isi) { | ||
1183 | dev_err(&pdev->dev, "Can't allocate interface!\n"); | ||
1184 | return -ENOMEM; | ||
1185 | } | ||
1186 | |||
1187 | isi->pclk = devm_clk_get(&pdev->dev, "isi_clk"); | ||
1188 | if (IS_ERR(isi->pclk)) | ||
1189 | return PTR_ERR(isi->pclk); | ||
1190 | |||
1191 | ret = atmel_isi_parse_dt(isi, pdev); | ||
1192 | if (ret) | ||
1193 | return ret; | ||
1194 | |||
1195 | isi->active = NULL; | ||
1196 | isi->dev = &pdev->dev; | ||
1197 | mutex_init(&isi->lock); | ||
1198 | spin_lock_init(&isi->irqlock); | ||
1199 | INIT_LIST_HEAD(&isi->video_buffer_list); | ||
1200 | INIT_LIST_HEAD(&isi->dma_desc_head); | ||
1201 | |||
1202 | q = &isi->queue; | ||
1203 | |||
1204 | /* Initialize the top-level structure */ | ||
1205 | ret = v4l2_device_register(&pdev->dev, &isi->v4l2_dev); | ||
1206 | if (ret) | ||
1207 | return ret; | ||
1208 | |||
1209 | isi->vdev = video_device_alloc(); | ||
1210 | if (isi->vdev == NULL) { | ||
1211 | ret = -ENOMEM; | ||
1212 | goto err_vdev_alloc; | ||
1213 | } | ||
1214 | |||
1215 | /* video node */ | ||
1216 | isi->vdev->fops = &isi_fops; | ||
1217 | isi->vdev->v4l2_dev = &isi->v4l2_dev; | ||
1218 | isi->vdev->queue = &isi->queue; | ||
1219 | strlcpy(isi->vdev->name, KBUILD_MODNAME, sizeof(isi->vdev->name)); | ||
1220 | isi->vdev->release = video_device_release; | ||
1221 | isi->vdev->ioctl_ops = &isi_ioctl_ops; | ||
1222 | isi->vdev->lock = &isi->lock; | ||
1223 | isi->vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | | ||
1224 | V4L2_CAP_READWRITE; | ||
1225 | video_set_drvdata(isi->vdev, isi); | ||
1226 | |||
1227 | /* buffer queue */ | ||
1228 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1229 | q->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF; | ||
1230 | q->lock = &isi->lock; | ||
1231 | q->drv_priv = isi; | ||
1232 | q->buf_struct_size = sizeof(struct frame_buffer); | ||
1233 | q->ops = &isi_video_qops; | ||
1234 | q->mem_ops = &vb2_dma_contig_memops; | ||
1235 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | ||
1236 | q->min_buffers_needed = 2; | ||
1237 | q->dev = &pdev->dev; | ||
1238 | |||
1239 | ret = vb2_queue_init(q); | ||
1240 | if (ret < 0) { | ||
1241 | dev_err(&pdev->dev, "failed to initialize VB2 queue\n"); | ||
1242 | goto err_vb2_queue; | ||
1243 | } | ||
1244 | isi->p_fb_descriptors = dma_alloc_coherent(&pdev->dev, | ||
1245 | sizeof(struct fbd) * VIDEO_MAX_FRAME, | ||
1246 | &isi->fb_descriptors_phys, | ||
1247 | GFP_KERNEL); | ||
1248 | if (!isi->p_fb_descriptors) { | ||
1249 | dev_err(&pdev->dev, "Can't allocate descriptors!\n"); | ||
1250 | ret = -ENOMEM; | ||
1251 | goto err_dma_alloc; | ||
1252 | } | ||
1253 | |||
1254 | for (i = 0; i < VIDEO_MAX_FRAME; i++) { | ||
1255 | isi->dma_desc[i].p_fbd = isi->p_fb_descriptors + i; | ||
1256 | isi->dma_desc[i].fbd_phys = isi->fb_descriptors_phys + | ||
1257 | i * sizeof(struct fbd); | ||
1258 | list_add(&isi->dma_desc[i].list, &isi->dma_desc_head); | ||
1259 | } | ||
1260 | |||
1261 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1262 | isi->regs = devm_ioremap_resource(&pdev->dev, regs); | ||
1263 | if (IS_ERR(isi->regs)) { | ||
1264 | ret = PTR_ERR(isi->regs); | ||
1265 | goto err_ioremap; | ||
1266 | } | ||
1267 | |||
1268 | if (isi->pdata.data_width_flags & ISI_DATAWIDTH_8) | ||
1269 | isi->width_flags = 1 << 7; | ||
1270 | if (isi->pdata.data_width_flags & ISI_DATAWIDTH_10) | ||
1271 | isi->width_flags |= 1 << 9; | ||
1272 | |||
1273 | irq = platform_get_irq(pdev, 0); | ||
1274 | if (irq < 0) { | ||
1275 | ret = irq; | ||
1276 | goto err_req_irq; | ||
1277 | } | ||
1278 | |||
1279 | ret = devm_request_irq(&pdev->dev, irq, isi_interrupt, 0, "isi", isi); | ||
1280 | if (ret) { | ||
1281 | dev_err(&pdev->dev, "Unable to request irq %d\n", irq); | ||
1282 | goto err_req_irq; | ||
1283 | } | ||
1284 | isi->irq = irq; | ||
1285 | |||
1286 | ret = isi_graph_init(isi); | ||
1287 | if (ret < 0) | ||
1288 | goto err_req_irq; | ||
1289 | |||
1290 | pm_suspend_ignore_children(&pdev->dev, true); | ||
1291 | pm_runtime_enable(&pdev->dev); | ||
1292 | platform_set_drvdata(pdev, isi); | ||
1293 | return 0; | ||
1294 | |||
1295 | err_req_irq: | ||
1296 | err_ioremap: | ||
1297 | dma_free_coherent(&pdev->dev, | ||
1298 | sizeof(struct fbd) * VIDEO_MAX_FRAME, | ||
1299 | isi->p_fb_descriptors, | ||
1300 | isi->fb_descriptors_phys); | ||
1301 | err_dma_alloc: | ||
1302 | err_vb2_queue: | ||
1303 | video_device_release(isi->vdev); | ||
1304 | err_vdev_alloc: | ||
1305 | v4l2_device_unregister(&isi->v4l2_dev); | ||
1306 | |||
1307 | return ret; | ||
1308 | } | ||
1309 | |||
1310 | static int atmel_isi_remove(struct platform_device *pdev) | ||
1311 | { | ||
1312 | struct atmel_isi *isi = platform_get_drvdata(pdev); | ||
1313 | |||
1314 | dma_free_coherent(&pdev->dev, | ||
1315 | sizeof(struct fbd) * VIDEO_MAX_FRAME, | ||
1316 | isi->p_fb_descriptors, | ||
1317 | isi->fb_descriptors_phys); | ||
1318 | pm_runtime_disable(&pdev->dev); | ||
1319 | v4l2_async_notifier_unregister(&isi->notifier); | ||
1320 | v4l2_device_unregister(&isi->v4l2_dev); | ||
1321 | |||
1322 | return 0; | ||
1323 | } | ||
1324 | |||
1325 | #ifdef CONFIG_PM | ||
1326 | static int atmel_isi_runtime_suspend(struct device *dev) | ||
1327 | { | ||
1328 | struct atmel_isi *isi = dev_get_drvdata(dev); | ||
1329 | |||
1330 | clk_disable_unprepare(isi->pclk); | ||
1331 | |||
1332 | return 0; | ||
1333 | } | ||
1334 | static int atmel_isi_runtime_resume(struct device *dev) | ||
1335 | { | ||
1336 | struct atmel_isi *isi = dev_get_drvdata(dev); | ||
1337 | |||
1338 | return clk_prepare_enable(isi->pclk); | ||
1339 | } | ||
1340 | #endif /* CONFIG_PM */ | ||
1341 | |||
1342 | static const struct dev_pm_ops atmel_isi_dev_pm_ops = { | ||
1343 | SET_RUNTIME_PM_OPS(atmel_isi_runtime_suspend, | ||
1344 | atmel_isi_runtime_resume, NULL) | ||
1345 | }; | ||
1346 | |||
1347 | static const struct of_device_id atmel_isi_of_match[] = { | ||
1348 | { .compatible = "atmel,at91sam9g45-isi" }, | ||
1349 | { } | ||
1350 | }; | ||
1351 | MODULE_DEVICE_TABLE(of, atmel_isi_of_match); | ||
1352 | |||
1353 | static struct platform_driver atmel_isi_driver = { | ||
1354 | .driver = { | ||
1355 | .name = "atmel_isi", | ||
1356 | .of_match_table = of_match_ptr(atmel_isi_of_match), | ||
1357 | .pm = &atmel_isi_dev_pm_ops, | ||
1358 | }, | ||
1359 | .probe = atmel_isi_probe, | ||
1360 | .remove = atmel_isi_remove, | ||
1361 | }; | ||
1362 | |||
1363 | module_platform_driver(atmel_isi_driver); | ||
1364 | |||
1365 | MODULE_AUTHOR("Josh Wu <josh.wu@atmel.com>"); | ||
1366 | MODULE_DESCRIPTION("The V4L2 driver for Atmel Linux"); | ||
1367 | MODULE_LICENSE("GPL"); | ||
1368 | MODULE_SUPPORTED_DEVICE("video"); | ||
diff --git a/drivers/media/platform/soc_camera/atmel-isi.h b/drivers/media/platform/atmel/atmel-isi.h index 0acb32a2b65c..0acb32a2b65c 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.h +++ b/drivers/media/platform/atmel/atmel-isi.h | |||
diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 466a44e4549e..403214e00e95 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c | |||
@@ -179,6 +179,25 @@ static void coda_kfifo_sync_to_device_write(struct coda_ctx *ctx) | |||
179 | coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); | 179 | coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); |
180 | } | 180 | } |
181 | 181 | ||
182 | static int coda_bitstream_pad(struct coda_ctx *ctx, u32 size) | ||
183 | { | ||
184 | unsigned char *buf; | ||
185 | u32 n; | ||
186 | |||
187 | if (size < 6) | ||
188 | size = 6; | ||
189 | |||
190 | buf = kmalloc(size, GFP_KERNEL); | ||
191 | if (!buf) | ||
192 | return -ENOMEM; | ||
193 | |||
194 | coda_h264_filler_nal(size, buf); | ||
195 | n = kfifo_in(&ctx->bitstream_fifo, buf, size); | ||
196 | kfree(buf); | ||
197 | |||
198 | return (n < size) ? -ENOSPC : 0; | ||
199 | } | ||
200 | |||
182 | static int coda_bitstream_queue(struct coda_ctx *ctx, | 201 | static int coda_bitstream_queue(struct coda_ctx *ctx, |
183 | struct vb2_v4l2_buffer *src_buf) | 202 | struct vb2_v4l2_buffer *src_buf) |
184 | { | 203 | { |
@@ -198,10 +217,10 @@ static int coda_bitstream_queue(struct coda_ctx *ctx, | |||
198 | static bool coda_bitstream_try_queue(struct coda_ctx *ctx, | 217 | static bool coda_bitstream_try_queue(struct coda_ctx *ctx, |
199 | struct vb2_v4l2_buffer *src_buf) | 218 | struct vb2_v4l2_buffer *src_buf) |
200 | { | 219 | { |
220 | unsigned long payload = vb2_get_plane_payload(&src_buf->vb2_buf, 0); | ||
201 | int ret; | 221 | int ret; |
202 | 222 | ||
203 | if (coda_get_bitstream_payload(ctx) + | 223 | if (coda_get_bitstream_payload(ctx) + payload + 512 >= |
204 | vb2_get_plane_payload(&src_buf->vb2_buf, 0) + 512 >= | ||
205 | ctx->bitstream.size) | 224 | ctx->bitstream.size) |
206 | return false; | 225 | return false; |
207 | 226 | ||
@@ -210,6 +229,11 @@ static bool coda_bitstream_try_queue(struct coda_ctx *ctx, | |||
210 | return true; | 229 | return true; |
211 | } | 230 | } |
212 | 231 | ||
232 | /* Add zero padding before the first H.264 buffer, if it is too small */ | ||
233 | if (ctx->qsequence == 0 && payload < 512 && | ||
234 | ctx->codec->src_fourcc == V4L2_PIX_FMT_H264) | ||
235 | coda_bitstream_pad(ctx, 512 - payload); | ||
236 | |||
213 | ret = coda_bitstream_queue(ctx, src_buf); | 237 | ret = coda_bitstream_queue(ctx, src_buf); |
214 | if (ret < 0) { | 238 | if (ret < 0) { |
215 | v4l2_err(&ctx->dev->v4l2_dev, "bitstream buffer overflow\n"); | 239 | v4l2_err(&ctx->dev->v4l2_dev, "bitstream buffer overflow\n"); |
@@ -224,7 +248,7 @@ static bool coda_bitstream_try_queue(struct coda_ctx *ctx, | |||
224 | return true; | 248 | return true; |
225 | } | 249 | } |
226 | 250 | ||
227 | void coda_fill_bitstream(struct coda_ctx *ctx, bool streaming) | 251 | void coda_fill_bitstream(struct coda_ctx *ctx, struct list_head *buffer_list) |
228 | { | 252 | { |
229 | struct vb2_v4l2_buffer *src_buf; | 253 | struct vb2_v4l2_buffer *src_buf; |
230 | struct coda_buffer_meta *meta; | 254 | struct coda_buffer_meta *meta; |
@@ -252,9 +276,16 @@ void coda_fill_bitstream(struct coda_ctx *ctx, bool streaming) | |||
252 | "dropping invalid JPEG frame %d\n", | 276 | "dropping invalid JPEG frame %d\n", |
253 | ctx->qsequence); | 277 | ctx->qsequence); |
254 | src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); | 278 | src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); |
255 | v4l2_m2m_buf_done(src_buf, streaming ? | 279 | if (buffer_list) { |
256 | VB2_BUF_STATE_ERROR : | 280 | struct v4l2_m2m_buffer *m2m_buf; |
257 | VB2_BUF_STATE_QUEUED); | 281 | |
282 | m2m_buf = container_of(src_buf, | ||
283 | struct v4l2_m2m_buffer, | ||
284 | vb); | ||
285 | list_add_tail(&m2m_buf->list, buffer_list); | ||
286 | } else { | ||
287 | v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); | ||
288 | } | ||
258 | continue; | 289 | continue; |
259 | } | 290 | } |
260 | 291 | ||
@@ -295,7 +326,16 @@ void coda_fill_bitstream(struct coda_ctx *ctx, bool streaming) | |||
295 | trace_coda_bit_queue(ctx, src_buf, meta); | 326 | trace_coda_bit_queue(ctx, src_buf, meta); |
296 | } | 327 | } |
297 | 328 | ||
298 | v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); | 329 | if (buffer_list) { |
330 | struct v4l2_m2m_buffer *m2m_buf; | ||
331 | |||
332 | m2m_buf = container_of(src_buf, | ||
333 | struct v4l2_m2m_buffer, | ||
334 | vb); | ||
335 | list_add_tail(&m2m_buf->list, buffer_list); | ||
336 | } else { | ||
337 | v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); | ||
338 | } | ||
299 | } else { | 339 | } else { |
300 | break; | 340 | break; |
301 | } | 341 | } |
@@ -1508,6 +1548,47 @@ static int coda_decoder_reqbufs(struct coda_ctx *ctx, | |||
1508 | return 0; | 1548 | return 0; |
1509 | } | 1549 | } |
1510 | 1550 | ||
1551 | static bool coda_reorder_enable(struct coda_ctx *ctx) | ||
1552 | { | ||
1553 | const char * const *profile_names; | ||
1554 | const char * const *level_names; | ||
1555 | struct coda_dev *dev = ctx->dev; | ||
1556 | int profile, level; | ||
1557 | |||
1558 | if (dev->devtype->product != CODA_7541 && | ||
1559 | dev->devtype->product != CODA_960) | ||
1560 | return false; | ||
1561 | |||
1562 | if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) | ||
1563 | return false; | ||
1564 | |||
1565 | if (ctx->codec->src_fourcc != V4L2_PIX_FMT_H264) | ||
1566 | return true; | ||
1567 | |||
1568 | profile = coda_h264_profile(ctx->params.h264_profile_idc); | ||
1569 | if (profile < 0) { | ||
1570 | v4l2_warn(&dev->v4l2_dev, "Invalid H264 Profile: %d\n", | ||
1571 | ctx->params.h264_profile_idc); | ||
1572 | return false; | ||
1573 | } | ||
1574 | |||
1575 | level = coda_h264_level(ctx->params.h264_level_idc); | ||
1576 | if (level < 0) { | ||
1577 | v4l2_warn(&dev->v4l2_dev, "Invalid H264 Level: %d\n", | ||
1578 | ctx->params.h264_level_idc); | ||
1579 | return false; | ||
1580 | } | ||
1581 | |||
1582 | profile_names = v4l2_ctrl_get_menu(V4L2_CID_MPEG_VIDEO_H264_PROFILE); | ||
1583 | level_names = v4l2_ctrl_get_menu(V4L2_CID_MPEG_VIDEO_H264_LEVEL); | ||
1584 | |||
1585 | v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "H264 Profile/Level: %s L%s\n", | ||
1586 | profile_names[profile], level_names[level]); | ||
1587 | |||
1588 | /* Baseline profile does not support reordering */ | ||
1589 | return profile > V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE; | ||
1590 | } | ||
1591 | |||
1511 | static int __coda_start_decoding(struct coda_ctx *ctx) | 1592 | static int __coda_start_decoding(struct coda_ctx *ctx) |
1512 | { | 1593 | { |
1513 | struct coda_q_data *q_data_src, *q_data_dst; | 1594 | struct coda_q_data *q_data_src, *q_data_dst; |
@@ -1554,8 +1635,7 @@ static int __coda_start_decoding(struct coda_ctx *ctx) | |||
1554 | coda_write(dev, bitstream_buf, CODA_CMD_DEC_SEQ_BB_START); | 1635 | coda_write(dev, bitstream_buf, CODA_CMD_DEC_SEQ_BB_START); |
1555 | coda_write(dev, bitstream_size / 1024, CODA_CMD_DEC_SEQ_BB_SIZE); | 1636 | coda_write(dev, bitstream_size / 1024, CODA_CMD_DEC_SEQ_BB_SIZE); |
1556 | val = 0; | 1637 | val = 0; |
1557 | if ((dev->devtype->product == CODA_7541) || | 1638 | if (coda_reorder_enable(ctx)) |
1558 | (dev->devtype->product == CODA_960)) | ||
1559 | val |= CODA_REORDER_ENABLE; | 1639 | val |= CODA_REORDER_ENABLE; |
1560 | if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) | 1640 | if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) |
1561 | val |= CODA_NO_INT_ENABLE; | 1641 | val |= CODA_NO_INT_ENABLE; |
@@ -1747,7 +1827,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx) | |||
1747 | 1827 | ||
1748 | /* Try to copy source buffer contents into the bitstream ringbuffer */ | 1828 | /* Try to copy source buffer contents into the bitstream ringbuffer */ |
1749 | mutex_lock(&ctx->bitstream_mutex); | 1829 | mutex_lock(&ctx->bitstream_mutex); |
1750 | coda_fill_bitstream(ctx, true); | 1830 | coda_fill_bitstream(ctx, NULL); |
1751 | mutex_unlock(&ctx->bitstream_mutex); | 1831 | mutex_unlock(&ctx->bitstream_mutex); |
1752 | 1832 | ||
1753 | if (coda_get_bitstream_payload(ctx) < 512 && | 1833 | if (coda_get_bitstream_payload(ctx) < 512 && |
diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index eb6548f46cba..d523e990d509 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c | |||
@@ -71,6 +71,10 @@ static int disable_vdoa; | |||
71 | module_param(disable_vdoa, int, 0644); | 71 | module_param(disable_vdoa, int, 0644); |
72 | MODULE_PARM_DESC(disable_vdoa, "Disable Video Data Order Adapter tiled to raster-scan conversion"); | 72 | MODULE_PARM_DESC(disable_vdoa, "Disable Video Data Order Adapter tiled to raster-scan conversion"); |
73 | 73 | ||
74 | static int enable_bwb = 0; | ||
75 | module_param(enable_bwb, int, 0644); | ||
76 | MODULE_PARM_DESC(enable_bwb, "Enable BWB unit, may crash on certain streams"); | ||
77 | |||
74 | void coda_write(struct coda_dev *dev, u32 data, u32 reg) | 78 | void coda_write(struct coda_dev *dev, u32 data, u32 reg) |
75 | { | 79 | { |
76 | v4l2_dbg(2, coda_debug, &dev->v4l2_dev, | 80 | v4l2_dbg(2, coda_debug, &dev->v4l2_dev, |
@@ -386,6 +390,7 @@ static int coda_enum_fmt(struct file *file, void *priv, | |||
386 | { | 390 | { |
387 | struct video_device *vdev = video_devdata(file); | 391 | struct video_device *vdev = video_devdata(file); |
388 | const struct coda_video_device *cvd = to_coda_video_device(vdev); | 392 | const struct coda_video_device *cvd = to_coda_video_device(vdev); |
393 | struct coda_ctx *ctx = fh_to_ctx(priv); | ||
389 | const u32 *formats; | 394 | const u32 *formats; |
390 | 395 | ||
391 | if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) | 396 | if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) |
@@ -398,6 +403,11 @@ static int coda_enum_fmt(struct file *file, void *priv, | |||
398 | if (f->index >= CODA_MAX_FORMATS || formats[f->index] == 0) | 403 | if (f->index >= CODA_MAX_FORMATS || formats[f->index] == 0) |
399 | return -EINVAL; | 404 | return -EINVAL; |
400 | 405 | ||
406 | /* Skip YUYV if the vdoa is not available */ | ||
407 | if (!ctx->vdoa && f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && | ||
408 | formats[f->index] == V4L2_PIX_FMT_YUYV) | ||
409 | return -EINVAL; | ||
410 | |||
401 | f->pixelformat = formats[f->index]; | 411 | f->pixelformat = formats[f->index]; |
402 | 412 | ||
403 | return 0; | 413 | return 0; |
@@ -813,10 +823,6 @@ static int coda_qbuf(struct file *file, void *priv, | |||
813 | static bool coda_buf_is_end_of_stream(struct coda_ctx *ctx, | 823 | static bool coda_buf_is_end_of_stream(struct coda_ctx *ctx, |
814 | struct vb2_v4l2_buffer *buf) | 824 | struct vb2_v4l2_buffer *buf) |
815 | { | 825 | { |
816 | struct vb2_queue *src_vq; | ||
817 | |||
818 | src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); | ||
819 | |||
820 | return ((ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) && | 826 | return ((ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) && |
821 | (buf->sequence == (ctx->qsequence - 1))); | 827 | (buf->sequence == (ctx->qsequence - 1))); |
822 | } | 828 | } |
@@ -881,6 +887,47 @@ static int coda_g_selection(struct file *file, void *fh, | |||
881 | return 0; | 887 | return 0; |
882 | } | 888 | } |
883 | 889 | ||
890 | static int coda_try_encoder_cmd(struct file *file, void *fh, | ||
891 | struct v4l2_encoder_cmd *ec) | ||
892 | { | ||
893 | if (ec->cmd != V4L2_ENC_CMD_STOP) | ||
894 | return -EINVAL; | ||
895 | |||
896 | if (ec->flags & V4L2_ENC_CMD_STOP_AT_GOP_END) | ||
897 | return -EINVAL; | ||
898 | |||
899 | return 0; | ||
900 | } | ||
901 | |||
902 | static int coda_encoder_cmd(struct file *file, void *fh, | ||
903 | struct v4l2_encoder_cmd *ec) | ||
904 | { | ||
905 | struct coda_ctx *ctx = fh_to_ctx(fh); | ||
906 | struct vb2_queue *dst_vq; | ||
907 | int ret; | ||
908 | |||
909 | ret = coda_try_encoder_cmd(file, fh, ec); | ||
910 | if (ret < 0) | ||
911 | return ret; | ||
912 | |||
913 | /* Ignore encoder stop command silently in decoder context */ | ||
914 | if (ctx->inst_type != CODA_INST_ENCODER) | ||
915 | return 0; | ||
916 | |||
917 | /* Set the stream-end flag on this context */ | ||
918 | ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; | ||
919 | |||
920 | /* If there is no buffer in flight, wake up */ | ||
921 | if (ctx->qsequence == ctx->osequence) { | ||
922 | dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, | ||
923 | V4L2_BUF_TYPE_VIDEO_CAPTURE); | ||
924 | dst_vq->last_buffer_dequeued = true; | ||
925 | wake_up(&dst_vq->done_wq); | ||
926 | } | ||
927 | |||
928 | return 0; | ||
929 | } | ||
930 | |||
884 | static int coda_try_decoder_cmd(struct file *file, void *fh, | 931 | static int coda_try_decoder_cmd(struct file *file, void *fh, |
885 | struct v4l2_decoder_cmd *dc) | 932 | struct v4l2_decoder_cmd *dc) |
886 | { | 933 | { |
@@ -1054,6 +1101,8 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = { | |||
1054 | 1101 | ||
1055 | .vidioc_g_selection = coda_g_selection, | 1102 | .vidioc_g_selection = coda_g_selection, |
1056 | 1103 | ||
1104 | .vidioc_try_encoder_cmd = coda_try_encoder_cmd, | ||
1105 | .vidioc_encoder_cmd = coda_encoder_cmd, | ||
1057 | .vidioc_try_decoder_cmd = coda_try_decoder_cmd, | 1106 | .vidioc_try_decoder_cmd = coda_try_decoder_cmd, |
1058 | .vidioc_decoder_cmd = coda_decoder_cmd, | 1107 | .vidioc_decoder_cmd = coda_decoder_cmd, |
1059 | 1108 | ||
@@ -1327,12 +1376,28 @@ static void coda_buf_queue(struct vb2_buffer *vb) | |||
1327 | */ | 1376 | */ |
1328 | if (vb2_get_plane_payload(vb, 0) == 0) | 1377 | if (vb2_get_plane_payload(vb, 0) == 0) |
1329 | coda_bit_stream_end_flag(ctx); | 1378 | coda_bit_stream_end_flag(ctx); |
1379 | |||
1380 | if (q_data->fourcc == V4L2_PIX_FMT_H264) { | ||
1381 | /* | ||
1382 | * Unless already done, try to obtain profile_idc and | ||
1383 | * level_idc from the SPS header. This allows to decide | ||
1384 | * whether to enable reordering during sequence | ||
1385 | * initialization. | ||
1386 | */ | ||
1387 | if (!ctx->params.h264_profile_idc) | ||
1388 | coda_sps_parse_profile(ctx, vb); | ||
1389 | } | ||
1390 | |||
1330 | mutex_lock(&ctx->bitstream_mutex); | 1391 | mutex_lock(&ctx->bitstream_mutex); |
1331 | v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); | 1392 | v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); |
1332 | if (vb2_is_streaming(vb->vb2_queue)) | 1393 | if (vb2_is_streaming(vb->vb2_queue)) |
1333 | coda_fill_bitstream(ctx, true); | 1394 | /* This set buf->sequence = ctx->qsequence++ */ |
1395 | coda_fill_bitstream(ctx, NULL); | ||
1334 | mutex_unlock(&ctx->bitstream_mutex); | 1396 | mutex_unlock(&ctx->bitstream_mutex); |
1335 | } else { | 1397 | } else { |
1398 | if (ctx->inst_type == CODA_INST_ENCODER && | ||
1399 | vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) | ||
1400 | vbuf->sequence = ctx->qsequence++; | ||
1336 | v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); | 1401 | v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); |
1337 | } | 1402 | } |
1338 | } | 1403 | } |
@@ -1344,7 +1409,7 @@ int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf, | |||
1344 | GFP_KERNEL); | 1409 | GFP_KERNEL); |
1345 | if (!buf->vaddr) { | 1410 | if (!buf->vaddr) { |
1346 | v4l2_err(&dev->v4l2_dev, | 1411 | v4l2_err(&dev->v4l2_dev, |
1347 | "Failed to allocate %s buffer of size %u\n", | 1412 | "Failed to allocate %s buffer of size %zu\n", |
1348 | name, size); | 1413 | name, size); |
1349 | return -ENOMEM; | 1414 | return -ENOMEM; |
1350 | } | 1415 | } |
@@ -1382,18 +1447,22 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) | |||
1382 | struct coda_ctx *ctx = vb2_get_drv_priv(q); | 1447 | struct coda_ctx *ctx = vb2_get_drv_priv(q); |
1383 | struct v4l2_device *v4l2_dev = &ctx->dev->v4l2_dev; | 1448 | struct v4l2_device *v4l2_dev = &ctx->dev->v4l2_dev; |
1384 | struct coda_q_data *q_data_src, *q_data_dst; | 1449 | struct coda_q_data *q_data_src, *q_data_dst; |
1450 | struct v4l2_m2m_buffer *m2m_buf, *tmp; | ||
1385 | struct vb2_v4l2_buffer *buf; | 1451 | struct vb2_v4l2_buffer *buf; |
1452 | struct list_head list; | ||
1386 | int ret = 0; | 1453 | int ret = 0; |
1387 | 1454 | ||
1388 | if (count < 1) | 1455 | if (count < 1) |
1389 | return -EINVAL; | 1456 | return -EINVAL; |
1390 | 1457 | ||
1458 | INIT_LIST_HEAD(&list); | ||
1459 | |||
1391 | q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); | 1460 | q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); |
1392 | if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { | 1461 | if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { |
1393 | if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) { | 1462 | if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) { |
1394 | /* copy the buffers that were queued before streamon */ | 1463 | /* copy the buffers that were queued before streamon */ |
1395 | mutex_lock(&ctx->bitstream_mutex); | 1464 | mutex_lock(&ctx->bitstream_mutex); |
1396 | coda_fill_bitstream(ctx, false); | 1465 | coda_fill_bitstream(ctx, &list); |
1397 | mutex_unlock(&ctx->bitstream_mutex); | 1466 | mutex_unlock(&ctx->bitstream_mutex); |
1398 | 1467 | ||
1399 | if (coda_get_bitstream_payload(ctx) < 512) { | 1468 | if (coda_get_bitstream_payload(ctx) < 512) { |
@@ -1408,8 +1477,8 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) | |||
1408 | } | 1477 | } |
1409 | 1478 | ||
1410 | /* Don't start the coda unless both queues are on */ | 1479 | /* Don't start the coda unless both queues are on */ |
1411 | if (!(ctx->streamon_out & ctx->streamon_cap)) | 1480 | if (!(ctx->streamon_out && ctx->streamon_cap)) |
1412 | return 0; | 1481 | goto out; |
1413 | 1482 | ||
1414 | q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); | 1483 | q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); |
1415 | if ((q_data_src->width != q_data_dst->width && | 1484 | if ((q_data_src->width != q_data_dst->width && |
@@ -1444,15 +1513,26 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) | |||
1444 | ret = ctx->ops->start_streaming(ctx); | 1513 | ret = ctx->ops->start_streaming(ctx); |
1445 | if (ctx->inst_type == CODA_INST_DECODER) { | 1514 | if (ctx->inst_type == CODA_INST_DECODER) { |
1446 | if (ret == -EAGAIN) | 1515 | if (ret == -EAGAIN) |
1447 | return 0; | 1516 | goto out; |
1448 | else if (ret < 0) | ||
1449 | goto err; | ||
1450 | } | 1517 | } |
1518 | if (ret < 0) | ||
1519 | goto err; | ||
1451 | 1520 | ||
1452 | return ret; | 1521 | out: |
1522 | if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { | ||
1523 | list_for_each_entry_safe(m2m_buf, tmp, &list, list) { | ||
1524 | list_del(&m2m_buf->list); | ||
1525 | v4l2_m2m_buf_done(&m2m_buf->vb, VB2_BUF_STATE_DONE); | ||
1526 | } | ||
1527 | } | ||
1528 | return 0; | ||
1453 | 1529 | ||
1454 | err: | 1530 | err: |
1455 | if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { | 1531 | if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { |
1532 | list_for_each_entry_safe(m2m_buf, tmp, &list, list) { | ||
1533 | list_del(&m2m_buf->list); | ||
1534 | v4l2_m2m_buf_done(&m2m_buf->vb, VB2_BUF_STATE_QUEUED); | ||
1535 | } | ||
1456 | while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) | 1536 | while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) |
1457 | v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED); | 1537 | v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED); |
1458 | } else { | 1538 | } else { |
@@ -1832,7 +1912,8 @@ static int coda_open(struct file *file) | |||
1832 | ctx->idx = idx; | 1912 | ctx->idx = idx; |
1833 | switch (dev->devtype->product) { | 1913 | switch (dev->devtype->product) { |
1834 | case CODA_960: | 1914 | case CODA_960: |
1835 | ctx->frame_mem_ctrl = 1 << 12; | 1915 | if (enable_bwb) |
1916 | ctx->frame_mem_ctrl = CODA9_FRAME_ENABLE_BWB; | ||
1836 | /* fallthrough */ | 1917 | /* fallthrough */ |
1837 | case CODA_7541: | 1918 | case CODA_7541: |
1838 | ctx->reg_idx = 0; | 1919 | ctx->reg_idx = 0; |
@@ -2126,7 +2207,12 @@ static void coda_fw_callback(const struct firmware *fw, void *context); | |||
2126 | 2207 | ||
2127 | static int coda_firmware_request(struct coda_dev *dev) | 2208 | static int coda_firmware_request(struct coda_dev *dev) |
2128 | { | 2209 | { |
2129 | char *fw = dev->devtype->firmware[dev->firmware]; | 2210 | char *fw; |
2211 | |||
2212 | if (dev->firmware >= ARRAY_SIZE(dev->devtype->firmware)) | ||
2213 | return -EINVAL; | ||
2214 | |||
2215 | fw = dev->devtype->firmware[dev->firmware]; | ||
2130 | 2216 | ||
2131 | dev_dbg(&dev->plat_dev->dev, "requesting firmware '%s' for %s\n", fw, | 2217 | dev_dbg(&dev->plat_dev->dev, "requesting firmware '%s' for %s\n", fw, |
2132 | coda_product_name(dev->devtype->product)); | 2218 | coda_product_name(dev->devtype->product)); |
@@ -2142,16 +2228,16 @@ static void coda_fw_callback(const struct firmware *fw, void *context) | |||
2142 | struct platform_device *pdev = dev->plat_dev; | 2228 | struct platform_device *pdev = dev->plat_dev; |
2143 | int i, ret; | 2229 | int i, ret; |
2144 | 2230 | ||
2145 | if (!fw && dev->firmware == 1) { | ||
2146 | v4l2_err(&dev->v4l2_dev, "firmware request failed\n"); | ||
2147 | goto put_pm; | ||
2148 | } | ||
2149 | if (!fw) { | 2231 | if (!fw) { |
2150 | dev->firmware = 1; | 2232 | dev->firmware++; |
2151 | coda_firmware_request(dev); | 2233 | ret = coda_firmware_request(dev); |
2234 | if (ret < 0) { | ||
2235 | v4l2_err(&dev->v4l2_dev, "firmware request failed\n"); | ||
2236 | goto put_pm; | ||
2237 | } | ||
2152 | return; | 2238 | return; |
2153 | } | 2239 | } |
2154 | if (dev->firmware == 1) { | 2240 | if (dev->firmware > 0) { |
2155 | /* | 2241 | /* |
2156 | * Since we can't suppress warnings for failed asynchronous | 2242 | * Since we can't suppress warnings for failed asynchronous |
2157 | * firmware requests, report that the fallback firmware was | 2243 | * firmware requests, report that the fallback firmware was |
diff --git a/drivers/media/platform/coda/coda-h264.c b/drivers/media/platform/coda/coda-h264.c index 09dfcca7cc50..0e27412e01f5 100644 --- a/drivers/media/platform/coda/coda-h264.c +++ b/drivers/media/platform/coda/coda-h264.c | |||
@@ -13,12 +13,59 @@ | |||
13 | 13 | ||
14 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
15 | #include <linux/string.h> | 15 | #include <linux/string.h> |
16 | #include <linux/videodev2.h> | ||
16 | #include <coda.h> | 17 | #include <coda.h> |
17 | 18 | ||
18 | static const u8 coda_filler_nal[14] = { 0x00, 0x00, 0x00, 0x01, 0x0c, 0xff, | ||
19 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 }; | ||
20 | static const u8 coda_filler_size[8] = { 0, 7, 14, 13, 12, 11, 10, 9 }; | 19 | static const u8 coda_filler_size[8] = { 0, 7, 14, 13, 12, 11, 10, 9 }; |
21 | 20 | ||
21 | static const u8 *coda_find_nal_header(const u8 *buf, const u8 *end) | ||
22 | { | ||
23 | u32 val = 0xffffffff; | ||
24 | |||
25 | do { | ||
26 | val = val << 8 | *buf++; | ||
27 | if (buf >= end) | ||
28 | return NULL; | ||
29 | } while (val != 0x00000001); | ||
30 | |||
31 | return buf; | ||
32 | } | ||
33 | |||
34 | int coda_sps_parse_profile(struct coda_ctx *ctx, struct vb2_buffer *vb) | ||
35 | { | ||
36 | const u8 *buf = vb2_plane_vaddr(vb, 0); | ||
37 | const u8 *end = buf + vb2_get_plane_payload(vb, 0); | ||
38 | |||
39 | /* Find SPS header */ | ||
40 | do { | ||
41 | buf = coda_find_nal_header(buf, end); | ||
42 | if (!buf) | ||
43 | return -EINVAL; | ||
44 | } while ((*buf++ & 0x1f) != 0x7); | ||
45 | |||
46 | ctx->params.h264_profile_idc = buf[0]; | ||
47 | ctx->params.h264_level_idc = buf[2]; | ||
48 | |||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | int coda_h264_filler_nal(int size, char *p) | ||
53 | { | ||
54 | if (size < 6) | ||
55 | return -EINVAL; | ||
56 | |||
57 | p[0] = 0x00; | ||
58 | p[1] = 0x00; | ||
59 | p[2] = 0x00; | ||
60 | p[3] = 0x01; | ||
61 | p[4] = 0x0c; | ||
62 | memset(p + 5, 0xff, size - 6); | ||
63 | /* Add rbsp stop bit and trailing at the end */ | ||
64 | p[size - 1] = 0x80; | ||
65 | |||
66 | return 0; | ||
67 | } | ||
68 | |||
22 | int coda_h264_padding(int size, char *p) | 69 | int coda_h264_padding(int size, char *p) |
23 | { | 70 | { |
24 | int nal_size; | 71 | int nal_size; |
@@ -29,10 +76,38 @@ int coda_h264_padding(int size, char *p) | |||
29 | return 0; | 76 | return 0; |
30 | 77 | ||
31 | nal_size = coda_filler_size[diff]; | 78 | nal_size = coda_filler_size[diff]; |
32 | memcpy(p, coda_filler_nal, nal_size); | 79 | coda_h264_filler_nal(nal_size, p); |
33 | |||
34 | /* Add rbsp stop bit and trailing at the end */ | ||
35 | *(p + nal_size - 1) = 0x80; | ||
36 | 80 | ||
37 | return nal_size; | 81 | return nal_size; |
38 | } | 82 | } |
83 | |||
84 | int coda_h264_profile(int profile_idc) | ||
85 | { | ||
86 | switch (profile_idc) { | ||
87 | case 66: return V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE; | ||
88 | case 77: return V4L2_MPEG_VIDEO_H264_PROFILE_MAIN; | ||
89 | case 88: return V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED; | ||
90 | case 100: return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH; | ||
91 | default: return -EINVAL; | ||
92 | } | ||
93 | } | ||
94 | |||
95 | int coda_h264_level(int level_idc) | ||
96 | { | ||
97 | switch (level_idc) { | ||
98 | case 10: return V4L2_MPEG_VIDEO_H264_LEVEL_1_0; | ||
99 | case 9: return V4L2_MPEG_VIDEO_H264_LEVEL_1B; | ||
100 | case 11: return V4L2_MPEG_VIDEO_H264_LEVEL_1_1; | ||
101 | case 12: return V4L2_MPEG_VIDEO_H264_LEVEL_1_2; | ||
102 | case 13: return V4L2_MPEG_VIDEO_H264_LEVEL_1_3; | ||
103 | case 20: return V4L2_MPEG_VIDEO_H264_LEVEL_2_0; | ||
104 | case 21: return V4L2_MPEG_VIDEO_H264_LEVEL_2_1; | ||
105 | case 22: return V4L2_MPEG_VIDEO_H264_LEVEL_2_2; | ||
106 | case 30: return V4L2_MPEG_VIDEO_H264_LEVEL_3_0; | ||
107 | case 31: return V4L2_MPEG_VIDEO_H264_LEVEL_3_1; | ||
108 | case 32: return V4L2_MPEG_VIDEO_H264_LEVEL_3_2; | ||
109 | case 40: return V4L2_MPEG_VIDEO_H264_LEVEL_4_0; | ||
110 | case 41: return V4L2_MPEG_VIDEO_H264_LEVEL_4_1; | ||
111 | default: return -EINVAL; | ||
112 | } | ||
113 | } | ||
diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index 4b831c91ae4a..20222befb9b2 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h | |||
@@ -28,7 +28,7 @@ | |||
28 | 28 | ||
29 | #include "coda_regs.h" | 29 | #include "coda_regs.h" |
30 | 30 | ||
31 | #define CODA_MAX_FRAMEBUFFERS 8 | 31 | #define CODA_MAX_FRAMEBUFFERS 17 |
32 | #define FMO_SLICE_SAVE_BUF_SIZE (32) | 32 | #define FMO_SLICE_SAVE_BUF_SIZE (32) |
33 | 33 | ||
34 | enum { | 34 | enum { |
@@ -117,6 +117,8 @@ struct coda_params { | |||
117 | u8 h264_deblk_enabled; | 117 | u8 h264_deblk_enabled; |
118 | u8 h264_deblk_alpha; | 118 | u8 h264_deblk_alpha; |
119 | u8 h264_deblk_beta; | 119 | u8 h264_deblk_beta; |
120 | u8 h264_profile_idc; | ||
121 | u8 h264_level_idc; | ||
120 | u8 mpeg4_intra_qp; | 122 | u8 mpeg4_intra_qp; |
121 | u8 mpeg4_inter_qp; | 123 | u8 mpeg4_inter_qp; |
122 | u8 gop_size; | 124 | u8 gop_size; |
@@ -259,7 +261,7 @@ int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq, | |||
259 | 261 | ||
260 | int coda_hw_reset(struct coda_ctx *ctx); | 262 | int coda_hw_reset(struct coda_ctx *ctx); |
261 | 263 | ||
262 | void coda_fill_bitstream(struct coda_ctx *ctx, bool streaming); | 264 | void coda_fill_bitstream(struct coda_ctx *ctx, struct list_head *buffer_list); |
263 | 265 | ||
264 | void coda_set_gdi_regs(struct coda_ctx *ctx); | 266 | void coda_set_gdi_regs(struct coda_ctx *ctx); |
265 | 267 | ||
@@ -290,7 +292,11 @@ void coda_bit_stream_end_flag(struct coda_ctx *ctx); | |||
290 | void coda_m2m_buf_done(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf, | 292 | void coda_m2m_buf_done(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf, |
291 | enum vb2_buffer_state state); | 293 | enum vb2_buffer_state state); |
292 | 294 | ||
295 | int coda_h264_filler_nal(int size, char *p); | ||
293 | int coda_h264_padding(int size, char *p); | 296 | int coda_h264_padding(int size, char *p); |
297 | int coda_h264_profile(int profile_idc); | ||
298 | int coda_h264_level(int level_idc); | ||
299 | int coda_sps_parse_profile(struct coda_ctx *ctx, struct vb2_buffer *vb); | ||
294 | 300 | ||
295 | bool coda_jpeg_check_buffer(struct coda_ctx *ctx, struct vb2_buffer *vb); | 301 | bool coda_jpeg_check_buffer(struct coda_ctx *ctx, struct vb2_buffer *vb); |
296 | int coda_jpeg_write_tables(struct coda_ctx *ctx); | 302 | int coda_jpeg_write_tables(struct coda_ctx *ctx); |
diff --git a/drivers/media/platform/coda/coda_regs.h b/drivers/media/platform/coda/coda_regs.h index 3490602fa6e1..77ee46a93427 100644 --- a/drivers/media/platform/coda/coda_regs.h +++ b/drivers/media/platform/coda/coda_regs.h | |||
@@ -51,6 +51,7 @@ | |||
51 | #define CODA7_STREAM_SEL_64BITS_ENDIAN (1 << 1) | 51 | #define CODA7_STREAM_SEL_64BITS_ENDIAN (1 << 1) |
52 | #define CODA_STREAM_ENDIAN_SELECT (1 << 0) | 52 | #define CODA_STREAM_ENDIAN_SELECT (1 << 0) |
53 | #define CODA_REG_BIT_FRAME_MEM_CTRL 0x110 | 53 | #define CODA_REG_BIT_FRAME_MEM_CTRL 0x110 |
54 | #define CODA9_FRAME_ENABLE_BWB (1 << 12) | ||
54 | #define CODA9_FRAME_TILED2LINEAR (1 << 11) | 55 | #define CODA9_FRAME_TILED2LINEAR (1 << 11) |
55 | #define CODA_FRAME_CHROMA_INTERLEAVE (1 << 2) | 56 | #define CODA_FRAME_CHROMA_INTERLEAVE (1 << 2) |
56 | #define CODA_IMAGE_ENDIAN_SELECT (1 << 0) | 57 | #define CODA_IMAGE_ENDIAN_SELECT (1 << 0) |
diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index 50c30731bb78..7e5cf9923c8d 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c | |||
@@ -1287,7 +1287,7 @@ static __init int vpif_probe(struct platform_device *pdev) | |||
1287 | } | 1287 | } |
1288 | 1288 | ||
1289 | if (!vpif_obj.config->asd_sizes) { | 1289 | if (!vpif_obj.config->asd_sizes) { |
1290 | i2c_adap = i2c_get_adapter(1); | 1290 | i2c_adap = i2c_get_adapter(vpif_obj.config->i2c_adapter_id); |
1291 | for (i = 0; i < subdev_count; i++) { | 1291 | for (i = 0; i < subdev_count; i++) { |
1292 | vpif_obj.sd[i] = | 1292 | vpif_obj.sd[i] = |
1293 | v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev, | 1293 | v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev, |
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index 0f0c389f8897..59a634201830 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c | |||
@@ -112,6 +112,15 @@ static const struct gsc_fmt gsc_formats[] = { | |||
112 | .num_planes = 1, | 112 | .num_planes = 1, |
113 | .num_comp = 2, | 113 | .num_comp = 2, |
114 | }, { | 114 | }, { |
115 | .name = "YUV 4:2:2 non-contig, Y/CbCr", | ||
116 | .pixelformat = V4L2_PIX_FMT_NV16M, | ||
117 | .depth = { 8, 8 }, | ||
118 | .color = GSC_YUV422, | ||
119 | .yorder = GSC_LSB_Y, | ||
120 | .corder = GSC_CBCR, | ||
121 | .num_planes = 2, | ||
122 | .num_comp = 2, | ||
123 | }, { | ||
115 | .name = "YUV 4:2:2 planar, Y/CrCb", | 124 | .name = "YUV 4:2:2 planar, Y/CrCb", |
116 | .pixelformat = V4L2_PIX_FMT_NV61, | 125 | .pixelformat = V4L2_PIX_FMT_NV61, |
117 | .depth = { 16 }, | 126 | .depth = { 16 }, |
@@ -121,6 +130,15 @@ static const struct gsc_fmt gsc_formats[] = { | |||
121 | .num_planes = 1, | 130 | .num_planes = 1, |
122 | .num_comp = 2, | 131 | .num_comp = 2, |
123 | }, { | 132 | }, { |
133 | .name = "YUV 4:2:2 non-contig, Y/CrCb", | ||
134 | .pixelformat = V4L2_PIX_FMT_NV61M, | ||
135 | .depth = { 8, 8 }, | ||
136 | .color = GSC_YUV422, | ||
137 | .yorder = GSC_LSB_Y, | ||
138 | .corder = GSC_CRCB, | ||
139 | .num_planes = 2, | ||
140 | .num_comp = 2, | ||
141 | }, { | ||
124 | .name = "YUV 4:2:0 planar, YCbCr", | 142 | .name = "YUV 4:2:0 planar, YCbCr", |
125 | .pixelformat = V4L2_PIX_FMT_YUV420, | 143 | .pixelformat = V4L2_PIX_FMT_YUV420, |
126 | .depth = { 12 }, | 144 | .depth = { 12 }, |
@@ -158,6 +176,15 @@ static const struct gsc_fmt gsc_formats[] = { | |||
158 | .num_planes = 1, | 176 | .num_planes = 1, |
159 | .num_comp = 2, | 177 | .num_comp = 2, |
160 | }, { | 178 | }, { |
179 | .name = "YUV 4:2:0 non-contig. 2p, Y/CrCb", | ||
180 | .pixelformat = V4L2_PIX_FMT_NV21M, | ||
181 | .depth = { 8, 4 }, | ||
182 | .color = GSC_YUV420, | ||
183 | .yorder = GSC_LSB_Y, | ||
184 | .corder = GSC_CRCB, | ||
185 | .num_planes = 2, | ||
186 | .num_comp = 2, | ||
187 | }, { | ||
161 | .name = "YUV 4:2:0 non-contig. 2p, Y/CbCr", | 188 | .name = "YUV 4:2:0 non-contig. 2p, Y/CbCr", |
162 | .pixelformat = V4L2_PIX_FMT_NV12M, | 189 | .pixelformat = V4L2_PIX_FMT_NV12M, |
163 | .depth = { 8, 4 }, | 190 | .depth = { 8, 4 }, |
diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c index ae8c6b35a357..97e164b2075a 100644 --- a/drivers/media/platform/fsl-viu.c +++ b/drivers/media/platform/fsl-viu.c | |||
@@ -1466,9 +1466,8 @@ static int viu_of_probe(struct platform_device *op) | |||
1466 | viu_dev->decoder = v4l2_i2c_new_subdev(&viu_dev->v4l2_dev, ad, | 1466 | viu_dev->decoder = v4l2_i2c_new_subdev(&viu_dev->v4l2_dev, ad, |
1467 | "saa7113", VIU_VIDEO_DECODER_ADDR, NULL); | 1467 | "saa7113", VIU_VIDEO_DECODER_ADDR, NULL); |
1468 | 1468 | ||
1469 | viu_dev->vidq.timeout.function = viu_vid_timeout; | 1469 | setup_timer(&viu_dev->vidq.timeout, viu_vid_timeout, |
1470 | viu_dev->vidq.timeout.data = (unsigned long)viu_dev; | 1470 | (unsigned long)viu_dev); |
1471 | init_timer(&viu_dev->vidq.timeout); | ||
1472 | viu_dev->std = V4L2_STD_NTSC_M; | 1471 | viu_dev->std = V4L2_STD_NTSC_M; |
1473 | viu_dev->first = 1; | 1472 | viu_dev->first = 1; |
1474 | 1473 | ||
diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c index bedc7cc4c7d6..980066b8d32a 100644 --- a/drivers/media/platform/m2m-deinterlace.c +++ b/drivers/media/platform/m2m-deinterlace.c | |||
@@ -1017,6 +1017,7 @@ static int deinterlace_probe(struct platform_device *pdev) | |||
1017 | 1017 | ||
1018 | if (!dma_has_cap(DMA_INTERLEAVE, pcdev->dma_chan->device->cap_mask)) { | 1018 | if (!dma_has_cap(DMA_INTERLEAVE, pcdev->dma_chan->device->cap_mask)) { |
1019 | dev_err(&pdev->dev, "DMA does not support INTERLEAVE\n"); | 1019 | dev_err(&pdev->dev, "DMA does not support INTERLEAVE\n"); |
1020 | ret = -ENODEV; | ||
1020 | goto rel_dma; | 1021 | goto rel_dma; |
1021 | } | 1022 | } |
1022 | 1023 | ||
diff --git a/drivers/media/platform/mtk-jpeg/Makefile b/drivers/media/platform/mtk-jpeg/Makefile new file mode 100644 index 000000000000..b2e6069f3959 --- /dev/null +++ b/drivers/media/platform/mtk-jpeg/Makefile | |||
@@ -0,0 +1,2 @@ | |||
1 | mtk_jpeg-objs := mtk_jpeg_core.o mtk_jpeg_hw.o mtk_jpeg_parse.o | ||
2 | obj-$(CONFIG_VIDEO_MEDIATEK_JPEG) += mtk_jpeg.o | ||
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c new file mode 100644 index 000000000000..451a54039e65 --- /dev/null +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c | |||
@@ -0,0 +1,1292 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2016 MediaTek Inc. | ||
3 | * Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com> | ||
4 | * Rick Chang <rick.chang@mediatek.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | #include <linux/clk.h> | ||
17 | #include <linux/err.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/io.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/of_platform.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/pm_runtime.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/spinlock.h> | ||
27 | #include <media/v4l2-event.h> | ||
28 | #include <media/v4l2-mem2mem.h> | ||
29 | #include <media/v4l2-ioctl.h> | ||
30 | #include <media/videobuf2-core.h> | ||
31 | #include <media/videobuf2-dma-contig.h> | ||
32 | #include <soc/mediatek/smi.h> | ||
33 | |||
34 | #include "mtk_jpeg_hw.h" | ||
35 | #include "mtk_jpeg_core.h" | ||
36 | #include "mtk_jpeg_parse.h" | ||
37 | |||
38 | static struct mtk_jpeg_fmt mtk_jpeg_formats[] = { | ||
39 | { | ||
40 | .fourcc = V4L2_PIX_FMT_JPEG, | ||
41 | .colplanes = 1, | ||
42 | .flags = MTK_JPEG_FMT_FLAG_DEC_OUTPUT, | ||
43 | }, | ||
44 | { | ||
45 | .fourcc = V4L2_PIX_FMT_YUV420M, | ||
46 | .h_sample = {4, 2, 2}, | ||
47 | .v_sample = {4, 2, 2}, | ||
48 | .colplanes = 3, | ||
49 | .h_align = 5, | ||
50 | .v_align = 4, | ||
51 | .flags = MTK_JPEG_FMT_FLAG_DEC_CAPTURE, | ||
52 | }, | ||
53 | { | ||
54 | .fourcc = V4L2_PIX_FMT_YUV422M, | ||
55 | .h_sample = {4, 2, 2}, | ||
56 | .v_sample = {4, 4, 4}, | ||
57 | .colplanes = 3, | ||
58 | .h_align = 5, | ||
59 | .v_align = 3, | ||
60 | .flags = MTK_JPEG_FMT_FLAG_DEC_CAPTURE, | ||
61 | }, | ||
62 | }; | ||
63 | |||
64 | #define MTK_JPEG_NUM_FORMATS ARRAY_SIZE(mtk_jpeg_formats) | ||
65 | |||
66 | enum { | ||
67 | MTK_JPEG_BUF_FLAGS_INIT = 0, | ||
68 | MTK_JPEG_BUF_FLAGS_LAST_FRAME = 1, | ||
69 | }; | ||
70 | |||
71 | struct mtk_jpeg_src_buf { | ||
72 | struct vb2_v4l2_buffer b; | ||
73 | struct list_head list; | ||
74 | int flags; | ||
75 | struct mtk_jpeg_dec_param dec_param; | ||
76 | }; | ||
77 | |||
78 | static int debug; | ||
79 | module_param(debug, int, 0644); | ||
80 | |||
81 | static inline struct mtk_jpeg_ctx *mtk_jpeg_fh_to_ctx(struct v4l2_fh *fh) | ||
82 | { | ||
83 | return container_of(fh, struct mtk_jpeg_ctx, fh); | ||
84 | } | ||
85 | |||
86 | static inline struct mtk_jpeg_src_buf *mtk_jpeg_vb2_to_srcbuf( | ||
87 | struct vb2_buffer *vb) | ||
88 | { | ||
89 | return container_of(to_vb2_v4l2_buffer(vb), struct mtk_jpeg_src_buf, b); | ||
90 | } | ||
91 | |||
92 | static int mtk_jpeg_querycap(struct file *file, void *priv, | ||
93 | struct v4l2_capability *cap) | ||
94 | { | ||
95 | struct mtk_jpeg_dev *jpeg = video_drvdata(file); | ||
96 | |||
97 | strlcpy(cap->driver, MTK_JPEG_NAME " decoder", sizeof(cap->driver)); | ||
98 | strlcpy(cap->card, MTK_JPEG_NAME " decoder", sizeof(cap->card)); | ||
99 | snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", | ||
100 | dev_name(jpeg->dev)); | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | static int mtk_jpeg_enum_fmt(struct mtk_jpeg_fmt *mtk_jpeg_formats, int n, | ||
106 | struct v4l2_fmtdesc *f, u32 type) | ||
107 | { | ||
108 | int i, num = 0; | ||
109 | |||
110 | for (i = 0; i < n; ++i) { | ||
111 | if (mtk_jpeg_formats[i].flags & type) { | ||
112 | if (num == f->index) | ||
113 | break; | ||
114 | ++num; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | if (i >= n) | ||
119 | return -EINVAL; | ||
120 | |||
121 | f->pixelformat = mtk_jpeg_formats[i].fourcc; | ||
122 | |||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | static int mtk_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, | ||
127 | struct v4l2_fmtdesc *f) | ||
128 | { | ||
129 | return mtk_jpeg_enum_fmt(mtk_jpeg_formats, MTK_JPEG_NUM_FORMATS, f, | ||
130 | MTK_JPEG_FMT_FLAG_DEC_CAPTURE); | ||
131 | } | ||
132 | |||
133 | static int mtk_jpeg_enum_fmt_vid_out(struct file *file, void *priv, | ||
134 | struct v4l2_fmtdesc *f) | ||
135 | { | ||
136 | return mtk_jpeg_enum_fmt(mtk_jpeg_formats, MTK_JPEG_NUM_FORMATS, f, | ||
137 | MTK_JPEG_FMT_FLAG_DEC_OUTPUT); | ||
138 | } | ||
139 | |||
140 | static struct mtk_jpeg_q_data *mtk_jpeg_get_q_data(struct mtk_jpeg_ctx *ctx, | ||
141 | enum v4l2_buf_type type) | ||
142 | { | ||
143 | if (V4L2_TYPE_IS_OUTPUT(type)) | ||
144 | return &ctx->out_q; | ||
145 | return &ctx->cap_q; | ||
146 | } | ||
147 | |||
148 | static struct mtk_jpeg_fmt *mtk_jpeg_find_format(struct mtk_jpeg_ctx *ctx, | ||
149 | u32 pixelformat, | ||
150 | unsigned int fmt_type) | ||
151 | { | ||
152 | unsigned int k, fmt_flag; | ||
153 | |||
154 | fmt_flag = (fmt_type == MTK_JPEG_FMT_TYPE_OUTPUT) ? | ||
155 | MTK_JPEG_FMT_FLAG_DEC_OUTPUT : | ||
156 | MTK_JPEG_FMT_FLAG_DEC_CAPTURE; | ||
157 | |||
158 | for (k = 0; k < MTK_JPEG_NUM_FORMATS; k++) { | ||
159 | struct mtk_jpeg_fmt *fmt = &mtk_jpeg_formats[k]; | ||
160 | |||
161 | if (fmt->fourcc == pixelformat && fmt->flags & fmt_flag) | ||
162 | return fmt; | ||
163 | } | ||
164 | |||
165 | return NULL; | ||
166 | } | ||
167 | |||
168 | static void mtk_jpeg_bound_align_image(u32 *w, unsigned int wmin, | ||
169 | unsigned int wmax, unsigned int walign, | ||
170 | u32 *h, unsigned int hmin, | ||
171 | unsigned int hmax, unsigned int halign) | ||
172 | { | ||
173 | int width, height, w_step, h_step; | ||
174 | |||
175 | width = *w; | ||
176 | height = *h; | ||
177 | w_step = 1 << walign; | ||
178 | h_step = 1 << halign; | ||
179 | |||
180 | v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0); | ||
181 | if (*w < width && (*w + w_step) <= wmax) | ||
182 | *w += w_step; | ||
183 | if (*h < height && (*h + h_step) <= hmax) | ||
184 | *h += h_step; | ||
185 | } | ||
186 | |||
187 | static void mtk_jpeg_adjust_fmt_mplane(struct mtk_jpeg_ctx *ctx, | ||
188 | struct v4l2_format *f) | ||
189 | { | ||
190 | struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; | ||
191 | struct mtk_jpeg_q_data *q_data; | ||
192 | int i; | ||
193 | |||
194 | q_data = mtk_jpeg_get_q_data(ctx, f->type); | ||
195 | |||
196 | pix_mp->width = q_data->w; | ||
197 | pix_mp->height = q_data->h; | ||
198 | pix_mp->pixelformat = q_data->fmt->fourcc; | ||
199 | pix_mp->num_planes = q_data->fmt->colplanes; | ||
200 | |||
201 | for (i = 0; i < pix_mp->num_planes; i++) { | ||
202 | pix_mp->plane_fmt[i].bytesperline = q_data->bytesperline[i]; | ||
203 | pix_mp->plane_fmt[i].sizeimage = q_data->sizeimage[i]; | ||
204 | } | ||
205 | } | ||
206 | |||
207 | static int mtk_jpeg_try_fmt_mplane(struct v4l2_format *f, | ||
208 | struct mtk_jpeg_fmt *fmt, | ||
209 | struct mtk_jpeg_ctx *ctx, int q_type) | ||
210 | { | ||
211 | struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; | ||
212 | struct mtk_jpeg_dev *jpeg = ctx->jpeg; | ||
213 | int i; | ||
214 | |||
215 | memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved)); | ||
216 | pix_mp->field = V4L2_FIELD_NONE; | ||
217 | |||
218 | if (ctx->state != MTK_JPEG_INIT) { | ||
219 | mtk_jpeg_adjust_fmt_mplane(ctx, f); | ||
220 | goto end; | ||
221 | } | ||
222 | |||
223 | pix_mp->num_planes = fmt->colplanes; | ||
224 | pix_mp->pixelformat = fmt->fourcc; | ||
225 | |||
226 | if (q_type == MTK_JPEG_FMT_TYPE_OUTPUT) { | ||
227 | struct v4l2_plane_pix_format *pfmt = &pix_mp->plane_fmt[0]; | ||
228 | |||
229 | mtk_jpeg_bound_align_image(&pix_mp->width, MTK_JPEG_MIN_WIDTH, | ||
230 | MTK_JPEG_MAX_WIDTH, 0, | ||
231 | &pix_mp->height, MTK_JPEG_MIN_HEIGHT, | ||
232 | MTK_JPEG_MAX_HEIGHT, 0); | ||
233 | |||
234 | memset(pfmt->reserved, 0, sizeof(pfmt->reserved)); | ||
235 | pfmt->bytesperline = 0; | ||
236 | /* Source size must be aligned to 128 */ | ||
237 | pfmt->sizeimage = mtk_jpeg_align(pfmt->sizeimage, 128); | ||
238 | if (pfmt->sizeimage == 0) | ||
239 | pfmt->sizeimage = MTK_JPEG_DEFAULT_SIZEIMAGE; | ||
240 | goto end; | ||
241 | } | ||
242 | |||
243 | /* type is MTK_JPEG_FMT_TYPE_CAPTURE */ | ||
244 | mtk_jpeg_bound_align_image(&pix_mp->width, MTK_JPEG_MIN_WIDTH, | ||
245 | MTK_JPEG_MAX_WIDTH, fmt->h_align, | ||
246 | &pix_mp->height, MTK_JPEG_MIN_HEIGHT, | ||
247 | MTK_JPEG_MAX_HEIGHT, fmt->v_align); | ||
248 | |||
249 | for (i = 0; i < fmt->colplanes; i++) { | ||
250 | struct v4l2_plane_pix_format *pfmt = &pix_mp->plane_fmt[i]; | ||
251 | u32 stride = pix_mp->width * fmt->h_sample[i] / 4; | ||
252 | u32 h = pix_mp->height * fmt->v_sample[i] / 4; | ||
253 | |||
254 | memset(pfmt->reserved, 0, sizeof(pfmt->reserved)); | ||
255 | pfmt->bytesperline = stride; | ||
256 | pfmt->sizeimage = stride * h; | ||
257 | } | ||
258 | end: | ||
259 | v4l2_dbg(2, debug, &jpeg->v4l2_dev, "wxh:%ux%u\n", | ||
260 | pix_mp->width, pix_mp->height); | ||
261 | for (i = 0; i < pix_mp->num_planes; i++) { | ||
262 | v4l2_dbg(2, debug, &jpeg->v4l2_dev, | ||
263 | "plane[%d] bpl=%u, size=%u\n", | ||
264 | i, | ||
265 | pix_mp->plane_fmt[i].bytesperline, | ||
266 | pix_mp->plane_fmt[i].sizeimage); | ||
267 | } | ||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | static int mtk_jpeg_g_fmt_vid_mplane(struct file *file, void *priv, | ||
272 | struct v4l2_format *f) | ||
273 | { | ||
274 | struct vb2_queue *vq; | ||
275 | struct mtk_jpeg_q_data *q_data = NULL; | ||
276 | struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; | ||
277 | struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); | ||
278 | struct mtk_jpeg_dev *jpeg = ctx->jpeg; | ||
279 | int i; | ||
280 | |||
281 | vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); | ||
282 | if (!vq) | ||
283 | return -EINVAL; | ||
284 | |||
285 | q_data = mtk_jpeg_get_q_data(ctx, f->type); | ||
286 | |||
287 | memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved)); | ||
288 | pix_mp->width = q_data->w; | ||
289 | pix_mp->height = q_data->h; | ||
290 | pix_mp->field = V4L2_FIELD_NONE; | ||
291 | pix_mp->pixelformat = q_data->fmt->fourcc; | ||
292 | pix_mp->num_planes = q_data->fmt->colplanes; | ||
293 | pix_mp->colorspace = ctx->colorspace; | ||
294 | pix_mp->ycbcr_enc = ctx->ycbcr_enc; | ||
295 | pix_mp->xfer_func = ctx->xfer_func; | ||
296 | pix_mp->quantization = ctx->quantization; | ||
297 | |||
298 | v4l2_dbg(1, debug, &jpeg->v4l2_dev, "(%d) g_fmt:%c%c%c%c wxh:%ux%u\n", | ||
299 | f->type, | ||
300 | (pix_mp->pixelformat & 0xff), | ||
301 | (pix_mp->pixelformat >> 8 & 0xff), | ||
302 | (pix_mp->pixelformat >> 16 & 0xff), | ||
303 | (pix_mp->pixelformat >> 24 & 0xff), | ||
304 | pix_mp->width, pix_mp->height); | ||
305 | |||
306 | for (i = 0; i < pix_mp->num_planes; i++) { | ||
307 | struct v4l2_plane_pix_format *pfmt = &pix_mp->plane_fmt[i]; | ||
308 | |||
309 | pfmt->bytesperline = q_data->bytesperline[i]; | ||
310 | pfmt->sizeimage = q_data->sizeimage[i]; | ||
311 | memset(pfmt->reserved, 0, sizeof(pfmt->reserved)); | ||
312 | |||
313 | v4l2_dbg(1, debug, &jpeg->v4l2_dev, | ||
314 | "plane[%d] bpl=%u, size=%u\n", | ||
315 | i, | ||
316 | pfmt->bytesperline, | ||
317 | pfmt->sizeimage); | ||
318 | } | ||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | static int mtk_jpeg_try_fmt_vid_cap_mplane(struct file *file, void *priv, | ||
323 | struct v4l2_format *f) | ||
324 | { | ||
325 | struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); | ||
326 | struct mtk_jpeg_fmt *fmt; | ||
327 | |||
328 | fmt = mtk_jpeg_find_format(ctx, f->fmt.pix_mp.pixelformat, | ||
329 | MTK_JPEG_FMT_TYPE_CAPTURE); | ||
330 | if (!fmt) | ||
331 | fmt = ctx->cap_q.fmt; | ||
332 | |||
333 | v4l2_dbg(2, debug, &ctx->jpeg->v4l2_dev, "(%d) try_fmt:%c%c%c%c\n", | ||
334 | f->type, | ||
335 | (fmt->fourcc & 0xff), | ||
336 | (fmt->fourcc >> 8 & 0xff), | ||
337 | (fmt->fourcc >> 16 & 0xff), | ||
338 | (fmt->fourcc >> 24 & 0xff)); | ||
339 | |||
340 | return mtk_jpeg_try_fmt_mplane(f, fmt, ctx, MTK_JPEG_FMT_TYPE_CAPTURE); | ||
341 | } | ||
342 | |||
343 | static int mtk_jpeg_try_fmt_vid_out_mplane(struct file *file, void *priv, | ||
344 | struct v4l2_format *f) | ||
345 | { | ||
346 | struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); | ||
347 | struct mtk_jpeg_fmt *fmt; | ||
348 | |||
349 | fmt = mtk_jpeg_find_format(ctx, f->fmt.pix_mp.pixelformat, | ||
350 | MTK_JPEG_FMT_TYPE_OUTPUT); | ||
351 | if (!fmt) | ||
352 | fmt = ctx->out_q.fmt; | ||
353 | |||
354 | v4l2_dbg(2, debug, &ctx->jpeg->v4l2_dev, "(%d) try_fmt:%c%c%c%c\n", | ||
355 | f->type, | ||
356 | (fmt->fourcc & 0xff), | ||
357 | (fmt->fourcc >> 8 & 0xff), | ||
358 | (fmt->fourcc >> 16 & 0xff), | ||
359 | (fmt->fourcc >> 24 & 0xff)); | ||
360 | |||
361 | return mtk_jpeg_try_fmt_mplane(f, fmt, ctx, MTK_JPEG_FMT_TYPE_OUTPUT); | ||
362 | } | ||
363 | |||
364 | static int mtk_jpeg_s_fmt_mplane(struct mtk_jpeg_ctx *ctx, | ||
365 | struct v4l2_format *f) | ||
366 | { | ||
367 | struct vb2_queue *vq; | ||
368 | struct mtk_jpeg_q_data *q_data = NULL; | ||
369 | struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; | ||
370 | struct mtk_jpeg_dev *jpeg = ctx->jpeg; | ||
371 | unsigned int f_type; | ||
372 | int i; | ||
373 | |||
374 | vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); | ||
375 | if (!vq) | ||
376 | return -EINVAL; | ||
377 | |||
378 | q_data = mtk_jpeg_get_q_data(ctx, f->type); | ||
379 | |||
380 | if (vb2_is_busy(vq)) { | ||
381 | v4l2_err(&jpeg->v4l2_dev, "queue busy\n"); | ||
382 | return -EBUSY; | ||
383 | } | ||
384 | |||
385 | f_type = V4L2_TYPE_IS_OUTPUT(f->type) ? | ||
386 | MTK_JPEG_FMT_TYPE_OUTPUT : MTK_JPEG_FMT_TYPE_CAPTURE; | ||
387 | |||
388 | q_data->fmt = mtk_jpeg_find_format(ctx, pix_mp->pixelformat, f_type); | ||
389 | q_data->w = pix_mp->width; | ||
390 | q_data->h = pix_mp->height; | ||
391 | ctx->colorspace = pix_mp->colorspace; | ||
392 | ctx->ycbcr_enc = pix_mp->ycbcr_enc; | ||
393 | ctx->xfer_func = pix_mp->xfer_func; | ||
394 | ctx->quantization = pix_mp->quantization; | ||
395 | |||
396 | v4l2_dbg(1, debug, &jpeg->v4l2_dev, "(%d) s_fmt:%c%c%c%c wxh:%ux%u\n", | ||
397 | f->type, | ||
398 | (q_data->fmt->fourcc & 0xff), | ||
399 | (q_data->fmt->fourcc >> 8 & 0xff), | ||
400 | (q_data->fmt->fourcc >> 16 & 0xff), | ||
401 | (q_data->fmt->fourcc >> 24 & 0xff), | ||
402 | q_data->w, q_data->h); | ||
403 | |||
404 | for (i = 0; i < q_data->fmt->colplanes; i++) { | ||
405 | q_data->bytesperline[i] = pix_mp->plane_fmt[i].bytesperline; | ||
406 | q_data->sizeimage[i] = pix_mp->plane_fmt[i].sizeimage; | ||
407 | |||
408 | v4l2_dbg(1, debug, &jpeg->v4l2_dev, | ||
409 | "plane[%d] bpl=%u, size=%u\n", | ||
410 | i, q_data->bytesperline[i], q_data->sizeimage[i]); | ||
411 | } | ||
412 | |||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | static int mtk_jpeg_s_fmt_vid_out_mplane(struct file *file, void *priv, | ||
417 | struct v4l2_format *f) | ||
418 | { | ||
419 | int ret; | ||
420 | |||
421 | ret = mtk_jpeg_try_fmt_vid_out_mplane(file, priv, f); | ||
422 | if (ret) | ||
423 | return ret; | ||
424 | |||
425 | return mtk_jpeg_s_fmt_mplane(mtk_jpeg_fh_to_ctx(priv), f); | ||
426 | } | ||
427 | |||
428 | static int mtk_jpeg_s_fmt_vid_cap_mplane(struct file *file, void *priv, | ||
429 | struct v4l2_format *f) | ||
430 | { | ||
431 | int ret; | ||
432 | |||
433 | ret = mtk_jpeg_try_fmt_vid_cap_mplane(file, priv, f); | ||
434 | if (ret) | ||
435 | return ret; | ||
436 | |||
437 | return mtk_jpeg_s_fmt_mplane(mtk_jpeg_fh_to_ctx(priv), f); | ||
438 | } | ||
439 | |||
440 | static void mtk_jpeg_queue_src_chg_event(struct mtk_jpeg_ctx *ctx) | ||
441 | { | ||
442 | static const struct v4l2_event ev_src_ch = { | ||
443 | .type = V4L2_EVENT_SOURCE_CHANGE, | ||
444 | .u.src_change.changes = | ||
445 | V4L2_EVENT_SRC_CH_RESOLUTION, | ||
446 | }; | ||
447 | |||
448 | v4l2_event_queue_fh(&ctx->fh, &ev_src_ch); | ||
449 | } | ||
450 | |||
451 | static int mtk_jpeg_subscribe_event(struct v4l2_fh *fh, | ||
452 | const struct v4l2_event_subscription *sub) | ||
453 | { | ||
454 | switch (sub->type) { | ||
455 | case V4L2_EVENT_SOURCE_CHANGE: | ||
456 | return v4l2_src_change_event_subscribe(fh, sub); | ||
457 | default: | ||
458 | return -EINVAL; | ||
459 | } | ||
460 | } | ||
461 | |||
462 | static int mtk_jpeg_g_selection(struct file *file, void *priv, | ||
463 | struct v4l2_selection *s) | ||
464 | { | ||
465 | struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); | ||
466 | |||
467 | if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
468 | return -EINVAL; | ||
469 | |||
470 | switch (s->target) { | ||
471 | case V4L2_SEL_TGT_COMPOSE: | ||
472 | case V4L2_SEL_TGT_COMPOSE_DEFAULT: | ||
473 | s->r.width = ctx->out_q.w; | ||
474 | s->r.height = ctx->out_q.h; | ||
475 | s->r.left = 0; | ||
476 | s->r.top = 0; | ||
477 | break; | ||
478 | case V4L2_SEL_TGT_COMPOSE_BOUNDS: | ||
479 | case V4L2_SEL_TGT_COMPOSE_PADDED: | ||
480 | s->r.width = ctx->cap_q.w; | ||
481 | s->r.height = ctx->cap_q.h; | ||
482 | s->r.left = 0; | ||
483 | s->r.top = 0; | ||
484 | break; | ||
485 | default: | ||
486 | return -EINVAL; | ||
487 | } | ||
488 | return 0; | ||
489 | } | ||
490 | |||
491 | static int mtk_jpeg_s_selection(struct file *file, void *priv, | ||
492 | struct v4l2_selection *s) | ||
493 | { | ||
494 | struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); | ||
495 | |||
496 | if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
497 | return -EINVAL; | ||
498 | |||
499 | switch (s->target) { | ||
500 | case V4L2_SEL_TGT_COMPOSE: | ||
501 | s->r.left = 0; | ||
502 | s->r.top = 0; | ||
503 | s->r.width = ctx->out_q.w; | ||
504 | s->r.height = ctx->out_q.h; | ||
505 | break; | ||
506 | default: | ||
507 | return -EINVAL; | ||
508 | } | ||
509 | return 0; | ||
510 | } | ||
511 | |||
512 | static int mtk_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | ||
513 | { | ||
514 | struct v4l2_fh *fh = file->private_data; | ||
515 | struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); | ||
516 | struct vb2_queue *vq; | ||
517 | struct vb2_buffer *vb; | ||
518 | struct mtk_jpeg_src_buf *jpeg_src_buf; | ||
519 | |||
520 | if (buf->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) | ||
521 | goto end; | ||
522 | |||
523 | vq = v4l2_m2m_get_vq(fh->m2m_ctx, buf->type); | ||
524 | if (buf->index >= vq->num_buffers) { | ||
525 | dev_err(ctx->jpeg->dev, "buffer index out of range\n"); | ||
526 | return -EINVAL; | ||
527 | } | ||
528 | |||
529 | vb = vq->bufs[buf->index]; | ||
530 | jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(vb); | ||
531 | jpeg_src_buf->flags = (buf->m.planes[0].bytesused == 0) ? | ||
532 | MTK_JPEG_BUF_FLAGS_LAST_FRAME : MTK_JPEG_BUF_FLAGS_INIT; | ||
533 | end: | ||
534 | return v4l2_m2m_qbuf(file, fh->m2m_ctx, buf); | ||
535 | } | ||
536 | |||
537 | static const struct v4l2_ioctl_ops mtk_jpeg_ioctl_ops = { | ||
538 | .vidioc_querycap = mtk_jpeg_querycap, | ||
539 | .vidioc_enum_fmt_vid_cap_mplane = mtk_jpeg_enum_fmt_vid_cap, | ||
540 | .vidioc_enum_fmt_vid_out_mplane = mtk_jpeg_enum_fmt_vid_out, | ||
541 | .vidioc_try_fmt_vid_cap_mplane = mtk_jpeg_try_fmt_vid_cap_mplane, | ||
542 | .vidioc_try_fmt_vid_out_mplane = mtk_jpeg_try_fmt_vid_out_mplane, | ||
543 | .vidioc_g_fmt_vid_cap_mplane = mtk_jpeg_g_fmt_vid_mplane, | ||
544 | .vidioc_g_fmt_vid_out_mplane = mtk_jpeg_g_fmt_vid_mplane, | ||
545 | .vidioc_s_fmt_vid_cap_mplane = mtk_jpeg_s_fmt_vid_cap_mplane, | ||
546 | .vidioc_s_fmt_vid_out_mplane = mtk_jpeg_s_fmt_vid_out_mplane, | ||
547 | .vidioc_qbuf = mtk_jpeg_qbuf, | ||
548 | .vidioc_subscribe_event = mtk_jpeg_subscribe_event, | ||
549 | .vidioc_g_selection = mtk_jpeg_g_selection, | ||
550 | .vidioc_s_selection = mtk_jpeg_s_selection, | ||
551 | |||
552 | .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, | ||
553 | .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, | ||
554 | .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, | ||
555 | .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, | ||
556 | .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, | ||
557 | .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, | ||
558 | .vidioc_streamon = v4l2_m2m_ioctl_streamon, | ||
559 | .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, | ||
560 | |||
561 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | ||
562 | }; | ||
563 | |||
564 | static int mtk_jpeg_queue_setup(struct vb2_queue *q, | ||
565 | unsigned int *num_buffers, | ||
566 | unsigned int *num_planes, | ||
567 | unsigned int sizes[], | ||
568 | struct device *alloc_ctxs[]) | ||
569 | { | ||
570 | struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(q); | ||
571 | struct mtk_jpeg_q_data *q_data = NULL; | ||
572 | struct mtk_jpeg_dev *jpeg = ctx->jpeg; | ||
573 | int i; | ||
574 | |||
575 | v4l2_dbg(1, debug, &jpeg->v4l2_dev, "(%d) buf_req count=%u\n", | ||
576 | q->type, *num_buffers); | ||
577 | |||
578 | q_data = mtk_jpeg_get_q_data(ctx, q->type); | ||
579 | if (!q_data) | ||
580 | return -EINVAL; | ||
581 | |||
582 | *num_planes = q_data->fmt->colplanes; | ||
583 | for (i = 0; i < q_data->fmt->colplanes; i++) { | ||
584 | sizes[i] = q_data->sizeimage[i]; | ||
585 | v4l2_dbg(1, debug, &jpeg->v4l2_dev, "sizeimage[%d]=%u\n", | ||
586 | i, sizes[i]); | ||
587 | } | ||
588 | |||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | static int mtk_jpeg_buf_prepare(struct vb2_buffer *vb) | ||
593 | { | ||
594 | struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); | ||
595 | struct mtk_jpeg_q_data *q_data = NULL; | ||
596 | int i; | ||
597 | |||
598 | q_data = mtk_jpeg_get_q_data(ctx, vb->vb2_queue->type); | ||
599 | if (!q_data) | ||
600 | return -EINVAL; | ||
601 | |||
602 | for (i = 0; i < q_data->fmt->colplanes; i++) | ||
603 | vb2_set_plane_payload(vb, i, q_data->sizeimage[i]); | ||
604 | |||
605 | return 0; | ||
606 | } | ||
607 | |||
608 | static bool mtk_jpeg_check_resolution_change(struct mtk_jpeg_ctx *ctx, | ||
609 | struct mtk_jpeg_dec_param *param) | ||
610 | { | ||
611 | struct mtk_jpeg_dev *jpeg = ctx->jpeg; | ||
612 | struct mtk_jpeg_q_data *q_data; | ||
613 | |||
614 | q_data = &ctx->out_q; | ||
615 | if (q_data->w != param->pic_w || q_data->h != param->pic_h) { | ||
616 | v4l2_dbg(1, debug, &jpeg->v4l2_dev, "Picture size change\n"); | ||
617 | return true; | ||
618 | } | ||
619 | |||
620 | q_data = &ctx->cap_q; | ||
621 | if (q_data->fmt != mtk_jpeg_find_format(ctx, param->dst_fourcc, | ||
622 | MTK_JPEG_FMT_TYPE_CAPTURE)) { | ||
623 | v4l2_dbg(1, debug, &jpeg->v4l2_dev, "format change\n"); | ||
624 | return true; | ||
625 | } | ||
626 | return false; | ||
627 | } | ||
628 | |||
629 | static void mtk_jpeg_set_queue_data(struct mtk_jpeg_ctx *ctx, | ||
630 | struct mtk_jpeg_dec_param *param) | ||
631 | { | ||
632 | struct mtk_jpeg_dev *jpeg = ctx->jpeg; | ||
633 | struct mtk_jpeg_q_data *q_data; | ||
634 | int i; | ||
635 | |||
636 | q_data = &ctx->out_q; | ||
637 | q_data->w = param->pic_w; | ||
638 | q_data->h = param->pic_h; | ||
639 | |||
640 | q_data = &ctx->cap_q; | ||
641 | q_data->w = param->dec_w; | ||
642 | q_data->h = param->dec_h; | ||
643 | q_data->fmt = mtk_jpeg_find_format(ctx, | ||
644 | param->dst_fourcc, | ||
645 | MTK_JPEG_FMT_TYPE_CAPTURE); | ||
646 | |||
647 | for (i = 0; i < q_data->fmt->colplanes; i++) { | ||
648 | q_data->bytesperline[i] = param->mem_stride[i]; | ||
649 | q_data->sizeimage[i] = param->comp_size[i]; | ||
650 | } | ||
651 | |||
652 | v4l2_dbg(1, debug, &jpeg->v4l2_dev, | ||
653 | "set_parse cap:%c%c%c%c pic(%u, %u), buf(%u, %u)\n", | ||
654 | (param->dst_fourcc & 0xff), | ||
655 | (param->dst_fourcc >> 8 & 0xff), | ||
656 | (param->dst_fourcc >> 16 & 0xff), | ||
657 | (param->dst_fourcc >> 24 & 0xff), | ||
658 | param->pic_w, param->pic_h, | ||
659 | param->dec_w, param->dec_h); | ||
660 | } | ||
661 | |||
662 | static void mtk_jpeg_buf_queue(struct vb2_buffer *vb) | ||
663 | { | ||
664 | struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); | ||
665 | struct mtk_jpeg_dec_param *param; | ||
666 | struct mtk_jpeg_dev *jpeg = ctx->jpeg; | ||
667 | struct mtk_jpeg_src_buf *jpeg_src_buf; | ||
668 | bool header_valid; | ||
669 | |||
670 | v4l2_dbg(2, debug, &jpeg->v4l2_dev, "(%d) buf_q id=%d, vb=%p\n", | ||
671 | vb->vb2_queue->type, vb->index, vb); | ||
672 | |||
673 | if (vb->vb2_queue->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) | ||
674 | goto end; | ||
675 | |||
676 | jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(vb); | ||
677 | param = &jpeg_src_buf->dec_param; | ||
678 | memset(param, 0, sizeof(*param)); | ||
679 | |||
680 | if (jpeg_src_buf->flags & MTK_JPEG_BUF_FLAGS_LAST_FRAME) { | ||
681 | v4l2_dbg(1, debug, &jpeg->v4l2_dev, "Got eos\n"); | ||
682 | goto end; | ||
683 | } | ||
684 | header_valid = mtk_jpeg_parse(param, (u8 *)vb2_plane_vaddr(vb, 0), | ||
685 | vb2_get_plane_payload(vb, 0)); | ||
686 | if (!header_valid) { | ||
687 | v4l2_err(&jpeg->v4l2_dev, "Header invalid.\n"); | ||
688 | vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); | ||
689 | return; | ||
690 | } | ||
691 | |||
692 | if (ctx->state == MTK_JPEG_INIT) { | ||
693 | struct vb2_queue *dst_vq = v4l2_m2m_get_vq( | ||
694 | ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); | ||
695 | |||
696 | mtk_jpeg_queue_src_chg_event(ctx); | ||
697 | mtk_jpeg_set_queue_data(ctx, param); | ||
698 | ctx->state = vb2_is_streaming(dst_vq) ? | ||
699 | MTK_JPEG_SOURCE_CHANGE : MTK_JPEG_RUNNING; | ||
700 | } | ||
701 | end: | ||
702 | v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, to_vb2_v4l2_buffer(vb)); | ||
703 | } | ||
704 | |||
705 | static void *mtk_jpeg_buf_remove(struct mtk_jpeg_ctx *ctx, | ||
706 | enum v4l2_buf_type type) | ||
707 | { | ||
708 | if (V4L2_TYPE_IS_OUTPUT(type)) | ||
709 | return v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); | ||
710 | else | ||
711 | return v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); | ||
712 | } | ||
713 | |||
714 | static int mtk_jpeg_start_streaming(struct vb2_queue *q, unsigned int count) | ||
715 | { | ||
716 | struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(q); | ||
717 | struct vb2_buffer *vb; | ||
718 | int ret = 0; | ||
719 | |||
720 | ret = pm_runtime_get_sync(ctx->jpeg->dev); | ||
721 | if (ret < 0) | ||
722 | goto err; | ||
723 | |||
724 | return 0; | ||
725 | err: | ||
726 | while ((vb = mtk_jpeg_buf_remove(ctx, q->type))) | ||
727 | v4l2_m2m_buf_done(to_vb2_v4l2_buffer(vb), VB2_BUF_STATE_QUEUED); | ||
728 | return ret; | ||
729 | } | ||
730 | |||
731 | static void mtk_jpeg_stop_streaming(struct vb2_queue *q) | ||
732 | { | ||
733 | struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(q); | ||
734 | struct vb2_buffer *vb; | ||
735 | |||
736 | /* | ||
737 | * STREAMOFF is an acknowledgment for source change event. | ||
738 | * Before STREAMOFF, we still have to return the old resolution and | ||
739 | * subsampling. Update capture queue when the stream is off. | ||
740 | */ | ||
741 | if (ctx->state == MTK_JPEG_SOURCE_CHANGE && | ||
742 | !V4L2_TYPE_IS_OUTPUT(q->type)) { | ||
743 | struct mtk_jpeg_src_buf *src_buf; | ||
744 | |||
745 | vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); | ||
746 | src_buf = mtk_jpeg_vb2_to_srcbuf(vb); | ||
747 | mtk_jpeg_set_queue_data(ctx, &src_buf->dec_param); | ||
748 | ctx->state = MTK_JPEG_RUNNING; | ||
749 | } else if (V4L2_TYPE_IS_OUTPUT(q->type)) { | ||
750 | ctx->state = MTK_JPEG_INIT; | ||
751 | } | ||
752 | |||
753 | while ((vb = mtk_jpeg_buf_remove(ctx, q->type))) | ||
754 | v4l2_m2m_buf_done(to_vb2_v4l2_buffer(vb), VB2_BUF_STATE_ERROR); | ||
755 | |||
756 | pm_runtime_put_sync(ctx->jpeg->dev); | ||
757 | } | ||
758 | |||
759 | static struct vb2_ops mtk_jpeg_qops = { | ||
760 | .queue_setup = mtk_jpeg_queue_setup, | ||
761 | .buf_prepare = mtk_jpeg_buf_prepare, | ||
762 | .buf_queue = mtk_jpeg_buf_queue, | ||
763 | .wait_prepare = vb2_ops_wait_prepare, | ||
764 | .wait_finish = vb2_ops_wait_finish, | ||
765 | .start_streaming = mtk_jpeg_start_streaming, | ||
766 | .stop_streaming = mtk_jpeg_stop_streaming, | ||
767 | }; | ||
768 | |||
769 | static void mtk_jpeg_set_dec_src(struct mtk_jpeg_ctx *ctx, | ||
770 | struct vb2_buffer *src_buf, | ||
771 | struct mtk_jpeg_bs *bs) | ||
772 | { | ||
773 | bs->str_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0); | ||
774 | bs->end_addr = bs->str_addr + | ||
775 | mtk_jpeg_align(vb2_get_plane_payload(src_buf, 0), 16); | ||
776 | bs->size = mtk_jpeg_align(vb2_plane_size(src_buf, 0), 128); | ||
777 | } | ||
778 | |||
779 | static int mtk_jpeg_set_dec_dst(struct mtk_jpeg_ctx *ctx, | ||
780 | struct mtk_jpeg_dec_param *param, | ||
781 | struct vb2_buffer *dst_buf, | ||
782 | struct mtk_jpeg_fb *fb) | ||
783 | { | ||
784 | int i; | ||
785 | |||
786 | if (param->comp_num != dst_buf->num_planes) { | ||
787 | dev_err(ctx->jpeg->dev, "plane number mismatch (%u != %u)\n", | ||
788 | param->comp_num, dst_buf->num_planes); | ||
789 | return -EINVAL; | ||
790 | } | ||
791 | |||
792 | for (i = 0; i < dst_buf->num_planes; i++) { | ||
793 | if (vb2_plane_size(dst_buf, i) < param->comp_size[i]) { | ||
794 | dev_err(ctx->jpeg->dev, | ||
795 | "buffer size is underflow (%lu < %u)\n", | ||
796 | vb2_plane_size(dst_buf, 0), | ||
797 | param->comp_size[i]); | ||
798 | return -EINVAL; | ||
799 | } | ||
800 | fb->plane_addr[i] = vb2_dma_contig_plane_dma_addr(dst_buf, i); | ||
801 | } | ||
802 | |||
803 | return 0; | ||
804 | } | ||
805 | |||
806 | static void mtk_jpeg_device_run(void *priv) | ||
807 | { | ||
808 | struct mtk_jpeg_ctx *ctx = priv; | ||
809 | struct mtk_jpeg_dev *jpeg = ctx->jpeg; | ||
810 | struct vb2_buffer *src_buf, *dst_buf; | ||
811 | enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR; | ||
812 | unsigned long flags; | ||
813 | struct mtk_jpeg_src_buf *jpeg_src_buf; | ||
814 | struct mtk_jpeg_bs bs; | ||
815 | struct mtk_jpeg_fb fb; | ||
816 | int i; | ||
817 | |||
818 | src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); | ||
819 | dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); | ||
820 | jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(src_buf); | ||
821 | |||
822 | if (jpeg_src_buf->flags & MTK_JPEG_BUF_FLAGS_LAST_FRAME) { | ||
823 | for (i = 0; i < dst_buf->num_planes; i++) | ||
824 | vb2_set_plane_payload(dst_buf, i, 0); | ||
825 | buf_state = VB2_BUF_STATE_DONE; | ||
826 | goto dec_end; | ||
827 | } | ||
828 | |||
829 | if (mtk_jpeg_check_resolution_change(ctx, &jpeg_src_buf->dec_param)) { | ||
830 | mtk_jpeg_queue_src_chg_event(ctx); | ||
831 | ctx->state = MTK_JPEG_SOURCE_CHANGE; | ||
832 | v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx); | ||
833 | return; | ||
834 | } | ||
835 | |||
836 | mtk_jpeg_set_dec_src(ctx, src_buf, &bs); | ||
837 | if (mtk_jpeg_set_dec_dst(ctx, &jpeg_src_buf->dec_param, dst_buf, &fb)) | ||
838 | goto dec_end; | ||
839 | |||
840 | spin_lock_irqsave(&jpeg->hw_lock, flags); | ||
841 | mtk_jpeg_dec_reset(jpeg->dec_reg_base); | ||
842 | mtk_jpeg_dec_set_config(jpeg->dec_reg_base, | ||
843 | &jpeg_src_buf->dec_param, &bs, &fb); | ||
844 | |||
845 | mtk_jpeg_dec_start(jpeg->dec_reg_base); | ||
846 | spin_unlock_irqrestore(&jpeg->hw_lock, flags); | ||
847 | return; | ||
848 | |||
849 | dec_end: | ||
850 | v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); | ||
851 | v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); | ||
852 | v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), buf_state); | ||
853 | v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), buf_state); | ||
854 | v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx); | ||
855 | } | ||
856 | |||
857 | static int mtk_jpeg_job_ready(void *priv) | ||
858 | { | ||
859 | struct mtk_jpeg_ctx *ctx = priv; | ||
860 | |||
861 | return (ctx->state == MTK_JPEG_RUNNING) ? 1 : 0; | ||
862 | } | ||
863 | |||
864 | static void mtk_jpeg_job_abort(void *priv) | ||
865 | { | ||
866 | } | ||
867 | |||
868 | static struct v4l2_m2m_ops mtk_jpeg_m2m_ops = { | ||
869 | .device_run = mtk_jpeg_device_run, | ||
870 | .job_ready = mtk_jpeg_job_ready, | ||
871 | .job_abort = mtk_jpeg_job_abort, | ||
872 | }; | ||
873 | |||
874 | static int mtk_jpeg_queue_init(void *priv, struct vb2_queue *src_vq, | ||
875 | struct vb2_queue *dst_vq) | ||
876 | { | ||
877 | struct mtk_jpeg_ctx *ctx = priv; | ||
878 | int ret; | ||
879 | |||
880 | src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | ||
881 | src_vq->io_modes = VB2_DMABUF | VB2_MMAP; | ||
882 | src_vq->drv_priv = ctx; | ||
883 | src_vq->buf_struct_size = sizeof(struct mtk_jpeg_src_buf); | ||
884 | src_vq->ops = &mtk_jpeg_qops; | ||
885 | src_vq->mem_ops = &vb2_dma_contig_memops; | ||
886 | src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; | ||
887 | src_vq->lock = &ctx->jpeg->lock; | ||
888 | src_vq->dev = ctx->jpeg->dev; | ||
889 | ret = vb2_queue_init(src_vq); | ||
890 | if (ret) | ||
891 | return ret; | ||
892 | |||
893 | dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | ||
894 | dst_vq->io_modes = VB2_DMABUF | VB2_MMAP; | ||
895 | dst_vq->drv_priv = ctx; | ||
896 | dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); | ||
897 | dst_vq->ops = &mtk_jpeg_qops; | ||
898 | dst_vq->mem_ops = &vb2_dma_contig_memops; | ||
899 | dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; | ||
900 | dst_vq->lock = &ctx->jpeg->lock; | ||
901 | dst_vq->dev = ctx->jpeg->dev; | ||
902 | ret = vb2_queue_init(dst_vq); | ||
903 | |||
904 | return ret; | ||
905 | } | ||
906 | |||
907 | static void mtk_jpeg_clk_on(struct mtk_jpeg_dev *jpeg) | ||
908 | { | ||
909 | int ret; | ||
910 | |||
911 | ret = mtk_smi_larb_get(jpeg->larb); | ||
912 | if (ret) | ||
913 | dev_err(jpeg->dev, "mtk_smi_larb_get larbvdec fail %d\n", ret); | ||
914 | clk_prepare_enable(jpeg->clk_jdec_smi); | ||
915 | clk_prepare_enable(jpeg->clk_jdec); | ||
916 | } | ||
917 | |||
918 | static void mtk_jpeg_clk_off(struct mtk_jpeg_dev *jpeg) | ||
919 | { | ||
920 | clk_disable_unprepare(jpeg->clk_jdec); | ||
921 | clk_disable_unprepare(jpeg->clk_jdec_smi); | ||
922 | mtk_smi_larb_put(jpeg->larb); | ||
923 | } | ||
924 | |||
925 | static irqreturn_t mtk_jpeg_dec_irq(int irq, void *priv) | ||
926 | { | ||
927 | struct mtk_jpeg_dev *jpeg = priv; | ||
928 | struct mtk_jpeg_ctx *ctx; | ||
929 | struct vb2_buffer *src_buf, *dst_buf; | ||
930 | struct mtk_jpeg_src_buf *jpeg_src_buf; | ||
931 | enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR; | ||
932 | u32 dec_irq_ret; | ||
933 | u32 dec_ret; | ||
934 | int i; | ||
935 | |||
936 | dec_ret = mtk_jpeg_dec_get_int_status(jpeg->dec_reg_base); | ||
937 | dec_irq_ret = mtk_jpeg_dec_enum_result(dec_ret); | ||
938 | ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev); | ||
939 | if (!ctx) { | ||
940 | v4l2_err(&jpeg->v4l2_dev, "Context is NULL\n"); | ||
941 | return IRQ_HANDLED; | ||
942 | } | ||
943 | |||
944 | src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); | ||
945 | dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); | ||
946 | jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(src_buf); | ||
947 | |||
948 | if (dec_irq_ret >= MTK_JPEG_DEC_RESULT_UNDERFLOW) | ||
949 | mtk_jpeg_dec_reset(jpeg->dec_reg_base); | ||
950 | |||
951 | if (dec_irq_ret != MTK_JPEG_DEC_RESULT_EOF_DONE) { | ||
952 | dev_err(jpeg->dev, "decode failed\n"); | ||
953 | goto dec_end; | ||
954 | } | ||
955 | |||
956 | for (i = 0; i < dst_buf->num_planes; i++) | ||
957 | vb2_set_plane_payload(dst_buf, i, | ||
958 | jpeg_src_buf->dec_param.comp_size[i]); | ||
959 | |||
960 | buf_state = VB2_BUF_STATE_DONE; | ||
961 | |||
962 | dec_end: | ||
963 | v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), buf_state); | ||
964 | v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), buf_state); | ||
965 | v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx); | ||
966 | return IRQ_HANDLED; | ||
967 | } | ||
968 | |||
969 | static void mtk_jpeg_set_default_params(struct mtk_jpeg_ctx *ctx) | ||
970 | { | ||
971 | struct mtk_jpeg_q_data *q = &ctx->out_q; | ||
972 | int i; | ||
973 | |||
974 | ctx->colorspace = V4L2_COLORSPACE_JPEG, | ||
975 | ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; | ||
976 | ctx->quantization = V4L2_QUANTIZATION_DEFAULT; | ||
977 | ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT; | ||
978 | |||
979 | q->fmt = mtk_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG, | ||
980 | MTK_JPEG_FMT_TYPE_OUTPUT); | ||
981 | q->w = MTK_JPEG_MIN_WIDTH; | ||
982 | q->h = MTK_JPEG_MIN_HEIGHT; | ||
983 | q->bytesperline[0] = 0; | ||
984 | q->sizeimage[0] = MTK_JPEG_DEFAULT_SIZEIMAGE; | ||
985 | |||
986 | q = &ctx->cap_q; | ||
987 | q->fmt = mtk_jpeg_find_format(ctx, V4L2_PIX_FMT_YUV420M, | ||
988 | MTK_JPEG_FMT_TYPE_CAPTURE); | ||
989 | q->w = MTK_JPEG_MIN_WIDTH; | ||
990 | q->h = MTK_JPEG_MIN_HEIGHT; | ||
991 | |||
992 | for (i = 0; i < q->fmt->colplanes; i++) { | ||
993 | u32 stride = q->w * q->fmt->h_sample[i] / 4; | ||
994 | u32 h = q->h * q->fmt->v_sample[i] / 4; | ||
995 | |||
996 | q->bytesperline[i] = stride; | ||
997 | q->sizeimage[i] = stride * h; | ||
998 | } | ||
999 | } | ||
1000 | |||
1001 | static int mtk_jpeg_open(struct file *file) | ||
1002 | { | ||
1003 | struct mtk_jpeg_dev *jpeg = video_drvdata(file); | ||
1004 | struct video_device *vfd = video_devdata(file); | ||
1005 | struct mtk_jpeg_ctx *ctx; | ||
1006 | int ret = 0; | ||
1007 | |||
1008 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); | ||
1009 | if (!ctx) | ||
1010 | return -ENOMEM; | ||
1011 | |||
1012 | if (mutex_lock_interruptible(&jpeg->lock)) { | ||
1013 | ret = -ERESTARTSYS; | ||
1014 | goto free; | ||
1015 | } | ||
1016 | |||
1017 | v4l2_fh_init(&ctx->fh, vfd); | ||
1018 | file->private_data = &ctx->fh; | ||
1019 | v4l2_fh_add(&ctx->fh); | ||
1020 | |||
1021 | ctx->jpeg = jpeg; | ||
1022 | ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, | ||
1023 | mtk_jpeg_queue_init); | ||
1024 | if (IS_ERR(ctx->fh.m2m_ctx)) { | ||
1025 | ret = PTR_ERR(ctx->fh.m2m_ctx); | ||
1026 | goto error; | ||
1027 | } | ||
1028 | |||
1029 | mtk_jpeg_set_default_params(ctx); | ||
1030 | mutex_unlock(&jpeg->lock); | ||
1031 | return 0; | ||
1032 | |||
1033 | error: | ||
1034 | v4l2_fh_del(&ctx->fh); | ||
1035 | v4l2_fh_exit(&ctx->fh); | ||
1036 | mutex_unlock(&jpeg->lock); | ||
1037 | free: | ||
1038 | kfree(ctx); | ||
1039 | return ret; | ||
1040 | } | ||
1041 | |||
1042 | static int mtk_jpeg_release(struct file *file) | ||
1043 | { | ||
1044 | struct mtk_jpeg_dev *jpeg = video_drvdata(file); | ||
1045 | struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(file->private_data); | ||
1046 | |||
1047 | mutex_lock(&jpeg->lock); | ||
1048 | v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); | ||
1049 | v4l2_fh_del(&ctx->fh); | ||
1050 | v4l2_fh_exit(&ctx->fh); | ||
1051 | kfree(ctx); | ||
1052 | mutex_unlock(&jpeg->lock); | ||
1053 | return 0; | ||
1054 | } | ||
1055 | |||
1056 | static const struct v4l2_file_operations mtk_jpeg_fops = { | ||
1057 | .owner = THIS_MODULE, | ||
1058 | .open = mtk_jpeg_open, | ||
1059 | .release = mtk_jpeg_release, | ||
1060 | .poll = v4l2_m2m_fop_poll, | ||
1061 | .unlocked_ioctl = video_ioctl2, | ||
1062 | .mmap = v4l2_m2m_fop_mmap, | ||
1063 | }; | ||
1064 | |||
1065 | static int mtk_jpeg_clk_init(struct mtk_jpeg_dev *jpeg) | ||
1066 | { | ||
1067 | struct device_node *node; | ||
1068 | struct platform_device *pdev; | ||
1069 | |||
1070 | node = of_parse_phandle(jpeg->dev->of_node, "mediatek,larb", 0); | ||
1071 | if (!node) | ||
1072 | return -EINVAL; | ||
1073 | pdev = of_find_device_by_node(node); | ||
1074 | if (WARN_ON(!pdev)) { | ||
1075 | of_node_put(node); | ||
1076 | return -EINVAL; | ||
1077 | } | ||
1078 | of_node_put(node); | ||
1079 | |||
1080 | jpeg->larb = &pdev->dev; | ||
1081 | |||
1082 | jpeg->clk_jdec = devm_clk_get(jpeg->dev, "jpgdec"); | ||
1083 | if (IS_ERR(jpeg->clk_jdec)) | ||
1084 | return -EINVAL; | ||
1085 | |||
1086 | jpeg->clk_jdec_smi = devm_clk_get(jpeg->dev, "jpgdec-smi"); | ||
1087 | if (IS_ERR(jpeg->clk_jdec_smi)) | ||
1088 | return -EINVAL; | ||
1089 | |||
1090 | return 0; | ||
1091 | } | ||
1092 | |||
1093 | static int mtk_jpeg_probe(struct platform_device *pdev) | ||
1094 | { | ||
1095 | struct mtk_jpeg_dev *jpeg; | ||
1096 | struct resource *res; | ||
1097 | int dec_irq; | ||
1098 | int ret; | ||
1099 | |||
1100 | jpeg = devm_kzalloc(&pdev->dev, sizeof(*jpeg), GFP_KERNEL); | ||
1101 | if (!jpeg) | ||
1102 | return -ENOMEM; | ||
1103 | |||
1104 | mutex_init(&jpeg->lock); | ||
1105 | spin_lock_init(&jpeg->hw_lock); | ||
1106 | jpeg->dev = &pdev->dev; | ||
1107 | |||
1108 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1109 | jpeg->dec_reg_base = devm_ioremap_resource(&pdev->dev, res); | ||
1110 | if (IS_ERR(jpeg->dec_reg_base)) { | ||
1111 | ret = PTR_ERR(jpeg->dec_reg_base); | ||
1112 | return ret; | ||
1113 | } | ||
1114 | |||
1115 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
1116 | dec_irq = platform_get_irq(pdev, 0); | ||
1117 | if (!res || dec_irq < 0) { | ||
1118 | dev_err(&pdev->dev, "Failed to get dec_irq %d.\n", dec_irq); | ||
1119 | ret = -EINVAL; | ||
1120 | return ret; | ||
1121 | } | ||
1122 | |||
1123 | ret = devm_request_irq(&pdev->dev, dec_irq, mtk_jpeg_dec_irq, 0, | ||
1124 | pdev->name, jpeg); | ||
1125 | if (ret) { | ||
1126 | dev_err(&pdev->dev, "Failed to request dec_irq %d (%d)\n", | ||
1127 | dec_irq, ret); | ||
1128 | ret = -EINVAL; | ||
1129 | goto err_req_irq; | ||
1130 | } | ||
1131 | |||
1132 | ret = mtk_jpeg_clk_init(jpeg); | ||
1133 | if (ret) { | ||
1134 | dev_err(&pdev->dev, "Failed to init clk, err %d\n", ret); | ||
1135 | goto err_clk_init; | ||
1136 | } | ||
1137 | |||
1138 | ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev); | ||
1139 | if (ret) { | ||
1140 | dev_err(&pdev->dev, "Failed to register v4l2 device\n"); | ||
1141 | ret = -EINVAL; | ||
1142 | goto err_dev_register; | ||
1143 | } | ||
1144 | |||
1145 | jpeg->m2m_dev = v4l2_m2m_init(&mtk_jpeg_m2m_ops); | ||
1146 | if (IS_ERR(jpeg->m2m_dev)) { | ||
1147 | v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n"); | ||
1148 | ret = PTR_ERR(jpeg->m2m_dev); | ||
1149 | goto err_m2m_init; | ||
1150 | } | ||
1151 | |||
1152 | jpeg->dec_vdev = video_device_alloc(); | ||
1153 | if (!jpeg->dec_vdev) { | ||
1154 | ret = -ENOMEM; | ||
1155 | goto err_dec_vdev_alloc; | ||
1156 | } | ||
1157 | snprintf(jpeg->dec_vdev->name, sizeof(jpeg->dec_vdev->name), | ||
1158 | "%s-dec", MTK_JPEG_NAME); | ||
1159 | jpeg->dec_vdev->fops = &mtk_jpeg_fops; | ||
1160 | jpeg->dec_vdev->ioctl_ops = &mtk_jpeg_ioctl_ops; | ||
1161 | jpeg->dec_vdev->minor = -1; | ||
1162 | jpeg->dec_vdev->release = video_device_release; | ||
1163 | jpeg->dec_vdev->lock = &jpeg->lock; | ||
1164 | jpeg->dec_vdev->v4l2_dev = &jpeg->v4l2_dev; | ||
1165 | jpeg->dec_vdev->vfl_dir = VFL_DIR_M2M; | ||
1166 | jpeg->dec_vdev->device_caps = V4L2_CAP_STREAMING | | ||
1167 | V4L2_CAP_VIDEO_M2M_MPLANE; | ||
1168 | |||
1169 | ret = video_register_device(jpeg->dec_vdev, VFL_TYPE_GRABBER, 3); | ||
1170 | if (ret) { | ||
1171 | v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n"); | ||
1172 | goto err_dec_vdev_register; | ||
1173 | } | ||
1174 | |||
1175 | video_set_drvdata(jpeg->dec_vdev, jpeg); | ||
1176 | v4l2_info(&jpeg->v4l2_dev, | ||
1177 | "decoder device registered as /dev/video%d (%d,%d)\n", | ||
1178 | jpeg->dec_vdev->num, VIDEO_MAJOR, jpeg->dec_vdev->minor); | ||
1179 | |||
1180 | platform_set_drvdata(pdev, jpeg); | ||
1181 | |||
1182 | pm_runtime_enable(&pdev->dev); | ||
1183 | |||
1184 | return 0; | ||
1185 | |||
1186 | err_dec_vdev_register: | ||
1187 | video_device_release(jpeg->dec_vdev); | ||
1188 | |||
1189 | err_dec_vdev_alloc: | ||
1190 | v4l2_m2m_release(jpeg->m2m_dev); | ||
1191 | |||
1192 | err_m2m_init: | ||
1193 | v4l2_device_unregister(&jpeg->v4l2_dev); | ||
1194 | |||
1195 | err_dev_register: | ||
1196 | |||
1197 | err_clk_init: | ||
1198 | |||
1199 | err_req_irq: | ||
1200 | |||
1201 | return ret; | ||
1202 | } | ||
1203 | |||
1204 | static int mtk_jpeg_remove(struct platform_device *pdev) | ||
1205 | { | ||
1206 | struct mtk_jpeg_dev *jpeg = platform_get_drvdata(pdev); | ||
1207 | |||
1208 | pm_runtime_disable(&pdev->dev); | ||
1209 | video_unregister_device(jpeg->dec_vdev); | ||
1210 | video_device_release(jpeg->dec_vdev); | ||
1211 | v4l2_m2m_release(jpeg->m2m_dev); | ||
1212 | v4l2_device_unregister(&jpeg->v4l2_dev); | ||
1213 | |||
1214 | return 0; | ||
1215 | } | ||
1216 | |||
1217 | static __maybe_unused int mtk_jpeg_pm_suspend(struct device *dev) | ||
1218 | { | ||
1219 | struct mtk_jpeg_dev *jpeg = dev_get_drvdata(dev); | ||
1220 | |||
1221 | mtk_jpeg_dec_reset(jpeg->dec_reg_base); | ||
1222 | mtk_jpeg_clk_off(jpeg); | ||
1223 | |||
1224 | return 0; | ||
1225 | } | ||
1226 | |||
1227 | static __maybe_unused int mtk_jpeg_pm_resume(struct device *dev) | ||
1228 | { | ||
1229 | struct mtk_jpeg_dev *jpeg = dev_get_drvdata(dev); | ||
1230 | |||
1231 | mtk_jpeg_clk_on(jpeg); | ||
1232 | mtk_jpeg_dec_reset(jpeg->dec_reg_base); | ||
1233 | |||
1234 | return 0; | ||
1235 | } | ||
1236 | |||
1237 | static __maybe_unused int mtk_jpeg_suspend(struct device *dev) | ||
1238 | { | ||
1239 | int ret; | ||
1240 | |||
1241 | if (pm_runtime_suspended(dev)) | ||
1242 | return 0; | ||
1243 | |||
1244 | ret = mtk_jpeg_pm_suspend(dev); | ||
1245 | return ret; | ||
1246 | } | ||
1247 | |||
1248 | static __maybe_unused int mtk_jpeg_resume(struct device *dev) | ||
1249 | { | ||
1250 | int ret; | ||
1251 | |||
1252 | if (pm_runtime_suspended(dev)) | ||
1253 | return 0; | ||
1254 | |||
1255 | ret = mtk_jpeg_pm_resume(dev); | ||
1256 | |||
1257 | return ret; | ||
1258 | } | ||
1259 | |||
1260 | static const struct dev_pm_ops mtk_jpeg_pm_ops = { | ||
1261 | SET_SYSTEM_SLEEP_PM_OPS(mtk_jpeg_suspend, mtk_jpeg_resume) | ||
1262 | SET_RUNTIME_PM_OPS(mtk_jpeg_pm_suspend, mtk_jpeg_pm_resume, NULL) | ||
1263 | }; | ||
1264 | |||
1265 | static const struct of_device_id mtk_jpeg_match[] = { | ||
1266 | { | ||
1267 | .compatible = "mediatek,mt8173-jpgdec", | ||
1268 | .data = NULL, | ||
1269 | }, | ||
1270 | { | ||
1271 | .compatible = "mediatek,mt2701-jpgdec", | ||
1272 | .data = NULL, | ||
1273 | }, | ||
1274 | {}, | ||
1275 | }; | ||
1276 | |||
1277 | MODULE_DEVICE_TABLE(of, mtk_jpeg_match); | ||
1278 | |||
1279 | static struct platform_driver mtk_jpeg_driver = { | ||
1280 | .probe = mtk_jpeg_probe, | ||
1281 | .remove = mtk_jpeg_remove, | ||
1282 | .driver = { | ||
1283 | .name = MTK_JPEG_NAME, | ||
1284 | .of_match_table = mtk_jpeg_match, | ||
1285 | .pm = &mtk_jpeg_pm_ops, | ||
1286 | }, | ||
1287 | }; | ||
1288 | |||
1289 | module_platform_driver(mtk_jpeg_driver); | ||
1290 | |||
1291 | MODULE_DESCRIPTION("MediaTek JPEG codec driver"); | ||
1292 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h new file mode 100644 index 000000000000..1a6cdfd4ea70 --- /dev/null +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h | |||
@@ -0,0 +1,139 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2016 MediaTek Inc. | ||
3 | * Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com> | ||
4 | * Rick Chang <rick.chang@mediatek.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | #ifndef _MTK_JPEG_CORE_H | ||
17 | #define _MTK_JPEG_CORE_H | ||
18 | |||
19 | #include <linux/interrupt.h> | ||
20 | #include <media/v4l2-ctrls.h> | ||
21 | #include <media/v4l2-device.h> | ||
22 | #include <media/v4l2-fh.h> | ||
23 | |||
24 | #define MTK_JPEG_NAME "mtk-jpeg" | ||
25 | |||
26 | #define MTK_JPEG_FMT_FLAG_DEC_OUTPUT BIT(0) | ||
27 | #define MTK_JPEG_FMT_FLAG_DEC_CAPTURE BIT(1) | ||
28 | |||
29 | #define MTK_JPEG_FMT_TYPE_OUTPUT 1 | ||
30 | #define MTK_JPEG_FMT_TYPE_CAPTURE 2 | ||
31 | |||
32 | #define MTK_JPEG_MIN_WIDTH 32 | ||
33 | #define MTK_JPEG_MIN_HEIGHT 32 | ||
34 | #define MTK_JPEG_MAX_WIDTH 8192 | ||
35 | #define MTK_JPEG_MAX_HEIGHT 8192 | ||
36 | |||
37 | #define MTK_JPEG_DEFAULT_SIZEIMAGE (1 * 1024 * 1024) | ||
38 | |||
39 | enum mtk_jpeg_ctx_state { | ||
40 | MTK_JPEG_INIT = 0, | ||
41 | MTK_JPEG_RUNNING, | ||
42 | MTK_JPEG_SOURCE_CHANGE, | ||
43 | }; | ||
44 | |||
45 | /** | ||
46 | * struct mt_jpeg - JPEG IP abstraction | ||
47 | * @lock: the mutex protecting this structure | ||
48 | * @hw_lock: spinlock protecting the hw device resource | ||
49 | * @workqueue: decode work queue | ||
50 | * @dev: JPEG device | ||
51 | * @v4l2_dev: v4l2 device for mem2mem mode | ||
52 | * @m2m_dev: v4l2 mem2mem device data | ||
53 | * @alloc_ctx: videobuf2 memory allocator's context | ||
54 | * @dec_vdev: video device node for decoder mem2mem mode | ||
55 | * @dec_reg_base: JPEG registers mapping | ||
56 | * @clk_jdec: JPEG hw working clock | ||
57 | * @clk_jdec_smi: JPEG SMI bus clock | ||
58 | * @larb: SMI device | ||
59 | */ | ||
60 | struct mtk_jpeg_dev { | ||
61 | struct mutex lock; | ||
62 | spinlock_t hw_lock; | ||
63 | struct workqueue_struct *workqueue; | ||
64 | struct device *dev; | ||
65 | struct v4l2_device v4l2_dev; | ||
66 | struct v4l2_m2m_dev *m2m_dev; | ||
67 | void *alloc_ctx; | ||
68 | struct video_device *dec_vdev; | ||
69 | void __iomem *dec_reg_base; | ||
70 | struct clk *clk_jdec; | ||
71 | struct clk *clk_jdec_smi; | ||
72 | struct device *larb; | ||
73 | }; | ||
74 | |||
75 | /** | ||
76 | * struct jpeg_fmt - driver's internal color format data | ||
77 | * @fourcc: the fourcc code, 0 if not applicable | ||
78 | * @h_sample: horizontal sample count of plane in 4 * 4 pixel image | ||
79 | * @v_sample: vertical sample count of plane in 4 * 4 pixel image | ||
80 | * @colplanes: number of color planes (1 for packed formats) | ||
81 | * @h_align: horizontal alignment order (align to 2^h_align) | ||
82 | * @v_align: vertical alignment order (align to 2^v_align) | ||
83 | * @flags: flags describing format applicability | ||
84 | */ | ||
85 | struct mtk_jpeg_fmt { | ||
86 | u32 fourcc; | ||
87 | int h_sample[VIDEO_MAX_PLANES]; | ||
88 | int v_sample[VIDEO_MAX_PLANES]; | ||
89 | int colplanes; | ||
90 | int h_align; | ||
91 | int v_align; | ||
92 | u32 flags; | ||
93 | }; | ||
94 | |||
95 | /** | ||
96 | * mtk_jpeg_q_data - parameters of one queue | ||
97 | * @fmt: driver-specific format of this queue | ||
98 | * @w: image width | ||
99 | * @h: image height | ||
100 | * @bytesperline: distance in bytes between the leftmost pixels in two adjacent | ||
101 | * lines | ||
102 | * @sizeimage: image buffer size in bytes | ||
103 | */ | ||
104 | struct mtk_jpeg_q_data { | ||
105 | struct mtk_jpeg_fmt *fmt; | ||
106 | u32 w; | ||
107 | u32 h; | ||
108 | u32 bytesperline[VIDEO_MAX_PLANES]; | ||
109 | u32 sizeimage[VIDEO_MAX_PLANES]; | ||
110 | }; | ||
111 | |||
112 | /** | ||
113 | * mtk_jpeg_ctx - the device context data | ||
114 | * @jpeg: JPEG IP device for this context | ||
115 | * @out_q: source (output) queue information | ||
116 | * @cap_q: destination (capture) queue queue information | ||
117 | * @fh: V4L2 file handle | ||
118 | * @dec_param parameters for HW decoding | ||
119 | * @state: state of the context | ||
120 | * @header_valid: set if header has been parsed and valid | ||
121 | * @colorspace: enum v4l2_colorspace; supplemental to pixelformat | ||
122 | * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding | ||
123 | * @quantization: enum v4l2_quantization, colorspace quantization | ||
124 | * @xfer_func: enum v4l2_xfer_func, colorspace transfer function | ||
125 | */ | ||
126 | struct mtk_jpeg_ctx { | ||
127 | struct mtk_jpeg_dev *jpeg; | ||
128 | struct mtk_jpeg_q_data out_q; | ||
129 | struct mtk_jpeg_q_data cap_q; | ||
130 | struct v4l2_fh fh; | ||
131 | enum mtk_jpeg_ctx_state state; | ||
132 | |||
133 | enum v4l2_colorspace colorspace; | ||
134 | enum v4l2_ycbcr_encoding ycbcr_enc; | ||
135 | enum v4l2_quantization quantization; | ||
136 | enum v4l2_xfer_func xfer_func; | ||
137 | }; | ||
138 | |||
139 | #endif /* _MTK_JPEG_CORE_H */ | ||
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.c new file mode 100644 index 000000000000..77b4cc6a8873 --- /dev/null +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.c | |||
@@ -0,0 +1,417 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2016 MediaTek Inc. | ||
3 | * Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com> | ||
4 | * Rick Chang <rick.chang@mediatek.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | #include <linux/io.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <media/videobuf2-core.h> | ||
19 | |||
20 | #include "mtk_jpeg_hw.h" | ||
21 | |||
22 | #define MTK_JPEG_DUNUM_MASK(val) (((val) - 1) & 0x3) | ||
23 | |||
24 | enum mtk_jpeg_color { | ||
25 | MTK_JPEG_COLOR_420 = 0x00221111, | ||
26 | MTK_JPEG_COLOR_422 = 0x00211111, | ||
27 | MTK_JPEG_COLOR_444 = 0x00111111, | ||
28 | MTK_JPEG_COLOR_422V = 0x00121111, | ||
29 | MTK_JPEG_COLOR_422X2 = 0x00412121, | ||
30 | MTK_JPEG_COLOR_422VX2 = 0x00222121, | ||
31 | MTK_JPEG_COLOR_400 = 0x00110000 | ||
32 | }; | ||
33 | |||
34 | static inline int mtk_jpeg_verify_align(u32 val, int align, u32 reg) | ||
35 | { | ||
36 | if (val & (align - 1)) { | ||
37 | pr_err("mtk-jpeg: write reg %x without %d align\n", reg, align); | ||
38 | return -1; | ||
39 | } | ||
40 | |||
41 | return 0; | ||
42 | } | ||
43 | |||
44 | static int mtk_jpeg_decide_format(struct mtk_jpeg_dec_param *param) | ||
45 | { | ||
46 | param->src_color = (param->sampling_w[0] << 20) | | ||
47 | (param->sampling_h[0] << 16) | | ||
48 | (param->sampling_w[1] << 12) | | ||
49 | (param->sampling_h[1] << 8) | | ||
50 | (param->sampling_w[2] << 4) | | ||
51 | (param->sampling_h[2]); | ||
52 | |||
53 | param->uv_brz_w = 0; | ||
54 | switch (param->src_color) { | ||
55 | case MTK_JPEG_COLOR_444: | ||
56 | param->uv_brz_w = 1; | ||
57 | param->dst_fourcc = V4L2_PIX_FMT_YUV422M; | ||
58 | break; | ||
59 | case MTK_JPEG_COLOR_422X2: | ||
60 | case MTK_JPEG_COLOR_422: | ||
61 | param->dst_fourcc = V4L2_PIX_FMT_YUV422M; | ||
62 | break; | ||
63 | case MTK_JPEG_COLOR_422V: | ||
64 | case MTK_JPEG_COLOR_422VX2: | ||
65 | param->uv_brz_w = 1; | ||
66 | param->dst_fourcc = V4L2_PIX_FMT_YUV420M; | ||
67 | break; | ||
68 | case MTK_JPEG_COLOR_420: | ||
69 | param->dst_fourcc = V4L2_PIX_FMT_YUV420M; | ||
70 | break; | ||
71 | case MTK_JPEG_COLOR_400: | ||
72 | param->dst_fourcc = V4L2_PIX_FMT_GREY; | ||
73 | break; | ||
74 | default: | ||
75 | param->dst_fourcc = 0; | ||
76 | return -1; | ||
77 | } | ||
78 | |||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static void mtk_jpeg_calc_mcu(struct mtk_jpeg_dec_param *param) | ||
83 | { | ||
84 | u32 factor_w, factor_h; | ||
85 | u32 i, comp, blk; | ||
86 | |||
87 | factor_w = 2 + param->sampling_w[0]; | ||
88 | factor_h = 2 + param->sampling_h[0]; | ||
89 | param->mcu_w = (param->pic_w + (1 << factor_w) - 1) >> factor_w; | ||
90 | param->mcu_h = (param->pic_h + (1 << factor_h) - 1) >> factor_h; | ||
91 | param->total_mcu = param->mcu_w * param->mcu_h; | ||
92 | param->unit_num = ((param->pic_w + 7) >> 3) * ((param->pic_h + 7) >> 3); | ||
93 | param->blk_num = 0; | ||
94 | for (i = 0; i < MTK_JPEG_COMP_MAX; i++) { | ||
95 | param->blk_comp[i] = 0; | ||
96 | if (i >= param->comp_num) | ||
97 | continue; | ||
98 | param->blk_comp[i] = param->sampling_w[i] * | ||
99 | param->sampling_h[i]; | ||
100 | param->blk_num += param->blk_comp[i]; | ||
101 | } | ||
102 | |||
103 | param->membership = 0; | ||
104 | for (i = 0, blk = 0, comp = 0; i < MTK_JPEG_BLOCK_MAX; i++) { | ||
105 | if (i < param->blk_num && comp < param->comp_num) { | ||
106 | u32 tmp; | ||
107 | |||
108 | tmp = (0x04 + (comp & 0x3)); | ||
109 | param->membership |= tmp << (i * 3); | ||
110 | if (++blk == param->blk_comp[comp]) { | ||
111 | comp++; | ||
112 | blk = 0; | ||
113 | } | ||
114 | } else { | ||
115 | param->membership |= 7 << (i * 3); | ||
116 | } | ||
117 | } | ||
118 | } | ||
119 | |||
120 | static void mtk_jpeg_calc_dma_group(struct mtk_jpeg_dec_param *param) | ||
121 | { | ||
122 | u32 factor_mcu = 3; | ||
123 | |||
124 | if (param->src_color == MTK_JPEG_COLOR_444 && | ||
125 | param->dst_fourcc == V4L2_PIX_FMT_YUV422M) | ||
126 | factor_mcu = 4; | ||
127 | else if (param->src_color == MTK_JPEG_COLOR_422V && | ||
128 | param->dst_fourcc == V4L2_PIX_FMT_YUV420M) | ||
129 | factor_mcu = 4; | ||
130 | else if (param->src_color == MTK_JPEG_COLOR_422X2 && | ||
131 | param->dst_fourcc == V4L2_PIX_FMT_YUV422M) | ||
132 | factor_mcu = 2; | ||
133 | else if (param->src_color == MTK_JPEG_COLOR_400 || | ||
134 | (param->src_color & 0x0FFFF) == 0) | ||
135 | factor_mcu = 4; | ||
136 | |||
137 | param->dma_mcu = 1 << factor_mcu; | ||
138 | param->dma_group = param->mcu_w / param->dma_mcu; | ||
139 | param->dma_last_mcu = param->mcu_w % param->dma_mcu; | ||
140 | if (param->dma_last_mcu) | ||
141 | param->dma_group++; | ||
142 | else | ||
143 | param->dma_last_mcu = param->dma_mcu; | ||
144 | } | ||
145 | |||
146 | static int mtk_jpeg_calc_dst_size(struct mtk_jpeg_dec_param *param) | ||
147 | { | ||
148 | u32 i, padding_w; | ||
149 | u32 ds_row_h[3]; | ||
150 | u32 brz_w[3]; | ||
151 | |||
152 | brz_w[0] = 0; | ||
153 | brz_w[1] = param->uv_brz_w; | ||
154 | brz_w[2] = brz_w[1]; | ||
155 | |||
156 | for (i = 0; i < param->comp_num; i++) { | ||
157 | if (brz_w[i] > 3) | ||
158 | return -1; | ||
159 | |||
160 | padding_w = param->mcu_w * MTK_JPEG_DCTSIZE * | ||
161 | param->sampling_w[i]; | ||
162 | /* output format is 420/422 */ | ||
163 | param->comp_w[i] = padding_w >> brz_w[i]; | ||
164 | param->comp_w[i] = mtk_jpeg_align(param->comp_w[i], | ||
165 | MTK_JPEG_DCTSIZE); | ||
166 | param->img_stride[i] = i ? mtk_jpeg_align(param->comp_w[i], 16) | ||
167 | : mtk_jpeg_align(param->comp_w[i], 32); | ||
168 | ds_row_h[i] = (MTK_JPEG_DCTSIZE * param->sampling_h[i]); | ||
169 | } | ||
170 | param->dec_w = param->img_stride[0]; | ||
171 | param->dec_h = ds_row_h[0] * param->mcu_h; | ||
172 | |||
173 | for (i = 0; i < MTK_JPEG_COMP_MAX; i++) { | ||
174 | /* They must be equal in frame mode. */ | ||
175 | param->mem_stride[i] = param->img_stride[i]; | ||
176 | param->comp_size[i] = param->mem_stride[i] * ds_row_h[i] * | ||
177 | param->mcu_h; | ||
178 | } | ||
179 | |||
180 | param->y_size = param->comp_size[0]; | ||
181 | param->uv_size = param->comp_size[1]; | ||
182 | param->dec_size = param->y_size + (param->uv_size << 1); | ||
183 | |||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | int mtk_jpeg_dec_fill_param(struct mtk_jpeg_dec_param *param) | ||
188 | { | ||
189 | if (mtk_jpeg_decide_format(param)) | ||
190 | return -1; | ||
191 | |||
192 | mtk_jpeg_calc_mcu(param); | ||
193 | mtk_jpeg_calc_dma_group(param); | ||
194 | if (mtk_jpeg_calc_dst_size(param)) | ||
195 | return -2; | ||
196 | |||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | u32 mtk_jpeg_dec_get_int_status(void __iomem *base) | ||
201 | { | ||
202 | u32 ret; | ||
203 | |||
204 | ret = readl(base + JPGDEC_REG_INTERRUPT_STATUS) & BIT_INQST_MASK_ALLIRQ; | ||
205 | if (ret) | ||
206 | writel(ret, base + JPGDEC_REG_INTERRUPT_STATUS); | ||
207 | |||
208 | return ret; | ||
209 | } | ||
210 | |||
211 | u32 mtk_jpeg_dec_enum_result(u32 irq_result) | ||
212 | { | ||
213 | if (irq_result & BIT_INQST_MASK_EOF) | ||
214 | return MTK_JPEG_DEC_RESULT_EOF_DONE; | ||
215 | if (irq_result & BIT_INQST_MASK_PAUSE) | ||
216 | return MTK_JPEG_DEC_RESULT_PAUSE; | ||
217 | if (irq_result & BIT_INQST_MASK_UNDERFLOW) | ||
218 | return MTK_JPEG_DEC_RESULT_UNDERFLOW; | ||
219 | if (irq_result & BIT_INQST_MASK_OVERFLOW) | ||
220 | return MTK_JPEG_DEC_RESULT_OVERFLOW; | ||
221 | if (irq_result & BIT_INQST_MASK_ERROR_BS) | ||
222 | return MTK_JPEG_DEC_RESULT_ERROR_BS; | ||
223 | |||
224 | return MTK_JPEG_DEC_RESULT_ERROR_UNKNOWN; | ||
225 | } | ||
226 | |||
227 | void mtk_jpeg_dec_start(void __iomem *base) | ||
228 | { | ||
229 | writel(0, base + JPGDEC_REG_TRIG); | ||
230 | } | ||
231 | |||
232 | static void mtk_jpeg_dec_soft_reset(void __iomem *base) | ||
233 | { | ||
234 | writel(0x0000FFFF, base + JPGDEC_REG_INTERRUPT_STATUS); | ||
235 | writel(0x00, base + JPGDEC_REG_RESET); | ||
236 | writel(0x01, base + JPGDEC_REG_RESET); | ||
237 | } | ||
238 | |||
239 | static void mtk_jpeg_dec_hard_reset(void __iomem *base) | ||
240 | { | ||
241 | writel(0x00, base + JPGDEC_REG_RESET); | ||
242 | writel(0x10, base + JPGDEC_REG_RESET); | ||
243 | } | ||
244 | |||
245 | void mtk_jpeg_dec_reset(void __iomem *base) | ||
246 | { | ||
247 | mtk_jpeg_dec_soft_reset(base); | ||
248 | mtk_jpeg_dec_hard_reset(base); | ||
249 | } | ||
250 | |||
251 | static void mtk_jpeg_dec_set_brz_factor(void __iomem *base, u8 yscale_w, | ||
252 | u8 yscale_h, u8 uvscale_w, u8 uvscale_h) | ||
253 | { | ||
254 | u32 val; | ||
255 | |||
256 | val = (uvscale_h << 12) | (uvscale_w << 8) | | ||
257 | (yscale_h << 4) | yscale_w; | ||
258 | writel(val, base + JPGDEC_REG_BRZ_FACTOR); | ||
259 | } | ||
260 | |||
261 | static void mtk_jpeg_dec_set_dst_bank0(void __iomem *base, u32 addr_y, | ||
262 | u32 addr_u, u32 addr_v) | ||
263 | { | ||
264 | mtk_jpeg_verify_align(addr_y, 16, JPGDEC_REG_DEST_ADDR0_Y); | ||
265 | writel(addr_y, base + JPGDEC_REG_DEST_ADDR0_Y); | ||
266 | mtk_jpeg_verify_align(addr_u, 16, JPGDEC_REG_DEST_ADDR0_U); | ||
267 | writel(addr_u, base + JPGDEC_REG_DEST_ADDR0_U); | ||
268 | mtk_jpeg_verify_align(addr_v, 16, JPGDEC_REG_DEST_ADDR0_V); | ||
269 | writel(addr_v, base + JPGDEC_REG_DEST_ADDR0_V); | ||
270 | } | ||
271 | |||
272 | static void mtk_jpeg_dec_set_dst_bank1(void __iomem *base, u32 addr_y, | ||
273 | u32 addr_u, u32 addr_v) | ||
274 | { | ||
275 | writel(addr_y, base + JPGDEC_REG_DEST_ADDR1_Y); | ||
276 | writel(addr_u, base + JPGDEC_REG_DEST_ADDR1_U); | ||
277 | writel(addr_v, base + JPGDEC_REG_DEST_ADDR1_V); | ||
278 | } | ||
279 | |||
280 | static void mtk_jpeg_dec_set_mem_stride(void __iomem *base, u32 stride_y, | ||
281 | u32 stride_uv) | ||
282 | { | ||
283 | writel((stride_y & 0xFFFF), base + JPGDEC_REG_STRIDE_Y); | ||
284 | writel((stride_uv & 0xFFFF), base + JPGDEC_REG_STRIDE_UV); | ||
285 | } | ||
286 | |||
287 | static void mtk_jpeg_dec_set_img_stride(void __iomem *base, u32 stride_y, | ||
288 | u32 stride_uv) | ||
289 | { | ||
290 | writel((stride_y & 0xFFFF), base + JPGDEC_REG_IMG_STRIDE_Y); | ||
291 | writel((stride_uv & 0xFFFF), base + JPGDEC_REG_IMG_STRIDE_UV); | ||
292 | } | ||
293 | |||
294 | static void mtk_jpeg_dec_set_pause_mcu_idx(void __iomem *base, u32 idx) | ||
295 | { | ||
296 | writel(idx & 0x0003FFFFFF, base + JPGDEC_REG_PAUSE_MCU_NUM); | ||
297 | } | ||
298 | |||
299 | static void mtk_jpeg_dec_set_dec_mode(void __iomem *base, u32 mode) | ||
300 | { | ||
301 | writel(mode & 0x03, base + JPGDEC_REG_OPERATION_MODE); | ||
302 | } | ||
303 | |||
304 | static void mtk_jpeg_dec_set_bs_write_ptr(void __iomem *base, u32 ptr) | ||
305 | { | ||
306 | mtk_jpeg_verify_align(ptr, 16, JPGDEC_REG_FILE_BRP); | ||
307 | writel(ptr, base + JPGDEC_REG_FILE_BRP); | ||
308 | } | ||
309 | |||
310 | static void mtk_jpeg_dec_set_bs_info(void __iomem *base, u32 addr, u32 size) | ||
311 | { | ||
312 | mtk_jpeg_verify_align(addr, 16, JPGDEC_REG_FILE_ADDR); | ||
313 | mtk_jpeg_verify_align(size, 128, JPGDEC_REG_FILE_TOTAL_SIZE); | ||
314 | writel(addr, base + JPGDEC_REG_FILE_ADDR); | ||
315 | writel(size, base + JPGDEC_REG_FILE_TOTAL_SIZE); | ||
316 | } | ||
317 | |||
318 | static void mtk_jpeg_dec_set_comp_id(void __iomem *base, u32 id_y, u32 id_u, | ||
319 | u32 id_v) | ||
320 | { | ||
321 | u32 val; | ||
322 | |||
323 | val = ((id_y & 0x00FF) << 24) | ((id_u & 0x00FF) << 16) | | ||
324 | ((id_v & 0x00FF) << 8); | ||
325 | writel(val, base + JPGDEC_REG_COMP_ID); | ||
326 | } | ||
327 | |||
328 | static void mtk_jpeg_dec_set_total_mcu(void __iomem *base, u32 num) | ||
329 | { | ||
330 | writel(num - 1, base + JPGDEC_REG_TOTAL_MCU_NUM); | ||
331 | } | ||
332 | |||
333 | static void mtk_jpeg_dec_set_comp0_du(void __iomem *base, u32 num) | ||
334 | { | ||
335 | writel(num - 1, base + JPGDEC_REG_COMP0_DATA_UNIT_NUM); | ||
336 | } | ||
337 | |||
338 | static void mtk_jpeg_dec_set_du_membership(void __iomem *base, u32 member, | ||
339 | u32 gmc, u32 isgray) | ||
340 | { | ||
341 | if (isgray) | ||
342 | member = 0x3FFFFFFC; | ||
343 | member |= (isgray << 31) | (gmc << 30); | ||
344 | writel(member, base + JPGDEC_REG_DU_CTRL); | ||
345 | } | ||
346 | |||
347 | static void mtk_jpeg_dec_set_q_table(void __iomem *base, u32 id0, u32 id1, | ||
348 | u32 id2) | ||
349 | { | ||
350 | u32 val; | ||
351 | |||
352 | val = ((id0 & 0x0f) << 8) | ((id1 & 0x0f) << 4) | ((id2 & 0x0f) << 0); | ||
353 | writel(val, base + JPGDEC_REG_QT_ID); | ||
354 | } | ||
355 | |||
356 | static void mtk_jpeg_dec_set_dma_group(void __iomem *base, u32 mcu_group, | ||
357 | u32 group_num, u32 last_mcu) | ||
358 | { | ||
359 | u32 val; | ||
360 | |||
361 | val = (((mcu_group - 1) & 0x00FF) << 16) | | ||
362 | (((group_num - 1) & 0x007F) << 8) | | ||
363 | ((last_mcu - 1) & 0x00FF); | ||
364 | writel(val, base + JPGDEC_REG_WDMA_CTRL); | ||
365 | } | ||
366 | |||
367 | static void mtk_jpeg_dec_set_sampling_factor(void __iomem *base, u32 comp_num, | ||
368 | u32 y_w, u32 y_h, u32 u_w, | ||
369 | u32 u_h, u32 v_w, u32 v_h) | ||
370 | { | ||
371 | u32 val; | ||
372 | u32 y_wh = (MTK_JPEG_DUNUM_MASK(y_w) << 2) | MTK_JPEG_DUNUM_MASK(y_h); | ||
373 | u32 u_wh = (MTK_JPEG_DUNUM_MASK(u_w) << 2) | MTK_JPEG_DUNUM_MASK(u_h); | ||
374 | u32 v_wh = (MTK_JPEG_DUNUM_MASK(v_w) << 2) | MTK_JPEG_DUNUM_MASK(v_h); | ||
375 | |||
376 | if (comp_num == 1) | ||
377 | val = 0; | ||
378 | else | ||
379 | val = (y_wh << 8) | (u_wh << 4) | v_wh; | ||
380 | writel(val, base + JPGDEC_REG_DU_NUM); | ||
381 | } | ||
382 | |||
383 | void mtk_jpeg_dec_set_config(void __iomem *base, | ||
384 | struct mtk_jpeg_dec_param *config, | ||
385 | struct mtk_jpeg_bs *bs, | ||
386 | struct mtk_jpeg_fb *fb) | ||
387 | { | ||
388 | mtk_jpeg_dec_set_brz_factor(base, 0, 0, config->uv_brz_w, 0); | ||
389 | mtk_jpeg_dec_set_dec_mode(base, 0); | ||
390 | mtk_jpeg_dec_set_comp0_du(base, config->unit_num); | ||
391 | mtk_jpeg_dec_set_total_mcu(base, config->total_mcu); | ||
392 | mtk_jpeg_dec_set_bs_info(base, bs->str_addr, bs->size); | ||
393 | mtk_jpeg_dec_set_bs_write_ptr(base, bs->end_addr); | ||
394 | mtk_jpeg_dec_set_du_membership(base, config->membership, 1, | ||
395 | (config->comp_num == 1) ? 1 : 0); | ||
396 | mtk_jpeg_dec_set_comp_id(base, config->comp_id[0], config->comp_id[1], | ||
397 | config->comp_id[2]); | ||
398 | mtk_jpeg_dec_set_q_table(base, config->qtbl_num[0], | ||
399 | config->qtbl_num[1], config->qtbl_num[2]); | ||
400 | mtk_jpeg_dec_set_sampling_factor(base, config->comp_num, | ||
401 | config->sampling_w[0], | ||
402 | config->sampling_h[0], | ||
403 | config->sampling_w[1], | ||
404 | config->sampling_h[1], | ||
405 | config->sampling_w[2], | ||
406 | config->sampling_h[2]); | ||
407 | mtk_jpeg_dec_set_mem_stride(base, config->mem_stride[0], | ||
408 | config->mem_stride[1]); | ||
409 | mtk_jpeg_dec_set_img_stride(base, config->img_stride[0], | ||
410 | config->img_stride[1]); | ||
411 | mtk_jpeg_dec_set_dst_bank0(base, fb->plane_addr[0], | ||
412 | fb->plane_addr[1], fb->plane_addr[2]); | ||
413 | mtk_jpeg_dec_set_dst_bank1(base, 0, 0, 0); | ||
414 | mtk_jpeg_dec_set_dma_group(base, config->dma_mcu, config->dma_group, | ||
415 | config->dma_last_mcu); | ||
416 | mtk_jpeg_dec_set_pause_mcu_idx(base, config->total_mcu); | ||
417 | } | ||
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.h b/drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.h new file mode 100644 index 000000000000..37152a630dea --- /dev/null +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.h | |||
@@ -0,0 +1,91 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2016 MediaTek Inc. | ||
3 | * Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com> | ||
4 | * Rick Chang <rick.chang@mediatek.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | #ifndef _MTK_JPEG_HW_H | ||
17 | #define _MTK_JPEG_HW_H | ||
18 | |||
19 | #include <media/videobuf2-core.h> | ||
20 | |||
21 | #include "mtk_jpeg_core.h" | ||
22 | #include "mtk_jpeg_reg.h" | ||
23 | |||
24 | enum { | ||
25 | MTK_JPEG_DEC_RESULT_EOF_DONE = 0, | ||
26 | MTK_JPEG_DEC_RESULT_PAUSE = 1, | ||
27 | MTK_JPEG_DEC_RESULT_UNDERFLOW = 2, | ||
28 | MTK_JPEG_DEC_RESULT_OVERFLOW = 3, | ||
29 | MTK_JPEG_DEC_RESULT_ERROR_BS = 4, | ||
30 | MTK_JPEG_DEC_RESULT_ERROR_UNKNOWN = 6 | ||
31 | }; | ||
32 | |||
33 | struct mtk_jpeg_dec_param { | ||
34 | u32 pic_w; | ||
35 | u32 pic_h; | ||
36 | u32 dec_w; | ||
37 | u32 dec_h; | ||
38 | u32 src_color; | ||
39 | u32 dst_fourcc; | ||
40 | u32 mcu_w; | ||
41 | u32 mcu_h; | ||
42 | u32 total_mcu; | ||
43 | u32 unit_num; | ||
44 | u32 comp_num; | ||
45 | u32 comp_id[MTK_JPEG_COMP_MAX]; | ||
46 | u32 sampling_w[MTK_JPEG_COMP_MAX]; | ||
47 | u32 sampling_h[MTK_JPEG_COMP_MAX]; | ||
48 | u32 qtbl_num[MTK_JPEG_COMP_MAX]; | ||
49 | u32 blk_num; | ||
50 | u32 blk_comp[MTK_JPEG_COMP_MAX]; | ||
51 | u32 membership; | ||
52 | u32 dma_mcu; | ||
53 | u32 dma_group; | ||
54 | u32 dma_last_mcu; | ||
55 | u32 img_stride[MTK_JPEG_COMP_MAX]; | ||
56 | u32 mem_stride[MTK_JPEG_COMP_MAX]; | ||
57 | u32 comp_w[MTK_JPEG_COMP_MAX]; | ||
58 | u32 comp_size[MTK_JPEG_COMP_MAX]; | ||
59 | u32 y_size; | ||
60 | u32 uv_size; | ||
61 | u32 dec_size; | ||
62 | u8 uv_brz_w; | ||
63 | }; | ||
64 | |||
65 | static inline u32 mtk_jpeg_align(u32 val, u32 align) | ||
66 | { | ||
67 | return (val + align - 1) & ~(align - 1); | ||
68 | } | ||
69 | |||
70 | struct mtk_jpeg_bs { | ||
71 | dma_addr_t str_addr; | ||
72 | dma_addr_t end_addr; | ||
73 | size_t size; | ||
74 | }; | ||
75 | |||
76 | struct mtk_jpeg_fb { | ||
77 | dma_addr_t plane_addr[MTK_JPEG_COMP_MAX]; | ||
78 | size_t size; | ||
79 | }; | ||
80 | |||
81 | int mtk_jpeg_dec_fill_param(struct mtk_jpeg_dec_param *param); | ||
82 | u32 mtk_jpeg_dec_get_int_status(void __iomem *dec_reg_base); | ||
83 | u32 mtk_jpeg_dec_enum_result(u32 irq_result); | ||
84 | void mtk_jpeg_dec_set_config(void __iomem *base, | ||
85 | struct mtk_jpeg_dec_param *config, | ||
86 | struct mtk_jpeg_bs *bs, | ||
87 | struct mtk_jpeg_fb *fb); | ||
88 | void mtk_jpeg_dec_reset(void __iomem *dec_reg_base); | ||
89 | void mtk_jpeg_dec_start(void __iomem *dec_reg_base); | ||
90 | |||
91 | #endif /* _MTK_JPEG_HW_H */ | ||
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.c new file mode 100644 index 000000000000..38868547f5d4 --- /dev/null +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.c | |||
@@ -0,0 +1,160 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2016 MediaTek Inc. | ||
3 | * Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com> | ||
4 | * Rick Chang <rick.chang@mediatek.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/videodev2.h> | ||
18 | |||
19 | #include "mtk_jpeg_parse.h" | ||
20 | |||
21 | #define TEM 0x01 | ||
22 | #define SOF0 0xc0 | ||
23 | #define RST 0xd0 | ||
24 | #define SOI 0xd8 | ||
25 | #define EOI 0xd9 | ||
26 | |||
27 | struct mtk_jpeg_stream { | ||
28 | u8 *addr; | ||
29 | u32 size; | ||
30 | u32 curr; | ||
31 | }; | ||
32 | |||
33 | static int read_byte(struct mtk_jpeg_stream *stream) | ||
34 | { | ||
35 | if (stream->curr >= stream->size) | ||
36 | return -1; | ||
37 | return stream->addr[stream->curr++]; | ||
38 | } | ||
39 | |||
40 | static int read_word_be(struct mtk_jpeg_stream *stream, u32 *word) | ||
41 | { | ||
42 | u32 temp; | ||
43 | int byte; | ||
44 | |||
45 | byte = read_byte(stream); | ||
46 | if (byte == -1) | ||
47 | return -1; | ||
48 | temp = byte << 8; | ||
49 | byte = read_byte(stream); | ||
50 | if (byte == -1) | ||
51 | return -1; | ||
52 | *word = (u32)byte | temp; | ||
53 | |||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | static void read_skip(struct mtk_jpeg_stream *stream, long len) | ||
58 | { | ||
59 | if (len <= 0) | ||
60 | return; | ||
61 | while (len--) | ||
62 | read_byte(stream); | ||
63 | } | ||
64 | |||
65 | static bool mtk_jpeg_do_parse(struct mtk_jpeg_dec_param *param, u8 *src_addr_va, | ||
66 | u32 src_size) | ||
67 | { | ||
68 | bool notfound = true; | ||
69 | struct mtk_jpeg_stream stream; | ||
70 | |||
71 | stream.addr = src_addr_va; | ||
72 | stream.size = src_size; | ||
73 | stream.curr = 0; | ||
74 | |||
75 | while (notfound) { | ||
76 | int i, length, byte; | ||
77 | u32 word; | ||
78 | |||
79 | byte = read_byte(&stream); | ||
80 | if (byte == -1) | ||
81 | return false; | ||
82 | if (byte != 0xff) | ||
83 | continue; | ||
84 | do | ||
85 | byte = read_byte(&stream); | ||
86 | while (byte == 0xff); | ||
87 | if (byte == -1) | ||
88 | return false; | ||
89 | if (byte == 0) | ||
90 | continue; | ||
91 | |||
92 | length = 0; | ||
93 | switch (byte) { | ||
94 | case SOF0: | ||
95 | /* length */ | ||
96 | if (read_word_be(&stream, &word)) | ||
97 | break; | ||
98 | |||
99 | /* precision */ | ||
100 | if (read_byte(&stream) == -1) | ||
101 | break; | ||
102 | |||
103 | if (read_word_be(&stream, &word)) | ||
104 | break; | ||
105 | param->pic_h = word; | ||
106 | |||
107 | if (read_word_be(&stream, &word)) | ||
108 | break; | ||
109 | param->pic_w = word; | ||
110 | |||
111 | param->comp_num = read_byte(&stream); | ||
112 | if (param->comp_num != 1 && param->comp_num != 3) | ||
113 | break; | ||
114 | |||
115 | for (i = 0; i < param->comp_num; i++) { | ||
116 | param->comp_id[i] = read_byte(&stream); | ||
117 | if (param->comp_id[i] == -1) | ||
118 | break; | ||
119 | |||
120 | /* sampling */ | ||
121 | byte = read_byte(&stream); | ||
122 | if (byte == -1) | ||
123 | break; | ||
124 | param->sampling_w[i] = (byte >> 4) & 0x0F; | ||
125 | param->sampling_h[i] = byte & 0x0F; | ||
126 | |||
127 | param->qtbl_num[i] = read_byte(&stream); | ||
128 | if (param->qtbl_num[i] == -1) | ||
129 | break; | ||
130 | } | ||
131 | |||
132 | notfound = !(i == param->comp_num); | ||
133 | break; | ||
134 | case RST ... RST + 7: | ||
135 | case SOI: | ||
136 | case EOI: | ||
137 | case TEM: | ||
138 | break; | ||
139 | default: | ||
140 | if (read_word_be(&stream, &word)) | ||
141 | break; | ||
142 | length = (long)word - 2; | ||
143 | read_skip(&stream, length); | ||
144 | break; | ||
145 | } | ||
146 | } | ||
147 | |||
148 | return !notfound; | ||
149 | } | ||
150 | |||
151 | bool mtk_jpeg_parse(struct mtk_jpeg_dec_param *param, u8 *src_addr_va, | ||
152 | u32 src_size) | ||
153 | { | ||
154 | if (!mtk_jpeg_do_parse(param, src_addr_va, src_size)) | ||
155 | return false; | ||
156 | if (mtk_jpeg_dec_fill_param(param)) | ||
157 | return false; | ||
158 | |||
159 | return true; | ||
160 | } | ||
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.h b/drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.h new file mode 100644 index 000000000000..5d92340ea81b --- /dev/null +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.h | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2016 MediaTek Inc. | ||
3 | * Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com> | ||
4 | * Rick Chang <rick.chang@mediatek.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | #ifndef _MTK_JPEG_PARSE_H | ||
17 | #define _MTK_JPEG_PARSE_H | ||
18 | |||
19 | #include "mtk_jpeg_hw.h" | ||
20 | |||
21 | bool mtk_jpeg_parse(struct mtk_jpeg_dec_param *param, u8 *src_addr_va, | ||
22 | u32 src_size); | ||
23 | |||
24 | #endif /* _MTK_JPEG_PARSE_H */ | ||
25 | |||
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_reg.h b/drivers/media/platform/mtk-jpeg/mtk_jpeg_reg.h new file mode 100644 index 000000000000..fc490d62b012 --- /dev/null +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_reg.h | |||
@@ -0,0 +1,58 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2016 MediaTek Inc. | ||
3 | * Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com> | ||
4 | * Rick Chang <rick.chang@mediatek.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | #ifndef _MTK_JPEG_REG_H | ||
17 | #define _MTK_JPEG_REG_H | ||
18 | |||
19 | #define MTK_JPEG_COMP_MAX 3 | ||
20 | #define MTK_JPEG_BLOCK_MAX 10 | ||
21 | #define MTK_JPEG_DCTSIZE 8 | ||
22 | |||
23 | #define BIT_INQST_MASK_ERROR_BS 0x20 | ||
24 | #define BIT_INQST_MASK_PAUSE 0x10 | ||
25 | #define BIT_INQST_MASK_OVERFLOW 0x04 | ||
26 | #define BIT_INQST_MASK_UNDERFLOW 0x02 | ||
27 | #define BIT_INQST_MASK_EOF 0x01 | ||
28 | #define BIT_INQST_MASK_ALLIRQ 0x37 | ||
29 | |||
30 | #define JPGDEC_REG_RESET 0x0090 | ||
31 | #define JPGDEC_REG_BRZ_FACTOR 0x00F8 | ||
32 | #define JPGDEC_REG_DU_NUM 0x00FC | ||
33 | #define JPGDEC_REG_DEST_ADDR0_Y 0x0140 | ||
34 | #define JPGDEC_REG_DEST_ADDR0_U 0x0144 | ||
35 | #define JPGDEC_REG_DEST_ADDR0_V 0x0148 | ||
36 | #define JPGDEC_REG_DEST_ADDR1_Y 0x014C | ||
37 | #define JPGDEC_REG_DEST_ADDR1_U 0x0150 | ||
38 | #define JPGDEC_REG_DEST_ADDR1_V 0x0154 | ||
39 | #define JPGDEC_REG_STRIDE_Y 0x0158 | ||
40 | #define JPGDEC_REG_STRIDE_UV 0x015C | ||
41 | #define JPGDEC_REG_IMG_STRIDE_Y 0x0160 | ||
42 | #define JPGDEC_REG_IMG_STRIDE_UV 0x0164 | ||
43 | #define JPGDEC_REG_WDMA_CTRL 0x016C | ||
44 | #define JPGDEC_REG_PAUSE_MCU_NUM 0x0170 | ||
45 | #define JPGDEC_REG_OPERATION_MODE 0x017C | ||
46 | #define JPGDEC_REG_FILE_ADDR 0x0200 | ||
47 | #define JPGDEC_REG_COMP_ID 0x020C | ||
48 | #define JPGDEC_REG_TOTAL_MCU_NUM 0x0210 | ||
49 | #define JPGDEC_REG_COMP0_DATA_UNIT_NUM 0x0224 | ||
50 | #define JPGDEC_REG_DU_CTRL 0x023C | ||
51 | #define JPGDEC_REG_TRIG 0x0240 | ||
52 | #define JPGDEC_REG_FILE_BRP 0x0248 | ||
53 | #define JPGDEC_REG_FILE_TOTAL_SIZE 0x024C | ||
54 | #define JPGDEC_REG_QT_ID 0x0270 | ||
55 | #define JPGDEC_REG_INTERRUPT_STATUS 0x0274 | ||
56 | #define JPGDEC_REG_STATUS 0x0278 | ||
57 | |||
58 | #endif /* _MTK_JPEG_REG_H */ | ||
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c index 502877a4b1df..a60b538686ea 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c | |||
@@ -420,6 +420,11 @@ static void mtk_vdec_worker(struct work_struct *work) | |||
420 | dst_buf->index, | 420 | dst_buf->index, |
421 | ret, res_chg); | 421 | ret, res_chg); |
422 | src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); | 422 | src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); |
423 | if (ret == -EIO) { | ||
424 | mutex_lock(&ctx->lock); | ||
425 | src_buf_info->error = true; | ||
426 | mutex_unlock(&ctx->lock); | ||
427 | } | ||
423 | v4l2_m2m_buf_done(&src_buf_info->vb, VB2_BUF_STATE_ERROR); | 428 | v4l2_m2m_buf_done(&src_buf_info->vb, VB2_BUF_STATE_ERROR); |
424 | } else if (res_chg == false) { | 429 | } else if (res_chg == false) { |
425 | /* | 430 | /* |
@@ -1170,8 +1175,16 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb) | |||
1170 | */ | 1175 | */ |
1171 | 1176 | ||
1172 | src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); | 1177 | src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); |
1173 | v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), | 1178 | if (ret == -EIO) { |
1174 | VB2_BUF_STATE_DONE); | 1179 | mtk_v4l2_err("[%d] Unrecoverable error in vdec_if_decode.", |
1180 | ctx->id); | ||
1181 | ctx->state = MTK_STATE_ABORT; | ||
1182 | v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), | ||
1183 | VB2_BUF_STATE_ERROR); | ||
1184 | } else { | ||
1185 | v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), | ||
1186 | VB2_BUF_STATE_DONE); | ||
1187 | } | ||
1175 | mtk_v4l2_debug(ret ? 0 : 1, | 1188 | mtk_v4l2_debug(ret ? 0 : 1, |
1176 | "[%d] vdec_if_decode() src_buf=%d, size=%zu, fail=%d, res_chg=%d", | 1189 | "[%d] vdec_if_decode() src_buf=%d, size=%zu, fail=%d, res_chg=%d", |
1177 | ctx->id, src_buf->index, | 1190 | ctx->id, src_buf->index, |
@@ -1216,16 +1229,22 @@ static void vb2ops_vdec_buf_finish(struct vb2_buffer *vb) | |||
1216 | struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); | 1229 | struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); |
1217 | struct vb2_v4l2_buffer *vb2_v4l2; | 1230 | struct vb2_v4l2_buffer *vb2_v4l2; |
1218 | struct mtk_video_dec_buf *buf; | 1231 | struct mtk_video_dec_buf *buf; |
1219 | 1232 | bool buf_error; | |
1220 | if (vb->vb2_queue->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) | ||
1221 | return; | ||
1222 | 1233 | ||
1223 | vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf); | 1234 | vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf); |
1224 | buf = container_of(vb2_v4l2, struct mtk_video_dec_buf, vb); | 1235 | buf = container_of(vb2_v4l2, struct mtk_video_dec_buf, vb); |
1225 | mutex_lock(&ctx->lock); | 1236 | mutex_lock(&ctx->lock); |
1226 | buf->queued_in_v4l2 = false; | 1237 | if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { |
1227 | buf->queued_in_vb2 = false; | 1238 | buf->queued_in_v4l2 = false; |
1239 | buf->queued_in_vb2 = false; | ||
1240 | } | ||
1241 | buf_error = buf->error; | ||
1228 | mutex_unlock(&ctx->lock); | 1242 | mutex_unlock(&ctx->lock); |
1243 | |||
1244 | if (buf_error) { | ||
1245 | mtk_v4l2_err("Unrecoverable error on buffer."); | ||
1246 | ctx->state = MTK_STATE_ABORT; | ||
1247 | } | ||
1229 | } | 1248 | } |
1230 | 1249 | ||
1231 | static int vb2ops_vdec_buf_init(struct vb2_buffer *vb) | 1250 | static int vb2ops_vdec_buf_init(struct vb2_buffer *vb) |
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h index 362f5a85762e..dc4fc1df63c5 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h | |||
@@ -50,6 +50,7 @@ struct vdec_fb { | |||
50 | * @queued_in_v4l2: Capture buffer is in v4l2 driver, but not in vb2 | 50 | * @queued_in_v4l2: Capture buffer is in v4l2 driver, but not in vb2 |
51 | * queue yet | 51 | * queue yet |
52 | * @lastframe: Intput buffer is last buffer - EOS | 52 | * @lastframe: Intput buffer is last buffer - EOS |
53 | * @error: An unrecoverable error occurs on this buffer. | ||
53 | * @frame_buffer: Decode status, and buffer information of Capture buffer | 54 | * @frame_buffer: Decode status, and buffer information of Capture buffer |
54 | * | 55 | * |
55 | * Note : These status information help us track and debug buffer state | 56 | * Note : These status information help us track and debug buffer state |
@@ -63,6 +64,7 @@ struct mtk_video_dec_buf { | |||
63 | bool queued_in_vb2; | 64 | bool queued_in_vb2; |
64 | bool queued_in_v4l2; | 65 | bool queued_in_v4l2; |
65 | bool lastframe; | 66 | bool lastframe; |
67 | bool error; | ||
66 | struct vdec_fb frame_buffer; | 68 | struct vdec_fb frame_buffer; |
67 | }; | 69 | }; |
68 | 70 | ||
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c index aa81f3ce9463..83f859e8509c 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c | |||
@@ -269,11 +269,6 @@ static int mtk_vcodec_probe(struct platform_device *pdev) | |||
269 | 269 | ||
270 | for (i = VENC_SYS, j = 0; i < NUM_MAX_VCODEC_REG_BASE; i++, j++) { | 270 | for (i = VENC_SYS, j = 0; i < NUM_MAX_VCODEC_REG_BASE; i++, j++) { |
271 | res = platform_get_resource(pdev, IORESOURCE_MEM, j); | 271 | res = platform_get_resource(pdev, IORESOURCE_MEM, j); |
272 | if (res == NULL) { | ||
273 | dev_err(&pdev->dev, "get memory resource failed."); | ||
274 | ret = -ENXIO; | ||
275 | goto err_res; | ||
276 | } | ||
277 | dev->reg_base[i] = devm_ioremap_resource(&pdev->dev, res); | 272 | dev->reg_base[i] = devm_ioremap_resource(&pdev->dev, res); |
278 | if (IS_ERR((__force void *)dev->reg_base[i])) { | 273 | if (IS_ERR((__force void *)dev->reg_base[i])) { |
279 | ret = PTR_ERR((__force void *)dev->reg_base[i]); | 274 | ret = PTR_ERR((__force void *)dev->reg_base[i]); |
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h index 7d55975d3185..237e144c194f 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h | |||
@@ -31,7 +31,6 @@ struct mtk_vcodec_dev; | |||
31 | extern int mtk_v4l2_dbg_level; | 31 | extern int mtk_v4l2_dbg_level; |
32 | extern bool mtk_vcodec_dbg; | 32 | extern bool mtk_vcodec_dbg; |
33 | 33 | ||
34 | #define DEBUG 1 | ||
35 | 34 | ||
36 | #if defined(DEBUG) | 35 | #if defined(DEBUG) |
37 | 36 | ||
@@ -67,15 +66,15 @@ extern bool mtk_vcodec_dbg; | |||
67 | 66 | ||
68 | #else | 67 | #else |
69 | 68 | ||
70 | #define mtk_v4l2_debug(level, fmt, args...) | 69 | #define mtk_v4l2_debug(level, fmt, args...) {} |
71 | #define mtk_v4l2_err(fmt, args...) | 70 | #define mtk_v4l2_err(fmt, args...) {} |
72 | #define mtk_v4l2_debug_enter() | 71 | #define mtk_v4l2_debug_enter() {} |
73 | #define mtk_v4l2_debug_leave() | 72 | #define mtk_v4l2_debug_leave() {} |
74 | 73 | ||
75 | #define mtk_vcodec_debug(h, fmt, args...) | 74 | #define mtk_vcodec_debug(h, fmt, args...) {} |
76 | #define mtk_vcodec_err(h, fmt, args...) | 75 | #define mtk_vcodec_err(h, fmt, args...) {} |
77 | #define mtk_vcodec_debug_enter(h) | 76 | #define mtk_vcodec_debug_enter(h) {} |
78 | #define mtk_vcodec_debug_leave(h) | 77 | #define mtk_vcodec_debug_leave(h) {} |
79 | 78 | ||
80 | #endif | 79 | #endif |
81 | 80 | ||
diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c index e91a3b425b0c..5539b1853f16 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c | |||
@@ -718,6 +718,26 @@ static void get_free_fb(struct vdec_vp9_inst *inst, struct vdec_fb **out_fb) | |||
718 | *out_fb = fb; | 718 | *out_fb = fb; |
719 | } | 719 | } |
720 | 720 | ||
721 | static int validate_vsi_array_indexes(struct vdec_vp9_inst *inst, | ||
722 | struct vdec_vp9_vsi *vsi) { | ||
723 | if (vsi->sf_frm_idx >= VP9_MAX_FRM_BUF_NUM - 1) { | ||
724 | mtk_vcodec_err(inst, "Invalid vsi->sf_frm_idx=%u.", | ||
725 | vsi->sf_frm_idx); | ||
726 | return -EIO; | ||
727 | } | ||
728 | if (vsi->frm_to_show_idx >= VP9_MAX_FRM_BUF_NUM) { | ||
729 | mtk_vcodec_err(inst, "Invalid vsi->frm_to_show_idx=%u.", | ||
730 | vsi->frm_to_show_idx); | ||
731 | return -EIO; | ||
732 | } | ||
733 | if (vsi->new_fb_idx >= VP9_MAX_FRM_BUF_NUM) { | ||
734 | mtk_vcodec_err(inst, "Invalid vsi->new_fb_idx=%u.", | ||
735 | vsi->new_fb_idx); | ||
736 | return -EIO; | ||
737 | } | ||
738 | return 0; | ||
739 | } | ||
740 | |||
721 | static void vdec_vp9_deinit(unsigned long h_vdec) | 741 | static void vdec_vp9_deinit(unsigned long h_vdec) |
722 | { | 742 | { |
723 | struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec; | 743 | struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec; |
@@ -834,6 +854,12 @@ static int vdec_vp9_decode(unsigned long h_vdec, struct mtk_vcodec_mem *bs, | |||
834 | goto DECODE_ERROR; | 854 | goto DECODE_ERROR; |
835 | } | 855 | } |
836 | 856 | ||
857 | ret = validate_vsi_array_indexes(inst, vsi); | ||
858 | if (ret) { | ||
859 | mtk_vcodec_err(inst, "Invalid values from VPU."); | ||
860 | goto DECODE_ERROR; | ||
861 | } | ||
862 | |||
837 | if (vsi->resolution_changed) { | 863 | if (vsi->resolution_changed) { |
838 | if (!vp9_alloc_work_buf(inst)) { | 864 | if (!vp9_alloc_work_buf(inst)) { |
839 | ret = -EINVAL; | 865 | ret = -EINVAL; |
diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.h b/drivers/media/platform/mtk-vcodec/vdec_drv_if.h index db6b5205ffb1..ded1154481cd 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_drv_if.h +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.h | |||
@@ -85,6 +85,8 @@ void vdec_if_deinit(struct mtk_vcodec_ctx *ctx); | |||
85 | * @res_chg : [out] resolution change happens if current bs have different | 85 | * @res_chg : [out] resolution change happens if current bs have different |
86 | * picture width/height | 86 | * picture width/height |
87 | * Note: To flush the decoder when reaching EOF, set input bitstream as NULL. | 87 | * Note: To flush the decoder when reaching EOF, set input bitstream as NULL. |
88 | * | ||
89 | * Return: 0 on success. -EIO on unrecoverable error. | ||
88 | */ | 90 | */ |
89 | int vdec_if_decode(struct mtk_vcodec_ctx *ctx, struct mtk_vcodec_mem *bs, | 91 | int vdec_if_decode(struct mtk_vcodec_ctx *ctx, struct mtk_vcodec_mem *bs, |
90 | struct vdec_fb *fb, bool *res_chg); | 92 | struct vdec_fb *fb, bool *res_chg); |
diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c index a6fa145f2c54..acb639c4abd2 100644 --- a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c +++ b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c | |||
@@ -155,7 +155,7 @@ static void vp8_enc_free_work_buf(struct venc_vp8_inst *inst) | |||
155 | 155 | ||
156 | /* Buffers need to be freed by AP. */ | 156 | /* Buffers need to be freed by AP. */ |
157 | for (i = 0; i < VENC_VP8_VPU_WORK_BUF_MAX; i++) { | 157 | for (i = 0; i < VENC_VP8_VPU_WORK_BUF_MAX; i++) { |
158 | if ((inst->work_bufs[i].size == 0)) | 158 | if (inst->work_bufs[i].size == 0) |
159 | continue; | 159 | continue; |
160 | mtk_vcodec_mem_free(inst->ctx, &inst->work_bufs[i]); | 160 | mtk_vcodec_mem_free(inst->ctx, &inst->work_bufs[i]); |
161 | } | 161 | } |
@@ -172,7 +172,7 @@ static int vp8_enc_alloc_work_buf(struct venc_vp8_inst *inst) | |||
172 | mtk_vcodec_debug_enter(inst); | 172 | mtk_vcodec_debug_enter(inst); |
173 | 173 | ||
174 | for (i = 0; i < VENC_VP8_VPU_WORK_BUF_MAX; i++) { | 174 | for (i = 0; i < VENC_VP8_VPU_WORK_BUF_MAX; i++) { |
175 | if ((wb[i].size == 0)) | 175 | if (wb[i].size == 0) |
176 | continue; | 176 | continue; |
177 | /* | 177 | /* |
178 | * This 'wb' structure is set by VPU side and shared to AP for | 178 | * This 'wb' structure is set by VPU side and shared to AP for |
diff --git a/drivers/media/platform/s5p-cec/Makefile b/drivers/media/platform/s5p-cec/Makefile new file mode 100644 index 000000000000..0e2cf457825a --- /dev/null +++ b/drivers/media/platform/s5p-cec/Makefile | |||
@@ -0,0 +1,2 @@ | |||
1 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_CEC) += s5p-cec.o | ||
2 | s5p-cec-y += s5p_cec.o exynos_hdmi_cecctrl.o | ||
diff --git a/drivers/media/platform/s5p-cec/exynos_hdmi_cec.h b/drivers/media/platform/s5p-cec/exynos_hdmi_cec.h new file mode 100644 index 000000000000..7d9453505dce --- /dev/null +++ b/drivers/media/platform/s5p-cec/exynos_hdmi_cec.h | |||
@@ -0,0 +1,37 @@ | |||
1 | /* drivers/media/platform/s5p-cec/exynos_hdmi_cec.h | ||
2 | * | ||
3 | * Copyright (c) 2010, 2014 Samsung Electronics | ||
4 | * http://www.samsung.com/ | ||
5 | * | ||
6 | * Header file for interface of Samsung Exynos hdmi cec hardware | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef _EXYNOS_HDMI_CEC_H_ | ||
14 | #define _EXYNOS_HDMI_CEC_H_ __FILE__ | ||
15 | |||
16 | #include <linux/regmap.h> | ||
17 | #include "s5p_cec.h" | ||
18 | |||
19 | void s5p_cec_set_divider(struct s5p_cec_dev *cec); | ||
20 | void s5p_cec_enable_rx(struct s5p_cec_dev *cec); | ||
21 | void s5p_cec_mask_rx_interrupts(struct s5p_cec_dev *cec); | ||
22 | void s5p_cec_unmask_rx_interrupts(struct s5p_cec_dev *cec); | ||
23 | void s5p_cec_mask_tx_interrupts(struct s5p_cec_dev *cec); | ||
24 | void s5p_cec_unmask_tx_interrupts(struct s5p_cec_dev *cec); | ||
25 | void s5p_cec_reset(struct s5p_cec_dev *cec); | ||
26 | void s5p_cec_tx_reset(struct s5p_cec_dev *cec); | ||
27 | void s5p_cec_rx_reset(struct s5p_cec_dev *cec); | ||
28 | void s5p_cec_threshold(struct s5p_cec_dev *cec); | ||
29 | void s5p_cec_copy_packet(struct s5p_cec_dev *cec, char *data, | ||
30 | size_t count, u8 retries); | ||
31 | void s5p_cec_set_addr(struct s5p_cec_dev *cec, u32 addr); | ||
32 | u32 s5p_cec_get_status(struct s5p_cec_dev *cec); | ||
33 | void s5p_clr_pending_tx(struct s5p_cec_dev *cec); | ||
34 | void s5p_clr_pending_rx(struct s5p_cec_dev *cec); | ||
35 | void s5p_cec_get_rx_buf(struct s5p_cec_dev *cec, u32 size, u8 *buffer); | ||
36 | |||
37 | #endif /* _EXYNOS_HDMI_CEC_H_ */ | ||
diff --git a/drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c b/drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c new file mode 100644 index 000000000000..1edf667d562a --- /dev/null +++ b/drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c | |||
@@ -0,0 +1,208 @@ | |||
1 | /* drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c | ||
2 | * | ||
3 | * Copyright (c) 2009, 2014 Samsung Electronics | ||
4 | * http://www.samsung.com/ | ||
5 | * | ||
6 | * cec ftn file for Samsung TVOUT driver | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/io.h> | ||
14 | #include <linux/device.h> | ||
15 | |||
16 | #include "exynos_hdmi_cec.h" | ||
17 | #include "regs-cec.h" | ||
18 | |||
19 | #define S5P_HDMI_FIN 24000000 | ||
20 | #define CEC_DIV_RATIO 320000 | ||
21 | |||
22 | #define CEC_MESSAGE_BROADCAST_MASK 0x0F | ||
23 | #define CEC_MESSAGE_BROADCAST 0x0F | ||
24 | #define CEC_FILTER_THRESHOLD 0x15 | ||
25 | |||
26 | void s5p_cec_set_divider(struct s5p_cec_dev *cec) | ||
27 | { | ||
28 | u32 div_ratio, div_val; | ||
29 | unsigned int reg; | ||
30 | |||
31 | div_ratio = S5P_HDMI_FIN / CEC_DIV_RATIO - 1; | ||
32 | |||
33 | if (regmap_read(cec->pmu, EXYNOS_HDMI_PHY_CONTROL, ®)) { | ||
34 | dev_err(cec->dev, "failed to read phy control\n"); | ||
35 | return; | ||
36 | } | ||
37 | |||
38 | reg = (reg & ~(0x3FF << 16)) | (div_ratio << 16); | ||
39 | |||
40 | if (regmap_write(cec->pmu, EXYNOS_HDMI_PHY_CONTROL, reg)) { | ||
41 | dev_err(cec->dev, "failed to write phy control\n"); | ||
42 | return; | ||
43 | } | ||
44 | |||
45 | div_val = CEC_DIV_RATIO * 0.00005 - 1; | ||
46 | |||
47 | writeb(0x0, cec->reg + S5P_CEC_DIVISOR_3); | ||
48 | writeb(0x0, cec->reg + S5P_CEC_DIVISOR_2); | ||
49 | writeb(0x0, cec->reg + S5P_CEC_DIVISOR_1); | ||
50 | writeb(div_val, cec->reg + S5P_CEC_DIVISOR_0); | ||
51 | } | ||
52 | |||
53 | void s5p_cec_enable_rx(struct s5p_cec_dev *cec) | ||
54 | { | ||
55 | u8 reg; | ||
56 | |||
57 | reg = readb(cec->reg + S5P_CEC_RX_CTRL); | ||
58 | reg |= S5P_CEC_RX_CTRL_ENABLE; | ||
59 | writeb(reg, cec->reg + S5P_CEC_RX_CTRL); | ||
60 | } | ||
61 | |||
62 | void s5p_cec_mask_rx_interrupts(struct s5p_cec_dev *cec) | ||
63 | { | ||
64 | u8 reg; | ||
65 | |||
66 | reg = readb(cec->reg + S5P_CEC_IRQ_MASK); | ||
67 | reg |= S5P_CEC_IRQ_RX_DONE; | ||
68 | reg |= S5P_CEC_IRQ_RX_ERROR; | ||
69 | writeb(reg, cec->reg + S5P_CEC_IRQ_MASK); | ||
70 | } | ||
71 | |||
72 | void s5p_cec_unmask_rx_interrupts(struct s5p_cec_dev *cec) | ||
73 | { | ||
74 | u8 reg; | ||
75 | |||
76 | reg = readb(cec->reg + S5P_CEC_IRQ_MASK); | ||
77 | reg &= ~S5P_CEC_IRQ_RX_DONE; | ||
78 | reg &= ~S5P_CEC_IRQ_RX_ERROR; | ||
79 | writeb(reg, cec->reg + S5P_CEC_IRQ_MASK); | ||
80 | } | ||
81 | |||
82 | void s5p_cec_mask_tx_interrupts(struct s5p_cec_dev *cec) | ||
83 | { | ||
84 | u8 reg; | ||
85 | |||
86 | reg = readb(cec->reg + S5P_CEC_IRQ_MASK); | ||
87 | reg |= S5P_CEC_IRQ_TX_DONE; | ||
88 | reg |= S5P_CEC_IRQ_TX_ERROR; | ||
89 | writeb(reg, cec->reg + S5P_CEC_IRQ_MASK); | ||
90 | } | ||
91 | |||
92 | void s5p_cec_unmask_tx_interrupts(struct s5p_cec_dev *cec) | ||
93 | { | ||
94 | u8 reg; | ||
95 | |||
96 | reg = readb(cec->reg + S5P_CEC_IRQ_MASK); | ||
97 | reg &= ~S5P_CEC_IRQ_TX_DONE; | ||
98 | reg &= ~S5P_CEC_IRQ_TX_ERROR; | ||
99 | writeb(reg, cec->reg + S5P_CEC_IRQ_MASK); | ||
100 | } | ||
101 | |||
102 | void s5p_cec_reset(struct s5p_cec_dev *cec) | ||
103 | { | ||
104 | u8 reg; | ||
105 | |||
106 | writeb(S5P_CEC_RX_CTRL_RESET, cec->reg + S5P_CEC_RX_CTRL); | ||
107 | writeb(S5P_CEC_TX_CTRL_RESET, cec->reg + S5P_CEC_TX_CTRL); | ||
108 | |||
109 | reg = readb(cec->reg + 0xc4); | ||
110 | reg &= ~0x1; | ||
111 | writeb(reg, cec->reg + 0xc4); | ||
112 | } | ||
113 | |||
114 | void s5p_cec_tx_reset(struct s5p_cec_dev *cec) | ||
115 | { | ||
116 | writeb(S5P_CEC_TX_CTRL_RESET, cec->reg + S5P_CEC_TX_CTRL); | ||
117 | } | ||
118 | |||
119 | void s5p_cec_rx_reset(struct s5p_cec_dev *cec) | ||
120 | { | ||
121 | u8 reg; | ||
122 | |||
123 | writeb(S5P_CEC_RX_CTRL_RESET, cec->reg + S5P_CEC_RX_CTRL); | ||
124 | |||
125 | reg = readb(cec->reg + 0xc4); | ||
126 | reg &= ~0x1; | ||
127 | writeb(reg, cec->reg + 0xc4); | ||
128 | } | ||
129 | |||
130 | void s5p_cec_threshold(struct s5p_cec_dev *cec) | ||
131 | { | ||
132 | writeb(CEC_FILTER_THRESHOLD, cec->reg + S5P_CEC_RX_FILTER_TH); | ||
133 | writeb(0, cec->reg + S5P_CEC_RX_FILTER_CTRL); | ||
134 | } | ||
135 | |||
136 | void s5p_cec_copy_packet(struct s5p_cec_dev *cec, char *data, | ||
137 | size_t count, u8 retries) | ||
138 | { | ||
139 | int i = 0; | ||
140 | u8 reg; | ||
141 | |||
142 | while (i < count) { | ||
143 | writeb(data[i], cec->reg + (S5P_CEC_TX_BUFF0 + (i * 4))); | ||
144 | i++; | ||
145 | } | ||
146 | |||
147 | writeb(count, cec->reg + S5P_CEC_TX_BYTES); | ||
148 | reg = readb(cec->reg + S5P_CEC_TX_CTRL); | ||
149 | reg |= S5P_CEC_TX_CTRL_START; | ||
150 | reg &= ~0x70; | ||
151 | reg |= retries << 4; | ||
152 | |||
153 | if ((data[0] & CEC_MESSAGE_BROADCAST_MASK) == CEC_MESSAGE_BROADCAST) { | ||
154 | dev_dbg(cec->dev, "Broadcast"); | ||
155 | reg |= S5P_CEC_TX_CTRL_BCAST; | ||
156 | } else { | ||
157 | dev_dbg(cec->dev, "No Broadcast"); | ||
158 | reg &= ~S5P_CEC_TX_CTRL_BCAST; | ||
159 | } | ||
160 | |||
161 | writeb(reg, cec->reg + S5P_CEC_TX_CTRL); | ||
162 | dev_dbg(cec->dev, "cec-tx: cec count (%zu): %*ph", count, | ||
163 | (int)count, data); | ||
164 | } | ||
165 | |||
166 | void s5p_cec_set_addr(struct s5p_cec_dev *cec, u32 addr) | ||
167 | { | ||
168 | writeb(addr & 0x0F, cec->reg + S5P_CEC_LOGIC_ADDR); | ||
169 | } | ||
170 | |||
171 | u32 s5p_cec_get_status(struct s5p_cec_dev *cec) | ||
172 | { | ||
173 | u32 status = 0; | ||
174 | |||
175 | status = readb(cec->reg + S5P_CEC_STATUS_0); | ||
176 | status |= readb(cec->reg + S5P_CEC_STATUS_1) << 8; | ||
177 | status |= readb(cec->reg + S5P_CEC_STATUS_2) << 16; | ||
178 | status |= readb(cec->reg + S5P_CEC_STATUS_3) << 24; | ||
179 | |||
180 | dev_dbg(cec->dev, "status = 0x%x!\n", status); | ||
181 | |||
182 | return status; | ||
183 | } | ||
184 | |||
185 | void s5p_clr_pending_tx(struct s5p_cec_dev *cec) | ||
186 | { | ||
187 | writeb(S5P_CEC_IRQ_TX_DONE | S5P_CEC_IRQ_TX_ERROR, | ||
188 | cec->reg + S5P_CEC_IRQ_CLEAR); | ||
189 | } | ||
190 | |||
191 | void s5p_clr_pending_rx(struct s5p_cec_dev *cec) | ||
192 | { | ||
193 | writeb(S5P_CEC_IRQ_RX_DONE | S5P_CEC_IRQ_RX_ERROR, | ||
194 | cec->reg + S5P_CEC_IRQ_CLEAR); | ||
195 | } | ||
196 | |||
197 | void s5p_cec_get_rx_buf(struct s5p_cec_dev *cec, u32 size, u8 *buffer) | ||
198 | { | ||
199 | u32 i = 0; | ||
200 | char debug[40]; | ||
201 | |||
202 | while (i < size) { | ||
203 | buffer[i] = readb(cec->reg + S5P_CEC_RX_BUFF0 + (i * 4)); | ||
204 | sprintf(debug + i * 2, "%02x ", buffer[i]); | ||
205 | i++; | ||
206 | } | ||
207 | dev_dbg(cec->dev, "cec-rx: cec size(%d): %s", size, debug); | ||
208 | } | ||
diff --git a/drivers/media/platform/s5p-cec/regs-cec.h b/drivers/media/platform/s5p-cec/regs-cec.h new file mode 100644 index 000000000000..b2e7e129920e --- /dev/null +++ b/drivers/media/platform/s5p-cec/regs-cec.h | |||
@@ -0,0 +1,96 @@ | |||
1 | /* drivers/media/platform/s5p-cec/regs-cec.h | ||
2 | * | ||
3 | * Copyright (c) 2010 Samsung Electronics | ||
4 | * http://www.samsung.com/ | ||
5 | * | ||
6 | * register header file for Samsung TVOUT driver | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef __EXYNOS_REGS__H | ||
14 | #define __EXYNOS_REGS__H | ||
15 | |||
16 | /* | ||
17 | * Register part | ||
18 | */ | ||
19 | #define S5P_CEC_STATUS_0 (0x0000) | ||
20 | #define S5P_CEC_STATUS_1 (0x0004) | ||
21 | #define S5P_CEC_STATUS_2 (0x0008) | ||
22 | #define S5P_CEC_STATUS_3 (0x000C) | ||
23 | #define S5P_CEC_IRQ_MASK (0x0010) | ||
24 | #define S5P_CEC_IRQ_CLEAR (0x0014) | ||
25 | #define S5P_CEC_LOGIC_ADDR (0x0020) | ||
26 | #define S5P_CEC_DIVISOR_0 (0x0030) | ||
27 | #define S5P_CEC_DIVISOR_1 (0x0034) | ||
28 | #define S5P_CEC_DIVISOR_2 (0x0038) | ||
29 | #define S5P_CEC_DIVISOR_3 (0x003C) | ||
30 | |||
31 | #define S5P_CEC_TX_CTRL (0x0040) | ||
32 | #define S5P_CEC_TX_BYTES (0x0044) | ||
33 | #define S5P_CEC_TX_STAT0 (0x0060) | ||
34 | #define S5P_CEC_TX_STAT1 (0x0064) | ||
35 | #define S5P_CEC_TX_BUFF0 (0x0080) | ||
36 | #define S5P_CEC_TX_BUFF1 (0x0084) | ||
37 | #define S5P_CEC_TX_BUFF2 (0x0088) | ||
38 | #define S5P_CEC_TX_BUFF3 (0x008C) | ||
39 | #define S5P_CEC_TX_BUFF4 (0x0090) | ||
40 | #define S5P_CEC_TX_BUFF5 (0x0094) | ||
41 | #define S5P_CEC_TX_BUFF6 (0x0098) | ||
42 | #define S5P_CEC_TX_BUFF7 (0x009C) | ||
43 | #define S5P_CEC_TX_BUFF8 (0x00A0) | ||
44 | #define S5P_CEC_TX_BUFF9 (0x00A4) | ||
45 | #define S5P_CEC_TX_BUFF10 (0x00A8) | ||
46 | #define S5P_CEC_TX_BUFF11 (0x00AC) | ||
47 | #define S5P_CEC_TX_BUFF12 (0x00B0) | ||
48 | #define S5P_CEC_TX_BUFF13 (0x00B4) | ||
49 | #define S5P_CEC_TX_BUFF14 (0x00B8) | ||
50 | #define S5P_CEC_TX_BUFF15 (0x00BC) | ||
51 | |||
52 | #define S5P_CEC_RX_CTRL (0x00C0) | ||
53 | #define S5P_CEC_RX_STAT0 (0x00E0) | ||
54 | #define S5P_CEC_RX_STAT1 (0x00E4) | ||
55 | #define S5P_CEC_RX_BUFF0 (0x0100) | ||
56 | #define S5P_CEC_RX_BUFF1 (0x0104) | ||
57 | #define S5P_CEC_RX_BUFF2 (0x0108) | ||
58 | #define S5P_CEC_RX_BUFF3 (0x010C) | ||
59 | #define S5P_CEC_RX_BUFF4 (0x0110) | ||
60 | #define S5P_CEC_RX_BUFF5 (0x0114) | ||
61 | #define S5P_CEC_RX_BUFF6 (0x0118) | ||
62 | #define S5P_CEC_RX_BUFF7 (0x011C) | ||
63 | #define S5P_CEC_RX_BUFF8 (0x0120) | ||
64 | #define S5P_CEC_RX_BUFF9 (0x0124) | ||
65 | #define S5P_CEC_RX_BUFF10 (0x0128) | ||
66 | #define S5P_CEC_RX_BUFF11 (0x012C) | ||
67 | #define S5P_CEC_RX_BUFF12 (0x0130) | ||
68 | #define S5P_CEC_RX_BUFF13 (0x0134) | ||
69 | #define S5P_CEC_RX_BUFF14 (0x0138) | ||
70 | #define S5P_CEC_RX_BUFF15 (0x013C) | ||
71 | |||
72 | #define S5P_CEC_RX_FILTER_CTRL (0x0180) | ||
73 | #define S5P_CEC_RX_FILTER_TH (0x0184) | ||
74 | |||
75 | /* | ||
76 | * Bit definition part | ||
77 | */ | ||
78 | #define S5P_CEC_IRQ_TX_DONE (1<<0) | ||
79 | #define S5P_CEC_IRQ_TX_ERROR (1<<1) | ||
80 | #define S5P_CEC_IRQ_RX_DONE (1<<4) | ||
81 | #define S5P_CEC_IRQ_RX_ERROR (1<<5) | ||
82 | |||
83 | #define S5P_CEC_TX_CTRL_START (1<<0) | ||
84 | #define S5P_CEC_TX_CTRL_BCAST (1<<1) | ||
85 | #define S5P_CEC_TX_CTRL_RETRY (0x04<<4) | ||
86 | #define S5P_CEC_TX_CTRL_RESET (1<<7) | ||
87 | |||
88 | #define S5P_CEC_RX_CTRL_ENABLE (1<<0) | ||
89 | #define S5P_CEC_RX_CTRL_RESET (1<<7) | ||
90 | |||
91 | #define S5P_CEC_LOGIC_ADDR_MASK (0xF) | ||
92 | |||
93 | /* PMU Registers for PHY */ | ||
94 | #define EXYNOS_HDMI_PHY_CONTROL 0x700 | ||
95 | |||
96 | #endif /* __EXYNOS_REGS__H */ | ||
diff --git a/drivers/media/platform/s5p-cec/s5p_cec.c b/drivers/media/platform/s5p-cec/s5p_cec.c new file mode 100644 index 000000000000..664937b61fa4 --- /dev/null +++ b/drivers/media/platform/s5p-cec/s5p_cec.c | |||
@@ -0,0 +1,304 @@ | |||
1 | /* drivers/media/platform/s5p-cec/s5p_cec.c | ||
2 | * | ||
3 | * Samsung S5P CEC driver | ||
4 | * | ||
5 | * Copyright (c) 2014 Samsung Electronics Co., Ltd. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This driver is based on the "cec interface driver for exynos soc" by | ||
13 | * SangPil Moon. | ||
14 | */ | ||
15 | |||
16 | #include <linux/clk.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/mfd/syscon.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/of.h> | ||
22 | #include <linux/of_platform.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/pm_runtime.h> | ||
25 | #include <linux/timer.h> | ||
26 | #include <linux/workqueue.h> | ||
27 | #include <media/cec.h> | ||
28 | #include <media/cec-notifier.h> | ||
29 | |||
30 | #include "exynos_hdmi_cec.h" | ||
31 | #include "regs-cec.h" | ||
32 | #include "s5p_cec.h" | ||
33 | |||
34 | #define CEC_NAME "s5p-cec" | ||
35 | |||
36 | static int debug; | ||
37 | module_param(debug, int, 0644); | ||
38 | MODULE_PARM_DESC(debug, "debug level (0-2)"); | ||
39 | |||
40 | static int s5p_cec_adap_enable(struct cec_adapter *adap, bool enable) | ||
41 | { | ||
42 | struct s5p_cec_dev *cec = cec_get_drvdata(adap); | ||
43 | |||
44 | if (enable) { | ||
45 | pm_runtime_get_sync(cec->dev); | ||
46 | |||
47 | s5p_cec_reset(cec); | ||
48 | |||
49 | s5p_cec_set_divider(cec); | ||
50 | s5p_cec_threshold(cec); | ||
51 | |||
52 | s5p_cec_unmask_tx_interrupts(cec); | ||
53 | s5p_cec_unmask_rx_interrupts(cec); | ||
54 | s5p_cec_enable_rx(cec); | ||
55 | } else { | ||
56 | s5p_cec_mask_tx_interrupts(cec); | ||
57 | s5p_cec_mask_rx_interrupts(cec); | ||
58 | pm_runtime_disable(cec->dev); | ||
59 | } | ||
60 | |||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | static int s5p_cec_adap_log_addr(struct cec_adapter *adap, u8 addr) | ||
65 | { | ||
66 | struct s5p_cec_dev *cec = cec_get_drvdata(adap); | ||
67 | |||
68 | s5p_cec_set_addr(cec, addr); | ||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | static int s5p_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, | ||
73 | u32 signal_free_time, struct cec_msg *msg) | ||
74 | { | ||
75 | struct s5p_cec_dev *cec = cec_get_drvdata(adap); | ||
76 | |||
77 | /* | ||
78 | * Unclear if 0 retries are allowed by the hardware, so have 1 as | ||
79 | * the minimum. | ||
80 | */ | ||
81 | s5p_cec_copy_packet(cec, msg->msg, msg->len, max(1, attempts - 1)); | ||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static irqreturn_t s5p_cec_irq_handler(int irq, void *priv) | ||
86 | { | ||
87 | struct s5p_cec_dev *cec = priv; | ||
88 | u32 status = 0; | ||
89 | |||
90 | status = s5p_cec_get_status(cec); | ||
91 | |||
92 | dev_dbg(cec->dev, "irq received\n"); | ||
93 | |||
94 | if (status & CEC_STATUS_TX_DONE) { | ||
95 | if (status & CEC_STATUS_TX_ERROR) { | ||
96 | dev_dbg(cec->dev, "CEC_STATUS_TX_ERROR set\n"); | ||
97 | cec->tx = STATE_ERROR; | ||
98 | } else { | ||
99 | dev_dbg(cec->dev, "CEC_STATUS_TX_DONE\n"); | ||
100 | cec->tx = STATE_DONE; | ||
101 | } | ||
102 | s5p_clr_pending_tx(cec); | ||
103 | } | ||
104 | |||
105 | if (status & CEC_STATUS_RX_DONE) { | ||
106 | if (status & CEC_STATUS_RX_ERROR) { | ||
107 | dev_dbg(cec->dev, "CEC_STATUS_RX_ERROR set\n"); | ||
108 | s5p_cec_rx_reset(cec); | ||
109 | s5p_cec_enable_rx(cec); | ||
110 | } else { | ||
111 | dev_dbg(cec->dev, "CEC_STATUS_RX_DONE set\n"); | ||
112 | if (cec->rx != STATE_IDLE) | ||
113 | dev_dbg(cec->dev, "Buffer overrun (worker did not process previous message)\n"); | ||
114 | cec->rx = STATE_BUSY; | ||
115 | cec->msg.len = status >> 24; | ||
116 | cec->msg.rx_status = CEC_RX_STATUS_OK; | ||
117 | s5p_cec_get_rx_buf(cec, cec->msg.len, | ||
118 | cec->msg.msg); | ||
119 | cec->rx = STATE_DONE; | ||
120 | s5p_cec_enable_rx(cec); | ||
121 | } | ||
122 | /* Clear interrupt pending bit */ | ||
123 | s5p_clr_pending_rx(cec); | ||
124 | } | ||
125 | return IRQ_WAKE_THREAD; | ||
126 | } | ||
127 | |||
128 | static irqreturn_t s5p_cec_irq_handler_thread(int irq, void *priv) | ||
129 | { | ||
130 | struct s5p_cec_dev *cec = priv; | ||
131 | |||
132 | dev_dbg(cec->dev, "irq processing thread\n"); | ||
133 | switch (cec->tx) { | ||
134 | case STATE_DONE: | ||
135 | cec_transmit_done(cec->adap, CEC_TX_STATUS_OK, 0, 0, 0, 0); | ||
136 | cec->tx = STATE_IDLE; | ||
137 | break; | ||
138 | case STATE_ERROR: | ||
139 | cec_transmit_done(cec->adap, | ||
140 | CEC_TX_STATUS_MAX_RETRIES | CEC_TX_STATUS_ERROR, | ||
141 | 0, 0, 0, 1); | ||
142 | cec->tx = STATE_IDLE; | ||
143 | break; | ||
144 | case STATE_BUSY: | ||
145 | dev_err(cec->dev, "state set to busy, this should not occur here\n"); | ||
146 | break; | ||
147 | default: | ||
148 | break; | ||
149 | } | ||
150 | |||
151 | switch (cec->rx) { | ||
152 | case STATE_DONE: | ||
153 | cec_received_msg(cec->adap, &cec->msg); | ||
154 | cec->rx = STATE_IDLE; | ||
155 | break; | ||
156 | default: | ||
157 | break; | ||
158 | } | ||
159 | |||
160 | return IRQ_HANDLED; | ||
161 | } | ||
162 | |||
163 | static const struct cec_adap_ops s5p_cec_adap_ops = { | ||
164 | .adap_enable = s5p_cec_adap_enable, | ||
165 | .adap_log_addr = s5p_cec_adap_log_addr, | ||
166 | .adap_transmit = s5p_cec_adap_transmit, | ||
167 | }; | ||
168 | |||
169 | static int s5p_cec_probe(struct platform_device *pdev) | ||
170 | { | ||
171 | struct device *dev = &pdev->dev; | ||
172 | struct device_node *np; | ||
173 | struct platform_device *hdmi_dev; | ||
174 | struct resource *res; | ||
175 | struct s5p_cec_dev *cec; | ||
176 | int ret; | ||
177 | |||
178 | np = of_parse_phandle(pdev->dev.of_node, "hdmi-phandle", 0); | ||
179 | |||
180 | if (!np) { | ||
181 | dev_err(&pdev->dev, "Failed to find hdmi node in device tree\n"); | ||
182 | return -ENODEV; | ||
183 | } | ||
184 | hdmi_dev = of_find_device_by_node(np); | ||
185 | if (hdmi_dev == NULL) | ||
186 | return -EPROBE_DEFER; | ||
187 | |||
188 | cec = devm_kzalloc(&pdev->dev, sizeof(*cec), GFP_KERNEL); | ||
189 | if (!cec) | ||
190 | return -ENOMEM; | ||
191 | |||
192 | cec->dev = dev; | ||
193 | |||
194 | cec->irq = platform_get_irq(pdev, 0); | ||
195 | if (cec->irq < 0) | ||
196 | return cec->irq; | ||
197 | |||
198 | ret = devm_request_threaded_irq(dev, cec->irq, s5p_cec_irq_handler, | ||
199 | s5p_cec_irq_handler_thread, 0, pdev->name, cec); | ||
200 | if (ret) | ||
201 | return ret; | ||
202 | |||
203 | cec->clk = devm_clk_get(dev, "hdmicec"); | ||
204 | if (IS_ERR(cec->clk)) | ||
205 | return PTR_ERR(cec->clk); | ||
206 | |||
207 | cec->pmu = syscon_regmap_lookup_by_phandle(dev->of_node, | ||
208 | "samsung,syscon-phandle"); | ||
209 | if (IS_ERR(cec->pmu)) | ||
210 | return -EPROBE_DEFER; | ||
211 | |||
212 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
213 | cec->reg = devm_ioremap_resource(dev, res); | ||
214 | if (IS_ERR(cec->reg)) | ||
215 | return PTR_ERR(cec->reg); | ||
216 | |||
217 | cec->notifier = cec_notifier_get(&hdmi_dev->dev); | ||
218 | if (cec->notifier == NULL) | ||
219 | return -ENOMEM; | ||
220 | |||
221 | cec->adap = cec_allocate_adapter(&s5p_cec_adap_ops, cec, | ||
222 | CEC_NAME, | ||
223 | CEC_CAP_LOG_ADDRS | CEC_CAP_TRANSMIT | | ||
224 | CEC_CAP_PASSTHROUGH | CEC_CAP_RC, 1); | ||
225 | ret = PTR_ERR_OR_ZERO(cec->adap); | ||
226 | if (ret) | ||
227 | return ret; | ||
228 | |||
229 | ret = cec_register_adapter(cec->adap, &pdev->dev); | ||
230 | if (ret) | ||
231 | goto err_delete_adapter; | ||
232 | |||
233 | cec_register_cec_notifier(cec->adap, cec->notifier); | ||
234 | |||
235 | platform_set_drvdata(pdev, cec); | ||
236 | pm_runtime_enable(dev); | ||
237 | |||
238 | dev_dbg(dev, "successfuly probed\n"); | ||
239 | return 0; | ||
240 | |||
241 | err_delete_adapter: | ||
242 | cec_delete_adapter(cec->adap); | ||
243 | return ret; | ||
244 | } | ||
245 | |||
246 | static int s5p_cec_remove(struct platform_device *pdev) | ||
247 | { | ||
248 | struct s5p_cec_dev *cec = platform_get_drvdata(pdev); | ||
249 | |||
250 | cec_unregister_adapter(cec->adap); | ||
251 | cec_notifier_put(cec->notifier); | ||
252 | pm_runtime_disable(&pdev->dev); | ||
253 | return 0; | ||
254 | } | ||
255 | |||
256 | static int __maybe_unused s5p_cec_runtime_suspend(struct device *dev) | ||
257 | { | ||
258 | struct s5p_cec_dev *cec = dev_get_drvdata(dev); | ||
259 | |||
260 | clk_disable_unprepare(cec->clk); | ||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | static int __maybe_unused s5p_cec_runtime_resume(struct device *dev) | ||
265 | { | ||
266 | struct s5p_cec_dev *cec = dev_get_drvdata(dev); | ||
267 | int ret; | ||
268 | |||
269 | ret = clk_prepare_enable(cec->clk); | ||
270 | if (ret < 0) | ||
271 | return ret; | ||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | static const struct dev_pm_ops s5p_cec_pm_ops = { | ||
276 | SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, | ||
277 | pm_runtime_force_resume) | ||
278 | SET_RUNTIME_PM_OPS(s5p_cec_runtime_suspend, s5p_cec_runtime_resume, | ||
279 | NULL) | ||
280 | }; | ||
281 | |||
282 | static const struct of_device_id s5p_cec_match[] = { | ||
283 | { | ||
284 | .compatible = "samsung,s5p-cec", | ||
285 | }, | ||
286 | {}, | ||
287 | }; | ||
288 | MODULE_DEVICE_TABLE(of, s5p_cec_match); | ||
289 | |||
290 | static struct platform_driver s5p_cec_pdrv = { | ||
291 | .probe = s5p_cec_probe, | ||
292 | .remove = s5p_cec_remove, | ||
293 | .driver = { | ||
294 | .name = CEC_NAME, | ||
295 | .of_match_table = s5p_cec_match, | ||
296 | .pm = &s5p_cec_pm_ops, | ||
297 | }, | ||
298 | }; | ||
299 | |||
300 | module_platform_driver(s5p_cec_pdrv); | ||
301 | |||
302 | MODULE_AUTHOR("Kamil Debski <kamil@wypas.org>"); | ||
303 | MODULE_LICENSE("GPL"); | ||
304 | MODULE_DESCRIPTION("Samsung S5P CEC driver"); | ||
diff --git a/drivers/media/platform/s5p-cec/s5p_cec.h b/drivers/media/platform/s5p-cec/s5p_cec.h new file mode 100644 index 000000000000..7015845c1caa --- /dev/null +++ b/drivers/media/platform/s5p-cec/s5p_cec.h | |||
@@ -0,0 +1,79 @@ | |||
1 | /* drivers/media/platform/s5p-cec/s5p_cec.h | ||
2 | * | ||
3 | * Samsung S5P HDMI CEC driver | ||
4 | * | ||
5 | * Copyright (c) 2014 Samsung Electronics Co., Ltd. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | #ifndef _S5P_CEC_H_ | ||
14 | #define _S5P_CEC_H_ __FILE__ | ||
15 | |||
16 | #include <linux/clk.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/mfd/syscon.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/of.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/pm_runtime.h> | ||
24 | #include <linux/timer.h> | ||
25 | #include <linux/version.h> | ||
26 | #include <linux/workqueue.h> | ||
27 | #include <media/cec.h> | ||
28 | |||
29 | #include "exynos_hdmi_cec.h" | ||
30 | #include "regs-cec.h" | ||
31 | #include "s5p_cec.h" | ||
32 | |||
33 | #define CEC_NAME "s5p-cec" | ||
34 | |||
35 | #define CEC_STATUS_TX_RUNNING (1 << 0) | ||
36 | #define CEC_STATUS_TX_TRANSFERRING (1 << 1) | ||
37 | #define CEC_STATUS_TX_DONE (1 << 2) | ||
38 | #define CEC_STATUS_TX_ERROR (1 << 3) | ||
39 | #define CEC_STATUS_TX_BYTES (0xFF << 8) | ||
40 | #define CEC_STATUS_RX_RUNNING (1 << 16) | ||
41 | #define CEC_STATUS_RX_RECEIVING (1 << 17) | ||
42 | #define CEC_STATUS_RX_DONE (1 << 18) | ||
43 | #define CEC_STATUS_RX_ERROR (1 << 19) | ||
44 | #define CEC_STATUS_RX_BCAST (1 << 20) | ||
45 | #define CEC_STATUS_RX_BYTES (0xFF << 24) | ||
46 | |||
47 | #define CEC_WORKER_TX_DONE (1 << 0) | ||
48 | #define CEC_WORKER_RX_MSG (1 << 1) | ||
49 | |||
50 | /* CEC Rx buffer size */ | ||
51 | #define CEC_RX_BUFF_SIZE 16 | ||
52 | /* CEC Tx buffer size */ | ||
53 | #define CEC_TX_BUFF_SIZE 16 | ||
54 | |||
55 | enum cec_state { | ||
56 | STATE_IDLE, | ||
57 | STATE_BUSY, | ||
58 | STATE_DONE, | ||
59 | STATE_ERROR | ||
60 | }; | ||
61 | |||
62 | struct cec_notifier; | ||
63 | |||
64 | struct s5p_cec_dev { | ||
65 | struct cec_adapter *adap; | ||
66 | struct clk *clk; | ||
67 | struct device *dev; | ||
68 | struct mutex lock; | ||
69 | struct regmap *pmu; | ||
70 | struct cec_notifier *notifier; | ||
71 | int irq; | ||
72 | void __iomem *reg; | ||
73 | |||
74 | enum cec_state rx; | ||
75 | enum cec_state tx; | ||
76 | struct cec_msg msg; | ||
77 | }; | ||
78 | |||
79 | #endif /* _S5P_CEC_H_ */ | ||
diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c index 62c0dec30b59..81ed5cd5cd5d 100644 --- a/drivers/media/platform/s5p-g2d/g2d.c +++ b/drivers/media/platform/s5p-g2d/g2d.c | |||
@@ -679,7 +679,7 @@ static int g2d_probe(struct platform_device *pdev) | |||
679 | 0, pdev->name, dev); | 679 | 0, pdev->name, dev); |
680 | if (ret) { | 680 | if (ret) { |
681 | dev_err(&pdev->dev, "failed to install IRQ\n"); | 681 | dev_err(&pdev->dev, "failed to install IRQ\n"); |
682 | goto put_clk_gate; | 682 | goto unprep_clk_gate; |
683 | } | 683 | } |
684 | 684 | ||
685 | vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); | 685 | vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); |
diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v6.h b/drivers/media/platform/s5p-mfc/regs-mfc-v6.h index d2cd35916dc5..c0166ee9a455 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc-v6.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc-v6.h | |||
@@ -403,7 +403,7 @@ | |||
403 | #define MFC_OTHER_ENC_CTX_BUF_SIZE_V6 (12 * SZ_1K) /* 12KB */ | 403 | #define MFC_OTHER_ENC_CTX_BUF_SIZE_V6 (12 * SZ_1K) /* 12KB */ |
404 | 404 | ||
405 | /* MFCv6 variant defines */ | 405 | /* MFCv6 variant defines */ |
406 | #define MAX_FW_SIZE_V6 (SZ_1M) /* 1MB */ | 406 | #define MAX_FW_SIZE_V6 (SZ_512K) /* 512KB */ |
407 | #define MAX_CPB_SIZE_V6 (3 * SZ_1M) /* 3MB */ | 407 | #define MAX_CPB_SIZE_V6 (3 * SZ_1M) /* 3MB */ |
408 | #define MFC_VERSION_V6 0x61 | 408 | #define MFC_VERSION_V6 0x61 |
409 | #define MFC_NUM_PORTS_V6 1 | 409 | #define MFC_NUM_PORTS_V6 1 |
diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v7.h b/drivers/media/platform/s5p-mfc/regs-mfc-v7.h index 1a5c6fdf7846..9f220769d970 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc-v7.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc-v7.h | |||
@@ -34,7 +34,7 @@ | |||
34 | #define S5P_FIMV_E_VP8_NUM_T_LAYER_V7 0xfdc4 | 34 | #define S5P_FIMV_E_VP8_NUM_T_LAYER_V7 0xfdc4 |
35 | 35 | ||
36 | /* MFCv7 variant defines */ | 36 | /* MFCv7 variant defines */ |
37 | #define MAX_FW_SIZE_V7 (SZ_1M) /* 1MB */ | 37 | #define MAX_FW_SIZE_V7 (SZ_512K) /* 512KB */ |
38 | #define MAX_CPB_SIZE_V7 (3 * SZ_1M) /* 3MB */ | 38 | #define MAX_CPB_SIZE_V7 (3 * SZ_1M) /* 3MB */ |
39 | #define MFC_VERSION_V7 0x72 | 39 | #define MFC_VERSION_V7 0x72 |
40 | #define MFC_NUM_PORTS_V7 1 | 40 | #define MFC_NUM_PORTS_V7 1 |
diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v8.h b/drivers/media/platform/s5p-mfc/regs-mfc-v8.h index 4d1c3750eb5e..75f5f7511d72 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc-v8.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc-v8.h | |||
@@ -116,7 +116,7 @@ | |||
116 | #define S5P_FIMV_D_ALIGN_PLANE_SIZE_V8 64 | 116 | #define S5P_FIMV_D_ALIGN_PLANE_SIZE_V8 64 |
117 | 117 | ||
118 | /* MFCv8 variant defines */ | 118 | /* MFCv8 variant defines */ |
119 | #define MAX_FW_SIZE_V8 (SZ_1M) /* 1MB */ | 119 | #define MAX_FW_SIZE_V8 (SZ_512K) /* 512KB */ |
120 | #define MAX_CPB_SIZE_V8 (3 * SZ_1M) /* 3MB */ | 120 | #define MAX_CPB_SIZE_V8 (3 * SZ_1M) /* 3MB */ |
121 | #define MFC_VERSION_V8 0x80 | 121 | #define MFC_VERSION_V8 0x80 |
122 | #define MFC_NUM_PORTS_V8 1 | 122 | #define MFC_NUM_PORTS_V8 1 |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index bb0a5887c9a9..1afde5021ca6 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <media/v4l2-event.h> | 22 | #include <media/v4l2-event.h> |
23 | #include <linux/workqueue.h> | 23 | #include <linux/workqueue.h> |
24 | #include <linux/of.h> | 24 | #include <linux/of.h> |
25 | #include <linux/of_device.h> | ||
25 | #include <linux/of_reserved_mem.h> | 26 | #include <linux/of_reserved_mem.h> |
26 | #include <media/videobuf2-v4l2.h> | 27 | #include <media/videobuf2-v4l2.h> |
27 | #include "s5p_mfc_common.h" | 28 | #include "s5p_mfc_common.h" |
@@ -42,6 +43,10 @@ int mfc_debug_level; | |||
42 | module_param_named(debug, mfc_debug_level, int, S_IRUGO | S_IWUSR); | 43 | module_param_named(debug, mfc_debug_level, int, S_IRUGO | S_IWUSR); |
43 | MODULE_PARM_DESC(debug, "Debug level - higher value produces more verbose messages"); | 44 | MODULE_PARM_DESC(debug, "Debug level - higher value produces more verbose messages"); |
44 | 45 | ||
46 | static char *mfc_mem_size; | ||
47 | module_param_named(mem, mfc_mem_size, charp, 0644); | ||
48 | MODULE_PARM_DESC(mem, "Preallocated memory size for the firmware and context buffers"); | ||
49 | |||
45 | /* Helper functions for interrupt processing */ | 50 | /* Helper functions for interrupt processing */ |
46 | 51 | ||
47 | /* Remove from hw execution round robin */ | 52 | /* Remove from hw execution round robin */ |
@@ -206,6 +211,7 @@ static void s5p_mfc_watchdog_worker(struct work_struct *work) | |||
206 | } | 211 | } |
207 | s5p_mfc_clock_on(); | 212 | s5p_mfc_clock_on(); |
208 | ret = s5p_mfc_init_hw(dev); | 213 | ret = s5p_mfc_init_hw(dev); |
214 | s5p_mfc_clock_off(); | ||
209 | if (ret) | 215 | if (ret) |
210 | mfc_err("Failed to reinit FW\n"); | 216 | mfc_err("Failed to reinit FW\n"); |
211 | } | 217 | } |
@@ -666,9 +672,9 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv) | |||
666 | break; | 672 | break; |
667 | } | 673 | } |
668 | s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); | 674 | s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); |
669 | wake_up_ctx(ctx, reason, err); | ||
670 | WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); | 675 | WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); |
671 | s5p_mfc_clock_off(); | 676 | s5p_mfc_clock_off(); |
677 | wake_up_ctx(ctx, reason, err); | ||
672 | s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); | 678 | s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); |
673 | } else { | 679 | } else { |
674 | s5p_mfc_handle_frame(ctx, reason, err); | 680 | s5p_mfc_handle_frame(ctx, reason, err); |
@@ -682,15 +688,11 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv) | |||
682 | case S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET: | 688 | case S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET: |
683 | ctx->inst_no = s5p_mfc_hw_call(dev->mfc_ops, get_inst_no, dev); | 689 | ctx->inst_no = s5p_mfc_hw_call(dev->mfc_ops, get_inst_no, dev); |
684 | ctx->state = MFCINST_GOT_INST; | 690 | ctx->state = MFCINST_GOT_INST; |
685 | clear_work_bit(ctx); | ||
686 | wake_up(&ctx->queue); | ||
687 | goto irq_cleanup_hw; | 691 | goto irq_cleanup_hw; |
688 | 692 | ||
689 | case S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET: | 693 | case S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET: |
690 | clear_work_bit(ctx); | ||
691 | ctx->inst_no = MFC_NO_INSTANCE_SET; | 694 | ctx->inst_no = MFC_NO_INSTANCE_SET; |
692 | ctx->state = MFCINST_FREE; | 695 | ctx->state = MFCINST_FREE; |
693 | wake_up(&ctx->queue); | ||
694 | goto irq_cleanup_hw; | 696 | goto irq_cleanup_hw; |
695 | 697 | ||
696 | case S5P_MFC_R2H_CMD_SYS_INIT_RET: | 698 | case S5P_MFC_R2H_CMD_SYS_INIT_RET: |
@@ -700,9 +702,9 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv) | |||
700 | if (ctx) | 702 | if (ctx) |
701 | clear_work_bit(ctx); | 703 | clear_work_bit(ctx); |
702 | s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); | 704 | s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); |
703 | wake_up_dev(dev, reason, err); | ||
704 | clear_bit(0, &dev->hw_lock); | 705 | clear_bit(0, &dev->hw_lock); |
705 | clear_bit(0, &dev->enter_suspend); | 706 | clear_bit(0, &dev->enter_suspend); |
707 | wake_up_dev(dev, reason, err); | ||
706 | break; | 708 | break; |
707 | 709 | ||
708 | case S5P_MFC_R2H_CMD_INIT_BUFFERS_RET: | 710 | case S5P_MFC_R2H_CMD_INIT_BUFFERS_RET: |
@@ -717,9 +719,7 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv) | |||
717 | break; | 719 | break; |
718 | 720 | ||
719 | case S5P_MFC_R2H_CMD_DPB_FLUSH_RET: | 721 | case S5P_MFC_R2H_CMD_DPB_FLUSH_RET: |
720 | clear_work_bit(ctx); | ||
721 | ctx->state = MFCINST_RUNNING; | 722 | ctx->state = MFCINST_RUNNING; |
722 | wake_up(&ctx->queue); | ||
723 | goto irq_cleanup_hw; | 723 | goto irq_cleanup_hw; |
724 | 724 | ||
725 | default: | 725 | default: |
@@ -738,6 +738,8 @@ irq_cleanup_hw: | |||
738 | mfc_err("Failed to unlock hw\n"); | 738 | mfc_err("Failed to unlock hw\n"); |
739 | 739 | ||
740 | s5p_mfc_clock_off(); | 740 | s5p_mfc_clock_off(); |
741 | clear_work_bit(ctx); | ||
742 | wake_up(&ctx->queue); | ||
741 | 743 | ||
742 | s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); | 744 | s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); |
743 | spin_unlock(&dev->irqlock); | 745 | spin_unlock(&dev->irqlock); |
@@ -764,6 +766,7 @@ static int s5p_mfc_open(struct file *file) | |||
764 | ret = -ENOMEM; | 766 | ret = -ENOMEM; |
765 | goto err_alloc; | 767 | goto err_alloc; |
766 | } | 768 | } |
769 | init_waitqueue_head(&ctx->queue); | ||
767 | v4l2_fh_init(&ctx->fh, vdev); | 770 | v4l2_fh_init(&ctx->fh, vdev); |
768 | file->private_data = &ctx->fh; | 771 | file->private_data = &ctx->fh; |
769 | v4l2_fh_add(&ctx->fh); | 772 | v4l2_fh_add(&ctx->fh); |
@@ -866,7 +869,6 @@ static int s5p_mfc_open(struct file *file) | |||
866 | /* Init videobuf2 queue for OUTPUT */ | 869 | /* Init videobuf2 queue for OUTPUT */ |
867 | q = &ctx->vq_src; | 870 | q = &ctx->vq_src; |
868 | q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | 871 | q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
869 | q->io_modes = VB2_MMAP; | ||
870 | q->drv_priv = &ctx->fh; | 872 | q->drv_priv = &ctx->fh; |
871 | q->lock = &dev->mfc_mutex; | 873 | q->lock = &dev->mfc_mutex; |
872 | if (vdev == dev->vfd_dec) { | 874 | if (vdev == dev->vfd_dec) { |
@@ -899,7 +901,6 @@ static int s5p_mfc_open(struct file *file) | |||
899 | mfc_err("Failed to initialize videobuf2 queue(output)\n"); | 901 | mfc_err("Failed to initialize videobuf2 queue(output)\n"); |
900 | goto err_queue_init; | 902 | goto err_queue_init; |
901 | } | 903 | } |
902 | init_waitqueue_head(&ctx->queue); | ||
903 | mutex_unlock(&dev->mfc_mutex); | 904 | mutex_unlock(&dev->mfc_mutex); |
904 | mfc_debug_leave(); | 905 | mfc_debug_leave(); |
905 | return ret; | 906 | return ret; |
@@ -1106,58 +1107,158 @@ static struct device *s5p_mfc_alloc_memdev(struct device *dev, | |||
1106 | return NULL; | 1107 | return NULL; |
1107 | } | 1108 | } |
1108 | 1109 | ||
1109 | static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) | 1110 | static int s5p_mfc_configure_2port_memory(struct s5p_mfc_dev *mfc_dev) |
1110 | { | 1111 | { |
1111 | struct device *dev = &mfc_dev->plat_dev->dev; | 1112 | struct device *dev = &mfc_dev->plat_dev->dev; |
1112 | 1113 | void *bank2_virt; | |
1113 | /* | 1114 | dma_addr_t bank2_dma_addr; |
1114 | * When IOMMU is available, we cannot use the default configuration, | 1115 | unsigned long align_size = 1 << MFC_BASE_ALIGN_ORDER; |
1115 | * because of MFC firmware requirements: address space limited to | 1116 | int ret; |
1116 | * 256M and non-zero default start address. | ||
1117 | * This is still simplified, not optimal configuration, but for now | ||
1118 | * IOMMU core doesn't allow to configure device's IOMMUs channel | ||
1119 | * separately. | ||
1120 | */ | ||
1121 | if (exynos_is_iommu_available(dev)) { | ||
1122 | int ret = exynos_configure_iommu(dev, S5P_MFC_IOMMU_DMA_BASE, | ||
1123 | S5P_MFC_IOMMU_DMA_SIZE); | ||
1124 | if (ret == 0) | ||
1125 | mfc_dev->mem_dev_l = mfc_dev->mem_dev_r = dev; | ||
1126 | return ret; | ||
1127 | } | ||
1128 | 1117 | ||
1129 | /* | 1118 | /* |
1130 | * Create and initialize virtual devices for accessing | 1119 | * Create and initialize virtual devices for accessing |
1131 | * reserved memory regions. | 1120 | * reserved memory regions. |
1132 | */ | 1121 | */ |
1133 | mfc_dev->mem_dev_l = s5p_mfc_alloc_memdev(dev, "left", | 1122 | mfc_dev->mem_dev[BANK_L_CTX] = s5p_mfc_alloc_memdev(dev, "left", |
1134 | MFC_BANK1_ALLOC_CTX); | 1123 | BANK_L_CTX); |
1135 | if (!mfc_dev->mem_dev_l) | 1124 | if (!mfc_dev->mem_dev[BANK_L_CTX]) |
1136 | return -ENODEV; | 1125 | return -ENODEV; |
1137 | mfc_dev->mem_dev_r = s5p_mfc_alloc_memdev(dev, "right", | 1126 | mfc_dev->mem_dev[BANK_R_CTX] = s5p_mfc_alloc_memdev(dev, "right", |
1138 | MFC_BANK2_ALLOC_CTX); | 1127 | BANK_R_CTX); |
1139 | if (!mfc_dev->mem_dev_r) { | 1128 | if (!mfc_dev->mem_dev[BANK_R_CTX]) { |
1140 | device_unregister(mfc_dev->mem_dev_l); | 1129 | device_unregister(mfc_dev->mem_dev[BANK_L_CTX]); |
1141 | return -ENODEV; | 1130 | return -ENODEV; |
1142 | } | 1131 | } |
1143 | 1132 | ||
1133 | /* Allocate memory for firmware and initialize both banks addresses */ | ||
1134 | ret = s5p_mfc_alloc_firmware(mfc_dev); | ||
1135 | if (ret) { | ||
1136 | device_unregister(mfc_dev->mem_dev[BANK_R_CTX]); | ||
1137 | device_unregister(mfc_dev->mem_dev[BANK_L_CTX]); | ||
1138 | return ret; | ||
1139 | } | ||
1140 | |||
1141 | mfc_dev->dma_base[BANK_L_CTX] = mfc_dev->fw_buf.dma; | ||
1142 | |||
1143 | bank2_virt = dma_alloc_coherent(mfc_dev->mem_dev[BANK_R_CTX], | ||
1144 | align_size, &bank2_dma_addr, GFP_KERNEL); | ||
1145 | if (!bank2_virt) { | ||
1146 | mfc_err("Allocating bank2 base failed\n"); | ||
1147 | s5p_mfc_release_firmware(mfc_dev); | ||
1148 | device_unregister(mfc_dev->mem_dev[BANK_R_CTX]); | ||
1149 | device_unregister(mfc_dev->mem_dev[BANK_L_CTX]); | ||
1150 | return -ENOMEM; | ||
1151 | } | ||
1152 | |||
1153 | /* Valid buffers passed to MFC encoder with LAST_FRAME command | ||
1154 | * should not have address of bank2 - MFC will treat it as a null frame. | ||
1155 | * To avoid such situation we set bank2 address below the pool address. | ||
1156 | */ | ||
1157 | mfc_dev->dma_base[BANK_R_CTX] = bank2_dma_addr - align_size; | ||
1158 | |||
1159 | dma_free_coherent(mfc_dev->mem_dev[BANK_R_CTX], align_size, bank2_virt, | ||
1160 | bank2_dma_addr); | ||
1161 | |||
1162 | vb2_dma_contig_set_max_seg_size(mfc_dev->mem_dev[BANK_L_CTX], | ||
1163 | DMA_BIT_MASK(32)); | ||
1164 | vb2_dma_contig_set_max_seg_size(mfc_dev->mem_dev[BANK_R_CTX], | ||
1165 | DMA_BIT_MASK(32)); | ||
1166 | |||
1144 | return 0; | 1167 | return 0; |
1145 | } | 1168 | } |
1146 | 1169 | ||
1147 | static void s5p_mfc_unconfigure_dma_memory(struct s5p_mfc_dev *mfc_dev) | 1170 | static void s5p_mfc_unconfigure_2port_memory(struct s5p_mfc_dev *mfc_dev) |
1171 | { | ||
1172 | device_unregister(mfc_dev->mem_dev[BANK_L_CTX]); | ||
1173 | device_unregister(mfc_dev->mem_dev[BANK_R_CTX]); | ||
1174 | vb2_dma_contig_clear_max_seg_size(mfc_dev->mem_dev[BANK_L_CTX]); | ||
1175 | vb2_dma_contig_clear_max_seg_size(mfc_dev->mem_dev[BANK_R_CTX]); | ||
1176 | } | ||
1177 | |||
1178 | static int s5p_mfc_configure_common_memory(struct s5p_mfc_dev *mfc_dev) | ||
1148 | { | 1179 | { |
1149 | struct device *dev = &mfc_dev->plat_dev->dev; | 1180 | struct device *dev = &mfc_dev->plat_dev->dev; |
1181 | unsigned long mem_size = SZ_4M; | ||
1182 | unsigned int bitmap_size; | ||
1150 | 1183 | ||
1151 | if (exynos_is_iommu_available(dev)) { | 1184 | if (IS_ENABLED(CONFIG_DMA_CMA) || exynos_is_iommu_available(dev)) |
1152 | exynos_unconfigure_iommu(dev); | 1185 | mem_size = SZ_8M; |
1153 | return; | 1186 | |
1187 | if (mfc_mem_size) | ||
1188 | mem_size = memparse(mfc_mem_size, NULL); | ||
1189 | |||
1190 | bitmap_size = BITS_TO_LONGS(mem_size >> PAGE_SHIFT) * sizeof(long); | ||
1191 | |||
1192 | mfc_dev->mem_bitmap = kzalloc(bitmap_size, GFP_KERNEL); | ||
1193 | if (!mfc_dev->mem_bitmap) | ||
1194 | return -ENOMEM; | ||
1195 | |||
1196 | mfc_dev->mem_virt = dma_alloc_coherent(dev, mem_size, | ||
1197 | &mfc_dev->mem_base, GFP_KERNEL); | ||
1198 | if (!mfc_dev->mem_virt) { | ||
1199 | kfree(mfc_dev->mem_bitmap); | ||
1200 | dev_err(dev, "failed to preallocate %ld MiB for the firmware and context buffers\n", | ||
1201 | (mem_size / SZ_1M)); | ||
1202 | return -ENOMEM; | ||
1154 | } | 1203 | } |
1204 | mfc_dev->mem_size = mem_size; | ||
1205 | mfc_dev->dma_base[BANK_L_CTX] = mfc_dev->mem_base; | ||
1206 | mfc_dev->dma_base[BANK_R_CTX] = mfc_dev->mem_base; | ||
1207 | |||
1208 | /* | ||
1209 | * MFC hardware cannot handle 0 as a base address, so mark first 128K | ||
1210 | * as used (to keep required base alignment) and adjust base address | ||
1211 | */ | ||
1212 | if (mfc_dev->mem_base == (dma_addr_t)0) { | ||
1213 | unsigned int offset = 1 << MFC_BASE_ALIGN_ORDER; | ||
1214 | |||
1215 | bitmap_set(mfc_dev->mem_bitmap, 0, offset >> PAGE_SHIFT); | ||
1216 | mfc_dev->dma_base[BANK_L_CTX] += offset; | ||
1217 | mfc_dev->dma_base[BANK_R_CTX] += offset; | ||
1218 | } | ||
1219 | |||
1220 | /* Firmware allocation cannot fail in this case */ | ||
1221 | s5p_mfc_alloc_firmware(mfc_dev); | ||
1155 | 1222 | ||
1156 | device_unregister(mfc_dev->mem_dev_l); | 1223 | mfc_dev->mem_dev[BANK_L_CTX] = mfc_dev->mem_dev[BANK_R_CTX] = dev; |
1157 | device_unregister(mfc_dev->mem_dev_r); | 1224 | vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); |
1225 | |||
1226 | dev_info(dev, "preallocated %ld MiB buffer for the firmware and context buffers\n", | ||
1227 | (mem_size / SZ_1M)); | ||
1228 | |||
1229 | return 0; | ||
1230 | } | ||
1231 | |||
1232 | static void s5p_mfc_unconfigure_common_memory(struct s5p_mfc_dev *mfc_dev) | ||
1233 | { | ||
1234 | struct device *dev = &mfc_dev->plat_dev->dev; | ||
1235 | |||
1236 | dma_free_coherent(dev, mfc_dev->mem_size, mfc_dev->mem_virt, | ||
1237 | mfc_dev->mem_base); | ||
1238 | kfree(mfc_dev->mem_bitmap); | ||
1239 | vb2_dma_contig_clear_max_seg_size(dev); | ||
1240 | } | ||
1241 | |||
1242 | static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) | ||
1243 | { | ||
1244 | struct device *dev = &mfc_dev->plat_dev->dev; | ||
1245 | |||
1246 | if (exynos_is_iommu_available(dev) || !IS_TWOPORT(mfc_dev)) | ||
1247 | return s5p_mfc_configure_common_memory(mfc_dev); | ||
1248 | else | ||
1249 | return s5p_mfc_configure_2port_memory(mfc_dev); | ||
1158 | } | 1250 | } |
1159 | 1251 | ||
1160 | static void *mfc_get_drv_data(struct platform_device *pdev); | 1252 | static void s5p_mfc_unconfigure_dma_memory(struct s5p_mfc_dev *mfc_dev) |
1253 | { | ||
1254 | struct device *dev = &mfc_dev->plat_dev->dev; | ||
1255 | |||
1256 | s5p_mfc_release_firmware(mfc_dev); | ||
1257 | if (exynos_is_iommu_available(dev) || !IS_TWOPORT(mfc_dev)) | ||
1258 | s5p_mfc_unconfigure_common_memory(mfc_dev); | ||
1259 | else | ||
1260 | s5p_mfc_unconfigure_2port_memory(mfc_dev); | ||
1261 | } | ||
1161 | 1262 | ||
1162 | /* MFC probe function */ | 1263 | /* MFC probe function */ |
1163 | static int s5p_mfc_probe(struct platform_device *pdev) | 1264 | static int s5p_mfc_probe(struct platform_device *pdev) |
@@ -1182,7 +1283,7 @@ static int s5p_mfc_probe(struct platform_device *pdev) | |||
1182 | return -ENODEV; | 1283 | return -ENODEV; |
1183 | } | 1284 | } |
1184 | 1285 | ||
1185 | dev->variant = mfc_get_drv_data(pdev); | 1286 | dev->variant = of_device_get_match_data(&pdev->dev); |
1186 | 1287 | ||
1187 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1288 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1188 | dev->regs_base = devm_ioremap_resource(&pdev->dev, res); | 1289 | dev->regs_base = devm_ioremap_resource(&pdev->dev, res); |
@@ -1214,19 +1315,18 @@ static int s5p_mfc_probe(struct platform_device *pdev) | |||
1214 | goto err_dma; | 1315 | goto err_dma; |
1215 | } | 1316 | } |
1216 | 1317 | ||
1217 | vb2_dma_contig_set_max_seg_size(dev->mem_dev_l, DMA_BIT_MASK(32)); | ||
1218 | vb2_dma_contig_set_max_seg_size(dev->mem_dev_r, DMA_BIT_MASK(32)); | ||
1219 | |||
1220 | mutex_init(&dev->mfc_mutex); | 1318 | mutex_init(&dev->mfc_mutex); |
1221 | 1319 | init_waitqueue_head(&dev->queue); | |
1222 | ret = s5p_mfc_alloc_firmware(dev); | 1320 | dev->hw_lock = 0; |
1223 | if (ret) | 1321 | INIT_WORK(&dev->watchdog_work, s5p_mfc_watchdog_worker); |
1224 | goto err_res; | 1322 | atomic_set(&dev->watchdog_cnt, 0); |
1323 | init_timer(&dev->watchdog_timer); | ||
1324 | dev->watchdog_timer.data = (unsigned long)dev; | ||
1325 | dev->watchdog_timer.function = s5p_mfc_watchdog; | ||
1225 | 1326 | ||
1226 | ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); | 1327 | ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); |
1227 | if (ret) | 1328 | if (ret) |
1228 | goto err_v4l2_dev_reg; | 1329 | goto err_v4l2_dev_reg; |
1229 | init_waitqueue_head(&dev->queue); | ||
1230 | 1330 | ||
1231 | /* decoder */ | 1331 | /* decoder */ |
1232 | vfd = video_device_alloc(); | 1332 | vfd = video_device_alloc(); |
@@ -1263,13 +1363,6 @@ static int s5p_mfc_probe(struct platform_device *pdev) | |||
1263 | video_set_drvdata(vfd, dev); | 1363 | video_set_drvdata(vfd, dev); |
1264 | platform_set_drvdata(pdev, dev); | 1364 | platform_set_drvdata(pdev, dev); |
1265 | 1365 | ||
1266 | dev->hw_lock = 0; | ||
1267 | INIT_WORK(&dev->watchdog_work, s5p_mfc_watchdog_worker); | ||
1268 | atomic_set(&dev->watchdog_cnt, 0); | ||
1269 | init_timer(&dev->watchdog_timer); | ||
1270 | dev->watchdog_timer.data = (unsigned long)dev; | ||
1271 | dev->watchdog_timer.function = s5p_mfc_watchdog; | ||
1272 | |||
1273 | /* Initialize HW ops and commands based on MFC version */ | 1366 | /* Initialize HW ops and commands based on MFC version */ |
1274 | s5p_mfc_init_hw_ops(dev); | 1367 | s5p_mfc_init_hw_ops(dev); |
1275 | s5p_mfc_init_hw_cmds(dev); | 1368 | s5p_mfc_init_hw_cmds(dev); |
@@ -1305,8 +1398,6 @@ err_enc_alloc: | |||
1305 | err_dec_alloc: | 1398 | err_dec_alloc: |
1306 | v4l2_device_unregister(&dev->v4l2_dev); | 1399 | v4l2_device_unregister(&dev->v4l2_dev); |
1307 | err_v4l2_dev_reg: | 1400 | err_v4l2_dev_reg: |
1308 | s5p_mfc_release_firmware(dev); | ||
1309 | err_res: | ||
1310 | s5p_mfc_final_pm(dev); | 1401 | s5p_mfc_final_pm(dev); |
1311 | err_dma: | 1402 | err_dma: |
1312 | s5p_mfc_unconfigure_dma_memory(dev); | 1403 | s5p_mfc_unconfigure_dma_memory(dev); |
@@ -1348,10 +1439,7 @@ static int s5p_mfc_remove(struct platform_device *pdev) | |||
1348 | video_device_release(dev->vfd_enc); | 1439 | video_device_release(dev->vfd_enc); |
1349 | video_device_release(dev->vfd_dec); | 1440 | video_device_release(dev->vfd_dec); |
1350 | v4l2_device_unregister(&dev->v4l2_dev); | 1441 | v4l2_device_unregister(&dev->v4l2_dev); |
1351 | s5p_mfc_release_firmware(dev); | ||
1352 | s5p_mfc_unconfigure_dma_memory(dev); | 1442 | s5p_mfc_unconfigure_dma_memory(dev); |
1353 | vb2_dma_contig_clear_max_seg_size(dev->mem_dev_l); | ||
1354 | vb2_dma_contig_clear_max_seg_size(dev->mem_dev_r); | ||
1355 | 1443 | ||
1356 | s5p_mfc_final_pm(dev); | 1444 | s5p_mfc_final_pm(dev); |
1357 | return 0; | 1445 | return 0; |
@@ -1423,16 +1511,11 @@ static struct s5p_mfc_buf_size buf_size_v5 = { | |||
1423 | .priv = &mfc_buf_size_v5, | 1511 | .priv = &mfc_buf_size_v5, |
1424 | }; | 1512 | }; |
1425 | 1513 | ||
1426 | static struct s5p_mfc_buf_align mfc_buf_align_v5 = { | ||
1427 | .base = MFC_BASE_ALIGN_ORDER, | ||
1428 | }; | ||
1429 | |||
1430 | static struct s5p_mfc_variant mfc_drvdata_v5 = { | 1514 | static struct s5p_mfc_variant mfc_drvdata_v5 = { |
1431 | .version = MFC_VERSION, | 1515 | .version = MFC_VERSION, |
1432 | .version_bit = MFC_V5_BIT, | 1516 | .version_bit = MFC_V5_BIT, |
1433 | .port_num = MFC_NUM_PORTS, | 1517 | .port_num = MFC_NUM_PORTS, |
1434 | .buf_size = &buf_size_v5, | 1518 | .buf_size = &buf_size_v5, |
1435 | .buf_align = &mfc_buf_align_v5, | ||
1436 | .fw_name[0] = "s5p-mfc.fw", | 1519 | .fw_name[0] = "s5p-mfc.fw", |
1437 | .clk_names = {"mfc", "sclk_mfc"}, | 1520 | .clk_names = {"mfc", "sclk_mfc"}, |
1438 | .num_clocks = 2, | 1521 | .num_clocks = 2, |
@@ -1453,16 +1536,11 @@ static struct s5p_mfc_buf_size buf_size_v6 = { | |||
1453 | .priv = &mfc_buf_size_v6, | 1536 | .priv = &mfc_buf_size_v6, |
1454 | }; | 1537 | }; |
1455 | 1538 | ||
1456 | static struct s5p_mfc_buf_align mfc_buf_align_v6 = { | ||
1457 | .base = 0, | ||
1458 | }; | ||
1459 | |||
1460 | static struct s5p_mfc_variant mfc_drvdata_v6 = { | 1539 | static struct s5p_mfc_variant mfc_drvdata_v6 = { |
1461 | .version = MFC_VERSION_V6, | 1540 | .version = MFC_VERSION_V6, |
1462 | .version_bit = MFC_V6_BIT, | 1541 | .version_bit = MFC_V6_BIT, |
1463 | .port_num = MFC_NUM_PORTS_V6, | 1542 | .port_num = MFC_NUM_PORTS_V6, |
1464 | .buf_size = &buf_size_v6, | 1543 | .buf_size = &buf_size_v6, |
1465 | .buf_align = &mfc_buf_align_v6, | ||
1466 | .fw_name[0] = "s5p-mfc-v6.fw", | 1544 | .fw_name[0] = "s5p-mfc-v6.fw", |
1467 | /* | 1545 | /* |
1468 | * v6-v2 firmware contains bug fixes and interface change | 1546 | * v6-v2 firmware contains bug fixes and interface change |
@@ -1487,16 +1565,11 @@ static struct s5p_mfc_buf_size buf_size_v7 = { | |||
1487 | .priv = &mfc_buf_size_v7, | 1565 | .priv = &mfc_buf_size_v7, |
1488 | }; | 1566 | }; |
1489 | 1567 | ||
1490 | static struct s5p_mfc_buf_align mfc_buf_align_v7 = { | ||
1491 | .base = 0, | ||
1492 | }; | ||
1493 | |||
1494 | static struct s5p_mfc_variant mfc_drvdata_v7 = { | 1568 | static struct s5p_mfc_variant mfc_drvdata_v7 = { |
1495 | .version = MFC_VERSION_V7, | 1569 | .version = MFC_VERSION_V7, |
1496 | .version_bit = MFC_V7_BIT, | 1570 | .version_bit = MFC_V7_BIT, |
1497 | .port_num = MFC_NUM_PORTS_V7, | 1571 | .port_num = MFC_NUM_PORTS_V7, |
1498 | .buf_size = &buf_size_v7, | 1572 | .buf_size = &buf_size_v7, |
1499 | .buf_align = &mfc_buf_align_v7, | ||
1500 | .fw_name[0] = "s5p-mfc-v7.fw", | 1573 | .fw_name[0] = "s5p-mfc-v7.fw", |
1501 | .clk_names = {"mfc", "sclk_mfc"}, | 1574 | .clk_names = {"mfc", "sclk_mfc"}, |
1502 | .num_clocks = 2, | 1575 | .num_clocks = 2, |
@@ -1516,16 +1589,11 @@ static struct s5p_mfc_buf_size buf_size_v8 = { | |||
1516 | .priv = &mfc_buf_size_v8, | 1589 | .priv = &mfc_buf_size_v8, |
1517 | }; | 1590 | }; |
1518 | 1591 | ||
1519 | static struct s5p_mfc_buf_align mfc_buf_align_v8 = { | ||
1520 | .base = 0, | ||
1521 | }; | ||
1522 | |||
1523 | static struct s5p_mfc_variant mfc_drvdata_v8 = { | 1592 | static struct s5p_mfc_variant mfc_drvdata_v8 = { |
1524 | .version = MFC_VERSION_V8, | 1593 | .version = MFC_VERSION_V8, |
1525 | .version_bit = MFC_V8_BIT, | 1594 | .version_bit = MFC_V8_BIT, |
1526 | .port_num = MFC_NUM_PORTS_V8, | 1595 | .port_num = MFC_NUM_PORTS_V8, |
1527 | .buf_size = &buf_size_v8, | 1596 | .buf_size = &buf_size_v8, |
1528 | .buf_align = &mfc_buf_align_v8, | ||
1529 | .fw_name[0] = "s5p-mfc-v8.fw", | 1597 | .fw_name[0] = "s5p-mfc-v8.fw", |
1530 | .clk_names = {"mfc"}, | 1598 | .clk_names = {"mfc"}, |
1531 | .num_clocks = 1, | 1599 | .num_clocks = 1, |
@@ -1536,7 +1604,6 @@ static struct s5p_mfc_variant mfc_drvdata_v8_5433 = { | |||
1536 | .version_bit = MFC_V8_BIT, | 1604 | .version_bit = MFC_V8_BIT, |
1537 | .port_num = MFC_NUM_PORTS_V8, | 1605 | .port_num = MFC_NUM_PORTS_V8, |
1538 | .buf_size = &buf_size_v8, | 1606 | .buf_size = &buf_size_v8, |
1539 | .buf_align = &mfc_buf_align_v8, | ||
1540 | .fw_name[0] = "s5p-mfc-v8.fw", | 1607 | .fw_name[0] = "s5p-mfc-v8.fw", |
1541 | .clk_names = {"pclk", "aclk", "aclk_xiu"}, | 1608 | .clk_names = {"pclk", "aclk", "aclk_xiu"}, |
1542 | .num_clocks = 3, | 1609 | .num_clocks = 3, |
@@ -1563,18 +1630,6 @@ static const struct of_device_id exynos_mfc_match[] = { | |||
1563 | }; | 1630 | }; |
1564 | MODULE_DEVICE_TABLE(of, exynos_mfc_match); | 1631 | MODULE_DEVICE_TABLE(of, exynos_mfc_match); |
1565 | 1632 | ||
1566 | static void *mfc_get_drv_data(struct platform_device *pdev) | ||
1567 | { | ||
1568 | struct s5p_mfc_variant *driver_data = NULL; | ||
1569 | const struct of_device_id *match; | ||
1570 | |||
1571 | match = of_match_node(exynos_mfc_match, pdev->dev.of_node); | ||
1572 | if (match) | ||
1573 | driver_data = (struct s5p_mfc_variant *)match->data; | ||
1574 | |||
1575 | return driver_data; | ||
1576 | } | ||
1577 | |||
1578 | static struct platform_driver s5p_mfc_driver = { | 1633 | static struct platform_driver s5p_mfc_driver = { |
1579 | .probe = s5p_mfc_probe, | 1634 | .probe = s5p_mfc_probe, |
1580 | .remove = s5p_mfc_remove, | 1635 | .remove = s5p_mfc_remove, |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c index 8c4739ca16d6..4c80bb4243be 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c | |||
@@ -47,7 +47,7 @@ static int s5p_mfc_sys_init_cmd_v5(struct s5p_mfc_dev *dev) | |||
47 | struct s5p_mfc_cmd_args h2r_args; | 47 | struct s5p_mfc_cmd_args h2r_args; |
48 | 48 | ||
49 | memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); | 49 | memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); |
50 | h2r_args.arg[0] = dev->fw_size; | 50 | h2r_args.arg[0] = dev->fw_buf.size; |
51 | return s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_SYS_INIT, | 51 | return s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_SYS_INIT, |
52 | &h2r_args); | 52 | &h2r_args); |
53 | } | 53 | } |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index ab23236aa942..4220914529b2 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h | |||
@@ -33,8 +33,9 @@ | |||
33 | * while mmaping */ | 33 | * while mmaping */ |
34 | #define DST_QUEUE_OFF_BASE (1 << 30) | 34 | #define DST_QUEUE_OFF_BASE (1 << 30) |
35 | 35 | ||
36 | #define MFC_BANK1_ALLOC_CTX 0 | 36 | #define BANK_L_CTX 0 |
37 | #define MFC_BANK2_ALLOC_CTX 1 | 37 | #define BANK_R_CTX 1 |
38 | #define BANK_CTX_NUM 2 | ||
38 | 39 | ||
39 | #define MFC_BANK1_ALIGN_ORDER 13 | 40 | #define MFC_BANK1_ALIGN_ORDER 13 |
40 | #define MFC_BANK2_ALIGN_ORDER 13 | 41 | #define MFC_BANK2_ALIGN_ORDER 13 |
@@ -44,14 +45,6 @@ | |||
44 | 45 | ||
45 | #include <media/videobuf2-dma-contig.h> | 46 | #include <media/videobuf2-dma-contig.h> |
46 | 47 | ||
47 | static inline dma_addr_t s5p_mfc_mem_cookie(void *a, void *b) | ||
48 | { | ||
49 | /* Same functionality as the vb2_dma_contig_plane_paddr */ | ||
50 | dma_addr_t *paddr = vb2_dma_contig_memops.cookie(b); | ||
51 | |||
52 | return *paddr; | ||
53 | } | ||
54 | |||
55 | /* MFC definitions */ | 48 | /* MFC definitions */ |
56 | #define MFC_MAX_EXTRA_DPB 5 | 49 | #define MFC_MAX_EXTRA_DPB 5 |
57 | #define MFC_MAX_BUFFERS 32 | 50 | #define MFC_MAX_BUFFERS 32 |
@@ -200,7 +193,7 @@ struct s5p_mfc_buf { | |||
200 | */ | 193 | */ |
201 | struct s5p_mfc_pm { | 194 | struct s5p_mfc_pm { |
202 | struct clk *clock_gate; | 195 | struct clk *clock_gate; |
203 | const char **clk_names; | 196 | const char * const *clk_names; |
204 | struct clk *clocks[MFC_MAX_CLOCKS]; | 197 | struct clk *clocks[MFC_MAX_CLOCKS]; |
205 | int num_clocks; | 198 | int num_clocks; |
206 | bool use_clock_gating; | 199 | bool use_clock_gating; |
@@ -229,16 +222,11 @@ struct s5p_mfc_buf_size { | |||
229 | void *priv; | 222 | void *priv; |
230 | }; | 223 | }; |
231 | 224 | ||
232 | struct s5p_mfc_buf_align { | ||
233 | unsigned int base; | ||
234 | }; | ||
235 | |||
236 | struct s5p_mfc_variant { | 225 | struct s5p_mfc_variant { |
237 | unsigned int version; | 226 | unsigned int version; |
238 | unsigned int port_num; | 227 | unsigned int port_num; |
239 | u32 version_bit; | 228 | u32 version_bit; |
240 | struct s5p_mfc_buf_size *buf_size; | 229 | struct s5p_mfc_buf_size *buf_size; |
241 | struct s5p_mfc_buf_align *buf_align; | ||
242 | char *fw_name[MFC_FW_MAX_VERSIONS]; | 230 | char *fw_name[MFC_FW_MAX_VERSIONS]; |
243 | const char *clk_names[MFC_MAX_CLOCKS]; | 231 | const char *clk_names[MFC_MAX_CLOCKS]; |
244 | int num_clocks; | 232 | int num_clocks; |
@@ -252,12 +240,14 @@ struct s5p_mfc_variant { | |||
252 | * buffer accessed by driver | 240 | * buffer accessed by driver |
253 | * @dma: DMA address, only valid when kernel DMA API used | 241 | * @dma: DMA address, only valid when kernel DMA API used |
254 | * @size: size of the buffer | 242 | * @size: size of the buffer |
243 | * @ctx: memory context (bank) used for this allocation | ||
255 | */ | 244 | */ |
256 | struct s5p_mfc_priv_buf { | 245 | struct s5p_mfc_priv_buf { |
257 | unsigned long ofs; | 246 | unsigned long ofs; |
258 | void *virt; | 247 | void *virt; |
259 | dma_addr_t dma; | 248 | dma_addr_t dma; |
260 | size_t size; | 249 | size_t size; |
250 | unsigned int ctx; | ||
261 | }; | 251 | }; |
262 | 252 | ||
263 | /** | 253 | /** |
@@ -267,8 +257,7 @@ struct s5p_mfc_priv_buf { | |||
267 | * @vfd_dec: video device for decoding | 257 | * @vfd_dec: video device for decoding |
268 | * @vfd_enc: video device for encoding | 258 | * @vfd_enc: video device for encoding |
269 | * @plat_dev: platform device | 259 | * @plat_dev: platform device |
270 | * @mem_dev_l: child device of the left memory bank (0) | 260 | * @mem_dev[]: child devices of the memory banks |
271 | * @mem_dev_r: child device of the right memory bank (1) | ||
272 | * @regs_base: base address of the MFC hw registers | 261 | * @regs_base: base address of the MFC hw registers |
273 | * @irq: irq resource | 262 | * @irq: irq resource |
274 | * @dec_ctrl_handler: control framework handler for decoding | 263 | * @dec_ctrl_handler: control framework handler for decoding |
@@ -286,8 +275,7 @@ struct s5p_mfc_priv_buf { | |||
286 | * @queue: waitqueue for waiting for completion of device commands | 275 | * @queue: waitqueue for waiting for completion of device commands |
287 | * @fw_size: size of firmware | 276 | * @fw_size: size of firmware |
288 | * @fw_virt_addr: virtual firmware address | 277 | * @fw_virt_addr: virtual firmware address |
289 | * @bank1: address of the beginning of bank 1 memory | 278 | * @dma_base[]: address of the beginning of memory banks |
290 | * @bank2: address of the beginning of bank 2 memory | ||
291 | * @hw_lock: used for hardware locking | 279 | * @hw_lock: used for hardware locking |
292 | * @ctx: array of driver contexts | 280 | * @ctx: array of driver contexts |
293 | * @curr_ctx: number of the currently running context | 281 | * @curr_ctx: number of the currently running context |
@@ -310,14 +298,13 @@ struct s5p_mfc_dev { | |||
310 | struct video_device *vfd_dec; | 298 | struct video_device *vfd_dec; |
311 | struct video_device *vfd_enc; | 299 | struct video_device *vfd_enc; |
312 | struct platform_device *plat_dev; | 300 | struct platform_device *plat_dev; |
313 | struct device *mem_dev_l; | 301 | struct device *mem_dev[BANK_CTX_NUM]; |
314 | struct device *mem_dev_r; | ||
315 | void __iomem *regs_base; | 302 | void __iomem *regs_base; |
316 | int irq; | 303 | int irq; |
317 | struct v4l2_ctrl_handler dec_ctrl_handler; | 304 | struct v4l2_ctrl_handler dec_ctrl_handler; |
318 | struct v4l2_ctrl_handler enc_ctrl_handler; | 305 | struct v4l2_ctrl_handler enc_ctrl_handler; |
319 | struct s5p_mfc_pm pm; | 306 | struct s5p_mfc_pm pm; |
320 | struct s5p_mfc_variant *variant; | 307 | const struct s5p_mfc_variant *variant; |
321 | int num_inst; | 308 | int num_inst; |
322 | spinlock_t irqlock; /* lock when operating on context */ | 309 | spinlock_t irqlock; /* lock when operating on context */ |
323 | spinlock_t condlock; /* lock when changing/checking if a context is | 310 | spinlock_t condlock; /* lock when changing/checking if a context is |
@@ -327,10 +314,12 @@ struct s5p_mfc_dev { | |||
327 | int int_type; | 314 | int int_type; |
328 | unsigned int int_err; | 315 | unsigned int int_err; |
329 | wait_queue_head_t queue; | 316 | wait_queue_head_t queue; |
330 | size_t fw_size; | 317 | struct s5p_mfc_priv_buf fw_buf; |
331 | void *fw_virt_addr; | 318 | size_t mem_size; |
332 | dma_addr_t bank1; | 319 | dma_addr_t mem_base; |
333 | dma_addr_t bank2; | 320 | unsigned long *mem_bitmap; |
321 | void *mem_virt; | ||
322 | dma_addr_t dma_base[BANK_CTX_NUM]; | ||
334 | unsigned long hw_lock; | 323 | unsigned long hw_lock; |
335 | struct s5p_mfc_ctx *ctx[MFC_NUM_CONTEXTS]; | 324 | struct s5p_mfc_ctx *ctx[MFC_NUM_CONTEXTS]; |
336 | int curr_ctx; | 325 | int curr_ctx; |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c index cc888713b3b6..69ef9c23a99a 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c | |||
@@ -26,51 +26,22 @@ | |||
26 | /* Allocate memory for firmware */ | 26 | /* Allocate memory for firmware */ |
27 | int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev) | 27 | int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev) |
28 | { | 28 | { |
29 | void *bank2_virt; | 29 | struct s5p_mfc_priv_buf *fw_buf = &dev->fw_buf; |
30 | dma_addr_t bank2_dma_addr; | 30 | int err; |
31 | 31 | ||
32 | dev->fw_size = dev->variant->buf_size->fw; | 32 | fw_buf->size = dev->variant->buf_size->fw; |
33 | 33 | ||
34 | if (dev->fw_virt_addr) { | 34 | if (fw_buf->virt) { |
35 | mfc_err("Attempting to allocate firmware when it seems that it is already loaded\n"); | 35 | mfc_err("Attempting to allocate firmware when it seems that it is already loaded\n"); |
36 | return -ENOMEM; | 36 | return -ENOMEM; |
37 | } | 37 | } |
38 | 38 | ||
39 | dev->fw_virt_addr = dma_alloc_coherent(dev->mem_dev_l, dev->fw_size, | 39 | err = s5p_mfc_alloc_priv_buf(dev, BANK_L_CTX, &dev->fw_buf); |
40 | &dev->bank1, GFP_KERNEL); | 40 | if (err) { |
41 | |||
42 | if (!dev->fw_virt_addr) { | ||
43 | mfc_err("Allocating bitprocessor buffer failed\n"); | 41 | mfc_err("Allocating bitprocessor buffer failed\n"); |
44 | return -ENOMEM; | 42 | return err; |
45 | } | 43 | } |
46 | 44 | ||
47 | if (HAS_PORTNUM(dev) && IS_TWOPORT(dev)) { | ||
48 | bank2_virt = dma_alloc_coherent(dev->mem_dev_r, 1 << MFC_BASE_ALIGN_ORDER, | ||
49 | &bank2_dma_addr, GFP_KERNEL); | ||
50 | |||
51 | if (!bank2_virt) { | ||
52 | mfc_err("Allocating bank2 base failed\n"); | ||
53 | dma_free_coherent(dev->mem_dev_l, dev->fw_size, | ||
54 | dev->fw_virt_addr, dev->bank1); | ||
55 | dev->fw_virt_addr = NULL; | ||
56 | return -ENOMEM; | ||
57 | } | ||
58 | |||
59 | /* Valid buffers passed to MFC encoder with LAST_FRAME command | ||
60 | * should not have address of bank2 - MFC will treat it as a null frame. | ||
61 | * To avoid such situation we set bank2 address below the pool address. | ||
62 | */ | ||
63 | dev->bank2 = bank2_dma_addr - (1 << MFC_BASE_ALIGN_ORDER); | ||
64 | |||
65 | dma_free_coherent(dev->mem_dev_r, 1 << MFC_BASE_ALIGN_ORDER, | ||
66 | bank2_virt, bank2_dma_addr); | ||
67 | |||
68 | } else { | ||
69 | /* In this case bank2 can point to the same address as bank1. | ||
70 | * Firmware will always occupy the beginning of this area so it is | ||
71 | * impossible having a video frame buffer with zero address. */ | ||
72 | dev->bank2 = dev->bank1; | ||
73 | } | ||
74 | return 0; | 45 | return 0; |
75 | } | 46 | } |
76 | 47 | ||
@@ -99,17 +70,17 @@ int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev) | |||
99 | mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); | 70 | mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); |
100 | return -EINVAL; | 71 | return -EINVAL; |
101 | } | 72 | } |
102 | if (fw_blob->size > dev->fw_size) { | 73 | if (fw_blob->size > dev->fw_buf.size) { |
103 | mfc_err("MFC firmware is too big to be loaded\n"); | 74 | mfc_err("MFC firmware is too big to be loaded\n"); |
104 | release_firmware(fw_blob); | 75 | release_firmware(fw_blob); |
105 | return -ENOMEM; | 76 | return -ENOMEM; |
106 | } | 77 | } |
107 | if (!dev->fw_virt_addr) { | 78 | if (!dev->fw_buf.virt) { |
108 | mfc_err("MFC firmware is not allocated\n"); | 79 | mfc_err("MFC firmware is not allocated\n"); |
109 | release_firmware(fw_blob); | 80 | release_firmware(fw_blob); |
110 | return -EINVAL; | 81 | return -EINVAL; |
111 | } | 82 | } |
112 | memcpy(dev->fw_virt_addr, fw_blob->data, fw_blob->size); | 83 | memcpy(dev->fw_buf.virt, fw_blob->data, fw_blob->size); |
113 | wmb(); | 84 | wmb(); |
114 | release_firmware(fw_blob); | 85 | release_firmware(fw_blob); |
115 | mfc_debug_leave(); | 86 | mfc_debug_leave(); |
@@ -121,11 +92,7 @@ int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev) | |||
121 | { | 92 | { |
122 | /* Before calling this function one has to make sure | 93 | /* Before calling this function one has to make sure |
123 | * that MFC is no longer processing */ | 94 | * that MFC is no longer processing */ |
124 | if (!dev->fw_virt_addr) | 95 | s5p_mfc_release_priv_buf(dev, &dev->fw_buf); |
125 | return -EINVAL; | ||
126 | dma_free_coherent(dev->mem_dev_l, dev->fw_size, dev->fw_virt_addr, | ||
127 | dev->bank1); | ||
128 | dev->fw_virt_addr = NULL; | ||
129 | return 0; | 96 | return 0; |
130 | } | 97 | } |
131 | 98 | ||
@@ -210,13 +177,18 @@ int s5p_mfc_reset(struct s5p_mfc_dev *dev) | |||
210 | static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev) | 177 | static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev) |
211 | { | 178 | { |
212 | if (IS_MFCV6_PLUS(dev)) { | 179 | if (IS_MFCV6_PLUS(dev)) { |
213 | mfc_write(dev, dev->bank1, S5P_FIMV_RISC_BASE_ADDRESS_V6); | 180 | mfc_write(dev, dev->dma_base[BANK_L_CTX], |
214 | mfc_debug(2, "Base Address : %pad\n", &dev->bank1); | 181 | S5P_FIMV_RISC_BASE_ADDRESS_V6); |
182 | mfc_debug(2, "Base Address : %pad\n", | ||
183 | &dev->dma_base[BANK_L_CTX]); | ||
215 | } else { | 184 | } else { |
216 | mfc_write(dev, dev->bank1, S5P_FIMV_MC_DRAMBASE_ADR_A); | 185 | mfc_write(dev, dev->dma_base[BANK_L_CTX], |
217 | mfc_write(dev, dev->bank2, S5P_FIMV_MC_DRAMBASE_ADR_B); | 186 | S5P_FIMV_MC_DRAMBASE_ADR_A); |
187 | mfc_write(dev, dev->dma_base[BANK_R_CTX], | ||
188 | S5P_FIMV_MC_DRAMBASE_ADR_B); | ||
218 | mfc_debug(2, "Bank1: %pad, Bank2: %pad\n", | 189 | mfc_debug(2, "Bank1: %pad, Bank2: %pad\n", |
219 | &dev->bank1, &dev->bank2); | 190 | &dev->dma_base[BANK_L_CTX], |
191 | &dev->dma_base[BANK_R_CTX]); | ||
220 | } | 192 | } |
221 | } | 193 | } |
222 | 194 | ||
@@ -240,7 +212,7 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) | |||
240 | int ret; | 212 | int ret; |
241 | 213 | ||
242 | mfc_debug_enter(); | 214 | mfc_debug_enter(); |
243 | if (!dev->fw_virt_addr) { | 215 | if (!dev->fw_buf.virt) { |
244 | mfc_err("Firmware memory is not allocated.\n"); | 216 | mfc_err("Firmware memory is not allocated.\n"); |
245 | return -EINVAL; | 217 | return -EINVAL; |
246 | } | 218 | } |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h index 8e5df041edf7..45c807bf19cc 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h | |||
@@ -18,7 +18,6 @@ | |||
18 | int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev); | 18 | int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev); |
19 | int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev); | 19 | int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev); |
20 | int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev); | 20 | int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev); |
21 | int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev); | ||
22 | 21 | ||
23 | int s5p_mfc_init_hw(struct s5p_mfc_dev *dev); | 22 | int s5p_mfc_init_hw(struct s5p_mfc_dev *dev); |
24 | void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev); | 23 | void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev); |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index 367ef8e8dbf0..8937b0af7cb3 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c | |||
@@ -931,14 +931,14 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, | |||
931 | psize[1] = ctx->chroma_size; | 931 | psize[1] = ctx->chroma_size; |
932 | 932 | ||
933 | if (IS_MFCV6_PLUS(dev)) | 933 | if (IS_MFCV6_PLUS(dev)) |
934 | alloc_devs[0] = ctx->dev->mem_dev_l; | 934 | alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX]; |
935 | else | 935 | else |
936 | alloc_devs[0] = ctx->dev->mem_dev_r; | 936 | alloc_devs[0] = ctx->dev->mem_dev[BANK_R_CTX]; |
937 | alloc_devs[1] = ctx->dev->mem_dev_l; | 937 | alloc_devs[1] = ctx->dev->mem_dev[BANK_L_CTX]; |
938 | } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && | 938 | } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && |
939 | ctx->state == MFCINST_INIT) { | 939 | ctx->state == MFCINST_INIT) { |
940 | psize[0] = ctx->dec_src_buf_size; | 940 | psize[0] = ctx->dec_src_buf_size; |
941 | alloc_devs[0] = ctx->dev->mem_dev_l; | 941 | alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX]; |
942 | } else { | 942 | } else { |
943 | mfc_err("This video node is dedicated to decoding. Decoding not initialized\n"); | 943 | mfc_err("This video node is dedicated to decoding. Decoding not initialized\n"); |
944 | return -EINVAL; | 944 | return -EINVAL; |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index e39d9e06e299..2a5fd7c42cd5 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | |||
@@ -1832,7 +1832,7 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, | |||
1832 | if (*buf_count > MFC_MAX_BUFFERS) | 1832 | if (*buf_count > MFC_MAX_BUFFERS) |
1833 | *buf_count = MFC_MAX_BUFFERS; | 1833 | *buf_count = MFC_MAX_BUFFERS; |
1834 | psize[0] = ctx->enc_dst_buf_size; | 1834 | psize[0] = ctx->enc_dst_buf_size; |
1835 | alloc_devs[0] = ctx->dev->mem_dev_l; | 1835 | alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX]; |
1836 | } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | 1836 | } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { |
1837 | if (ctx->src_fmt) | 1837 | if (ctx->src_fmt) |
1838 | *plane_count = ctx->src_fmt->num_planes; | 1838 | *plane_count = ctx->src_fmt->num_planes; |
@@ -1848,11 +1848,11 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, | |||
1848 | psize[1] = ctx->chroma_size; | 1848 | psize[1] = ctx->chroma_size; |
1849 | 1849 | ||
1850 | if (IS_MFCV6_PLUS(dev)) { | 1850 | if (IS_MFCV6_PLUS(dev)) { |
1851 | alloc_devs[0] = ctx->dev->mem_dev_l; | 1851 | alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX]; |
1852 | alloc_devs[1] = ctx->dev->mem_dev_l; | 1852 | alloc_devs[1] = ctx->dev->mem_dev[BANK_L_CTX]; |
1853 | } else { | 1853 | } else { |
1854 | alloc_devs[0] = ctx->dev->mem_dev_r; | 1854 | alloc_devs[0] = ctx->dev->mem_dev[BANK_R_CTX]; |
1855 | alloc_devs[1] = ctx->dev->mem_dev_r; | 1855 | alloc_devs[1] = ctx->dev->mem_dev[BANK_R_CTX]; |
1856 | } | 1856 | } |
1857 | } else { | 1857 | } else { |
1858 | mfc_err("invalid queue type: %d\n", vq->type); | 1858 | mfc_err("invalid queue type: %d\n", vq->type); |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h b/drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h index 6962132ae8fa..76667924ee2a 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h | |||
@@ -11,54 +11,13 @@ | |||
11 | #ifndef S5P_MFC_IOMMU_H_ | 11 | #ifndef S5P_MFC_IOMMU_H_ |
12 | #define S5P_MFC_IOMMU_H_ | 12 | #define S5P_MFC_IOMMU_H_ |
13 | 13 | ||
14 | #define S5P_MFC_IOMMU_DMA_BASE 0x20000000lu | 14 | #if defined(CONFIG_EXYNOS_IOMMU) |
15 | #define S5P_MFC_IOMMU_DMA_SIZE SZ_256M | ||
16 | |||
17 | #if defined(CONFIG_EXYNOS_IOMMU) && defined(CONFIG_ARM_DMA_USE_IOMMU) | ||
18 | |||
19 | #include <asm/dma-iommu.h> | ||
20 | 15 | ||
21 | static inline bool exynos_is_iommu_available(struct device *dev) | 16 | static inline bool exynos_is_iommu_available(struct device *dev) |
22 | { | 17 | { |
23 | return dev->archdata.iommu != NULL; | 18 | return dev->archdata.iommu != NULL; |
24 | } | 19 | } |
25 | 20 | ||
26 | static inline void exynos_unconfigure_iommu(struct device *dev) | ||
27 | { | ||
28 | struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev); | ||
29 | |||
30 | arm_iommu_detach_device(dev); | ||
31 | arm_iommu_release_mapping(mapping); | ||
32 | } | ||
33 | |||
34 | static inline int exynos_configure_iommu(struct device *dev, | ||
35 | unsigned int base, unsigned int size) | ||
36 | { | ||
37 | struct dma_iommu_mapping *mapping = NULL; | ||
38 | int ret; | ||
39 | |||
40 | /* Disable the default mapping created by device core */ | ||
41 | if (to_dma_iommu_mapping(dev)) | ||
42 | exynos_unconfigure_iommu(dev); | ||
43 | |||
44 | mapping = arm_iommu_create_mapping(dev->bus, base, size); | ||
45 | if (IS_ERR(mapping)) { | ||
46 | pr_warn("Failed to create IOMMU mapping for device %s\n", | ||
47 | dev_name(dev)); | ||
48 | return PTR_ERR(mapping); | ||
49 | } | ||
50 | |||
51 | ret = arm_iommu_attach_device(dev, mapping); | ||
52 | if (ret) { | ||
53 | pr_warn("Failed to attached device %s to IOMMU_mapping\n", | ||
54 | dev_name(dev)); | ||
55 | arm_iommu_release_mapping(mapping); | ||
56 | return ret; | ||
57 | } | ||
58 | |||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | #else | 21 | #else |
63 | 22 | ||
64 | static inline bool exynos_is_iommu_available(struct device *dev) | 23 | static inline bool exynos_is_iommu_available(struct device *dev) |
@@ -66,14 +25,6 @@ static inline bool exynos_is_iommu_available(struct device *dev) | |||
66 | return false; | 25 | return false; |
67 | } | 26 | } |
68 | 27 | ||
69 | static inline int exynos_configure_iommu(struct device *dev, | ||
70 | unsigned int base, unsigned int size) | ||
71 | { | ||
72 | return -ENOSYS; | ||
73 | } | ||
74 | |||
75 | static inline void exynos_unconfigure_iommu(struct device *dev) { } | ||
76 | |||
77 | #endif | 28 | #endif |
78 | 29 | ||
79 | #endif /* S5P_MFC_IOMMU_H_ */ | 30 | #endif /* S5P_MFC_IOMMU_H_ */ |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c index 99f65a92a6be..7f33cf23947f 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c | |||
@@ -37,38 +37,91 @@ void s5p_mfc_init_regs(struct s5p_mfc_dev *dev) | |||
37 | dev->mfc_regs = s5p_mfc_init_regs_v6_plus(dev); | 37 | dev->mfc_regs = s5p_mfc_init_regs_v6_plus(dev); |
38 | } | 38 | } |
39 | 39 | ||
40 | int s5p_mfc_alloc_priv_buf(struct device *dev, dma_addr_t base, | 40 | int s5p_mfc_alloc_priv_buf(struct s5p_mfc_dev *dev, unsigned int mem_ctx, |
41 | struct s5p_mfc_priv_buf *b) | 41 | struct s5p_mfc_priv_buf *b) |
42 | { | 42 | { |
43 | unsigned int bits = dev->mem_size >> PAGE_SHIFT; | ||
44 | unsigned int count = b->size >> PAGE_SHIFT; | ||
45 | unsigned int align = (SZ_64K >> PAGE_SHIFT) - 1; | ||
46 | unsigned int start, offset; | ||
47 | |||
43 | mfc_debug(3, "Allocating priv: %zu\n", b->size); | 48 | mfc_debug(3, "Allocating priv: %zu\n", b->size); |
44 | 49 | ||
45 | b->virt = dma_alloc_coherent(dev, b->size, &b->dma, GFP_KERNEL); | 50 | if (dev->mem_virt) { |
51 | start = bitmap_find_next_zero_area(dev->mem_bitmap, bits, 0, count, align); | ||
52 | if (start > bits) | ||
53 | goto no_mem; | ||
46 | 54 | ||
47 | if (!b->virt) { | 55 | bitmap_set(dev->mem_bitmap, start, count); |
48 | mfc_err("Allocating private buffer of size %zu failed\n", | 56 | offset = start << PAGE_SHIFT; |
49 | b->size); | 57 | b->virt = dev->mem_virt + offset; |
50 | return -ENOMEM; | 58 | b->dma = dev->mem_base + offset; |
51 | } | 59 | } else { |
60 | struct device *mem_dev = dev->mem_dev[mem_ctx]; | ||
61 | dma_addr_t base = dev->dma_base[mem_ctx]; | ||
52 | 62 | ||
53 | if (b->dma < base) { | 63 | b->ctx = mem_ctx; |
54 | mfc_err("Invalid memory configuration - buffer (%pad) is below base memory address(%pad)\n", | 64 | b->virt = dma_alloc_coherent(mem_dev, b->size, &b->dma, GFP_KERNEL); |
55 | &b->dma, &base); | 65 | if (!b->virt) |
56 | dma_free_coherent(dev, b->size, b->virt, b->dma); | 66 | goto no_mem; |
57 | return -ENOMEM; | 67 | if (b->dma < base) { |
68 | mfc_err("Invalid memory configuration - buffer (%pad) is below base memory address(%pad)\n", | ||
69 | &b->dma, &base); | ||
70 | dma_free_coherent(mem_dev, b->size, b->virt, b->dma); | ||
71 | return -ENOMEM; | ||
72 | } | ||
58 | } | 73 | } |
59 | 74 | ||
60 | mfc_debug(3, "Allocated addr %p %pad\n", b->virt, &b->dma); | 75 | mfc_debug(3, "Allocated addr %p %pad\n", b->virt, &b->dma); |
61 | return 0; | 76 | return 0; |
77 | no_mem: | ||
78 | mfc_err("Allocating private buffer of size %zu failed\n", b->size); | ||
79 | return -ENOMEM; | ||
80 | } | ||
81 | |||
82 | int s5p_mfc_alloc_generic_buf(struct s5p_mfc_dev *dev, unsigned int mem_ctx, | ||
83 | struct s5p_mfc_priv_buf *b) | ||
84 | { | ||
85 | struct device *mem_dev = dev->mem_dev[mem_ctx]; | ||
86 | |||
87 | mfc_debug(3, "Allocating generic buf: %zu\n", b->size); | ||
88 | |||
89 | b->ctx = mem_ctx; | ||
90 | b->virt = dma_alloc_coherent(mem_dev, b->size, &b->dma, GFP_KERNEL); | ||
91 | if (!b->virt) | ||
92 | goto no_mem; | ||
93 | |||
94 | mfc_debug(3, "Allocated addr %p %pad\n", b->virt, &b->dma); | ||
95 | return 0; | ||
96 | no_mem: | ||
97 | mfc_err("Allocating generic buffer of size %zu failed\n", b->size); | ||
98 | return -ENOMEM; | ||
62 | } | 99 | } |
63 | 100 | ||
64 | void s5p_mfc_release_priv_buf(struct device *dev, | 101 | void s5p_mfc_release_priv_buf(struct s5p_mfc_dev *dev, |
65 | struct s5p_mfc_priv_buf *b) | 102 | struct s5p_mfc_priv_buf *b) |
66 | { | 103 | { |
67 | if (b->virt) { | 104 | if (dev->mem_virt) { |
68 | dma_free_coherent(dev, b->size, b->virt, b->dma); | 105 | unsigned int start = (b->dma - dev->mem_base) >> PAGE_SHIFT; |
69 | b->virt = NULL; | 106 | unsigned int count = b->size >> PAGE_SHIFT; |
70 | b->dma = 0; | 107 | |
71 | b->size = 0; | 108 | bitmap_clear(dev->mem_bitmap, start, count); |
109 | } else { | ||
110 | struct device *mem_dev = dev->mem_dev[b->ctx]; | ||
111 | |||
112 | dma_free_coherent(mem_dev, b->size, b->virt, b->dma); | ||
72 | } | 113 | } |
114 | b->virt = NULL; | ||
115 | b->dma = 0; | ||
116 | b->size = 0; | ||
73 | } | 117 | } |
74 | 118 | ||
119 | void s5p_mfc_release_generic_buf(struct s5p_mfc_dev *dev, | ||
120 | struct s5p_mfc_priv_buf *b) | ||
121 | { | ||
122 | struct device *mem_dev = dev->mem_dev[b->ctx]; | ||
123 | dma_free_coherent(mem_dev, b->size, b->virt, b->dma); | ||
124 | b->virt = NULL; | ||
125 | b->dma = 0; | ||
126 | b->size = 0; | ||
127 | } | ||
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h index b6ac417ab63e..16d553fcff08 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h | |||
@@ -315,10 +315,14 @@ struct s5p_mfc_hw_ops { | |||
315 | 315 | ||
316 | void s5p_mfc_init_hw_ops(struct s5p_mfc_dev *dev); | 316 | void s5p_mfc_init_hw_ops(struct s5p_mfc_dev *dev); |
317 | void s5p_mfc_init_regs(struct s5p_mfc_dev *dev); | 317 | void s5p_mfc_init_regs(struct s5p_mfc_dev *dev); |
318 | int s5p_mfc_alloc_priv_buf(struct device *dev, dma_addr_t base, | 318 | int s5p_mfc_alloc_priv_buf(struct s5p_mfc_dev *dev, unsigned int mem_ctx, |
319 | struct s5p_mfc_priv_buf *b); | 319 | struct s5p_mfc_priv_buf *b); |
320 | void s5p_mfc_release_priv_buf(struct device *dev, | 320 | void s5p_mfc_release_priv_buf(struct s5p_mfc_dev *dev, |
321 | struct s5p_mfc_priv_buf *b); | 321 | struct s5p_mfc_priv_buf *b); |
322 | int s5p_mfc_alloc_generic_buf(struct s5p_mfc_dev *dev, unsigned int mem_ctx, | ||
323 | struct s5p_mfc_priv_buf *b); | ||
324 | void s5p_mfc_release_generic_buf(struct s5p_mfc_dev *dev, | ||
325 | struct s5p_mfc_priv_buf *b); | ||
322 | 326 | ||
323 | 327 | ||
324 | #endif /* S5P_MFC_OPR_H_ */ | 328 | #endif /* S5P_MFC_OPR_H_ */ |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c index f4301d5bbd32..b41ee608c171 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c | |||
@@ -30,8 +30,8 @@ | |||
30 | #include <linux/mm.h> | 30 | #include <linux/mm.h> |
31 | #include <linux/sched.h> | 31 | #include <linux/sched.h> |
32 | 32 | ||
33 | #define OFFSETA(x) (((x) - dev->bank1) >> MFC_OFFSET_SHIFT) | 33 | #define OFFSETA(x) (((x) - dev->dma_base[BANK_L_CTX]) >> MFC_OFFSET_SHIFT) |
34 | #define OFFSETB(x) (((x) - dev->bank2) >> MFC_OFFSET_SHIFT) | 34 | #define OFFSETB(x) (((x) - dev->dma_base[BANK_R_CTX]) >> MFC_OFFSET_SHIFT) |
35 | 35 | ||
36 | /* Allocate temporary buffers for decoding */ | 36 | /* Allocate temporary buffers for decoding */ |
37 | static int s5p_mfc_alloc_dec_temp_buffers_v5(struct s5p_mfc_ctx *ctx) | 37 | static int s5p_mfc_alloc_dec_temp_buffers_v5(struct s5p_mfc_ctx *ctx) |
@@ -41,7 +41,7 @@ static int s5p_mfc_alloc_dec_temp_buffers_v5(struct s5p_mfc_ctx *ctx) | |||
41 | int ret; | 41 | int ret; |
42 | 42 | ||
43 | ctx->dsc.size = buf_size->dsc; | 43 | ctx->dsc.size = buf_size->dsc; |
44 | ret = s5p_mfc_alloc_priv_buf(dev->mem_dev_l, dev->bank1, &ctx->dsc); | 44 | ret = s5p_mfc_alloc_priv_buf(dev, BANK_L_CTX, &ctx->dsc); |
45 | if (ret) { | 45 | if (ret) { |
46 | mfc_err("Failed to allocate temporary buffer\n"); | 46 | mfc_err("Failed to allocate temporary buffer\n"); |
47 | return ret; | 47 | return ret; |
@@ -57,7 +57,7 @@ static int s5p_mfc_alloc_dec_temp_buffers_v5(struct s5p_mfc_ctx *ctx) | |||
57 | /* Release temporary buffers for decoding */ | 57 | /* Release temporary buffers for decoding */ |
58 | static void s5p_mfc_release_dec_desc_buffer_v5(struct s5p_mfc_ctx *ctx) | 58 | static void s5p_mfc_release_dec_desc_buffer_v5(struct s5p_mfc_ctx *ctx) |
59 | { | 59 | { |
60 | s5p_mfc_release_priv_buf(ctx->dev->mem_dev_l, &ctx->dsc); | 60 | s5p_mfc_release_priv_buf(ctx->dev, &ctx->dsc); |
61 | } | 61 | } |
62 | 62 | ||
63 | /* Allocate codec buffers */ | 63 | /* Allocate codec buffers */ |
@@ -172,8 +172,7 @@ static int s5p_mfc_alloc_codec_buffers_v5(struct s5p_mfc_ctx *ctx) | |||
172 | /* Allocate only if memory from bank 1 is necessary */ | 172 | /* Allocate only if memory from bank 1 is necessary */ |
173 | if (ctx->bank1.size > 0) { | 173 | if (ctx->bank1.size > 0) { |
174 | 174 | ||
175 | ret = s5p_mfc_alloc_priv_buf(dev->mem_dev_l, dev->bank1, | 175 | ret = s5p_mfc_alloc_priv_buf(dev, BANK_L_CTX, &ctx->bank1); |
176 | &ctx->bank1); | ||
177 | if (ret) { | 176 | if (ret) { |
178 | mfc_err("Failed to allocate Bank1 temporary buffer\n"); | 177 | mfc_err("Failed to allocate Bank1 temporary buffer\n"); |
179 | return ret; | 178 | return ret; |
@@ -182,11 +181,10 @@ static int s5p_mfc_alloc_codec_buffers_v5(struct s5p_mfc_ctx *ctx) | |||
182 | } | 181 | } |
183 | /* Allocate only if memory from bank 2 is necessary */ | 182 | /* Allocate only if memory from bank 2 is necessary */ |
184 | if (ctx->bank2.size > 0) { | 183 | if (ctx->bank2.size > 0) { |
185 | ret = s5p_mfc_alloc_priv_buf(dev->mem_dev_r, dev->bank2, | 184 | ret = s5p_mfc_alloc_priv_buf(dev, BANK_R_CTX, &ctx->bank2); |
186 | &ctx->bank2); | ||
187 | if (ret) { | 185 | if (ret) { |
188 | mfc_err("Failed to allocate Bank2 temporary buffer\n"); | 186 | mfc_err("Failed to allocate Bank2 temporary buffer\n"); |
189 | s5p_mfc_release_priv_buf(ctx->dev->mem_dev_l, &ctx->bank1); | 187 | s5p_mfc_release_priv_buf(ctx->dev, &ctx->bank1); |
190 | return ret; | 188 | return ret; |
191 | } | 189 | } |
192 | BUG_ON(ctx->bank2.dma & ((1 << MFC_BANK2_ALIGN_ORDER) - 1)); | 190 | BUG_ON(ctx->bank2.dma & ((1 << MFC_BANK2_ALIGN_ORDER) - 1)); |
@@ -197,8 +195,8 @@ static int s5p_mfc_alloc_codec_buffers_v5(struct s5p_mfc_ctx *ctx) | |||
197 | /* Release buffers allocated for codec */ | 195 | /* Release buffers allocated for codec */ |
198 | static void s5p_mfc_release_codec_buffers_v5(struct s5p_mfc_ctx *ctx) | 196 | static void s5p_mfc_release_codec_buffers_v5(struct s5p_mfc_ctx *ctx) |
199 | { | 197 | { |
200 | s5p_mfc_release_priv_buf(ctx->dev->mem_dev_l, &ctx->bank1); | 198 | s5p_mfc_release_priv_buf(ctx->dev, &ctx->bank1); |
201 | s5p_mfc_release_priv_buf(ctx->dev->mem_dev_r, &ctx->bank2); | 199 | s5p_mfc_release_priv_buf(ctx->dev, &ctx->bank2); |
202 | } | 200 | } |
203 | 201 | ||
204 | /* Allocate memory for instance data buffer */ | 202 | /* Allocate memory for instance data buffer */ |
@@ -214,7 +212,7 @@ static int s5p_mfc_alloc_instance_buffer_v5(struct s5p_mfc_ctx *ctx) | |||
214 | else | 212 | else |
215 | ctx->ctx.size = buf_size->non_h264_ctx; | 213 | ctx->ctx.size = buf_size->non_h264_ctx; |
216 | 214 | ||
217 | ret = s5p_mfc_alloc_priv_buf(dev->mem_dev_l, dev->bank1, &ctx->ctx); | 215 | ret = s5p_mfc_alloc_priv_buf(dev, BANK_L_CTX, &ctx->ctx); |
218 | if (ret) { | 216 | if (ret) { |
219 | mfc_err("Failed to allocate instance buffer\n"); | 217 | mfc_err("Failed to allocate instance buffer\n"); |
220 | return ret; | 218 | return ret; |
@@ -227,15 +225,15 @@ static int s5p_mfc_alloc_instance_buffer_v5(struct s5p_mfc_ctx *ctx) | |||
227 | 225 | ||
228 | /* Initialize shared memory */ | 226 | /* Initialize shared memory */ |
229 | ctx->shm.size = buf_size->shm; | 227 | ctx->shm.size = buf_size->shm; |
230 | ret = s5p_mfc_alloc_priv_buf(dev->mem_dev_l, dev->bank1, &ctx->shm); | 228 | ret = s5p_mfc_alloc_priv_buf(dev, BANK_L_CTX, &ctx->shm); |
231 | if (ret) { | 229 | if (ret) { |
232 | mfc_err("Failed to allocate shared memory buffer\n"); | 230 | mfc_err("Failed to allocate shared memory buffer\n"); |
233 | s5p_mfc_release_priv_buf(dev->mem_dev_l, &ctx->ctx); | 231 | s5p_mfc_release_priv_buf(dev, &ctx->ctx); |
234 | return ret; | 232 | return ret; |
235 | } | 233 | } |
236 | 234 | ||
237 | /* shared memory offset only keeps the offset from base (port a) */ | 235 | /* shared memory offset only keeps the offset from base (port a) */ |
238 | ctx->shm.ofs = ctx->shm.dma - dev->bank1; | 236 | ctx->shm.ofs = ctx->shm.dma - dev->dma_base[BANK_L_CTX]; |
239 | BUG_ON(ctx->shm.ofs & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); | 237 | BUG_ON(ctx->shm.ofs & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); |
240 | 238 | ||
241 | memset(ctx->shm.virt, 0, buf_size->shm); | 239 | memset(ctx->shm.virt, 0, buf_size->shm); |
@@ -246,8 +244,8 @@ static int s5p_mfc_alloc_instance_buffer_v5(struct s5p_mfc_ctx *ctx) | |||
246 | /* Release instance buffer */ | 244 | /* Release instance buffer */ |
247 | static void s5p_mfc_release_instance_buffer_v5(struct s5p_mfc_ctx *ctx) | 245 | static void s5p_mfc_release_instance_buffer_v5(struct s5p_mfc_ctx *ctx) |
248 | { | 246 | { |
249 | s5p_mfc_release_priv_buf(ctx->dev->mem_dev_l, &ctx->ctx); | 247 | s5p_mfc_release_priv_buf(ctx->dev, &ctx->ctx); |
250 | s5p_mfc_release_priv_buf(ctx->dev->mem_dev_l, &ctx->shm); | 248 | s5p_mfc_release_priv_buf(ctx->dev, &ctx->shm); |
251 | } | 249 | } |
252 | 250 | ||
253 | static int s5p_mfc_alloc_dev_context_buffer_v5(struct s5p_mfc_dev *dev) | 251 | static int s5p_mfc_alloc_dev_context_buffer_v5(struct s5p_mfc_dev *dev) |
@@ -534,10 +532,10 @@ static void s5p_mfc_get_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx, | |||
534 | { | 532 | { |
535 | struct s5p_mfc_dev *dev = ctx->dev; | 533 | struct s5p_mfc_dev *dev = ctx->dev; |
536 | 534 | ||
537 | *y_addr = dev->bank2 + (mfc_read(dev, S5P_FIMV_ENCODED_Y_ADDR) | 535 | *y_addr = dev->dma_base[BANK_R_CTX] + |
538 | << MFC_OFFSET_SHIFT); | 536 | (mfc_read(dev, S5P_FIMV_ENCODED_Y_ADDR) << MFC_OFFSET_SHIFT); |
539 | *c_addr = dev->bank2 + (mfc_read(dev, S5P_FIMV_ENCODED_C_ADDR) | 537 | *c_addr = dev->dma_base[BANK_R_CTX] + |
540 | << MFC_OFFSET_SHIFT); | 538 | (mfc_read(dev, S5P_FIMV_ENCODED_C_ADDR) << MFC_OFFSET_SHIFT); |
541 | } | 539 | } |
542 | 540 | ||
543 | /* Set encoding ref & codec buffer */ | 541 | /* Set encoding ref & codec buffer */ |
@@ -1214,7 +1212,8 @@ static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) | |||
1214 | } | 1212 | } |
1215 | if (list_empty(&ctx->src_queue)) { | 1213 | if (list_empty(&ctx->src_queue)) { |
1216 | /* send null frame */ | 1214 | /* send null frame */ |
1217 | s5p_mfc_set_enc_frame_buffer_v5(ctx, dev->bank2, dev->bank2); | 1215 | s5p_mfc_set_enc_frame_buffer_v5(ctx, dev->dma_base[BANK_R_CTX], |
1216 | dev->dma_base[BANK_R_CTX]); | ||
1218 | src_mb = NULL; | 1217 | src_mb = NULL; |
1219 | } else { | 1218 | } else { |
1220 | src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, | 1219 | src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, |
@@ -1222,8 +1221,9 @@ static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) | |||
1222 | src_mb->flags |= MFC_BUF_FLAG_USED; | 1221 | src_mb->flags |= MFC_BUF_FLAG_USED; |
1223 | if (src_mb->b->vb2_buf.planes[0].bytesused == 0) { | 1222 | if (src_mb->b->vb2_buf.planes[0].bytesused == 0) { |
1224 | /* send null frame */ | 1223 | /* send null frame */ |
1225 | s5p_mfc_set_enc_frame_buffer_v5(ctx, dev->bank2, | 1224 | s5p_mfc_set_enc_frame_buffer_v5(ctx, |
1226 | dev->bank2); | 1225 | dev->dma_base[BANK_R_CTX], |
1226 | dev->dma_base[BANK_R_CTX]); | ||
1227 | ctx->state = MFCINST_FINISHING; | 1227 | ctx->state = MFCINST_FINISHING; |
1228 | } else { | 1228 | } else { |
1229 | src_y_addr = vb2_dma_contig_plane_dma_addr( | 1229 | src_y_addr = vb2_dma_contig_plane_dma_addr( |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c index d6f207e859ab..85880e9106be 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | |||
@@ -239,8 +239,7 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) | |||
239 | 239 | ||
240 | /* Allocate only if memory from bank 1 is necessary */ | 240 | /* Allocate only if memory from bank 1 is necessary */ |
241 | if (ctx->bank1.size > 0) { | 241 | if (ctx->bank1.size > 0) { |
242 | ret = s5p_mfc_alloc_priv_buf(dev->mem_dev_l, dev->bank1, | 242 | ret = s5p_mfc_alloc_generic_buf(dev, BANK_L_CTX, &ctx->bank1); |
243 | &ctx->bank1); | ||
244 | if (ret) { | 243 | if (ret) { |
245 | mfc_err("Failed to allocate Bank1 memory\n"); | 244 | mfc_err("Failed to allocate Bank1 memory\n"); |
246 | return ret; | 245 | return ret; |
@@ -253,7 +252,7 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) | |||
253 | /* Release buffers allocated for codec */ | 252 | /* Release buffers allocated for codec */ |
254 | static void s5p_mfc_release_codec_buffers_v6(struct s5p_mfc_ctx *ctx) | 253 | static void s5p_mfc_release_codec_buffers_v6(struct s5p_mfc_ctx *ctx) |
255 | { | 254 | { |
256 | s5p_mfc_release_priv_buf(ctx->dev->mem_dev_l, &ctx->bank1); | 255 | s5p_mfc_release_generic_buf(ctx->dev, &ctx->bank1); |
257 | } | 256 | } |
258 | 257 | ||
259 | /* Allocate memory for instance data buffer */ | 258 | /* Allocate memory for instance data buffer */ |
@@ -292,7 +291,7 @@ static int s5p_mfc_alloc_instance_buffer_v6(struct s5p_mfc_ctx *ctx) | |||
292 | break; | 291 | break; |
293 | } | 292 | } |
294 | 293 | ||
295 | ret = s5p_mfc_alloc_priv_buf(dev->mem_dev_l, dev->bank1, &ctx->ctx); | 294 | ret = s5p_mfc_alloc_priv_buf(dev, BANK_L_CTX, &ctx->ctx); |
296 | if (ret) { | 295 | if (ret) { |
297 | mfc_err("Failed to allocate instance buffer\n"); | 296 | mfc_err("Failed to allocate instance buffer\n"); |
298 | return ret; | 297 | return ret; |
@@ -309,7 +308,7 @@ static int s5p_mfc_alloc_instance_buffer_v6(struct s5p_mfc_ctx *ctx) | |||
309 | /* Release instance buffer */ | 308 | /* Release instance buffer */ |
310 | static void s5p_mfc_release_instance_buffer_v6(struct s5p_mfc_ctx *ctx) | 309 | static void s5p_mfc_release_instance_buffer_v6(struct s5p_mfc_ctx *ctx) |
311 | { | 310 | { |
312 | s5p_mfc_release_priv_buf(ctx->dev->mem_dev_l, &ctx->ctx); | 311 | s5p_mfc_release_priv_buf(ctx->dev, &ctx->ctx); |
313 | } | 312 | } |
314 | 313 | ||
315 | /* Allocate context buffers for SYS_INIT */ | 314 | /* Allocate context buffers for SYS_INIT */ |
@@ -321,8 +320,7 @@ static int s5p_mfc_alloc_dev_context_buffer_v6(struct s5p_mfc_dev *dev) | |||
321 | mfc_debug_enter(); | 320 | mfc_debug_enter(); |
322 | 321 | ||
323 | dev->ctx_buf.size = buf_size->dev_ctx; | 322 | dev->ctx_buf.size = buf_size->dev_ctx; |
324 | ret = s5p_mfc_alloc_priv_buf(dev->mem_dev_l, dev->bank1, | 323 | ret = s5p_mfc_alloc_priv_buf(dev, BANK_L_CTX, &dev->ctx_buf); |
325 | &dev->ctx_buf); | ||
326 | if (ret) { | 324 | if (ret) { |
327 | mfc_err("Failed to allocate device context buffer\n"); | 325 | mfc_err("Failed to allocate device context buffer\n"); |
328 | return ret; | 326 | return ret; |
@@ -339,7 +337,7 @@ static int s5p_mfc_alloc_dev_context_buffer_v6(struct s5p_mfc_dev *dev) | |||
339 | /* Release context buffers for SYS_INIT */ | 337 | /* Release context buffers for SYS_INIT */ |
340 | static void s5p_mfc_release_dev_context_buffer_v6(struct s5p_mfc_dev *dev) | 338 | static void s5p_mfc_release_dev_context_buffer_v6(struct s5p_mfc_dev *dev) |
341 | { | 339 | { |
342 | s5p_mfc_release_priv_buf(dev->mem_dev_l, &dev->ctx_buf); | 340 | s5p_mfc_release_priv_buf(dev, &dev->ctx_buf); |
343 | } | 341 | } |
344 | 342 | ||
345 | static int calc_plane(int width, int height) | 343 | static int calc_plane(int width, int height) |
@@ -497,7 +495,7 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx) | |||
497 | } | 495 | } |
498 | } | 496 | } |
499 | 497 | ||
500 | mfc_debug(2, "Buf1: %zu, buf_size1: %d (frames %d)\n", | 498 | mfc_debug(2, "Buf1: %zx, buf_size1: %d (frames %d)\n", |
501 | buf_addr1, buf_size1, ctx->total_dpb_count); | 499 | buf_addr1, buf_size1, ctx->total_dpb_count); |
502 | if (buf_size1 < 0) { | 500 | if (buf_size1 < 0) { |
503 | mfc_debug(2, "Not enough memory has been allocated.\n"); | 501 | mfc_debug(2, "Not enough memory has been allocated.\n"); |
diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index ef2a519bcd4c..992d61a8b961 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c | |||
@@ -813,8 +813,8 @@ static u32 sh_vou_ntsc_mode(enum sh_vou_bus_fmt bus_fmt) | |||
813 | { | 813 | { |
814 | switch (bus_fmt) { | 814 | switch (bus_fmt) { |
815 | default: | 815 | default: |
816 | pr_warning("%s(): Invalid bus-format code %d, using default 8-bit\n", | 816 | pr_warn("%s(): Invalid bus-format code %d, using default 8-bit\n", |
817 | __func__, bus_fmt); | 817 | __func__, bus_fmt); |
818 | case SH_VOU_BUS_8BIT: | 818 | case SH_VOU_BUS_8BIT: |
819 | return 1; | 819 | return 1; |
820 | case SH_VOU_BUS_16BIT: | 820 | case SH_VOU_BUS_16BIT: |
diff --git a/drivers/media/platform/soc_camera/Kconfig b/drivers/media/platform/soc_camera/Kconfig index 86d74788544f..f5979c12ad61 100644 --- a/drivers/media/platform/soc_camera/Kconfig +++ b/drivers/media/platform/soc_camera/Kconfig | |||
@@ -1,7 +1,6 @@ | |||
1 | config SOC_CAMERA | 1 | config SOC_CAMERA |
2 | tristate "SoC camera support" | 2 | tristate "SoC camera support" |
3 | depends on VIDEO_V4L2 && HAS_DMA && I2C | 3 | depends on VIDEO_V4L2 && HAS_DMA && I2C |
4 | select VIDEOBUF_GEN | ||
5 | select VIDEOBUF2_CORE | 4 | select VIDEOBUF2_CORE |
6 | help | 5 | help |
7 | SoC Camera is a common API to several cameras, not connecting | 6 | SoC Camera is a common API to several cameras, not connecting |
@@ -26,14 +25,3 @@ config VIDEO_SH_MOBILE_CEU | |||
26 | select SOC_CAMERA_SCALE_CROP | 25 | select SOC_CAMERA_SCALE_CROP |
27 | ---help--- | 26 | ---help--- |
28 | This is a v4l2 driver for the SuperH Mobile CEU Interface | 27 | This is a v4l2 driver for the SuperH Mobile CEU Interface |
29 | |||
30 | config VIDEO_ATMEL_ISI | ||
31 | tristate "ATMEL Image Sensor Interface (ISI) support" | ||
32 | depends on VIDEO_DEV && SOC_CAMERA | ||
33 | depends on ARCH_AT91 || COMPILE_TEST | ||
34 | depends on HAS_DMA | ||
35 | select VIDEOBUF2_DMA_CONTIG | ||
36 | ---help--- | ||
37 | This module makes the ATMEL Image Sensor Interface available | ||
38 | as a v4l2 device. | ||
39 | |||
diff --git a/drivers/media/platform/soc_camera/Makefile b/drivers/media/platform/soc_camera/Makefile index 7633a0f2f66f..07a451e8b228 100644 --- a/drivers/media/platform/soc_camera/Makefile +++ b/drivers/media/platform/soc_camera/Makefile | |||
@@ -6,5 +6,4 @@ obj-$(CONFIG_SOC_CAMERA_SCALE_CROP) += soc_scale_crop.o | |||
6 | obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o | 6 | obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o |
7 | 7 | ||
8 | # soc-camera host drivers have to be linked after camera drivers | 8 | # soc-camera host drivers have to be linked after camera drivers |
9 | obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o | ||
10 | obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o | 9 | obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o |
diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c deleted file mode 100644 index 46de657c3e6d..000000000000 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ /dev/null | |||
@@ -1,1167 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2011 Atmel Corporation | ||
3 | * Josh Wu, <josh.wu@atmel.com> | ||
4 | * | ||
5 | * Based on previous work by Lars Haring, <lars.haring@atmel.com> | ||
6 | * and Sedji Gaouaou | ||
7 | * Based on the bttv driver for Bt848 with respective copyright holders | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/clk.h> | ||
15 | #include <linux/completion.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/fs.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/pm_runtime.h> | ||
24 | #include <linux/slab.h> | ||
25 | |||
26 | #include <media/soc_camera.h> | ||
27 | #include <media/drv-intf/soc_mediabus.h> | ||
28 | #include <media/v4l2-of.h> | ||
29 | #include <media/videobuf2-dma-contig.h> | ||
30 | |||
31 | #include "atmel-isi.h" | ||
32 | |||
33 | #define MAX_BUFFER_NUM 32 | ||
34 | #define MAX_SUPPORT_WIDTH 2048 | ||
35 | #define MAX_SUPPORT_HEIGHT 2048 | ||
36 | #define VID_LIMIT_BYTES (16 * 1024 * 1024) | ||
37 | #define MIN_FRAME_RATE 15 | ||
38 | #define FRAME_INTERVAL_MILLI_SEC (1000 / MIN_FRAME_RATE) | ||
39 | |||
40 | /* Frame buffer descriptor */ | ||
41 | struct fbd { | ||
42 | /* Physical address of the frame buffer */ | ||
43 | u32 fb_address; | ||
44 | /* DMA Control Register(only in HISI2) */ | ||
45 | u32 dma_ctrl; | ||
46 | /* Physical address of the next fbd */ | ||
47 | u32 next_fbd_address; | ||
48 | }; | ||
49 | |||
50 | static void set_dma_ctrl(struct fbd *fb_desc, u32 ctrl) | ||
51 | { | ||
52 | fb_desc->dma_ctrl = ctrl; | ||
53 | } | ||
54 | |||
55 | struct isi_dma_desc { | ||
56 | struct list_head list; | ||
57 | struct fbd *p_fbd; | ||
58 | dma_addr_t fbd_phys; | ||
59 | }; | ||
60 | |||
61 | /* Frame buffer data */ | ||
62 | struct frame_buffer { | ||
63 | struct vb2_v4l2_buffer vb; | ||
64 | struct isi_dma_desc *p_dma_desc; | ||
65 | struct list_head list; | ||
66 | }; | ||
67 | |||
68 | struct atmel_isi { | ||
69 | /* Protects the access of variables shared with the ISR */ | ||
70 | spinlock_t lock; | ||
71 | void __iomem *regs; | ||
72 | |||
73 | int sequence; | ||
74 | |||
75 | /* Allocate descriptors for dma buffer use */ | ||
76 | struct fbd *p_fb_descriptors; | ||
77 | dma_addr_t fb_descriptors_phys; | ||
78 | struct list_head dma_desc_head; | ||
79 | struct isi_dma_desc dma_desc[MAX_BUFFER_NUM]; | ||
80 | bool enable_preview_path; | ||
81 | |||
82 | struct completion complete; | ||
83 | /* ISI peripherial clock */ | ||
84 | struct clk *pclk; | ||
85 | unsigned int irq; | ||
86 | |||
87 | struct isi_platform_data pdata; | ||
88 | u16 width_flags; /* max 12 bits */ | ||
89 | |||
90 | struct list_head video_buffer_list; | ||
91 | struct frame_buffer *active; | ||
92 | |||
93 | struct soc_camera_host soc_host; | ||
94 | }; | ||
95 | |||
96 | static void isi_writel(struct atmel_isi *isi, u32 reg, u32 val) | ||
97 | { | ||
98 | writel(val, isi->regs + reg); | ||
99 | } | ||
100 | static u32 isi_readl(struct atmel_isi *isi, u32 reg) | ||
101 | { | ||
102 | return readl(isi->regs + reg); | ||
103 | } | ||
104 | |||
105 | static u32 setup_cfg2_yuv_swap(struct atmel_isi *isi, | ||
106 | const struct soc_camera_format_xlate *xlate) | ||
107 | { | ||
108 | if (xlate->host_fmt->fourcc == V4L2_PIX_FMT_YUYV) { | ||
109 | /* all convert to YUYV */ | ||
110 | switch (xlate->code) { | ||
111 | case MEDIA_BUS_FMT_VYUY8_2X8: | ||
112 | return ISI_CFG2_YCC_SWAP_MODE_3; | ||
113 | case MEDIA_BUS_FMT_UYVY8_2X8: | ||
114 | return ISI_CFG2_YCC_SWAP_MODE_2; | ||
115 | case MEDIA_BUS_FMT_YVYU8_2X8: | ||
116 | return ISI_CFG2_YCC_SWAP_MODE_1; | ||
117 | } | ||
118 | } else if (xlate->host_fmt->fourcc == V4L2_PIX_FMT_RGB565) { | ||
119 | /* | ||
120 | * Preview path is enabled, it will convert UYVY to RGB format. | ||
121 | * But if sensor output format is not UYVY, we need to set | ||
122 | * YCC_SWAP_MODE to convert it as UYVY. | ||
123 | */ | ||
124 | switch (xlate->code) { | ||
125 | case MEDIA_BUS_FMT_VYUY8_2X8: | ||
126 | return ISI_CFG2_YCC_SWAP_MODE_1; | ||
127 | case MEDIA_BUS_FMT_YUYV8_2X8: | ||
128 | return ISI_CFG2_YCC_SWAP_MODE_2; | ||
129 | case MEDIA_BUS_FMT_YVYU8_2X8: | ||
130 | return ISI_CFG2_YCC_SWAP_MODE_3; | ||
131 | } | ||
132 | } | ||
133 | |||
134 | /* | ||
135 | * By default, no swap for the codec path of Atmel ISI. So codec | ||
136 | * output is same as sensor's output. | ||
137 | * For instance, if sensor's output is YUYV, then codec outputs YUYV. | ||
138 | * And if sensor's output is UYVY, then codec outputs UYVY. | ||
139 | */ | ||
140 | return ISI_CFG2_YCC_SWAP_DEFAULT; | ||
141 | } | ||
142 | |||
143 | static void configure_geometry(struct atmel_isi *isi, u32 width, | ||
144 | u32 height, const struct soc_camera_format_xlate *xlate) | ||
145 | { | ||
146 | u32 cfg2, psize; | ||
147 | u32 fourcc = xlate->host_fmt->fourcc; | ||
148 | |||
149 | isi->enable_preview_path = fourcc == V4L2_PIX_FMT_RGB565 || | ||
150 | fourcc == V4L2_PIX_FMT_RGB32; | ||
151 | |||
152 | /* According to sensor's output format to set cfg2 */ | ||
153 | switch (xlate->code) { | ||
154 | default: | ||
155 | /* Grey */ | ||
156 | case MEDIA_BUS_FMT_Y8_1X8: | ||
157 | cfg2 = ISI_CFG2_GRAYSCALE | ISI_CFG2_COL_SPACE_YCbCr; | ||
158 | break; | ||
159 | /* YUV */ | ||
160 | case MEDIA_BUS_FMT_VYUY8_2X8: | ||
161 | case MEDIA_BUS_FMT_UYVY8_2X8: | ||
162 | case MEDIA_BUS_FMT_YVYU8_2X8: | ||
163 | case MEDIA_BUS_FMT_YUYV8_2X8: | ||
164 | cfg2 = ISI_CFG2_COL_SPACE_YCbCr | | ||
165 | setup_cfg2_yuv_swap(isi, xlate); | ||
166 | break; | ||
167 | /* RGB, TODO */ | ||
168 | } | ||
169 | |||
170 | isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); | ||
171 | /* Set width */ | ||
172 | cfg2 |= ((width - 1) << ISI_CFG2_IM_HSIZE_OFFSET) & | ||
173 | ISI_CFG2_IM_HSIZE_MASK; | ||
174 | /* Set height */ | ||
175 | cfg2 |= ((height - 1) << ISI_CFG2_IM_VSIZE_OFFSET) | ||
176 | & ISI_CFG2_IM_VSIZE_MASK; | ||
177 | isi_writel(isi, ISI_CFG2, cfg2); | ||
178 | |||
179 | /* No down sampling, preview size equal to sensor output size */ | ||
180 | psize = ((width - 1) << ISI_PSIZE_PREV_HSIZE_OFFSET) & | ||
181 | ISI_PSIZE_PREV_HSIZE_MASK; | ||
182 | psize |= ((height - 1) << ISI_PSIZE_PREV_VSIZE_OFFSET) & | ||
183 | ISI_PSIZE_PREV_VSIZE_MASK; | ||
184 | isi_writel(isi, ISI_PSIZE, psize); | ||
185 | isi_writel(isi, ISI_PDECF, ISI_PDECF_NO_SAMPLING); | ||
186 | |||
187 | return; | ||
188 | } | ||
189 | |||
190 | static bool is_supported(struct soc_camera_device *icd, | ||
191 | const u32 pixformat) | ||
192 | { | ||
193 | switch (pixformat) { | ||
194 | /* YUV, including grey */ | ||
195 | case V4L2_PIX_FMT_GREY: | ||
196 | case V4L2_PIX_FMT_YUYV: | ||
197 | case V4L2_PIX_FMT_UYVY: | ||
198 | case V4L2_PIX_FMT_YVYU: | ||
199 | case V4L2_PIX_FMT_VYUY: | ||
200 | /* RGB */ | ||
201 | case V4L2_PIX_FMT_RGB565: | ||
202 | return true; | ||
203 | default: | ||
204 | return false; | ||
205 | } | ||
206 | } | ||
207 | |||
208 | static irqreturn_t atmel_isi_handle_streaming(struct atmel_isi *isi) | ||
209 | { | ||
210 | if (isi->active) { | ||
211 | struct vb2_v4l2_buffer *vbuf = &isi->active->vb; | ||
212 | struct frame_buffer *buf = isi->active; | ||
213 | |||
214 | list_del_init(&buf->list); | ||
215 | vbuf->vb2_buf.timestamp = ktime_get_ns(); | ||
216 | vbuf->sequence = isi->sequence++; | ||
217 | vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE); | ||
218 | } | ||
219 | |||
220 | if (list_empty(&isi->video_buffer_list)) { | ||
221 | isi->active = NULL; | ||
222 | } else { | ||
223 | /* start next dma frame. */ | ||
224 | isi->active = list_entry(isi->video_buffer_list.next, | ||
225 | struct frame_buffer, list); | ||
226 | if (!isi->enable_preview_path) { | ||
227 | isi_writel(isi, ISI_DMA_C_DSCR, | ||
228 | (u32)isi->active->p_dma_desc->fbd_phys); | ||
229 | isi_writel(isi, ISI_DMA_C_CTRL, | ||
230 | ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); | ||
231 | isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH); | ||
232 | } else { | ||
233 | isi_writel(isi, ISI_DMA_P_DSCR, | ||
234 | (u32)isi->active->p_dma_desc->fbd_phys); | ||
235 | isi_writel(isi, ISI_DMA_P_CTRL, | ||
236 | ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); | ||
237 | isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_P_CH); | ||
238 | } | ||
239 | } | ||
240 | return IRQ_HANDLED; | ||
241 | } | ||
242 | |||
243 | /* ISI interrupt service routine */ | ||
244 | static irqreturn_t isi_interrupt(int irq, void *dev_id) | ||
245 | { | ||
246 | struct atmel_isi *isi = dev_id; | ||
247 | u32 status, mask, pending; | ||
248 | irqreturn_t ret = IRQ_NONE; | ||
249 | |||
250 | spin_lock(&isi->lock); | ||
251 | |||
252 | status = isi_readl(isi, ISI_STATUS); | ||
253 | mask = isi_readl(isi, ISI_INTMASK); | ||
254 | pending = status & mask; | ||
255 | |||
256 | if (pending & ISI_CTRL_SRST) { | ||
257 | complete(&isi->complete); | ||
258 | isi_writel(isi, ISI_INTDIS, ISI_CTRL_SRST); | ||
259 | ret = IRQ_HANDLED; | ||
260 | } else if (pending & ISI_CTRL_DIS) { | ||
261 | complete(&isi->complete); | ||
262 | isi_writel(isi, ISI_INTDIS, ISI_CTRL_DIS); | ||
263 | ret = IRQ_HANDLED; | ||
264 | } else { | ||
265 | if (likely(pending & ISI_SR_CXFR_DONE) || | ||
266 | likely(pending & ISI_SR_PXFR_DONE)) | ||
267 | ret = atmel_isi_handle_streaming(isi); | ||
268 | } | ||
269 | |||
270 | spin_unlock(&isi->lock); | ||
271 | return ret; | ||
272 | } | ||
273 | |||
274 | #define WAIT_ISI_RESET 1 | ||
275 | #define WAIT_ISI_DISABLE 0 | ||
276 | static int atmel_isi_wait_status(struct atmel_isi *isi, int wait_reset) | ||
277 | { | ||
278 | unsigned long timeout; | ||
279 | /* | ||
280 | * The reset or disable will only succeed if we have a | ||
281 | * pixel clock from the camera. | ||
282 | */ | ||
283 | init_completion(&isi->complete); | ||
284 | |||
285 | if (wait_reset) { | ||
286 | isi_writel(isi, ISI_INTEN, ISI_CTRL_SRST); | ||
287 | isi_writel(isi, ISI_CTRL, ISI_CTRL_SRST); | ||
288 | } else { | ||
289 | isi_writel(isi, ISI_INTEN, ISI_CTRL_DIS); | ||
290 | isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); | ||
291 | } | ||
292 | |||
293 | timeout = wait_for_completion_timeout(&isi->complete, | ||
294 | msecs_to_jiffies(500)); | ||
295 | if (timeout == 0) | ||
296 | return -ETIMEDOUT; | ||
297 | |||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | /* ------------------------------------------------------------------ | ||
302 | Videobuf operations | ||
303 | ------------------------------------------------------------------*/ | ||
304 | static int queue_setup(struct vb2_queue *vq, | ||
305 | unsigned int *nbuffers, unsigned int *nplanes, | ||
306 | unsigned int sizes[], struct device *alloc_devs[]) | ||
307 | { | ||
308 | struct soc_camera_device *icd = soc_camera_from_vb2q(vq); | ||
309 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
310 | struct atmel_isi *isi = ici->priv; | ||
311 | unsigned long size; | ||
312 | |||
313 | size = icd->sizeimage; | ||
314 | |||
315 | if (!*nbuffers || *nbuffers > MAX_BUFFER_NUM) | ||
316 | *nbuffers = MAX_BUFFER_NUM; | ||
317 | |||
318 | if (size * *nbuffers > VID_LIMIT_BYTES) | ||
319 | *nbuffers = VID_LIMIT_BYTES / size; | ||
320 | |||
321 | *nplanes = 1; | ||
322 | sizes[0] = size; | ||
323 | |||
324 | isi->sequence = 0; | ||
325 | isi->active = NULL; | ||
326 | |||
327 | dev_dbg(icd->parent, "%s, count=%d, size=%ld\n", __func__, | ||
328 | *nbuffers, size); | ||
329 | |||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | static int buffer_init(struct vb2_buffer *vb) | ||
334 | { | ||
335 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | ||
336 | struct frame_buffer *buf = container_of(vbuf, struct frame_buffer, vb); | ||
337 | |||
338 | buf->p_dma_desc = NULL; | ||
339 | INIT_LIST_HEAD(&buf->list); | ||
340 | |||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | static int buffer_prepare(struct vb2_buffer *vb) | ||
345 | { | ||
346 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | ||
347 | struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); | ||
348 | struct frame_buffer *buf = container_of(vbuf, struct frame_buffer, vb); | ||
349 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
350 | struct atmel_isi *isi = ici->priv; | ||
351 | unsigned long size; | ||
352 | struct isi_dma_desc *desc; | ||
353 | |||
354 | size = icd->sizeimage; | ||
355 | |||
356 | if (vb2_plane_size(vb, 0) < size) { | ||
357 | dev_err(icd->parent, "%s data will not fit into plane (%lu < %lu)\n", | ||
358 | __func__, vb2_plane_size(vb, 0), size); | ||
359 | return -EINVAL; | ||
360 | } | ||
361 | |||
362 | vb2_set_plane_payload(vb, 0, size); | ||
363 | |||
364 | if (!buf->p_dma_desc) { | ||
365 | if (list_empty(&isi->dma_desc_head)) { | ||
366 | dev_err(icd->parent, "Not enough dma descriptors.\n"); | ||
367 | return -EINVAL; | ||
368 | } else { | ||
369 | /* Get an available descriptor */ | ||
370 | desc = list_entry(isi->dma_desc_head.next, | ||
371 | struct isi_dma_desc, list); | ||
372 | /* Delete the descriptor since now it is used */ | ||
373 | list_del_init(&desc->list); | ||
374 | |||
375 | /* Initialize the dma descriptor */ | ||
376 | desc->p_fbd->fb_address = | ||
377 | vb2_dma_contig_plane_dma_addr(vb, 0); | ||
378 | desc->p_fbd->next_fbd_address = 0; | ||
379 | set_dma_ctrl(desc->p_fbd, ISI_DMA_CTRL_WB); | ||
380 | |||
381 | buf->p_dma_desc = desc; | ||
382 | } | ||
383 | } | ||
384 | return 0; | ||
385 | } | ||
386 | |||
387 | static void buffer_cleanup(struct vb2_buffer *vb) | ||
388 | { | ||
389 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | ||
390 | struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); | ||
391 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
392 | struct atmel_isi *isi = ici->priv; | ||
393 | struct frame_buffer *buf = container_of(vbuf, struct frame_buffer, vb); | ||
394 | |||
395 | /* This descriptor is available now and we add to head list */ | ||
396 | if (buf->p_dma_desc) | ||
397 | list_add(&buf->p_dma_desc->list, &isi->dma_desc_head); | ||
398 | } | ||
399 | |||
400 | static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer) | ||
401 | { | ||
402 | u32 ctrl, cfg1; | ||
403 | |||
404 | cfg1 = isi_readl(isi, ISI_CFG1); | ||
405 | /* Enable irq: cxfr for the codec path, pxfr for the preview path */ | ||
406 | isi_writel(isi, ISI_INTEN, | ||
407 | ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE); | ||
408 | |||
409 | /* Check if already in a frame */ | ||
410 | if (!isi->enable_preview_path) { | ||
411 | if (isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) { | ||
412 | dev_err(isi->soc_host.icd->parent, "Already in frame handling.\n"); | ||
413 | return; | ||
414 | } | ||
415 | |||
416 | isi_writel(isi, ISI_DMA_C_DSCR, | ||
417 | (u32)buffer->p_dma_desc->fbd_phys); | ||
418 | isi_writel(isi, ISI_DMA_C_CTRL, | ||
419 | ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); | ||
420 | isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH); | ||
421 | } else { | ||
422 | isi_writel(isi, ISI_DMA_P_DSCR, | ||
423 | (u32)buffer->p_dma_desc->fbd_phys); | ||
424 | isi_writel(isi, ISI_DMA_P_CTRL, | ||
425 | ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); | ||
426 | isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_P_CH); | ||
427 | } | ||
428 | |||
429 | cfg1 &= ~ISI_CFG1_FRATE_DIV_MASK; | ||
430 | /* Enable linked list */ | ||
431 | cfg1 |= isi->pdata.frate | ISI_CFG1_DISCR; | ||
432 | |||
433 | /* Enable ISI */ | ||
434 | ctrl = ISI_CTRL_EN; | ||
435 | |||
436 | if (!isi->enable_preview_path) | ||
437 | ctrl |= ISI_CTRL_CDC; | ||
438 | |||
439 | isi_writel(isi, ISI_CTRL, ctrl); | ||
440 | isi_writel(isi, ISI_CFG1, cfg1); | ||
441 | } | ||
442 | |||
443 | static void buffer_queue(struct vb2_buffer *vb) | ||
444 | { | ||
445 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | ||
446 | struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); | ||
447 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
448 | struct atmel_isi *isi = ici->priv; | ||
449 | struct frame_buffer *buf = container_of(vbuf, struct frame_buffer, vb); | ||
450 | unsigned long flags = 0; | ||
451 | |||
452 | spin_lock_irqsave(&isi->lock, flags); | ||
453 | list_add_tail(&buf->list, &isi->video_buffer_list); | ||
454 | |||
455 | if (isi->active == NULL) { | ||
456 | isi->active = buf; | ||
457 | if (vb2_is_streaming(vb->vb2_queue)) | ||
458 | start_dma(isi, buf); | ||
459 | } | ||
460 | spin_unlock_irqrestore(&isi->lock, flags); | ||
461 | } | ||
462 | |||
463 | static int start_streaming(struct vb2_queue *vq, unsigned int count) | ||
464 | { | ||
465 | struct soc_camera_device *icd = soc_camera_from_vb2q(vq); | ||
466 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
467 | struct atmel_isi *isi = ici->priv; | ||
468 | int ret; | ||
469 | |||
470 | pm_runtime_get_sync(ici->v4l2_dev.dev); | ||
471 | |||
472 | /* Reset ISI */ | ||
473 | ret = atmel_isi_wait_status(isi, WAIT_ISI_RESET); | ||
474 | if (ret < 0) { | ||
475 | dev_err(icd->parent, "Reset ISI timed out\n"); | ||
476 | pm_runtime_put(ici->v4l2_dev.dev); | ||
477 | return ret; | ||
478 | } | ||
479 | /* Disable all interrupts */ | ||
480 | isi_writel(isi, ISI_INTDIS, (u32)~0UL); | ||
481 | |||
482 | configure_geometry(isi, icd->user_width, icd->user_height, | ||
483 | icd->current_fmt); | ||
484 | |||
485 | spin_lock_irq(&isi->lock); | ||
486 | /* Clear any pending interrupt */ | ||
487 | isi_readl(isi, ISI_STATUS); | ||
488 | |||
489 | if (count) | ||
490 | start_dma(isi, isi->active); | ||
491 | spin_unlock_irq(&isi->lock); | ||
492 | |||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | /* abort streaming and wait for last buffer */ | ||
497 | static void stop_streaming(struct vb2_queue *vq) | ||
498 | { | ||
499 | struct soc_camera_device *icd = soc_camera_from_vb2q(vq); | ||
500 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
501 | struct atmel_isi *isi = ici->priv; | ||
502 | struct frame_buffer *buf, *node; | ||
503 | int ret = 0; | ||
504 | unsigned long timeout; | ||
505 | |||
506 | spin_lock_irq(&isi->lock); | ||
507 | isi->active = NULL; | ||
508 | /* Release all active buffers */ | ||
509 | list_for_each_entry_safe(buf, node, &isi->video_buffer_list, list) { | ||
510 | list_del_init(&buf->list); | ||
511 | vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); | ||
512 | } | ||
513 | spin_unlock_irq(&isi->lock); | ||
514 | |||
515 | if (!isi->enable_preview_path) { | ||
516 | timeout = jiffies + FRAME_INTERVAL_MILLI_SEC * HZ; | ||
517 | /* Wait until the end of the current frame. */ | ||
518 | while ((isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) && | ||
519 | time_before(jiffies, timeout)) | ||
520 | msleep(1); | ||
521 | |||
522 | if (time_after(jiffies, timeout)) | ||
523 | dev_err(icd->parent, | ||
524 | "Timeout waiting for finishing codec request\n"); | ||
525 | } | ||
526 | |||
527 | /* Disable interrupts */ | ||
528 | isi_writel(isi, ISI_INTDIS, | ||
529 | ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE); | ||
530 | |||
531 | /* Disable ISI and wait for it is done */ | ||
532 | ret = atmel_isi_wait_status(isi, WAIT_ISI_DISABLE); | ||
533 | if (ret < 0) | ||
534 | dev_err(icd->parent, "Disable ISI timed out\n"); | ||
535 | |||
536 | pm_runtime_put(ici->v4l2_dev.dev); | ||
537 | } | ||
538 | |||
539 | static const struct vb2_ops isi_video_qops = { | ||
540 | .queue_setup = queue_setup, | ||
541 | .buf_init = buffer_init, | ||
542 | .buf_prepare = buffer_prepare, | ||
543 | .buf_cleanup = buffer_cleanup, | ||
544 | .buf_queue = buffer_queue, | ||
545 | .start_streaming = start_streaming, | ||
546 | .stop_streaming = stop_streaming, | ||
547 | .wait_prepare = vb2_ops_wait_prepare, | ||
548 | .wait_finish = vb2_ops_wait_finish, | ||
549 | }; | ||
550 | |||
551 | /* ------------------------------------------------------------------ | ||
552 | SOC camera operations for the device | ||
553 | ------------------------------------------------------------------*/ | ||
554 | static int isi_camera_init_videobuf(struct vb2_queue *q, | ||
555 | struct soc_camera_device *icd) | ||
556 | { | ||
557 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
558 | |||
559 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
560 | q->io_modes = VB2_MMAP; | ||
561 | q->drv_priv = icd; | ||
562 | q->buf_struct_size = sizeof(struct frame_buffer); | ||
563 | q->ops = &isi_video_qops; | ||
564 | q->mem_ops = &vb2_dma_contig_memops; | ||
565 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | ||
566 | q->lock = &ici->host_lock; | ||
567 | q->dev = ici->v4l2_dev.dev; | ||
568 | |||
569 | return vb2_queue_init(q); | ||
570 | } | ||
571 | |||
572 | static int isi_camera_set_fmt(struct soc_camera_device *icd, | ||
573 | struct v4l2_format *f) | ||
574 | { | ||
575 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
576 | const struct soc_camera_format_xlate *xlate; | ||
577 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
578 | struct v4l2_subdev_format format = { | ||
579 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
580 | }; | ||
581 | struct v4l2_mbus_framefmt *mf = &format.format; | ||
582 | int ret; | ||
583 | |||
584 | /* check with atmel-isi support format, if not support use YUYV */ | ||
585 | if (!is_supported(icd, pix->pixelformat)) | ||
586 | pix->pixelformat = V4L2_PIX_FMT_YUYV; | ||
587 | |||
588 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); | ||
589 | if (!xlate) { | ||
590 | dev_warn(icd->parent, "Format %x not found\n", | ||
591 | pix->pixelformat); | ||
592 | return -EINVAL; | ||
593 | } | ||
594 | |||
595 | dev_dbg(icd->parent, "Plan to set format %dx%d\n", | ||
596 | pix->width, pix->height); | ||
597 | |||
598 | mf->width = pix->width; | ||
599 | mf->height = pix->height; | ||
600 | mf->field = pix->field; | ||
601 | mf->colorspace = pix->colorspace; | ||
602 | mf->code = xlate->code; | ||
603 | |||
604 | ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &format); | ||
605 | if (ret < 0) | ||
606 | return ret; | ||
607 | |||
608 | if (mf->code != xlate->code) | ||
609 | return -EINVAL; | ||
610 | |||
611 | pix->width = mf->width; | ||
612 | pix->height = mf->height; | ||
613 | pix->field = mf->field; | ||
614 | pix->colorspace = mf->colorspace; | ||
615 | icd->current_fmt = xlate; | ||
616 | |||
617 | dev_dbg(icd->parent, "Finally set format %dx%d\n", | ||
618 | pix->width, pix->height); | ||
619 | |||
620 | return ret; | ||
621 | } | ||
622 | |||
623 | static int isi_camera_try_fmt(struct soc_camera_device *icd, | ||
624 | struct v4l2_format *f) | ||
625 | { | ||
626 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
627 | const struct soc_camera_format_xlate *xlate; | ||
628 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
629 | struct v4l2_subdev_pad_config pad_cfg; | ||
630 | struct v4l2_subdev_format format = { | ||
631 | .which = V4L2_SUBDEV_FORMAT_TRY, | ||
632 | }; | ||
633 | struct v4l2_mbus_framefmt *mf = &format.format; | ||
634 | u32 pixfmt = pix->pixelformat; | ||
635 | int ret; | ||
636 | |||
637 | /* check with atmel-isi support format, if not support use YUYV */ | ||
638 | if (!is_supported(icd, pix->pixelformat)) | ||
639 | pix->pixelformat = V4L2_PIX_FMT_YUYV; | ||
640 | |||
641 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | ||
642 | if (pixfmt && !xlate) { | ||
643 | dev_warn(icd->parent, "Format %x not found\n", pixfmt); | ||
644 | return -EINVAL; | ||
645 | } | ||
646 | |||
647 | /* limit to Atmel ISI hardware capabilities */ | ||
648 | if (pix->height > MAX_SUPPORT_HEIGHT) | ||
649 | pix->height = MAX_SUPPORT_HEIGHT; | ||
650 | if (pix->width > MAX_SUPPORT_WIDTH) | ||
651 | pix->width = MAX_SUPPORT_WIDTH; | ||
652 | |||
653 | /* limit to sensor capabilities */ | ||
654 | mf->width = pix->width; | ||
655 | mf->height = pix->height; | ||
656 | mf->field = pix->field; | ||
657 | mf->colorspace = pix->colorspace; | ||
658 | mf->code = xlate->code; | ||
659 | |||
660 | ret = v4l2_subdev_call(sd, pad, set_fmt, &pad_cfg, &format); | ||
661 | if (ret < 0) | ||
662 | return ret; | ||
663 | |||
664 | pix->width = mf->width; | ||
665 | pix->height = mf->height; | ||
666 | pix->colorspace = mf->colorspace; | ||
667 | |||
668 | switch (mf->field) { | ||
669 | case V4L2_FIELD_ANY: | ||
670 | pix->field = V4L2_FIELD_NONE; | ||
671 | break; | ||
672 | case V4L2_FIELD_NONE: | ||
673 | break; | ||
674 | default: | ||
675 | dev_err(icd->parent, "Field type %d unsupported.\n", | ||
676 | mf->field); | ||
677 | ret = -EINVAL; | ||
678 | } | ||
679 | |||
680 | return ret; | ||
681 | } | ||
682 | |||
683 | static const struct soc_mbus_pixelfmt isi_camera_formats[] = { | ||
684 | { | ||
685 | .fourcc = V4L2_PIX_FMT_YUYV, | ||
686 | .name = "Packed YUV422 16 bit", | ||
687 | .bits_per_sample = 8, | ||
688 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
689 | .order = SOC_MBUS_ORDER_LE, | ||
690 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
691 | }, | ||
692 | { | ||
693 | .fourcc = V4L2_PIX_FMT_RGB565, | ||
694 | .name = "RGB565", | ||
695 | .bits_per_sample = 8, | ||
696 | .packing = SOC_MBUS_PACKING_2X8_PADHI, | ||
697 | .order = SOC_MBUS_ORDER_LE, | ||
698 | .layout = SOC_MBUS_LAYOUT_PACKED, | ||
699 | }, | ||
700 | }; | ||
701 | |||
702 | /* This will be corrected as we get more formats */ | ||
703 | static bool isi_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt) | ||
704 | { | ||
705 | return fmt->packing == SOC_MBUS_PACKING_NONE || | ||
706 | (fmt->bits_per_sample == 8 && | ||
707 | fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) || | ||
708 | (fmt->bits_per_sample > 8 && | ||
709 | fmt->packing == SOC_MBUS_PACKING_EXTEND16); | ||
710 | } | ||
711 | |||
712 | #define ISI_BUS_PARAM (V4L2_MBUS_MASTER | \ | ||
713 | V4L2_MBUS_HSYNC_ACTIVE_HIGH | \ | ||
714 | V4L2_MBUS_HSYNC_ACTIVE_LOW | \ | ||
715 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | \ | ||
716 | V4L2_MBUS_VSYNC_ACTIVE_LOW | \ | ||
717 | V4L2_MBUS_PCLK_SAMPLE_RISING | \ | ||
718 | V4L2_MBUS_PCLK_SAMPLE_FALLING | \ | ||
719 | V4L2_MBUS_DATA_ACTIVE_HIGH) | ||
720 | |||
721 | static int isi_camera_try_bus_param(struct soc_camera_device *icd, | ||
722 | unsigned char buswidth) | ||
723 | { | ||
724 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
725 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
726 | struct atmel_isi *isi = ici->priv; | ||
727 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; | ||
728 | unsigned long common_flags; | ||
729 | int ret; | ||
730 | |||
731 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); | ||
732 | if (!ret) { | ||
733 | common_flags = soc_mbus_config_compatible(&cfg, | ||
734 | ISI_BUS_PARAM); | ||
735 | if (!common_flags) { | ||
736 | dev_warn(icd->parent, | ||
737 | "Flags incompatible: camera 0x%x, host 0x%x\n", | ||
738 | cfg.flags, ISI_BUS_PARAM); | ||
739 | return -EINVAL; | ||
740 | } | ||
741 | } else if (ret != -ENOIOCTLCMD) { | ||
742 | return ret; | ||
743 | } | ||
744 | |||
745 | if ((1 << (buswidth - 1)) & isi->width_flags) | ||
746 | return 0; | ||
747 | return -EINVAL; | ||
748 | } | ||
749 | |||
750 | |||
751 | static int isi_camera_get_formats(struct soc_camera_device *icd, | ||
752 | unsigned int idx, | ||
753 | struct soc_camera_format_xlate *xlate) | ||
754 | { | ||
755 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
756 | int formats = 0, ret, i, n; | ||
757 | /* sensor format */ | ||
758 | struct v4l2_subdev_mbus_code_enum code = { | ||
759 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
760 | .index = idx, | ||
761 | }; | ||
762 | /* soc camera host format */ | ||
763 | const struct soc_mbus_pixelfmt *fmt; | ||
764 | |||
765 | ret = v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code); | ||
766 | if (ret < 0) | ||
767 | /* No more formats */ | ||
768 | return 0; | ||
769 | |||
770 | fmt = soc_mbus_get_fmtdesc(code.code); | ||
771 | if (!fmt) { | ||
772 | dev_err(icd->parent, | ||
773 | "Invalid format code #%u: %d\n", idx, code.code); | ||
774 | return 0; | ||
775 | } | ||
776 | |||
777 | /* This also checks support for the requested bits-per-sample */ | ||
778 | ret = isi_camera_try_bus_param(icd, fmt->bits_per_sample); | ||
779 | if (ret < 0) { | ||
780 | dev_err(icd->parent, | ||
781 | "Fail to try the bus parameters.\n"); | ||
782 | return 0; | ||
783 | } | ||
784 | |||
785 | switch (code.code) { | ||
786 | case MEDIA_BUS_FMT_UYVY8_2X8: | ||
787 | case MEDIA_BUS_FMT_VYUY8_2X8: | ||
788 | case MEDIA_BUS_FMT_YUYV8_2X8: | ||
789 | case MEDIA_BUS_FMT_YVYU8_2X8: | ||
790 | n = ARRAY_SIZE(isi_camera_formats); | ||
791 | formats += n; | ||
792 | for (i = 0; xlate && i < n; i++, xlate++) { | ||
793 | xlate->host_fmt = &isi_camera_formats[i]; | ||
794 | xlate->code = code.code; | ||
795 | dev_dbg(icd->parent, "Providing format %s using code %d\n", | ||
796 | xlate->host_fmt->name, xlate->code); | ||
797 | } | ||
798 | break; | ||
799 | default: | ||
800 | if (!isi_camera_packing_supported(fmt)) | ||
801 | return 0; | ||
802 | if (xlate) | ||
803 | dev_dbg(icd->parent, | ||
804 | "Providing format %s in pass-through mode\n", | ||
805 | fmt->name); | ||
806 | } | ||
807 | |||
808 | /* Generic pass-through */ | ||
809 | formats++; | ||
810 | if (xlate) { | ||
811 | xlate->host_fmt = fmt; | ||
812 | xlate->code = code.code; | ||
813 | xlate++; | ||
814 | } | ||
815 | |||
816 | return formats; | ||
817 | } | ||
818 | |||
819 | static int isi_camera_add_device(struct soc_camera_device *icd) | ||
820 | { | ||
821 | dev_dbg(icd->parent, "Atmel ISI Camera driver attached to camera %d\n", | ||
822 | icd->devnum); | ||
823 | |||
824 | return 0; | ||
825 | } | ||
826 | |||
827 | static void isi_camera_remove_device(struct soc_camera_device *icd) | ||
828 | { | ||
829 | dev_dbg(icd->parent, "Atmel ISI Camera driver detached from camera %d\n", | ||
830 | icd->devnum); | ||
831 | } | ||
832 | |||
833 | static unsigned int isi_camera_poll(struct file *file, poll_table *pt) | ||
834 | { | ||
835 | struct soc_camera_device *icd = file->private_data; | ||
836 | |||
837 | return vb2_poll(&icd->vb2_vidq, file, pt); | ||
838 | } | ||
839 | |||
840 | static int isi_camera_querycap(struct soc_camera_host *ici, | ||
841 | struct v4l2_capability *cap) | ||
842 | { | ||
843 | strcpy(cap->driver, "atmel-isi"); | ||
844 | strcpy(cap->card, "Atmel Image Sensor Interface"); | ||
845 | cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; | ||
846 | cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; | ||
847 | |||
848 | return 0; | ||
849 | } | ||
850 | |||
851 | static int isi_camera_set_bus_param(struct soc_camera_device *icd) | ||
852 | { | ||
853 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | ||
854 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
855 | struct atmel_isi *isi = ici->priv; | ||
856 | struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; | ||
857 | unsigned long common_flags; | ||
858 | int ret; | ||
859 | u32 cfg1 = 0; | ||
860 | |||
861 | ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); | ||
862 | if (!ret) { | ||
863 | common_flags = soc_mbus_config_compatible(&cfg, | ||
864 | ISI_BUS_PARAM); | ||
865 | if (!common_flags) { | ||
866 | dev_warn(icd->parent, | ||
867 | "Flags incompatible: camera 0x%x, host 0x%x\n", | ||
868 | cfg.flags, ISI_BUS_PARAM); | ||
869 | return -EINVAL; | ||
870 | } | ||
871 | } else if (ret != -ENOIOCTLCMD) { | ||
872 | return ret; | ||
873 | } else { | ||
874 | common_flags = ISI_BUS_PARAM; | ||
875 | } | ||
876 | dev_dbg(icd->parent, "Flags cam: 0x%x host: 0x%x common: 0x%lx\n", | ||
877 | cfg.flags, ISI_BUS_PARAM, common_flags); | ||
878 | |||
879 | /* Make choises, based on platform preferences */ | ||
880 | if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && | ||
881 | (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { | ||
882 | if (isi->pdata.hsync_act_low) | ||
883 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; | ||
884 | else | ||
885 | common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; | ||
886 | } | ||
887 | |||
888 | if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && | ||
889 | (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { | ||
890 | if (isi->pdata.vsync_act_low) | ||
891 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; | ||
892 | else | ||
893 | common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; | ||
894 | } | ||
895 | |||
896 | if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) && | ||
897 | (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) { | ||
898 | if (isi->pdata.pclk_act_falling) | ||
899 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING; | ||
900 | else | ||
901 | common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING; | ||
902 | } | ||
903 | |||
904 | cfg.flags = common_flags; | ||
905 | ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); | ||
906 | if (ret < 0 && ret != -ENOIOCTLCMD) { | ||
907 | dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n", | ||
908 | common_flags, ret); | ||
909 | return ret; | ||
910 | } | ||
911 | |||
912 | /* set bus param for ISI */ | ||
913 | if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) | ||
914 | cfg1 |= ISI_CFG1_HSYNC_POL_ACTIVE_LOW; | ||
915 | if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) | ||
916 | cfg1 |= ISI_CFG1_VSYNC_POL_ACTIVE_LOW; | ||
917 | if (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) | ||
918 | cfg1 |= ISI_CFG1_PIXCLK_POL_ACTIVE_FALLING; | ||
919 | |||
920 | dev_dbg(icd->parent, "vsync active %s, hsync active %s, sampling on pix clock %s edge\n", | ||
921 | common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW ? "low" : "high", | ||
922 | common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW ? "low" : "high", | ||
923 | common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING ? "falling" : "rising"); | ||
924 | |||
925 | if (isi->pdata.has_emb_sync) | ||
926 | cfg1 |= ISI_CFG1_EMB_SYNC; | ||
927 | if (isi->pdata.full_mode) | ||
928 | cfg1 |= ISI_CFG1_FULL_MODE; | ||
929 | |||
930 | cfg1 |= ISI_CFG1_THMASK_BEATS_16; | ||
931 | |||
932 | /* Enable PM and peripheral clock before operate isi registers */ | ||
933 | pm_runtime_get_sync(ici->v4l2_dev.dev); | ||
934 | |||
935 | isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); | ||
936 | isi_writel(isi, ISI_CFG1, cfg1); | ||
937 | |||
938 | pm_runtime_put(ici->v4l2_dev.dev); | ||
939 | |||
940 | return 0; | ||
941 | } | ||
942 | |||
943 | static struct soc_camera_host_ops isi_soc_camera_host_ops = { | ||
944 | .owner = THIS_MODULE, | ||
945 | .add = isi_camera_add_device, | ||
946 | .remove = isi_camera_remove_device, | ||
947 | .set_fmt = isi_camera_set_fmt, | ||
948 | .try_fmt = isi_camera_try_fmt, | ||
949 | .get_formats = isi_camera_get_formats, | ||
950 | .init_videobuf2 = isi_camera_init_videobuf, | ||
951 | .poll = isi_camera_poll, | ||
952 | .querycap = isi_camera_querycap, | ||
953 | .set_bus_param = isi_camera_set_bus_param, | ||
954 | }; | ||
955 | |||
956 | /* -----------------------------------------------------------------------*/ | ||
957 | static int atmel_isi_remove(struct platform_device *pdev) | ||
958 | { | ||
959 | struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); | ||
960 | struct atmel_isi *isi = container_of(soc_host, | ||
961 | struct atmel_isi, soc_host); | ||
962 | |||
963 | soc_camera_host_unregister(soc_host); | ||
964 | dma_free_coherent(&pdev->dev, | ||
965 | sizeof(struct fbd) * MAX_BUFFER_NUM, | ||
966 | isi->p_fb_descriptors, | ||
967 | isi->fb_descriptors_phys); | ||
968 | pm_runtime_disable(&pdev->dev); | ||
969 | |||
970 | return 0; | ||
971 | } | ||
972 | |||
973 | static int atmel_isi_parse_dt(struct atmel_isi *isi, | ||
974 | struct platform_device *pdev) | ||
975 | { | ||
976 | struct device_node *np= pdev->dev.of_node; | ||
977 | struct v4l2_of_endpoint ep; | ||
978 | int err; | ||
979 | |||
980 | /* Default settings for ISI */ | ||
981 | isi->pdata.full_mode = 1; | ||
982 | isi->pdata.frate = ISI_CFG1_FRATE_CAPTURE_ALL; | ||
983 | |||
984 | np = of_graph_get_next_endpoint(np, NULL); | ||
985 | if (!np) { | ||
986 | dev_err(&pdev->dev, "Could not find the endpoint\n"); | ||
987 | return -EINVAL; | ||
988 | } | ||
989 | |||
990 | err = v4l2_of_parse_endpoint(np, &ep); | ||
991 | of_node_put(np); | ||
992 | if (err) { | ||
993 | dev_err(&pdev->dev, "Could not parse the endpoint\n"); | ||
994 | return err; | ||
995 | } | ||
996 | |||
997 | switch (ep.bus.parallel.bus_width) { | ||
998 | case 8: | ||
999 | isi->pdata.data_width_flags = ISI_DATAWIDTH_8; | ||
1000 | break; | ||
1001 | case 10: | ||
1002 | isi->pdata.data_width_flags = | ||
1003 | ISI_DATAWIDTH_8 | ISI_DATAWIDTH_10; | ||
1004 | break; | ||
1005 | default: | ||
1006 | dev_err(&pdev->dev, "Unsupported bus width: %d\n", | ||
1007 | ep.bus.parallel.bus_width); | ||
1008 | return -EINVAL; | ||
1009 | } | ||
1010 | |||
1011 | if (ep.bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) | ||
1012 | isi->pdata.hsync_act_low = true; | ||
1013 | if (ep.bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) | ||
1014 | isi->pdata.vsync_act_low = true; | ||
1015 | if (ep.bus.parallel.flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) | ||
1016 | isi->pdata.pclk_act_falling = true; | ||
1017 | |||
1018 | if (ep.bus_type == V4L2_MBUS_BT656) | ||
1019 | isi->pdata.has_emb_sync = true; | ||
1020 | |||
1021 | return 0; | ||
1022 | } | ||
1023 | |||
1024 | static int atmel_isi_probe(struct platform_device *pdev) | ||
1025 | { | ||
1026 | int irq; | ||
1027 | struct atmel_isi *isi; | ||
1028 | struct resource *regs; | ||
1029 | int ret, i; | ||
1030 | struct soc_camera_host *soc_host; | ||
1031 | |||
1032 | isi = devm_kzalloc(&pdev->dev, sizeof(struct atmel_isi), GFP_KERNEL); | ||
1033 | if (!isi) { | ||
1034 | dev_err(&pdev->dev, "Can't allocate interface!\n"); | ||
1035 | return -ENOMEM; | ||
1036 | } | ||
1037 | |||
1038 | isi->pclk = devm_clk_get(&pdev->dev, "isi_clk"); | ||
1039 | if (IS_ERR(isi->pclk)) | ||
1040 | return PTR_ERR(isi->pclk); | ||
1041 | |||
1042 | ret = atmel_isi_parse_dt(isi, pdev); | ||
1043 | if (ret) | ||
1044 | return ret; | ||
1045 | |||
1046 | isi->active = NULL; | ||
1047 | spin_lock_init(&isi->lock); | ||
1048 | INIT_LIST_HEAD(&isi->video_buffer_list); | ||
1049 | INIT_LIST_HEAD(&isi->dma_desc_head); | ||
1050 | |||
1051 | isi->p_fb_descriptors = dma_alloc_coherent(&pdev->dev, | ||
1052 | sizeof(struct fbd) * MAX_BUFFER_NUM, | ||
1053 | &isi->fb_descriptors_phys, | ||
1054 | GFP_KERNEL); | ||
1055 | if (!isi->p_fb_descriptors) { | ||
1056 | dev_err(&pdev->dev, "Can't allocate descriptors!\n"); | ||
1057 | return -ENOMEM; | ||
1058 | } | ||
1059 | |||
1060 | for (i = 0; i < MAX_BUFFER_NUM; i++) { | ||
1061 | isi->dma_desc[i].p_fbd = isi->p_fb_descriptors + i; | ||
1062 | isi->dma_desc[i].fbd_phys = isi->fb_descriptors_phys + | ||
1063 | i * sizeof(struct fbd); | ||
1064 | list_add(&isi->dma_desc[i].list, &isi->dma_desc_head); | ||
1065 | } | ||
1066 | |||
1067 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1068 | isi->regs = devm_ioremap_resource(&pdev->dev, regs); | ||
1069 | if (IS_ERR(isi->regs)) { | ||
1070 | ret = PTR_ERR(isi->regs); | ||
1071 | goto err_ioremap; | ||
1072 | } | ||
1073 | |||
1074 | if (isi->pdata.data_width_flags & ISI_DATAWIDTH_8) | ||
1075 | isi->width_flags = 1 << 7; | ||
1076 | if (isi->pdata.data_width_flags & ISI_DATAWIDTH_10) | ||
1077 | isi->width_flags |= 1 << 9; | ||
1078 | |||
1079 | irq = platform_get_irq(pdev, 0); | ||
1080 | if (irq < 0) { | ||
1081 | ret = irq; | ||
1082 | goto err_req_irq; | ||
1083 | } | ||
1084 | |||
1085 | ret = devm_request_irq(&pdev->dev, irq, isi_interrupt, 0, "isi", isi); | ||
1086 | if (ret) { | ||
1087 | dev_err(&pdev->dev, "Unable to request irq %d\n", irq); | ||
1088 | goto err_req_irq; | ||
1089 | } | ||
1090 | isi->irq = irq; | ||
1091 | |||
1092 | soc_host = &isi->soc_host; | ||
1093 | soc_host->drv_name = "isi-camera"; | ||
1094 | soc_host->ops = &isi_soc_camera_host_ops; | ||
1095 | soc_host->priv = isi; | ||
1096 | soc_host->v4l2_dev.dev = &pdev->dev; | ||
1097 | soc_host->nr = pdev->id; | ||
1098 | |||
1099 | pm_suspend_ignore_children(&pdev->dev, true); | ||
1100 | pm_runtime_enable(&pdev->dev); | ||
1101 | |||
1102 | ret = soc_camera_host_register(soc_host); | ||
1103 | if (ret) { | ||
1104 | dev_err(&pdev->dev, "Unable to register soc camera host\n"); | ||
1105 | goto err_register_soc_camera_host; | ||
1106 | } | ||
1107 | return 0; | ||
1108 | |||
1109 | err_register_soc_camera_host: | ||
1110 | pm_runtime_disable(&pdev->dev); | ||
1111 | err_req_irq: | ||
1112 | err_ioremap: | ||
1113 | dma_free_coherent(&pdev->dev, | ||
1114 | sizeof(struct fbd) * MAX_BUFFER_NUM, | ||
1115 | isi->p_fb_descriptors, | ||
1116 | isi->fb_descriptors_phys); | ||
1117 | |||
1118 | return ret; | ||
1119 | } | ||
1120 | |||
1121 | #ifdef CONFIG_PM | ||
1122 | static int atmel_isi_runtime_suspend(struct device *dev) | ||
1123 | { | ||
1124 | struct soc_camera_host *soc_host = to_soc_camera_host(dev); | ||
1125 | struct atmel_isi *isi = container_of(soc_host, | ||
1126 | struct atmel_isi, soc_host); | ||
1127 | |||
1128 | clk_disable_unprepare(isi->pclk); | ||
1129 | |||
1130 | return 0; | ||
1131 | } | ||
1132 | static int atmel_isi_runtime_resume(struct device *dev) | ||
1133 | { | ||
1134 | struct soc_camera_host *soc_host = to_soc_camera_host(dev); | ||
1135 | struct atmel_isi *isi = container_of(soc_host, | ||
1136 | struct atmel_isi, soc_host); | ||
1137 | |||
1138 | return clk_prepare_enable(isi->pclk); | ||
1139 | } | ||
1140 | #endif /* CONFIG_PM */ | ||
1141 | |||
1142 | static const struct dev_pm_ops atmel_isi_dev_pm_ops = { | ||
1143 | SET_RUNTIME_PM_OPS(atmel_isi_runtime_suspend, | ||
1144 | atmel_isi_runtime_resume, NULL) | ||
1145 | }; | ||
1146 | |||
1147 | static const struct of_device_id atmel_isi_of_match[] = { | ||
1148 | { .compatible = "atmel,at91sam9g45-isi" }, | ||
1149 | { } | ||
1150 | }; | ||
1151 | MODULE_DEVICE_TABLE(of, atmel_isi_of_match); | ||
1152 | |||
1153 | static struct platform_driver atmel_isi_driver = { | ||
1154 | .remove = atmel_isi_remove, | ||
1155 | .driver = { | ||
1156 | .name = "atmel_isi", | ||
1157 | .of_match_table = of_match_ptr(atmel_isi_of_match), | ||
1158 | .pm = &atmel_isi_dev_pm_ops, | ||
1159 | }, | ||
1160 | }; | ||
1161 | |||
1162 | module_platform_driver_probe(atmel_isi_driver, atmel_isi_probe); | ||
1163 | |||
1164 | MODULE_AUTHOR("Josh Wu <josh.wu@atmel.com>"); | ||
1165 | MODULE_DESCRIPTION("The V4L2 driver for Atmel Linux"); | ||
1166 | MODULE_LICENSE("GPL"); | ||
1167 | MODULE_SUPPORTED_DEVICE("video"); | ||
diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c index a15bfb5aea47..96dc01750bc0 100644 --- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c +++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c | |||
@@ -1801,18 +1801,7 @@ static struct platform_driver sh_mobile_ceu_driver = { | |||
1801 | .remove = sh_mobile_ceu_remove, | 1801 | .remove = sh_mobile_ceu_remove, |
1802 | }; | 1802 | }; |
1803 | 1803 | ||
1804 | static int __init sh_mobile_ceu_init(void) | 1804 | module_platform_driver(sh_mobile_ceu_driver); |
1805 | { | ||
1806 | return platform_driver_register(&sh_mobile_ceu_driver); | ||
1807 | } | ||
1808 | |||
1809 | static void __exit sh_mobile_ceu_exit(void) | ||
1810 | { | ||
1811 | platform_driver_unregister(&sh_mobile_ceu_driver); | ||
1812 | } | ||
1813 | |||
1814 | module_init(sh_mobile_ceu_init); | ||
1815 | module_exit(sh_mobile_ceu_exit); | ||
1816 | 1805 | ||
1817 | MODULE_DESCRIPTION("SuperH Mobile CEU driver"); | 1806 | MODULE_DESCRIPTION("SuperH Mobile CEU driver"); |
1818 | MODULE_AUTHOR("Magnus Damm"); | 1807 | MODULE_AUTHOR("Magnus Damm"); |
diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index edd1c1de4e33..3c9421f4d8e3 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c | |||
@@ -37,18 +37,12 @@ | |||
37 | #include <media/v4l2-ioctl.h> | 37 | #include <media/v4l2-ioctl.h> |
38 | #include <media/v4l2-dev.h> | 38 | #include <media/v4l2-dev.h> |
39 | #include <media/v4l2-of.h> | 39 | #include <media/v4l2-of.h> |
40 | #include <media/videobuf-core.h> | ||
41 | #include <media/videobuf2-v4l2.h> | 40 | #include <media/videobuf2-v4l2.h> |
42 | 41 | ||
43 | /* Default to VGA resolution */ | 42 | /* Default to VGA resolution */ |
44 | #define DEFAULT_WIDTH 640 | 43 | #define DEFAULT_WIDTH 640 |
45 | #define DEFAULT_HEIGHT 480 | 44 | #define DEFAULT_HEIGHT 480 |
46 | 45 | ||
47 | #define is_streaming(ici, icd) \ | ||
48 | (((ici)->ops->init_videobuf) ? \ | ||
49 | (icd)->vb_vidq.streaming : \ | ||
50 | vb2_is_streaming(&(icd)->vb2_vidq)) | ||
51 | |||
52 | #define MAP_MAX_NUM 32 | 46 | #define MAP_MAX_NUM 32 |
53 | static DECLARE_BITMAP(device_map, MAP_MAX_NUM); | 47 | static DECLARE_BITMAP(device_map, MAP_MAX_NUM); |
54 | static LIST_HEAD(hosts); | 48 | static LIST_HEAD(hosts); |
@@ -367,23 +361,13 @@ static int soc_camera_reqbufs(struct file *file, void *priv, | |||
367 | { | 361 | { |
368 | int ret; | 362 | int ret; |
369 | struct soc_camera_device *icd = file->private_data; | 363 | struct soc_camera_device *icd = file->private_data; |
370 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
371 | 364 | ||
372 | WARN_ON(priv != file->private_data); | 365 | WARN_ON(priv != file->private_data); |
373 | 366 | ||
374 | if (icd->streamer && icd->streamer != file) | 367 | if (icd->streamer && icd->streamer != file) |
375 | return -EBUSY; | 368 | return -EBUSY; |
376 | 369 | ||
377 | if (ici->ops->init_videobuf) { | 370 | ret = vb2_reqbufs(&icd->vb2_vidq, p); |
378 | ret = videobuf_reqbufs(&icd->vb_vidq, p); | ||
379 | if (ret < 0) | ||
380 | return ret; | ||
381 | |||
382 | ret = ici->ops->reqbufs(icd, p); | ||
383 | } else { | ||
384 | ret = vb2_reqbufs(&icd->vb2_vidq, p); | ||
385 | } | ||
386 | |||
387 | if (!ret) | 371 | if (!ret) |
388 | icd->streamer = p->count ? file : NULL; | 372 | icd->streamer = p->count ? file : NULL; |
389 | return ret; | 373 | return ret; |
@@ -393,61 +377,44 @@ static int soc_camera_querybuf(struct file *file, void *priv, | |||
393 | struct v4l2_buffer *p) | 377 | struct v4l2_buffer *p) |
394 | { | 378 | { |
395 | struct soc_camera_device *icd = file->private_data; | 379 | struct soc_camera_device *icd = file->private_data; |
396 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
397 | 380 | ||
398 | WARN_ON(priv != file->private_data); | 381 | WARN_ON(priv != file->private_data); |
399 | 382 | ||
400 | if (ici->ops->init_videobuf) | 383 | return vb2_querybuf(&icd->vb2_vidq, p); |
401 | return videobuf_querybuf(&icd->vb_vidq, p); | ||
402 | else | ||
403 | return vb2_querybuf(&icd->vb2_vidq, p); | ||
404 | } | 384 | } |
405 | 385 | ||
406 | static int soc_camera_qbuf(struct file *file, void *priv, | 386 | static int soc_camera_qbuf(struct file *file, void *priv, |
407 | struct v4l2_buffer *p) | 387 | struct v4l2_buffer *p) |
408 | { | 388 | { |
409 | struct soc_camera_device *icd = file->private_data; | 389 | struct soc_camera_device *icd = file->private_data; |
410 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
411 | 390 | ||
412 | WARN_ON(priv != file->private_data); | 391 | WARN_ON(priv != file->private_data); |
413 | 392 | ||
414 | if (icd->streamer != file) | 393 | if (icd->streamer != file) |
415 | return -EBUSY; | 394 | return -EBUSY; |
416 | 395 | ||
417 | if (ici->ops->init_videobuf) | 396 | return vb2_qbuf(&icd->vb2_vidq, p); |
418 | return videobuf_qbuf(&icd->vb_vidq, p); | ||
419 | else | ||
420 | return vb2_qbuf(&icd->vb2_vidq, p); | ||
421 | } | 397 | } |
422 | 398 | ||
423 | static int soc_camera_dqbuf(struct file *file, void *priv, | 399 | static int soc_camera_dqbuf(struct file *file, void *priv, |
424 | struct v4l2_buffer *p) | 400 | struct v4l2_buffer *p) |
425 | { | 401 | { |
426 | struct soc_camera_device *icd = file->private_data; | 402 | struct soc_camera_device *icd = file->private_data; |
427 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
428 | 403 | ||
429 | WARN_ON(priv != file->private_data); | 404 | WARN_ON(priv != file->private_data); |
430 | 405 | ||
431 | if (icd->streamer != file) | 406 | if (icd->streamer != file) |
432 | return -EBUSY; | 407 | return -EBUSY; |
433 | 408 | ||
434 | if (ici->ops->init_videobuf) | 409 | return vb2_dqbuf(&icd->vb2_vidq, p, file->f_flags & O_NONBLOCK); |
435 | return videobuf_dqbuf(&icd->vb_vidq, p, file->f_flags & O_NONBLOCK); | ||
436 | else | ||
437 | return vb2_dqbuf(&icd->vb2_vidq, p, file->f_flags & O_NONBLOCK); | ||
438 | } | 410 | } |
439 | 411 | ||
440 | static int soc_camera_create_bufs(struct file *file, void *priv, | 412 | static int soc_camera_create_bufs(struct file *file, void *priv, |
441 | struct v4l2_create_buffers *create) | 413 | struct v4l2_create_buffers *create) |
442 | { | 414 | { |
443 | struct soc_camera_device *icd = file->private_data; | 415 | struct soc_camera_device *icd = file->private_data; |
444 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
445 | int ret; | 416 | int ret; |
446 | 417 | ||
447 | /* videobuf2 only */ | ||
448 | if (ici->ops->init_videobuf) | ||
449 | return -ENOTTY; | ||
450 | |||
451 | if (icd->streamer && icd->streamer != file) | 418 | if (icd->streamer && icd->streamer != file) |
452 | return -EBUSY; | 419 | return -EBUSY; |
453 | 420 | ||
@@ -461,24 +428,14 @@ static int soc_camera_prepare_buf(struct file *file, void *priv, | |||
461 | struct v4l2_buffer *b) | 428 | struct v4l2_buffer *b) |
462 | { | 429 | { |
463 | struct soc_camera_device *icd = file->private_data; | 430 | struct soc_camera_device *icd = file->private_data; |
464 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
465 | 431 | ||
466 | /* videobuf2 only */ | 432 | return vb2_prepare_buf(&icd->vb2_vidq, b); |
467 | if (ici->ops->init_videobuf) | ||
468 | return -EINVAL; | ||
469 | else | ||
470 | return vb2_prepare_buf(&icd->vb2_vidq, b); | ||
471 | } | 433 | } |
472 | 434 | ||
473 | static int soc_camera_expbuf(struct file *file, void *priv, | 435 | static int soc_camera_expbuf(struct file *file, void *priv, |
474 | struct v4l2_exportbuffer *p) | 436 | struct v4l2_exportbuffer *p) |
475 | { | 437 | { |
476 | struct soc_camera_device *icd = file->private_data; | 438 | struct soc_camera_device *icd = file->private_data; |
477 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
478 | |||
479 | /* videobuf2 only */ | ||
480 | if (ici->ops->init_videobuf) | ||
481 | return -ENOTTY; | ||
482 | 439 | ||
483 | if (icd->streamer && icd->streamer != file) | 440 | if (icd->streamer && icd->streamer != file) |
484 | return -EBUSY; | 441 | return -EBUSY; |
@@ -602,8 +559,6 @@ static int soc_camera_set_fmt(struct soc_camera_device *icd, | |||
602 | icd->sizeimage = pix->sizeimage; | 559 | icd->sizeimage = pix->sizeimage; |
603 | icd->colorspace = pix->colorspace; | 560 | icd->colorspace = pix->colorspace; |
604 | icd->field = pix->field; | 561 | icd->field = pix->field; |
605 | if (ici->ops->init_videobuf) | ||
606 | icd->vb_vidq.field = pix->field; | ||
607 | 562 | ||
608 | dev_dbg(icd->pdev, "set width: %d height: %d\n", | 563 | dev_dbg(icd->pdev, "set width: %d height: %d\n", |
609 | icd->user_width, icd->user_height); | 564 | icd->user_width, icd->user_height); |
@@ -745,13 +700,9 @@ static int soc_camera_open(struct file *file) | |||
745 | if (ret < 0) | 700 | if (ret < 0) |
746 | goto esfmt; | 701 | goto esfmt; |
747 | 702 | ||
748 | if (ici->ops->init_videobuf) { | 703 | ret = ici->ops->init_videobuf2(&icd->vb2_vidq, icd); |
749 | ici->ops->init_videobuf(&icd->vb_vidq, icd); | 704 | if (ret < 0) |
750 | } else { | 705 | goto einitvb; |
751 | ret = ici->ops->init_videobuf2(&icd->vb2_vidq, icd); | ||
752 | if (ret < 0) | ||
753 | goto einitvb; | ||
754 | } | ||
755 | v4l2_ctrl_handler_setup(&icd->ctrl_handler); | 706 | v4l2_ctrl_handler_setup(&icd->ctrl_handler); |
756 | } | 707 | } |
757 | mutex_unlock(&ici->host_lock); | 708 | mutex_unlock(&ici->host_lock); |
@@ -842,10 +793,7 @@ static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma) | |||
842 | 793 | ||
843 | if (mutex_lock_interruptible(&ici->host_lock)) | 794 | if (mutex_lock_interruptible(&ici->host_lock)) |
844 | return -ERESTARTSYS; | 795 | return -ERESTARTSYS; |
845 | if (ici->ops->init_videobuf) | 796 | err = vb2_mmap(&icd->vb2_vidq, vma); |
846 | err = videobuf_mmap_mapper(&icd->vb_vidq, vma); | ||
847 | else | ||
848 | err = vb2_mmap(&icd->vb2_vidq, vma); | ||
849 | mutex_unlock(&ici->host_lock); | 797 | mutex_unlock(&ici->host_lock); |
850 | 798 | ||
851 | dev_dbg(icd->pdev, "vma start=0x%08lx, size=%ld, ret=%d\n", | 799 | dev_dbg(icd->pdev, "vma start=0x%08lx, size=%ld, ret=%d\n", |
@@ -866,10 +814,7 @@ static unsigned int soc_camera_poll(struct file *file, poll_table *pt) | |||
866 | return POLLERR; | 814 | return POLLERR; |
867 | 815 | ||
868 | mutex_lock(&ici->host_lock); | 816 | mutex_lock(&ici->host_lock); |
869 | if (ici->ops->init_videobuf && list_empty(&icd->vb_vidq.stream)) | 817 | res = ici->ops->poll(file, pt); |
870 | dev_err(icd->pdev, "Trying to poll with no queued buffers!\n"); | ||
871 | else | ||
872 | res = ici->ops->poll(file, pt); | ||
873 | mutex_unlock(&ici->host_lock); | 818 | mutex_unlock(&ici->host_lock); |
874 | return res; | 819 | return res; |
875 | } | 820 | } |
@@ -900,7 +845,7 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, | |||
900 | if (icd->streamer && icd->streamer != file) | 845 | if (icd->streamer && icd->streamer != file) |
901 | return -EBUSY; | 846 | return -EBUSY; |
902 | 847 | ||
903 | if (is_streaming(to_soc_camera_host(icd->parent), icd)) { | 848 | if (vb2_is_streaming(&icd->vb2_vidq)) { |
904 | dev_err(icd->pdev, "S_FMT denied: queue initialised\n"); | 849 | dev_err(icd->pdev, "S_FMT denied: queue initialised\n"); |
905 | return -EBUSY; | 850 | return -EBUSY; |
906 | } | 851 | } |
@@ -971,7 +916,6 @@ static int soc_camera_streamon(struct file *file, void *priv, | |||
971 | enum v4l2_buf_type i) | 916 | enum v4l2_buf_type i) |
972 | { | 917 | { |
973 | struct soc_camera_device *icd = file->private_data; | 918 | struct soc_camera_device *icd = file->private_data; |
974 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
975 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 919 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
976 | int ret; | 920 | int ret; |
977 | 921 | ||
@@ -983,12 +927,8 @@ static int soc_camera_streamon(struct file *file, void *priv, | |||
983 | if (icd->streamer != file) | 927 | if (icd->streamer != file) |
984 | return -EBUSY; | 928 | return -EBUSY; |
985 | 929 | ||
986 | /* This calls buf_queue from host driver's videobuf_queue_ops */ | 930 | /* This calls buf_queue from host driver's videobuf2_queue_ops */ |
987 | if (ici->ops->init_videobuf) | 931 | ret = vb2_streamon(&icd->vb2_vidq, i); |
988 | ret = videobuf_streamon(&icd->vb_vidq); | ||
989 | else | ||
990 | ret = vb2_streamon(&icd->vb2_vidq, i); | ||
991 | |||
992 | if (!ret) | 932 | if (!ret) |
993 | v4l2_subdev_call(sd, video, s_stream, 1); | 933 | v4l2_subdev_call(sd, video, s_stream, 1); |
994 | 934 | ||
@@ -1000,7 +940,6 @@ static int soc_camera_streamoff(struct file *file, void *priv, | |||
1000 | { | 940 | { |
1001 | struct soc_camera_device *icd = file->private_data; | 941 | struct soc_camera_device *icd = file->private_data; |
1002 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); | 942 | struct v4l2_subdev *sd = soc_camera_to_subdev(icd); |
1003 | struct soc_camera_host *ici = to_soc_camera_host(icd->parent); | ||
1004 | int ret; | 943 | int ret; |
1005 | 944 | ||
1006 | WARN_ON(priv != file->private_data); | 945 | WARN_ON(priv != file->private_data); |
@@ -1012,13 +951,10 @@ static int soc_camera_streamoff(struct file *file, void *priv, | |||
1012 | return -EBUSY; | 951 | return -EBUSY; |
1013 | 952 | ||
1014 | /* | 953 | /* |
1015 | * This calls buf_release from host driver's videobuf_queue_ops for all | 954 | * This calls buf_release from host driver's videobuf2_queue_ops for all |
1016 | * remaining buffers. When the last buffer is freed, stop capture | 955 | * remaining buffers. When the last buffer is freed, stop capture |
1017 | */ | 956 | */ |
1018 | if (ici->ops->init_videobuf) | 957 | ret = vb2_streamoff(&icd->vb2_vidq, i); |
1019 | ret = videobuf_streamoff(&icd->vb_vidq); | ||
1020 | else | ||
1021 | ret = vb2_streamoff(&icd->vb2_vidq, i); | ||
1022 | 958 | ||
1023 | v4l2_subdev_call(sd, video, s_stream, 0); | 959 | v4l2_subdev_call(sd, video, s_stream, 0); |
1024 | 960 | ||
@@ -1053,7 +989,7 @@ static int soc_camera_s_selection(struct file *file, void *fh, | |||
1053 | 989 | ||
1054 | if (s->target == V4L2_SEL_TGT_COMPOSE) { | 990 | if (s->target == V4L2_SEL_TGT_COMPOSE) { |
1055 | /* No output size change during a running capture! */ | 991 | /* No output size change during a running capture! */ |
1056 | if (is_streaming(ici, icd) && | 992 | if (vb2_is_streaming(&icd->vb2_vidq) && |
1057 | (icd->user_width != s->r.width || | 993 | (icd->user_width != s->r.width || |
1058 | icd->user_height != s->r.height)) | 994 | icd->user_height != s->r.height)) |
1059 | return -EBUSY; | 995 | return -EBUSY; |
@@ -1066,7 +1002,8 @@ static int soc_camera_s_selection(struct file *file, void *fh, | |||
1066 | return -EBUSY; | 1002 | return -EBUSY; |
1067 | } | 1003 | } |
1068 | 1004 | ||
1069 | if (s->target == V4L2_SEL_TGT_CROP && is_streaming(ici, icd) && | 1005 | if (s->target == V4L2_SEL_TGT_CROP && |
1006 | vb2_is_streaming(&icd->vb2_vidq) && | ||
1070 | ici->ops->set_liveselection) | 1007 | ici->ops->set_liveselection) |
1071 | ret = ici->ops->set_liveselection(icd, s); | 1008 | ret = ici->ops->set_liveselection(icd, s); |
1072 | else | 1009 | else |
@@ -1910,9 +1847,7 @@ int soc_camera_host_register(struct soc_camera_host *ici) | |||
1910 | !ici->ops->set_fmt || | 1847 | !ici->ops->set_fmt || |
1911 | !ici->ops->set_bus_param || | 1848 | !ici->ops->set_bus_param || |
1912 | !ici->ops->querycap || | 1849 | !ici->ops->querycap || |
1913 | ((!ici->ops->init_videobuf || | 1850 | !ici->ops->init_videobuf2 || |
1914 | !ici->ops->reqbufs) && | ||
1915 | !ici->ops->init_videobuf2) || | ||
1916 | !ici->ops->poll || | 1851 | !ici->ops->poll || |
1917 | !ici->v4l2_dev.dev) | 1852 | !ici->v4l2_dev.dev) |
1918 | return -EINVAL; | 1853 | return -EINVAL; |
diff --git a/drivers/media/platform/soc_camera/soc_scale_crop.c b/drivers/media/platform/soc_camera/soc_scale_crop.c index f77252d6ccd3..0116097c0c0f 100644 --- a/drivers/media/platform/soc_camera/soc_scale_crop.c +++ b/drivers/media/platform/soc_camera/soc_scale_crop.c | |||
@@ -62,7 +62,8 @@ int soc_camera_client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect) | |||
62 | EXPORT_SYMBOL(soc_camera_client_g_rect); | 62 | EXPORT_SYMBOL(soc_camera_client_g_rect); |
63 | 63 | ||
64 | /* Client crop has changed, update our sub-rectangle to remain within the area */ | 64 | /* Client crop has changed, update our sub-rectangle to remain within the area */ |
65 | static void update_subrect(struct v4l2_rect *rect, struct v4l2_rect *subrect) | 65 | static void move_and_crop_subrect(struct v4l2_rect *rect, |
66 | struct v4l2_rect *subrect) | ||
66 | { | 67 | { |
67 | if (rect->width < subrect->width) | 68 | if (rect->width < subrect->width) |
68 | subrect->width = rect->width; | 69 | subrect->width = rect->width; |
@@ -72,14 +73,14 @@ static void update_subrect(struct v4l2_rect *rect, struct v4l2_rect *subrect) | |||
72 | 73 | ||
73 | if (rect->left > subrect->left) | 74 | if (rect->left > subrect->left) |
74 | subrect->left = rect->left; | 75 | subrect->left = rect->left; |
75 | else if (rect->left + rect->width > | 76 | else if (rect->left + rect->width < |
76 | subrect->left + subrect->width) | 77 | subrect->left + subrect->width) |
77 | subrect->left = rect->left + rect->width - | 78 | subrect->left = rect->left + rect->width - |
78 | subrect->width; | 79 | subrect->width; |
79 | 80 | ||
80 | if (rect->top > subrect->top) | 81 | if (rect->top > subrect->top) |
81 | subrect->top = rect->top; | 82 | subrect->top = rect->top; |
82 | else if (rect->top + rect->height > | 83 | else if (rect->top + rect->height < |
83 | subrect->top + subrect->height) | 84 | subrect->top + subrect->height) |
84 | subrect->top = rect->top + rect->height - | 85 | subrect->top = rect->top + rect->height - |
85 | subrect->height; | 86 | subrect->height; |
@@ -216,7 +217,7 @@ int soc_camera_client_s_selection(struct v4l2_subdev *sd, | |||
216 | 217 | ||
217 | if (!ret) { | 218 | if (!ret) { |
218 | *target_rect = *cam_rect; | 219 | *target_rect = *cam_rect; |
219 | update_subrect(target_rect, subrect); | 220 | move_and_crop_subrect(target_rect, subrect); |
220 | } | 221 | } |
221 | 222 | ||
222 | return ret; | 223 | return ret; |
@@ -299,7 +300,7 @@ update_cache: | |||
299 | if (host_1to1) | 300 | if (host_1to1) |
300 | *subrect = *rect; | 301 | *subrect = *rect; |
301 | else | 302 | else |
302 | update_subrect(rect, subrect); | 303 | move_and_crop_subrect(rect, subrect); |
303 | 304 | ||
304 | return 0; | 305 | return 0; |
305 | } | 306 | } |
diff --git a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c index 7652ce2ec1dc..59280ac31937 100644 --- a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c +++ b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c | |||
@@ -865,9 +865,8 @@ static int c8sectpfe_probe(struct platform_device *pdev) | |||
865 | } | 865 | } |
866 | 866 | ||
867 | /* Setup timer interrupt */ | 867 | /* Setup timer interrupt */ |
868 | init_timer(&fei->timer); | 868 | setup_timer(&fei->timer, c8sectpfe_timer_interrupt, |
869 | fei->timer.function = c8sectpfe_timer_interrupt; | 869 | (unsigned long)fei); |
870 | fei->timer.data = (unsigned long)fei; | ||
871 | 870 | ||
872 | mutex_init(&fei->lock); | 871 | mutex_init(&fei->lock); |
873 | 872 | ||
diff --git a/drivers/media/platform/sti/cec/Makefile b/drivers/media/platform/sti/cec/Makefile new file mode 100644 index 000000000000..f07905e1448a --- /dev/null +++ b/drivers/media/platform/sti/cec/Makefile | |||
@@ -0,0 +1 @@ | |||
obj-$(CONFIG_VIDEO_STI_HDMI_CEC) += stih-cec.o | |||
diff --git a/drivers/media/platform/sti/cec/stih-cec.c b/drivers/media/platform/sti/cec/stih-cec.c new file mode 100644 index 000000000000..39ff55145a82 --- /dev/null +++ b/drivers/media/platform/sti/cec/stih-cec.c | |||
@@ -0,0 +1,404 @@ | |||
1 | /* | ||
2 | * STIH4xx CEC driver | ||
3 | * Copyright (C) STMicroelectronic SA 2016 | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | */ | ||
10 | #include <linux/clk.h> | ||
11 | #include <linux/interrupt.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/mfd/syscon.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/of.h> | ||
16 | #include <linux/of_platform.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | |||
19 | #include <media/cec.h> | ||
20 | #include <media/cec-notifier.h> | ||
21 | |||
22 | #define CEC_NAME "stih-cec" | ||
23 | |||
24 | /* CEC registers */ | ||
25 | #define CEC_CLK_DIV 0x0 | ||
26 | #define CEC_CTRL 0x4 | ||
27 | #define CEC_IRQ_CTRL 0x8 | ||
28 | #define CEC_STATUS 0xC | ||
29 | #define CEC_EXT_STATUS 0x10 | ||
30 | #define CEC_TX_CTRL 0x14 | ||
31 | #define CEC_FREE_TIME_THRESH 0x18 | ||
32 | #define CEC_BIT_TOUT_THRESH 0x1C | ||
33 | #define CEC_BIT_PULSE_THRESH 0x20 | ||
34 | #define CEC_DATA 0x24 | ||
35 | #define CEC_TX_ARRAY_CTRL 0x28 | ||
36 | #define CEC_CTRL2 0x2C | ||
37 | #define CEC_TX_ERROR_STS 0x30 | ||
38 | #define CEC_ADDR_TABLE 0x34 | ||
39 | #define CEC_DATA_ARRAY_CTRL 0x38 | ||
40 | #define CEC_DATA_ARRAY_STATUS 0x3C | ||
41 | #define CEC_TX_DATA_BASE 0x40 | ||
42 | #define CEC_TX_DATA_TOP 0x50 | ||
43 | #define CEC_TX_DATA_SIZE 0x1 | ||
44 | #define CEC_RX_DATA_BASE 0x54 | ||
45 | #define CEC_RX_DATA_TOP 0x64 | ||
46 | #define CEC_RX_DATA_SIZE 0x1 | ||
47 | |||
48 | /* CEC_CTRL2 */ | ||
49 | #define CEC_LINE_INACTIVE_EN BIT(0) | ||
50 | #define CEC_AUTO_BUS_ERR_EN BIT(1) | ||
51 | #define CEC_STOP_ON_ARB_ERR_EN BIT(2) | ||
52 | #define CEC_TX_REQ_WAIT_EN BIT(3) | ||
53 | |||
54 | /* CEC_DATA_ARRAY_CTRL */ | ||
55 | #define CEC_TX_ARRAY_EN BIT(0) | ||
56 | #define CEC_RX_ARRAY_EN BIT(1) | ||
57 | #define CEC_TX_ARRAY_RESET BIT(2) | ||
58 | #define CEC_RX_ARRAY_RESET BIT(3) | ||
59 | #define CEC_TX_N_OF_BYTES_IRQ_EN BIT(4) | ||
60 | #define CEC_TX_STOP_ON_NACK BIT(7) | ||
61 | |||
62 | /* CEC_TX_ARRAY_CTRL */ | ||
63 | #define CEC_TX_N_OF_BYTES 0x1F | ||
64 | #define CEC_TX_START BIT(5) | ||
65 | #define CEC_TX_AUTO_SOM_EN BIT(6) | ||
66 | #define CEC_TX_AUTO_EOM_EN BIT(7) | ||
67 | |||
68 | /* CEC_IRQ_CTRL */ | ||
69 | #define CEC_TX_DONE_IRQ_EN BIT(0) | ||
70 | #define CEC_ERROR_IRQ_EN BIT(2) | ||
71 | #define CEC_RX_DONE_IRQ_EN BIT(3) | ||
72 | #define CEC_RX_SOM_IRQ_EN BIT(4) | ||
73 | #define CEC_RX_EOM_IRQ_EN BIT(5) | ||
74 | #define CEC_FREE_TIME_IRQ_EN BIT(6) | ||
75 | #define CEC_PIN_STS_IRQ_EN BIT(7) | ||
76 | |||
77 | /* CEC_CTRL */ | ||
78 | #define CEC_IN_FILTER_EN BIT(0) | ||
79 | #define CEC_PWR_SAVE_EN BIT(1) | ||
80 | #define CEC_EN BIT(4) | ||
81 | #define CEC_ACK_CTRL BIT(5) | ||
82 | #define CEC_RX_RESET_EN BIT(6) | ||
83 | #define CEC_IGNORE_RX_ERROR BIT(7) | ||
84 | |||
85 | /* CEC_STATUS */ | ||
86 | #define CEC_TX_DONE_STS BIT(0) | ||
87 | #define CEC_TX_ACK_GET_STS BIT(1) | ||
88 | #define CEC_ERROR_STS BIT(2) | ||
89 | #define CEC_RX_DONE_STS BIT(3) | ||
90 | #define CEC_RX_SOM_STS BIT(4) | ||
91 | #define CEC_RX_EOM_STS BIT(5) | ||
92 | #define CEC_FREE_TIME_IRQ_STS BIT(6) | ||
93 | #define CEC_PIN_STS BIT(7) | ||
94 | #define CEC_SBIT_TOUT_STS BIT(8) | ||
95 | #define CEC_DBIT_TOUT_STS BIT(9) | ||
96 | #define CEC_LPULSE_ERROR_STS BIT(10) | ||
97 | #define CEC_HPULSE_ERROR_STS BIT(11) | ||
98 | #define CEC_TX_ERROR BIT(12) | ||
99 | #define CEC_TX_ARB_ERROR BIT(13) | ||
100 | #define CEC_RX_ERROR_MIN BIT(14) | ||
101 | #define CEC_RX_ERROR_MAX BIT(15) | ||
102 | |||
103 | /* Signal free time in bit periods (2.4ms) */ | ||
104 | #define CEC_PRESENT_INIT_SFT 7 | ||
105 | #define CEC_NEW_INIT_SFT 5 | ||
106 | #define CEC_RETRANSMIT_SFT 3 | ||
107 | |||
108 | /* Constants for CEC_BIT_TOUT_THRESH register */ | ||
109 | #define CEC_SBIT_TOUT_47MS BIT(1) | ||
110 | #define CEC_SBIT_TOUT_48MS (BIT(0) | BIT(1)) | ||
111 | #define CEC_SBIT_TOUT_50MS BIT(2) | ||
112 | #define CEC_DBIT_TOUT_27MS BIT(0) | ||
113 | #define CEC_DBIT_TOUT_28MS BIT(1) | ||
114 | #define CEC_DBIT_TOUT_29MS (BIT(0) | BIT(1)) | ||
115 | |||
116 | /* Constants for CEC_BIT_PULSE_THRESH register */ | ||
117 | #define CEC_BIT_LPULSE_03MS BIT(1) | ||
118 | #define CEC_BIT_HPULSE_03MS BIT(3) | ||
119 | |||
120 | /* Constants for CEC_DATA_ARRAY_STATUS register */ | ||
121 | #define CEC_RX_N_OF_BYTES 0x1F | ||
122 | #define CEC_TX_N_OF_BYTES_SENT BIT(5) | ||
123 | #define CEC_RX_OVERRUN BIT(6) | ||
124 | |||
125 | struct stih_cec { | ||
126 | struct cec_adapter *adap; | ||
127 | struct device *dev; | ||
128 | struct clk *clk; | ||
129 | void __iomem *regs; | ||
130 | int irq; | ||
131 | u32 irq_status; | ||
132 | struct cec_notifier *notifier; | ||
133 | }; | ||
134 | |||
135 | static int stih_cec_adap_enable(struct cec_adapter *adap, bool enable) | ||
136 | { | ||
137 | struct stih_cec *cec = cec_get_drvdata(adap); | ||
138 | |||
139 | if (enable) { | ||
140 | /* The doc says (input TCLK_PERIOD * CEC_CLK_DIV) = 0.1ms */ | ||
141 | unsigned long clk_freq = clk_get_rate(cec->clk); | ||
142 | u32 cec_clk_div = clk_freq / 10000; | ||
143 | |||
144 | writel(cec_clk_div, cec->regs + CEC_CLK_DIV); | ||
145 | |||
146 | /* Configuration of the durations activating a timeout */ | ||
147 | writel(CEC_SBIT_TOUT_47MS | (CEC_DBIT_TOUT_28MS << 4), | ||
148 | cec->regs + CEC_BIT_TOUT_THRESH); | ||
149 | |||
150 | /* Configuration of the smallest allowed duration for pulses */ | ||
151 | writel(CEC_BIT_LPULSE_03MS | CEC_BIT_HPULSE_03MS, | ||
152 | cec->regs + CEC_BIT_PULSE_THRESH); | ||
153 | |||
154 | /* Minimum received bit period threshold */ | ||
155 | writel(BIT(5) | BIT(7), cec->regs + CEC_TX_CTRL); | ||
156 | |||
157 | /* Configuration of transceiver data arrays */ | ||
158 | writel(CEC_TX_ARRAY_EN | CEC_RX_ARRAY_EN | CEC_TX_STOP_ON_NACK, | ||
159 | cec->regs + CEC_DATA_ARRAY_CTRL); | ||
160 | |||
161 | /* Configuration of the control bits for CEC Transceiver */ | ||
162 | writel(CEC_IN_FILTER_EN | CEC_EN | CEC_RX_RESET_EN, | ||
163 | cec->regs + CEC_CTRL); | ||
164 | |||
165 | /* Clear logical addresses */ | ||
166 | writel(0, cec->regs + CEC_ADDR_TABLE); | ||
167 | |||
168 | /* Clear the status register */ | ||
169 | writel(0x0, cec->regs + CEC_STATUS); | ||
170 | |||
171 | /* Enable the interrupts */ | ||
172 | writel(CEC_TX_DONE_IRQ_EN | CEC_RX_DONE_IRQ_EN | | ||
173 | CEC_RX_SOM_IRQ_EN | CEC_RX_EOM_IRQ_EN | | ||
174 | CEC_ERROR_IRQ_EN, | ||
175 | cec->regs + CEC_IRQ_CTRL); | ||
176 | |||
177 | } else { | ||
178 | /* Clear logical addresses */ | ||
179 | writel(0, cec->regs + CEC_ADDR_TABLE); | ||
180 | |||
181 | /* Clear the status register */ | ||
182 | writel(0x0, cec->regs + CEC_STATUS); | ||
183 | |||
184 | /* Disable the interrupts */ | ||
185 | writel(0, cec->regs + CEC_IRQ_CTRL); | ||
186 | } | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | static int stih_cec_adap_log_addr(struct cec_adapter *adap, u8 logical_addr) | ||
192 | { | ||
193 | struct stih_cec *cec = cec_get_drvdata(adap); | ||
194 | u32 reg = readl(cec->regs + CEC_ADDR_TABLE); | ||
195 | |||
196 | reg |= 1 << logical_addr; | ||
197 | |||
198 | if (logical_addr == CEC_LOG_ADDR_INVALID) | ||
199 | reg = 0; | ||
200 | |||
201 | writel(reg, cec->regs + CEC_ADDR_TABLE); | ||
202 | |||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | static int stih_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, | ||
207 | u32 signal_free_time, struct cec_msg *msg) | ||
208 | { | ||
209 | struct stih_cec *cec = cec_get_drvdata(adap); | ||
210 | int i; | ||
211 | |||
212 | /* Copy message into registers */ | ||
213 | for (i = 0; i < msg->len; i++) | ||
214 | writeb(msg->msg[i], cec->regs + CEC_TX_DATA_BASE + i); | ||
215 | |||
216 | /* Start transmission, configure hardware to add start and stop bits | ||
217 | * Signal free time is handled by the hardware | ||
218 | */ | ||
219 | writel(CEC_TX_AUTO_SOM_EN | CEC_TX_AUTO_EOM_EN | CEC_TX_START | | ||
220 | msg->len, cec->regs + CEC_TX_ARRAY_CTRL); | ||
221 | |||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static void stih_tx_done(struct stih_cec *cec, u32 status) | ||
226 | { | ||
227 | if (status & CEC_TX_ERROR) { | ||
228 | cec_transmit_done(cec->adap, CEC_TX_STATUS_ERROR, 0, 0, 0, 1); | ||
229 | return; | ||
230 | } | ||
231 | |||
232 | if (status & CEC_TX_ARB_ERROR) { | ||
233 | cec_transmit_done(cec->adap, | ||
234 | CEC_TX_STATUS_ARB_LOST, 1, 0, 0, 0); | ||
235 | return; | ||
236 | } | ||
237 | |||
238 | if (!(status & CEC_TX_ACK_GET_STS)) { | ||
239 | cec_transmit_done(cec->adap, CEC_TX_STATUS_NACK, 0, 1, 0, 0); | ||
240 | return; | ||
241 | } | ||
242 | |||
243 | cec_transmit_done(cec->adap, CEC_TX_STATUS_OK, 0, 0, 0, 0); | ||
244 | } | ||
245 | |||
246 | static void stih_rx_done(struct stih_cec *cec, u32 status) | ||
247 | { | ||
248 | struct cec_msg msg = {}; | ||
249 | u8 i; | ||
250 | |||
251 | if (status & CEC_RX_ERROR_MIN) | ||
252 | return; | ||
253 | |||
254 | if (status & CEC_RX_ERROR_MAX) | ||
255 | return; | ||
256 | |||
257 | msg.len = readl(cec->regs + CEC_DATA_ARRAY_STATUS) & 0x1f; | ||
258 | |||
259 | if (!msg.len) | ||
260 | return; | ||
261 | |||
262 | if (msg.len > 16) | ||
263 | msg.len = 16; | ||
264 | |||
265 | for (i = 0; i < msg.len; i++) | ||
266 | msg.msg[i] = readl(cec->regs + CEC_RX_DATA_BASE + i); | ||
267 | |||
268 | cec_received_msg(cec->adap, &msg); | ||
269 | } | ||
270 | |||
271 | static irqreturn_t stih_cec_irq_handler_thread(int irq, void *priv) | ||
272 | { | ||
273 | struct stih_cec *cec = priv; | ||
274 | |||
275 | if (cec->irq_status & CEC_TX_DONE_STS) | ||
276 | stih_tx_done(cec, cec->irq_status); | ||
277 | |||
278 | if (cec->irq_status & CEC_RX_DONE_STS) | ||
279 | stih_rx_done(cec, cec->irq_status); | ||
280 | |||
281 | cec->irq_status = 0; | ||
282 | |||
283 | return IRQ_HANDLED; | ||
284 | } | ||
285 | |||
286 | static irqreturn_t stih_cec_irq_handler(int irq, void *priv) | ||
287 | { | ||
288 | struct stih_cec *cec = priv; | ||
289 | |||
290 | cec->irq_status = readl(cec->regs + CEC_STATUS); | ||
291 | writel(cec->irq_status, cec->regs + CEC_STATUS); | ||
292 | |||
293 | return IRQ_WAKE_THREAD; | ||
294 | } | ||
295 | |||
296 | static const struct cec_adap_ops sti_cec_adap_ops = { | ||
297 | .adap_enable = stih_cec_adap_enable, | ||
298 | .adap_log_addr = stih_cec_adap_log_addr, | ||
299 | .adap_transmit = stih_cec_adap_transmit, | ||
300 | }; | ||
301 | |||
302 | static int stih_cec_probe(struct platform_device *pdev) | ||
303 | { | ||
304 | struct device *dev = &pdev->dev; | ||
305 | struct resource *res; | ||
306 | struct stih_cec *cec; | ||
307 | struct device_node *np; | ||
308 | struct platform_device *hdmi_dev; | ||
309 | int ret; | ||
310 | |||
311 | cec = devm_kzalloc(dev, sizeof(*cec), GFP_KERNEL); | ||
312 | if (!cec) | ||
313 | return -ENOMEM; | ||
314 | |||
315 | np = of_parse_phandle(pdev->dev.of_node, "hdmi-phandle", 0); | ||
316 | |||
317 | if (!np) { | ||
318 | dev_err(&pdev->dev, "Failed to find hdmi node in device tree\n"); | ||
319 | return -ENODEV; | ||
320 | } | ||
321 | |||
322 | hdmi_dev = of_find_device_by_node(np); | ||
323 | if (!hdmi_dev) | ||
324 | return -EPROBE_DEFER; | ||
325 | |||
326 | cec->notifier = cec_notifier_get(&hdmi_dev->dev); | ||
327 | if (!cec->notifier) | ||
328 | return -ENOMEM; | ||
329 | |||
330 | cec->dev = dev; | ||
331 | |||
332 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
333 | cec->regs = devm_ioremap_resource(dev, res); | ||
334 | if (IS_ERR(cec->regs)) | ||
335 | return PTR_ERR(cec->regs); | ||
336 | |||
337 | cec->irq = platform_get_irq(pdev, 0); | ||
338 | if (cec->irq < 0) | ||
339 | return cec->irq; | ||
340 | |||
341 | ret = devm_request_threaded_irq(dev, cec->irq, stih_cec_irq_handler, | ||
342 | stih_cec_irq_handler_thread, 0, | ||
343 | pdev->name, cec); | ||
344 | if (ret) | ||
345 | return ret; | ||
346 | |||
347 | cec->clk = devm_clk_get(dev, "cec-clk"); | ||
348 | if (IS_ERR(cec->clk)) { | ||
349 | dev_err(dev, "Cannot get cec clock\n"); | ||
350 | return PTR_ERR(cec->clk); | ||
351 | } | ||
352 | |||
353 | cec->adap = cec_allocate_adapter(&sti_cec_adap_ops, cec, | ||
354 | CEC_NAME, | ||
355 | CEC_CAP_LOG_ADDRS | CEC_CAP_PASSTHROUGH | | ||
356 | CEC_CAP_TRANSMIT, 1); | ||
357 | ret = PTR_ERR_OR_ZERO(cec->adap); | ||
358 | if (ret) | ||
359 | return ret; | ||
360 | |||
361 | ret = cec_register_adapter(cec->adap, &pdev->dev); | ||
362 | if (ret) { | ||
363 | cec_delete_adapter(cec->adap); | ||
364 | return ret; | ||
365 | } | ||
366 | |||
367 | cec_register_cec_notifier(cec->adap, cec->notifier); | ||
368 | |||
369 | platform_set_drvdata(pdev, cec); | ||
370 | return 0; | ||
371 | } | ||
372 | |||
373 | static int stih_cec_remove(struct platform_device *pdev) | ||
374 | { | ||
375 | struct stih_cec *cec = platform_get_drvdata(pdev); | ||
376 | |||
377 | cec_unregister_adapter(cec->adap); | ||
378 | cec_notifier_put(cec->notifier); | ||
379 | |||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | static const struct of_device_id stih_cec_match[] = { | ||
384 | { | ||
385 | .compatible = "st,stih-cec", | ||
386 | }, | ||
387 | {}, | ||
388 | }; | ||
389 | MODULE_DEVICE_TABLE(of, stih_cec_match); | ||
390 | |||
391 | static struct platform_driver stih_cec_pdrv = { | ||
392 | .probe = stih_cec_probe, | ||
393 | .remove = stih_cec_remove, | ||
394 | .driver = { | ||
395 | .name = CEC_NAME, | ||
396 | .of_match_table = stih_cec_match, | ||
397 | }, | ||
398 | }; | ||
399 | |||
400 | module_platform_driver(stih_cec_pdrv); | ||
401 | |||
402 | MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@linaro.org>"); | ||
403 | MODULE_LICENSE("GPL"); | ||
404 | MODULE_DESCRIPTION("STIH4xx CEC driver"); | ||
diff --git a/drivers/media/platform/sti/delta/delta-mjpeg-dec.c b/drivers/media/platform/sti/delta/delta-mjpeg-dec.c index e79bdc611432..84ea43c0eb46 100644 --- a/drivers/media/platform/sti/delta/delta-mjpeg-dec.c +++ b/drivers/media/platform/sti/delta/delta-mjpeg-dec.c | |||
@@ -375,7 +375,7 @@ static int delta_mjpeg_decode(struct delta_ctx *pctx, struct delta_au *pau) | |||
375 | struct delta_mjpeg_ctx *ctx = to_ctx(pctx); | 375 | struct delta_mjpeg_ctx *ctx = to_ctx(pctx); |
376 | int ret; | 376 | int ret; |
377 | struct delta_au au = *pau; | 377 | struct delta_au au = *pau; |
378 | unsigned int data_offset; | 378 | unsigned int data_offset = 0; |
379 | struct mjpeg_header *header = &ctx->header_struct; | 379 | struct mjpeg_header *header = &ctx->header_struct; |
380 | 380 | ||
381 | if (!ctx->header) { | 381 | if (!ctx->header) { |
diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c index 23472e3784ff..e2cf2b90e500 100644 --- a/drivers/media/platform/ti-vpe/vpdma.c +++ b/drivers/media/platform/ti-vpe/vpdma.c | |||
@@ -801,17 +801,17 @@ static void dump_dtd(struct vpdma_dtd *dtd) | |||
801 | * flags: VPDMA flags to configure some descriptor fileds | 801 | * flags: VPDMA flags to configure some descriptor fileds |
802 | */ | 802 | */ |
803 | void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width, | 803 | void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width, |
804 | const struct v4l2_rect *c_rect, | 804 | int stride, const struct v4l2_rect *c_rect, |
805 | const struct vpdma_data_format *fmt, dma_addr_t dma_addr, | 805 | const struct vpdma_data_format *fmt, dma_addr_t dma_addr, |
806 | int max_w, int max_h, enum vpdma_channel chan, u32 flags) | 806 | int max_w, int max_h, enum vpdma_channel chan, u32 flags) |
807 | { | 807 | { |
808 | vpdma_rawchan_add_out_dtd(list, width, c_rect, fmt, dma_addr, | 808 | vpdma_rawchan_add_out_dtd(list, width, stride, c_rect, fmt, dma_addr, |
809 | max_w, max_h, chan_info[chan].num, flags); | 809 | max_w, max_h, chan_info[chan].num, flags); |
810 | } | 810 | } |
811 | EXPORT_SYMBOL(vpdma_add_out_dtd); | 811 | EXPORT_SYMBOL(vpdma_add_out_dtd); |
812 | 812 | ||
813 | void vpdma_rawchan_add_out_dtd(struct vpdma_desc_list *list, int width, | 813 | void vpdma_rawchan_add_out_dtd(struct vpdma_desc_list *list, int width, |
814 | const struct v4l2_rect *c_rect, | 814 | int stride, const struct v4l2_rect *c_rect, |
815 | const struct vpdma_data_format *fmt, dma_addr_t dma_addr, | 815 | const struct vpdma_data_format *fmt, dma_addr_t dma_addr, |
816 | int max_w, int max_h, int raw_vpdma_chan, u32 flags) | 816 | int max_w, int max_h, int raw_vpdma_chan, u32 flags) |
817 | { | 817 | { |
@@ -821,7 +821,6 @@ void vpdma_rawchan_add_out_dtd(struct vpdma_desc_list *list, int width, | |||
821 | int channel, next_chan; | 821 | int channel, next_chan; |
822 | struct v4l2_rect rect = *c_rect; | 822 | struct v4l2_rect rect = *c_rect; |
823 | int depth = fmt->depth; | 823 | int depth = fmt->depth; |
824 | int stride; | ||
825 | struct vpdma_dtd *dtd; | 824 | struct vpdma_dtd *dtd; |
826 | 825 | ||
827 | channel = next_chan = raw_vpdma_chan; | 826 | channel = next_chan = raw_vpdma_chan; |
@@ -833,8 +832,6 @@ void vpdma_rawchan_add_out_dtd(struct vpdma_desc_list *list, int width, | |||
833 | depth = 8; | 832 | depth = 8; |
834 | } | 833 | } |
835 | 834 | ||
836 | stride = ALIGN((depth * width) >> 3, VPDMA_STRIDE_ALIGN); | ||
837 | |||
838 | dma_addr += rect.top * stride + (rect.left * depth >> 3); | 835 | dma_addr += rect.top * stride + (rect.left * depth >> 3); |
839 | 836 | ||
840 | dtd = list->next; | 837 | dtd = list->next; |
@@ -882,7 +879,7 @@ EXPORT_SYMBOL(vpdma_rawchan_add_out_dtd); | |||
882 | * contribute to the client) | 879 | * contribute to the client) |
883 | */ | 880 | */ |
884 | void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width, | 881 | void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width, |
885 | const struct v4l2_rect *c_rect, | 882 | int stride, const struct v4l2_rect *c_rect, |
886 | const struct vpdma_data_format *fmt, dma_addr_t dma_addr, | 883 | const struct vpdma_data_format *fmt, dma_addr_t dma_addr, |
887 | enum vpdma_channel chan, int field, u32 flags, int frame_width, | 884 | enum vpdma_channel chan, int field, u32 flags, int frame_width, |
888 | int frame_height, int start_h, int start_v) | 885 | int frame_height, int start_h, int start_v) |
@@ -892,7 +889,6 @@ void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width, | |||
892 | int depth = fmt->depth; | 889 | int depth = fmt->depth; |
893 | int channel, next_chan; | 890 | int channel, next_chan; |
894 | struct v4l2_rect rect = *c_rect; | 891 | struct v4l2_rect rect = *c_rect; |
895 | int stride; | ||
896 | struct vpdma_dtd *dtd; | 892 | struct vpdma_dtd *dtd; |
897 | 893 | ||
898 | channel = next_chan = chan_info[chan].num; | 894 | channel = next_chan = chan_info[chan].num; |
@@ -904,8 +900,6 @@ void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width, | |||
904 | depth = 8; | 900 | depth = 8; |
905 | } | 901 | } |
906 | 902 | ||
907 | stride = ALIGN((depth * width) >> 3, VPDMA_STRIDE_ALIGN); | ||
908 | |||
909 | dma_addr += rect.top * stride + (rect.left * depth >> 3); | 903 | dma_addr += rect.top * stride + (rect.left * depth >> 3); |
910 | 904 | ||
911 | dtd = list->next; | 905 | dtd = list->next; |
diff --git a/drivers/media/platform/ti-vpe/vpdma.h b/drivers/media/platform/ti-vpe/vpdma.h index 131700c112b2..7e611501c291 100644 --- a/drivers/media/platform/ti-vpe/vpdma.h +++ b/drivers/media/platform/ti-vpe/vpdma.h | |||
@@ -242,16 +242,16 @@ void vpdma_add_sync_on_channel_ctd(struct vpdma_desc_list *list, | |||
242 | void vpdma_add_abort_channel_ctd(struct vpdma_desc_list *list, | 242 | void vpdma_add_abort_channel_ctd(struct vpdma_desc_list *list, |
243 | int chan_num); | 243 | int chan_num); |
244 | void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width, | 244 | void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width, |
245 | const struct v4l2_rect *c_rect, | 245 | int stride, const struct v4l2_rect *c_rect, |
246 | const struct vpdma_data_format *fmt, dma_addr_t dma_addr, | 246 | const struct vpdma_data_format *fmt, dma_addr_t dma_addr, |
247 | int max_w, int max_h, enum vpdma_channel chan, u32 flags); | 247 | int max_w, int max_h, enum vpdma_channel chan, u32 flags); |
248 | void vpdma_rawchan_add_out_dtd(struct vpdma_desc_list *list, int width, | 248 | void vpdma_rawchan_add_out_dtd(struct vpdma_desc_list *list, int width, |
249 | const struct v4l2_rect *c_rect, | 249 | int stride, const struct v4l2_rect *c_rect, |
250 | const struct vpdma_data_format *fmt, dma_addr_t dma_addr, | 250 | const struct vpdma_data_format *fmt, dma_addr_t dma_addr, |
251 | int max_w, int max_h, int raw_vpdma_chan, u32 flags); | 251 | int max_w, int max_h, int raw_vpdma_chan, u32 flags); |
252 | 252 | ||
253 | void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width, | 253 | void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width, |
254 | const struct v4l2_rect *c_rect, | 254 | int stride, const struct v4l2_rect *c_rect, |
255 | const struct vpdma_data_format *fmt, dma_addr_t dma_addr, | 255 | const struct vpdma_data_format *fmt, dma_addr_t dma_addr, |
256 | enum vpdma_channel chan, int field, u32 flags, int frame_width, | 256 | enum vpdma_channel chan, int field, u32 flags, int frame_width, |
257 | int frame_height, int start_h, int start_v); | 257 | int frame_height, int start_h, int start_v); |
diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index f0156b7759e9..c47151495b6f 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c | |||
@@ -1085,7 +1085,8 @@ static void add_out_dtd(struct vpe_ctx *ctx, int port) | |||
1085 | vpdma_set_max_size(ctx->dev->vpdma, VPDMA_MAX_SIZE1, | 1085 | vpdma_set_max_size(ctx->dev->vpdma, VPDMA_MAX_SIZE1, |
1086 | MAX_W, MAX_H); | 1086 | MAX_W, MAX_H); |
1087 | 1087 | ||
1088 | vpdma_add_out_dtd(&ctx->desc_list, q_data->width, &q_data->c_rect, | 1088 | vpdma_add_out_dtd(&ctx->desc_list, q_data->width, |
1089 | q_data->bytesperline[VPE_LUMA], &q_data->c_rect, | ||
1089 | vpdma_fmt, dma_addr, MAX_OUT_WIDTH_REG1, | 1090 | vpdma_fmt, dma_addr, MAX_OUT_WIDTH_REG1, |
1090 | MAX_OUT_HEIGHT_REG1, p_data->channel, flags); | 1091 | MAX_OUT_HEIGHT_REG1, p_data->channel, flags); |
1091 | } | 1092 | } |
@@ -1169,7 +1170,8 @@ static void add_in_dtd(struct vpe_ctx *ctx, int port) | |||
1169 | if (p_data->vb_part && fmt->fourcc == V4L2_PIX_FMT_NV12) | 1170 | if (p_data->vb_part && fmt->fourcc == V4L2_PIX_FMT_NV12) |
1170 | frame_height /= 2; | 1171 | frame_height /= 2; |
1171 | 1172 | ||
1172 | vpdma_add_in_dtd(&ctx->desc_list, q_data->width, &q_data->c_rect, | 1173 | vpdma_add_in_dtd(&ctx->desc_list, q_data->width, |
1174 | q_data->bytesperline[VPE_LUMA], &q_data->c_rect, | ||
1173 | vpdma_fmt, dma_addr, p_data->channel, field, flags, frame_width, | 1175 | vpdma_fmt, dma_addr, p_data->channel, field, flags, frame_width, |
1174 | frame_height, 0, 0); | 1176 | frame_height, 0, 0); |
1175 | } | 1177 | } |
@@ -1595,6 +1597,7 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f, | |||
1595 | struct v4l2_plane_pix_format *plane_fmt; | 1597 | struct v4l2_plane_pix_format *plane_fmt; |
1596 | unsigned int w_align; | 1598 | unsigned int w_align; |
1597 | int i, depth, depth_bytes, height; | 1599 | int i, depth, depth_bytes, height; |
1600 | unsigned int stride = 0; | ||
1598 | 1601 | ||
1599 | if (!fmt || !(fmt->types & type)) { | 1602 | if (!fmt || !(fmt->types & type)) { |
1600 | vpe_err(ctx->dev, "Fourcc format (0x%08x) invalid.\n", | 1603 | vpe_err(ctx->dev, "Fourcc format (0x%08x) invalid.\n", |
@@ -1681,16 +1684,27 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f, | |||
1681 | plane_fmt = &pix->plane_fmt[i]; | 1684 | plane_fmt = &pix->plane_fmt[i]; |
1682 | depth = fmt->vpdma_fmt[i]->depth; | 1685 | depth = fmt->vpdma_fmt[i]->depth; |
1683 | 1686 | ||
1684 | if (i == VPE_LUMA) | 1687 | stride = (pix->width * fmt->vpdma_fmt[VPE_LUMA]->depth) >> 3; |
1685 | plane_fmt->bytesperline = (pix->width * depth) >> 3; | 1688 | if (stride > plane_fmt->bytesperline) |
1686 | else | 1689 | plane_fmt->bytesperline = stride; |
1687 | plane_fmt->bytesperline = pix->width; | 1690 | |
1691 | plane_fmt->bytesperline = ALIGN(plane_fmt->bytesperline, | ||
1692 | VPDMA_STRIDE_ALIGN); | ||
1688 | 1693 | ||
1689 | if (pix->num_planes == 1 && fmt->coplanar) | 1694 | if (i == VPE_LUMA) { |
1690 | depth += fmt->vpdma_fmt[VPE_CHROMA]->depth; | 1695 | plane_fmt->sizeimage = pix->height * |
1691 | plane_fmt->sizeimage = | 1696 | plane_fmt->bytesperline; |
1692 | (pix->height * pix->width * depth) >> 3; | ||
1693 | 1697 | ||
1698 | if (pix->num_planes == 1 && fmt->coplanar) | ||
1699 | plane_fmt->sizeimage += pix->height * | ||
1700 | plane_fmt->bytesperline * | ||
1701 | fmt->vpdma_fmt[VPE_CHROMA]->depth >> 3; | ||
1702 | |||
1703 | } else { /* i == VIP_CHROMA */ | ||
1704 | plane_fmt->sizeimage = (pix->height * | ||
1705 | plane_fmt->bytesperline * | ||
1706 | depth) >> 3; | ||
1707 | } | ||
1694 | memset(plane_fmt->reserved, 0, sizeof(plane_fmt->reserved)); | 1708 | memset(plane_fmt->reserved, 0, sizeof(plane_fmt->reserved)); |
1695 | } | 1709 | } |
1696 | 1710 | ||
diff --git a/drivers/media/platform/vimc/Kconfig b/drivers/media/platform/vimc/Kconfig new file mode 100644 index 000000000000..a18f6352c422 --- /dev/null +++ b/drivers/media/platform/vimc/Kconfig | |||
@@ -0,0 +1,14 @@ | |||
1 | config VIDEO_VIMC | ||
2 | tristate "Virtual Media Controller Driver (VIMC)" | ||
3 | depends on VIDEO_DEV && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API | ||
4 | select VIDEOBUF2_VMALLOC | ||
5 | default n | ||
6 | ---help--- | ||
7 | Skeleton driver for Virtual Media Controller | ||
8 | |||
9 | This driver can be compared to the vivid driver for emulating | ||
10 | a media node that exposes a complex media topology. The topology | ||
11 | is hard coded for now but is meant to be highly configurable in | ||
12 | the future. | ||
13 | |||
14 | When in doubt, say N. | ||
diff --git a/drivers/media/platform/vimc/Makefile b/drivers/media/platform/vimc/Makefile new file mode 100644 index 000000000000..c45195e5e05c --- /dev/null +++ b/drivers/media/platform/vimc/Makefile | |||
@@ -0,0 +1,3 @@ | |||
1 | vimc-objs := vimc-core.o vimc-capture.o vimc-sensor.o | ||
2 | |||
3 | obj-$(CONFIG_VIDEO_VIMC) += vimc.o | ||
diff --git a/drivers/media/platform/vimc/vimc-capture.c b/drivers/media/platform/vimc/vimc-capture.c new file mode 100644 index 000000000000..9adb06d7e13d --- /dev/null +++ b/drivers/media/platform/vimc/vimc-capture.c | |||
@@ -0,0 +1,498 @@ | |||
1 | /* | ||
2 | * vimc-capture.c Virtual Media Controller Driver | ||
3 | * | ||
4 | * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <media/v4l2-ioctl.h> | ||
19 | #include <media/videobuf2-core.h> | ||
20 | #include <media/videobuf2-vmalloc.h> | ||
21 | |||
22 | #include "vimc-capture.h" | ||
23 | |||
24 | struct vimc_cap_device { | ||
25 | struct vimc_ent_device ved; | ||
26 | struct video_device vdev; | ||
27 | struct v4l2_pix_format format; | ||
28 | struct vb2_queue queue; | ||
29 | struct list_head buf_list; | ||
30 | /* | ||
31 | * NOTE: in a real driver, a spin lock must be used to access the | ||
32 | * queue because the frames are generated from a hardware interruption | ||
33 | * and the isr is not allowed to sleep. | ||
34 | * Even if it is not necessary a spinlock in the vimc driver, we | ||
35 | * use it here as a code reference | ||
36 | */ | ||
37 | spinlock_t qlock; | ||
38 | struct mutex lock; | ||
39 | u32 sequence; | ||
40 | struct media_pipeline pipe; | ||
41 | }; | ||
42 | |||
43 | struct vimc_cap_buffer { | ||
44 | /* | ||
45 | * struct vb2_v4l2_buffer must be the first element | ||
46 | * the videobuf2 framework will allocate this struct based on | ||
47 | * buf_struct_size and use the first sizeof(struct vb2_buffer) bytes of | ||
48 | * memory as a vb2_buffer | ||
49 | */ | ||
50 | struct vb2_v4l2_buffer vb2; | ||
51 | struct list_head list; | ||
52 | }; | ||
53 | |||
54 | static int vimc_cap_querycap(struct file *file, void *priv, | ||
55 | struct v4l2_capability *cap) | ||
56 | { | ||
57 | struct vimc_cap_device *vcap = video_drvdata(file); | ||
58 | |||
59 | strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); | ||
60 | strlcpy(cap->card, KBUILD_MODNAME, sizeof(cap->card)); | ||
61 | snprintf(cap->bus_info, sizeof(cap->bus_info), | ||
62 | "platform:%s", vcap->vdev.v4l2_dev->name); | ||
63 | |||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | static int vimc_cap_fmt_vid_cap(struct file *file, void *priv, | ||
68 | struct v4l2_format *f) | ||
69 | { | ||
70 | struct vimc_cap_device *vcap = video_drvdata(file); | ||
71 | |||
72 | f->fmt.pix = vcap->format; | ||
73 | |||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | static int vimc_cap_enum_fmt_vid_cap(struct file *file, void *priv, | ||
78 | struct v4l2_fmtdesc *f) | ||
79 | { | ||
80 | struct vimc_cap_device *vcap = video_drvdata(file); | ||
81 | |||
82 | if (f->index > 0) | ||
83 | return -EINVAL; | ||
84 | |||
85 | /* We only support one format for now */ | ||
86 | f->pixelformat = vcap->format.pixelformat; | ||
87 | |||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | static const struct v4l2_file_operations vimc_cap_fops = { | ||
92 | .owner = THIS_MODULE, | ||
93 | .open = v4l2_fh_open, | ||
94 | .release = vb2_fop_release, | ||
95 | .read = vb2_fop_read, | ||
96 | .poll = vb2_fop_poll, | ||
97 | .unlocked_ioctl = video_ioctl2, | ||
98 | .mmap = vb2_fop_mmap, | ||
99 | }; | ||
100 | |||
101 | static const struct v4l2_ioctl_ops vimc_cap_ioctl_ops = { | ||
102 | .vidioc_querycap = vimc_cap_querycap, | ||
103 | |||
104 | .vidioc_g_fmt_vid_cap = vimc_cap_fmt_vid_cap, | ||
105 | .vidioc_s_fmt_vid_cap = vimc_cap_fmt_vid_cap, | ||
106 | .vidioc_try_fmt_vid_cap = vimc_cap_fmt_vid_cap, | ||
107 | .vidioc_enum_fmt_vid_cap = vimc_cap_enum_fmt_vid_cap, | ||
108 | |||
109 | .vidioc_reqbufs = vb2_ioctl_reqbufs, | ||
110 | .vidioc_create_bufs = vb2_ioctl_create_bufs, | ||
111 | .vidioc_prepare_buf = vb2_ioctl_prepare_buf, | ||
112 | .vidioc_querybuf = vb2_ioctl_querybuf, | ||
113 | .vidioc_qbuf = vb2_ioctl_qbuf, | ||
114 | .vidioc_dqbuf = vb2_ioctl_dqbuf, | ||
115 | .vidioc_expbuf = vb2_ioctl_expbuf, | ||
116 | .vidioc_streamon = vb2_ioctl_streamon, | ||
117 | .vidioc_streamoff = vb2_ioctl_streamoff, | ||
118 | }; | ||
119 | |||
120 | static void vimc_cap_return_all_buffers(struct vimc_cap_device *vcap, | ||
121 | enum vb2_buffer_state state) | ||
122 | { | ||
123 | struct vimc_cap_buffer *vbuf, *node; | ||
124 | |||
125 | spin_lock(&vcap->qlock); | ||
126 | |||
127 | list_for_each_entry_safe(vbuf, node, &vcap->buf_list, list) { | ||
128 | list_del(&vbuf->list); | ||
129 | vb2_buffer_done(&vbuf->vb2.vb2_buf, state); | ||
130 | } | ||
131 | |||
132 | spin_unlock(&vcap->qlock); | ||
133 | } | ||
134 | |||
135 | static int vimc_cap_pipeline_s_stream(struct vimc_cap_device *vcap, int enable) | ||
136 | { | ||
137 | struct v4l2_subdev *sd; | ||
138 | struct media_pad *pad; | ||
139 | int ret; | ||
140 | |||
141 | /* Start the stream in the subdevice direct connected */ | ||
142 | pad = media_entity_remote_pad(&vcap->vdev.entity.pads[0]); | ||
143 | |||
144 | /* | ||
145 | * if it is a raw node from vimc-core, there is nothing to activate | ||
146 | * TODO: remove this when there are no more raw nodes in the | ||
147 | * core and return error instead | ||
148 | */ | ||
149 | if (pad->entity->obj_type == MEDIA_ENTITY_TYPE_BASE) | ||
150 | return 0; | ||
151 | |||
152 | sd = media_entity_to_v4l2_subdev(pad->entity); | ||
153 | ret = v4l2_subdev_call(sd, video, s_stream, enable); | ||
154 | if (ret && ret != -ENOIOCTLCMD) | ||
155 | return ret; | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static int vimc_cap_start_streaming(struct vb2_queue *vq, unsigned int count) | ||
161 | { | ||
162 | struct vimc_cap_device *vcap = vb2_get_drv_priv(vq); | ||
163 | struct media_entity *entity = &vcap->vdev.entity; | ||
164 | int ret; | ||
165 | |||
166 | vcap->sequence = 0; | ||
167 | |||
168 | /* Start the media pipeline */ | ||
169 | ret = media_pipeline_start(entity, &vcap->pipe); | ||
170 | if (ret) { | ||
171 | vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_QUEUED); | ||
172 | return ret; | ||
173 | } | ||
174 | |||
175 | /* Enable streaming from the pipe */ | ||
176 | ret = vimc_cap_pipeline_s_stream(vcap, 1); | ||
177 | if (ret) { | ||
178 | media_pipeline_stop(entity); | ||
179 | vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_QUEUED); | ||
180 | return ret; | ||
181 | } | ||
182 | |||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | /* | ||
187 | * Stop the stream engine. Any remaining buffers in the stream queue are | ||
188 | * dequeued and passed on to the vb2 framework marked as STATE_ERROR. | ||
189 | */ | ||
190 | static void vimc_cap_stop_streaming(struct vb2_queue *vq) | ||
191 | { | ||
192 | struct vimc_cap_device *vcap = vb2_get_drv_priv(vq); | ||
193 | |||
194 | /* Disable streaming from the pipe */ | ||
195 | vimc_cap_pipeline_s_stream(vcap, 0); | ||
196 | |||
197 | /* Stop the media pipeline */ | ||
198 | media_pipeline_stop(&vcap->vdev.entity); | ||
199 | |||
200 | /* Release all active buffers */ | ||
201 | vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_ERROR); | ||
202 | } | ||
203 | |||
204 | static void vimc_cap_buf_queue(struct vb2_buffer *vb2_buf) | ||
205 | { | ||
206 | struct vimc_cap_device *vcap = vb2_get_drv_priv(vb2_buf->vb2_queue); | ||
207 | struct vimc_cap_buffer *buf = container_of(vb2_buf, | ||
208 | struct vimc_cap_buffer, | ||
209 | vb2.vb2_buf); | ||
210 | |||
211 | spin_lock(&vcap->qlock); | ||
212 | list_add_tail(&buf->list, &vcap->buf_list); | ||
213 | spin_unlock(&vcap->qlock); | ||
214 | } | ||
215 | |||
216 | static int vimc_cap_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, | ||
217 | unsigned int *nplanes, unsigned int sizes[], | ||
218 | struct device *alloc_devs[]) | ||
219 | { | ||
220 | struct vimc_cap_device *vcap = vb2_get_drv_priv(vq); | ||
221 | |||
222 | if (*nplanes) | ||
223 | return sizes[0] < vcap->format.sizeimage ? -EINVAL : 0; | ||
224 | /* We don't support multiplanes for now */ | ||
225 | *nplanes = 1; | ||
226 | sizes[0] = vcap->format.sizeimage; | ||
227 | |||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | static int vimc_cap_buffer_prepare(struct vb2_buffer *vb) | ||
232 | { | ||
233 | struct vimc_cap_device *vcap = vb2_get_drv_priv(vb->vb2_queue); | ||
234 | unsigned long size = vcap->format.sizeimage; | ||
235 | |||
236 | if (vb2_plane_size(vb, 0) < size) { | ||
237 | dev_err(vcap->vdev.v4l2_dev->dev, | ||
238 | "%s: buffer too small (%lu < %lu)\n", | ||
239 | vcap->vdev.name, vb2_plane_size(vb, 0), size); | ||
240 | return -EINVAL; | ||
241 | } | ||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | static const struct vb2_ops vimc_cap_qops = { | ||
246 | .start_streaming = vimc_cap_start_streaming, | ||
247 | .stop_streaming = vimc_cap_stop_streaming, | ||
248 | .buf_queue = vimc_cap_buf_queue, | ||
249 | .queue_setup = vimc_cap_queue_setup, | ||
250 | .buf_prepare = vimc_cap_buffer_prepare, | ||
251 | /* | ||
252 | * Since q->lock is set we can use the standard | ||
253 | * vb2_ops_wait_prepare/finish helper functions. | ||
254 | */ | ||
255 | .wait_prepare = vb2_ops_wait_prepare, | ||
256 | .wait_finish = vb2_ops_wait_finish, | ||
257 | }; | ||
258 | |||
259 | /* | ||
260 | * NOTE: this function is a copy of v4l2_subdev_link_validate_get_format | ||
261 | * maybe the v4l2 function should be public | ||
262 | */ | ||
263 | static int vimc_cap_v4l2_subdev_link_validate_get_format(struct media_pad *pad, | ||
264 | struct v4l2_subdev_format *fmt) | ||
265 | { | ||
266 | struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(pad->entity); | ||
267 | |||
268 | fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE; | ||
269 | fmt->pad = pad->index; | ||
270 | |||
271 | return v4l2_subdev_call(sd, pad, get_fmt, NULL, fmt); | ||
272 | } | ||
273 | |||
274 | static int vimc_cap_link_validate(struct media_link *link) | ||
275 | { | ||
276 | struct v4l2_subdev_format source_fmt; | ||
277 | const struct vimc_pix_map *vpix; | ||
278 | struct vimc_cap_device *vcap = container_of(link->sink->entity, | ||
279 | struct vimc_cap_device, | ||
280 | vdev.entity); | ||
281 | struct v4l2_pix_format *sink_fmt = &vcap->format; | ||
282 | int ret; | ||
283 | |||
284 | /* | ||
285 | * if it is a raw node from vimc-core, ignore the link for now | ||
286 | * TODO: remove this when there are no more raw nodes in the | ||
287 | * core and return error instead | ||
288 | */ | ||
289 | if (link->source->entity->obj_type == MEDIA_ENTITY_TYPE_BASE) | ||
290 | return 0; | ||
291 | |||
292 | /* Get the the format of the subdev */ | ||
293 | ret = vimc_cap_v4l2_subdev_link_validate_get_format(link->source, | ||
294 | &source_fmt); | ||
295 | if (ret) | ||
296 | return ret; | ||
297 | |||
298 | dev_dbg(vcap->vdev.v4l2_dev->dev, | ||
299 | "%s: link validate formats src:%dx%d %d sink:%dx%d %d\n", | ||
300 | vcap->vdev.name, | ||
301 | source_fmt.format.width, source_fmt.format.height, | ||
302 | source_fmt.format.code, | ||
303 | sink_fmt->width, sink_fmt->height, | ||
304 | sink_fmt->pixelformat); | ||
305 | |||
306 | /* The width, height and code must match. */ | ||
307 | vpix = vimc_pix_map_by_pixelformat(sink_fmt->pixelformat); | ||
308 | if (source_fmt.format.width != sink_fmt->width | ||
309 | || source_fmt.format.height != sink_fmt->height | ||
310 | || vpix->code != source_fmt.format.code) | ||
311 | return -EPIPE; | ||
312 | |||
313 | /* | ||
314 | * The field order must match, or the sink field order must be NONE | ||
315 | * to support interlaced hardware connected to bridges that support | ||
316 | * progressive formats only. | ||
317 | */ | ||
318 | if (source_fmt.format.field != sink_fmt->field && | ||
319 | sink_fmt->field != V4L2_FIELD_NONE) | ||
320 | return -EPIPE; | ||
321 | |||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | static const struct media_entity_operations vimc_cap_mops = { | ||
326 | .link_validate = vimc_cap_link_validate, | ||
327 | }; | ||
328 | |||
329 | static void vimc_cap_destroy(struct vimc_ent_device *ved) | ||
330 | { | ||
331 | struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, | ||
332 | ved); | ||
333 | |||
334 | vb2_queue_release(&vcap->queue); | ||
335 | media_entity_cleanup(ved->ent); | ||
336 | video_unregister_device(&vcap->vdev); | ||
337 | vimc_pads_cleanup(vcap->ved.pads); | ||
338 | kfree(vcap); | ||
339 | } | ||
340 | |||
341 | static void vimc_cap_process_frame(struct vimc_ent_device *ved, | ||
342 | struct media_pad *sink, const void *frame) | ||
343 | { | ||
344 | struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, | ||
345 | ved); | ||
346 | struct vimc_cap_buffer *vimc_buf; | ||
347 | void *vbuf; | ||
348 | |||
349 | spin_lock(&vcap->qlock); | ||
350 | |||
351 | /* Get the first entry of the list */ | ||
352 | vimc_buf = list_first_entry_or_null(&vcap->buf_list, | ||
353 | typeof(*vimc_buf), list); | ||
354 | if (!vimc_buf) { | ||
355 | spin_unlock(&vcap->qlock); | ||
356 | return; | ||
357 | } | ||
358 | |||
359 | /* Remove this entry from the list */ | ||
360 | list_del(&vimc_buf->list); | ||
361 | |||
362 | spin_unlock(&vcap->qlock); | ||
363 | |||
364 | /* Fill the buffer */ | ||
365 | vimc_buf->vb2.vb2_buf.timestamp = ktime_get_ns(); | ||
366 | vimc_buf->vb2.sequence = vcap->sequence++; | ||
367 | vimc_buf->vb2.field = vcap->format.field; | ||
368 | |||
369 | vbuf = vb2_plane_vaddr(&vimc_buf->vb2.vb2_buf, 0); | ||
370 | |||
371 | memcpy(vbuf, frame, vcap->format.sizeimage); | ||
372 | |||
373 | /* Set it as ready */ | ||
374 | vb2_set_plane_payload(&vimc_buf->vb2.vb2_buf, 0, | ||
375 | vcap->format.sizeimage); | ||
376 | vb2_buffer_done(&vimc_buf->vb2.vb2_buf, VB2_BUF_STATE_DONE); | ||
377 | } | ||
378 | |||
379 | struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev, | ||
380 | const char *const name, | ||
381 | u16 num_pads, | ||
382 | const unsigned long *pads_flag) | ||
383 | { | ||
384 | const struct vimc_pix_map *vpix; | ||
385 | struct vimc_cap_device *vcap; | ||
386 | struct video_device *vdev; | ||
387 | struct vb2_queue *q; | ||
388 | int ret; | ||
389 | |||
390 | /* | ||
391 | * Check entity configuration params | ||
392 | * NOTE: we only support a single sink pad | ||
393 | */ | ||
394 | if (!name || num_pads != 1 || !pads_flag || | ||
395 | !(pads_flag[0] & MEDIA_PAD_FL_SINK)) | ||
396 | return ERR_PTR(-EINVAL); | ||
397 | |||
398 | /* Allocate the vimc_cap_device struct */ | ||
399 | vcap = kzalloc(sizeof(*vcap), GFP_KERNEL); | ||
400 | if (!vcap) | ||
401 | return ERR_PTR(-ENOMEM); | ||
402 | |||
403 | /* Allocate the pads */ | ||
404 | vcap->ved.pads = vimc_pads_init(num_pads, pads_flag); | ||
405 | if (IS_ERR(vcap->ved.pads)) { | ||
406 | ret = PTR_ERR(vcap->ved.pads); | ||
407 | goto err_free_vcap; | ||
408 | } | ||
409 | |||
410 | /* Initialize the media entity */ | ||
411 | vcap->vdev.entity.name = name; | ||
412 | vcap->vdev.entity.function = MEDIA_ENT_F_IO_V4L; | ||
413 | ret = media_entity_pads_init(&vcap->vdev.entity, | ||
414 | num_pads, vcap->ved.pads); | ||
415 | if (ret) | ||
416 | goto err_clean_pads; | ||
417 | |||
418 | /* Initialize the lock */ | ||
419 | mutex_init(&vcap->lock); | ||
420 | |||
421 | /* Initialize the vb2 queue */ | ||
422 | q = &vcap->queue; | ||
423 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
424 | q->io_modes = VB2_MMAP | VB2_DMABUF; | ||
425 | q->drv_priv = vcap; | ||
426 | q->buf_struct_size = sizeof(struct vimc_cap_buffer); | ||
427 | q->ops = &vimc_cap_qops; | ||
428 | q->mem_ops = &vb2_vmalloc_memops; | ||
429 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | ||
430 | q->min_buffers_needed = 2; | ||
431 | q->lock = &vcap->lock; | ||
432 | |||
433 | ret = vb2_queue_init(q); | ||
434 | if (ret) { | ||
435 | dev_err(vcap->vdev.v4l2_dev->dev, | ||
436 | "%s: vb2 queue init failed (err=%d)\n", | ||
437 | vcap->vdev.name, ret); | ||
438 | goto err_clean_m_ent; | ||
439 | } | ||
440 | |||
441 | /* Initialize buffer list and its lock */ | ||
442 | INIT_LIST_HEAD(&vcap->buf_list); | ||
443 | spin_lock_init(&vcap->qlock); | ||
444 | |||
445 | /* Set the frame format (this is hardcoded for now) */ | ||
446 | vcap->format.width = 640; | ||
447 | vcap->format.height = 480; | ||
448 | vcap->format.pixelformat = V4L2_PIX_FMT_RGB24; | ||
449 | vcap->format.field = V4L2_FIELD_NONE; | ||
450 | vcap->format.colorspace = V4L2_COLORSPACE_SRGB; | ||
451 | |||
452 | vpix = vimc_pix_map_by_pixelformat(vcap->format.pixelformat); | ||
453 | |||
454 | vcap->format.bytesperline = vcap->format.width * vpix->bpp; | ||
455 | vcap->format.sizeimage = vcap->format.bytesperline * | ||
456 | vcap->format.height; | ||
457 | |||
458 | /* Fill the vimc_ent_device struct */ | ||
459 | vcap->ved.destroy = vimc_cap_destroy; | ||
460 | vcap->ved.ent = &vcap->vdev.entity; | ||
461 | vcap->ved.process_frame = vimc_cap_process_frame; | ||
462 | |||
463 | /* Initialize the video_device struct */ | ||
464 | vdev = &vcap->vdev; | ||
465 | vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; | ||
466 | vdev->entity.ops = &vimc_cap_mops; | ||
467 | vdev->release = video_device_release_empty; | ||
468 | vdev->fops = &vimc_cap_fops; | ||
469 | vdev->ioctl_ops = &vimc_cap_ioctl_ops; | ||
470 | vdev->lock = &vcap->lock; | ||
471 | vdev->queue = q; | ||
472 | vdev->v4l2_dev = v4l2_dev; | ||
473 | vdev->vfl_dir = VFL_DIR_RX; | ||
474 | strlcpy(vdev->name, name, sizeof(vdev->name)); | ||
475 | video_set_drvdata(vdev, &vcap->ved); | ||
476 | |||
477 | /* Register the video_device with the v4l2 and the media framework */ | ||
478 | ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); | ||
479 | if (ret) { | ||
480 | dev_err(vcap->vdev.v4l2_dev->dev, | ||
481 | "%s: video register failed (err=%d)\n", | ||
482 | vcap->vdev.name, ret); | ||
483 | goto err_release_queue; | ||
484 | } | ||
485 | |||
486 | return &vcap->ved; | ||
487 | |||
488 | err_release_queue: | ||
489 | vb2_queue_release(q); | ||
490 | err_clean_m_ent: | ||
491 | media_entity_cleanup(&vcap->vdev.entity); | ||
492 | err_clean_pads: | ||
493 | vimc_pads_cleanup(vcap->ved.pads); | ||
494 | err_free_vcap: | ||
495 | kfree(vcap); | ||
496 | |||
497 | return ERR_PTR(ret); | ||
498 | } | ||
diff --git a/drivers/media/platform/vimc/vimc-capture.h b/drivers/media/platform/vimc/vimc-capture.h new file mode 100644 index 000000000000..581a813abdf1 --- /dev/null +++ b/drivers/media/platform/vimc/vimc-capture.h | |||
@@ -0,0 +1,28 @@ | |||
1 | /* | ||
2 | * vimc-capture.h Virtual Media Controller Driver | ||
3 | * | ||
4 | * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #ifndef _VIMC_CAPTURE_H_ | ||
19 | #define _VIMC_CAPTURE_H_ | ||
20 | |||
21 | #include "vimc-core.h" | ||
22 | |||
23 | struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev, | ||
24 | const char *const name, | ||
25 | u16 num_pads, | ||
26 | const unsigned long *pads_flag); | ||
27 | |||
28 | #endif | ||
diff --git a/drivers/media/platform/vimc/vimc-core.c b/drivers/media/platform/vimc/vimc-core.c new file mode 100644 index 000000000000..bc107da8fbd5 --- /dev/null +++ b/drivers/media/platform/vimc/vimc-core.c | |||
@@ -0,0 +1,695 @@ | |||
1 | /* | ||
2 | * vimc-core.c Virtual Media Controller Driver | ||
3 | * | ||
4 | * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/init.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <media/media-device.h> | ||
22 | #include <media/v4l2-device.h> | ||
23 | |||
24 | #include "vimc-capture.h" | ||
25 | #include "vimc-core.h" | ||
26 | #include "vimc-sensor.h" | ||
27 | |||
28 | #define VIMC_PDEV_NAME "vimc" | ||
29 | #define VIMC_MDEV_MODEL_NAME "VIMC MDEV" | ||
30 | |||
31 | #define VIMC_ENT_LINK(src, srcpad, sink, sinkpad, link_flags) { \ | ||
32 | .src_ent = src, \ | ||
33 | .src_pad = srcpad, \ | ||
34 | .sink_ent = sink, \ | ||
35 | .sink_pad = sinkpad, \ | ||
36 | .flags = link_flags, \ | ||
37 | } | ||
38 | |||
39 | struct vimc_device { | ||
40 | /* | ||
41 | * The pipeline configuration | ||
42 | * (filled before calling vimc_device_register) | ||
43 | */ | ||
44 | const struct vimc_pipeline_config *pipe_cfg; | ||
45 | |||
46 | /* The Associated media_device parent */ | ||
47 | struct media_device mdev; | ||
48 | |||
49 | /* Internal v4l2 parent device*/ | ||
50 | struct v4l2_device v4l2_dev; | ||
51 | |||
52 | /* Internal topology */ | ||
53 | struct vimc_ent_device **ved; | ||
54 | }; | ||
55 | |||
56 | /** | ||
57 | * enum vimc_ent_node - Select the functionality of a node in the topology | ||
58 | * @VIMC_ENT_NODE_SENSOR: A node of type SENSOR simulates a camera sensor | ||
59 | * generating internal images in bayer format and | ||
60 | * propagating those images through the pipeline | ||
61 | * @VIMC_ENT_NODE_CAPTURE: A node of type CAPTURE is a v4l2 video_device | ||
62 | * that exposes the received image from the | ||
63 | * pipeline to the user space | ||
64 | * @VIMC_ENT_NODE_INPUT: A node of type INPUT is a v4l2 video_device that | ||
65 | * receives images from the user space and | ||
66 | * propagates them through the pipeline | ||
67 | * @VIMC_ENT_NODE_DEBAYER: A node type DEBAYER expects to receive a frame | ||
68 | * in bayer format converts it to RGB | ||
69 | * @VIMC_ENT_NODE_SCALER: A node of type SCALER scales the received image | ||
70 | * by a given multiplier | ||
71 | * | ||
72 | * This enum is used in the entity configuration struct to allow the definition | ||
73 | * of a custom topology specifying the role of each node on it. | ||
74 | */ | ||
75 | enum vimc_ent_node { | ||
76 | VIMC_ENT_NODE_SENSOR, | ||
77 | VIMC_ENT_NODE_CAPTURE, | ||
78 | VIMC_ENT_NODE_INPUT, | ||
79 | VIMC_ENT_NODE_DEBAYER, | ||
80 | VIMC_ENT_NODE_SCALER, | ||
81 | }; | ||
82 | |||
83 | /* Structure which describes individual configuration for each entity */ | ||
84 | struct vimc_ent_config { | ||
85 | const char *name; | ||
86 | size_t pads_qty; | ||
87 | const unsigned long *pads_flag; | ||
88 | enum vimc_ent_node node; | ||
89 | }; | ||
90 | |||
91 | /* Structure which describes links between entities */ | ||
92 | struct vimc_ent_link { | ||
93 | unsigned int src_ent; | ||
94 | u16 src_pad; | ||
95 | unsigned int sink_ent; | ||
96 | u16 sink_pad; | ||
97 | u32 flags; | ||
98 | }; | ||
99 | |||
100 | /* Structure which describes the whole topology */ | ||
101 | struct vimc_pipeline_config { | ||
102 | const struct vimc_ent_config *ents; | ||
103 | size_t num_ents; | ||
104 | const struct vimc_ent_link *links; | ||
105 | size_t num_links; | ||
106 | }; | ||
107 | |||
108 | /* -------------------------------------------------------------------------- | ||
109 | * Topology Configuration | ||
110 | */ | ||
111 | |||
112 | static const struct vimc_ent_config ent_config[] = { | ||
113 | { | ||
114 | .name = "Sensor A", | ||
115 | .pads_qty = 1, | ||
116 | .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SOURCE}, | ||
117 | .node = VIMC_ENT_NODE_SENSOR, | ||
118 | }, | ||
119 | { | ||
120 | .name = "Sensor B", | ||
121 | .pads_qty = 1, | ||
122 | .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SOURCE}, | ||
123 | .node = VIMC_ENT_NODE_SENSOR, | ||
124 | }, | ||
125 | { | ||
126 | .name = "Debayer A", | ||
127 | .pads_qty = 2, | ||
128 | .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SINK, | ||
129 | MEDIA_PAD_FL_SOURCE}, | ||
130 | .node = VIMC_ENT_NODE_DEBAYER, | ||
131 | }, | ||
132 | { | ||
133 | .name = "Debayer B", | ||
134 | .pads_qty = 2, | ||
135 | .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SINK, | ||
136 | MEDIA_PAD_FL_SOURCE}, | ||
137 | .node = VIMC_ENT_NODE_DEBAYER, | ||
138 | }, | ||
139 | { | ||
140 | .name = "Raw Capture 0", | ||
141 | .pads_qty = 1, | ||
142 | .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SINK}, | ||
143 | .node = VIMC_ENT_NODE_CAPTURE, | ||
144 | }, | ||
145 | { | ||
146 | .name = "Raw Capture 1", | ||
147 | .pads_qty = 1, | ||
148 | .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SINK}, | ||
149 | .node = VIMC_ENT_NODE_CAPTURE, | ||
150 | }, | ||
151 | { | ||
152 | .name = "RGB/YUV Input", | ||
153 | .pads_qty = 1, | ||
154 | .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SOURCE}, | ||
155 | .node = VIMC_ENT_NODE_INPUT, | ||
156 | }, | ||
157 | { | ||
158 | .name = "Scaler", | ||
159 | .pads_qty = 2, | ||
160 | .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SINK, | ||
161 | MEDIA_PAD_FL_SOURCE}, | ||
162 | .node = VIMC_ENT_NODE_SCALER, | ||
163 | }, | ||
164 | { | ||
165 | .name = "RGB/YUV Capture", | ||
166 | .pads_qty = 1, | ||
167 | .pads_flag = (const unsigned long[]){MEDIA_PAD_FL_SINK}, | ||
168 | .node = VIMC_ENT_NODE_CAPTURE, | ||
169 | }, | ||
170 | }; | ||
171 | |||
172 | static const struct vimc_ent_link ent_links[] = { | ||
173 | /* Link: Sensor A (Pad 0)->(Pad 0) Debayer A */ | ||
174 | VIMC_ENT_LINK(0, 0, 2, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), | ||
175 | /* Link: Sensor A (Pad 0)->(Pad 0) Raw Capture 0 */ | ||
176 | VIMC_ENT_LINK(0, 0, 4, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), | ||
177 | /* Link: Sensor B (Pad 0)->(Pad 0) Debayer B */ | ||
178 | VIMC_ENT_LINK(1, 0, 3, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), | ||
179 | /* Link: Sensor B (Pad 0)->(Pad 0) Raw Capture 1 */ | ||
180 | VIMC_ENT_LINK(1, 0, 5, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), | ||
181 | /* Link: Debayer A (Pad 1)->(Pad 0) Scaler */ | ||
182 | VIMC_ENT_LINK(2, 1, 7, 0, MEDIA_LNK_FL_ENABLED), | ||
183 | /* Link: Debayer B (Pad 1)->(Pad 0) Scaler */ | ||
184 | VIMC_ENT_LINK(3, 1, 7, 0, 0), | ||
185 | /* Link: RGB/YUV Input (Pad 0)->(Pad 0) Scaler */ | ||
186 | VIMC_ENT_LINK(6, 0, 7, 0, 0), | ||
187 | /* Link: Scaler (Pad 1)->(Pad 0) RGB/YUV Capture */ | ||
188 | VIMC_ENT_LINK(7, 1, 8, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), | ||
189 | }; | ||
190 | |||
191 | static const struct vimc_pipeline_config pipe_cfg = { | ||
192 | .ents = ent_config, | ||
193 | .num_ents = ARRAY_SIZE(ent_config), | ||
194 | .links = ent_links, | ||
195 | .num_links = ARRAY_SIZE(ent_links) | ||
196 | }; | ||
197 | |||
198 | /* -------------------------------------------------------------------------- */ | ||
199 | |||
200 | static const struct vimc_pix_map vimc_pix_map_list[] = { | ||
201 | /* TODO: add all missing formats */ | ||
202 | |||
203 | /* RGB formats */ | ||
204 | { | ||
205 | .code = MEDIA_BUS_FMT_BGR888_1X24, | ||
206 | .pixelformat = V4L2_PIX_FMT_BGR24, | ||
207 | .bpp = 3, | ||
208 | }, | ||
209 | { | ||
210 | .code = MEDIA_BUS_FMT_RGB888_1X24, | ||
211 | .pixelformat = V4L2_PIX_FMT_RGB24, | ||
212 | .bpp = 3, | ||
213 | }, | ||
214 | { | ||
215 | .code = MEDIA_BUS_FMT_ARGB8888_1X32, | ||
216 | .pixelformat = V4L2_PIX_FMT_ARGB32, | ||
217 | .bpp = 4, | ||
218 | }, | ||
219 | |||
220 | /* Bayer formats */ | ||
221 | { | ||
222 | .code = MEDIA_BUS_FMT_SBGGR8_1X8, | ||
223 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
224 | .bpp = 1, | ||
225 | }, | ||
226 | { | ||
227 | .code = MEDIA_BUS_FMT_SGBRG8_1X8, | ||
228 | .pixelformat = V4L2_PIX_FMT_SGBRG8, | ||
229 | .bpp = 1, | ||
230 | }, | ||
231 | { | ||
232 | .code = MEDIA_BUS_FMT_SGRBG8_1X8, | ||
233 | .pixelformat = V4L2_PIX_FMT_SGRBG8, | ||
234 | .bpp = 1, | ||
235 | }, | ||
236 | { | ||
237 | .code = MEDIA_BUS_FMT_SRGGB8_1X8, | ||
238 | .pixelformat = V4L2_PIX_FMT_SRGGB8, | ||
239 | .bpp = 1, | ||
240 | }, | ||
241 | { | ||
242 | .code = MEDIA_BUS_FMT_SBGGR10_1X10, | ||
243 | .pixelformat = V4L2_PIX_FMT_SBGGR10, | ||
244 | .bpp = 2, | ||
245 | }, | ||
246 | { | ||
247 | .code = MEDIA_BUS_FMT_SGBRG10_1X10, | ||
248 | .pixelformat = V4L2_PIX_FMT_SGBRG10, | ||
249 | .bpp = 2, | ||
250 | }, | ||
251 | { | ||
252 | .code = MEDIA_BUS_FMT_SGRBG10_1X10, | ||
253 | .pixelformat = V4L2_PIX_FMT_SGRBG10, | ||
254 | .bpp = 2, | ||
255 | }, | ||
256 | { | ||
257 | .code = MEDIA_BUS_FMT_SRGGB10_1X10, | ||
258 | .pixelformat = V4L2_PIX_FMT_SRGGB10, | ||
259 | .bpp = 2, | ||
260 | }, | ||
261 | |||
262 | /* 10bit raw bayer a-law compressed to 8 bits */ | ||
263 | { | ||
264 | .code = MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8, | ||
265 | .pixelformat = V4L2_PIX_FMT_SBGGR10ALAW8, | ||
266 | .bpp = 1, | ||
267 | }, | ||
268 | { | ||
269 | .code = MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8, | ||
270 | .pixelformat = V4L2_PIX_FMT_SGBRG10ALAW8, | ||
271 | .bpp = 1, | ||
272 | }, | ||
273 | { | ||
274 | .code = MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8, | ||
275 | .pixelformat = V4L2_PIX_FMT_SGRBG10ALAW8, | ||
276 | .bpp = 1, | ||
277 | }, | ||
278 | { | ||
279 | .code = MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8, | ||
280 | .pixelformat = V4L2_PIX_FMT_SRGGB10ALAW8, | ||
281 | .bpp = 1, | ||
282 | }, | ||
283 | |||
284 | /* 10bit raw bayer DPCM compressed to 8 bits */ | ||
285 | { | ||
286 | .code = MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, | ||
287 | .pixelformat = V4L2_PIX_FMT_SBGGR10DPCM8, | ||
288 | .bpp = 1, | ||
289 | }, | ||
290 | { | ||
291 | .code = MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, | ||
292 | .pixelformat = V4L2_PIX_FMT_SGBRG10DPCM8, | ||
293 | .bpp = 1, | ||
294 | }, | ||
295 | { | ||
296 | .code = MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, | ||
297 | .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8, | ||
298 | .bpp = 1, | ||
299 | }, | ||
300 | { | ||
301 | .code = MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, | ||
302 | .pixelformat = V4L2_PIX_FMT_SRGGB10DPCM8, | ||
303 | .bpp = 1, | ||
304 | }, | ||
305 | { | ||
306 | .code = MEDIA_BUS_FMT_SBGGR12_1X12, | ||
307 | .pixelformat = V4L2_PIX_FMT_SBGGR12, | ||
308 | .bpp = 2, | ||
309 | }, | ||
310 | { | ||
311 | .code = MEDIA_BUS_FMT_SGBRG12_1X12, | ||
312 | .pixelformat = V4L2_PIX_FMT_SGBRG12, | ||
313 | .bpp = 2, | ||
314 | }, | ||
315 | { | ||
316 | .code = MEDIA_BUS_FMT_SGRBG12_1X12, | ||
317 | .pixelformat = V4L2_PIX_FMT_SGRBG12, | ||
318 | .bpp = 2, | ||
319 | }, | ||
320 | { | ||
321 | .code = MEDIA_BUS_FMT_SRGGB12_1X12, | ||
322 | .pixelformat = V4L2_PIX_FMT_SRGGB12, | ||
323 | .bpp = 2, | ||
324 | }, | ||
325 | }; | ||
326 | |||
327 | const struct vimc_pix_map *vimc_pix_map_by_code(u32 code) | ||
328 | { | ||
329 | unsigned int i; | ||
330 | |||
331 | for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) { | ||
332 | if (vimc_pix_map_list[i].code == code) | ||
333 | return &vimc_pix_map_list[i]; | ||
334 | } | ||
335 | return NULL; | ||
336 | } | ||
337 | |||
338 | const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat) | ||
339 | { | ||
340 | unsigned int i; | ||
341 | |||
342 | for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) { | ||
343 | if (vimc_pix_map_list[i].pixelformat == pixelformat) | ||
344 | return &vimc_pix_map_list[i]; | ||
345 | } | ||
346 | return NULL; | ||
347 | } | ||
348 | |||
349 | int vimc_propagate_frame(struct media_pad *src, const void *frame) | ||
350 | { | ||
351 | struct media_link *link; | ||
352 | |||
353 | if (!(src->flags & MEDIA_PAD_FL_SOURCE)) | ||
354 | return -EINVAL; | ||
355 | |||
356 | /* Send this frame to all sink pads that are direct linked */ | ||
357 | list_for_each_entry(link, &src->entity->links, list) { | ||
358 | if (link->source == src && | ||
359 | (link->flags & MEDIA_LNK_FL_ENABLED)) { | ||
360 | struct vimc_ent_device *ved = NULL; | ||
361 | struct media_entity *entity = link->sink->entity; | ||
362 | |||
363 | if (is_media_entity_v4l2_subdev(entity)) { | ||
364 | struct v4l2_subdev *sd = | ||
365 | container_of(entity, struct v4l2_subdev, | ||
366 | entity); | ||
367 | ved = v4l2_get_subdevdata(sd); | ||
368 | } else if (is_media_entity_v4l2_video_device(entity)) { | ||
369 | struct video_device *vdev = | ||
370 | container_of(entity, | ||
371 | struct video_device, | ||
372 | entity); | ||
373 | ved = video_get_drvdata(vdev); | ||
374 | } | ||
375 | if (ved && ved->process_frame) | ||
376 | ved->process_frame(ved, link->sink, frame); | ||
377 | } | ||
378 | } | ||
379 | |||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | static void vimc_device_unregister(struct vimc_device *vimc) | ||
384 | { | ||
385 | unsigned int i; | ||
386 | |||
387 | media_device_unregister(&vimc->mdev); | ||
388 | /* Cleanup (only initialized) entities */ | ||
389 | for (i = 0; i < vimc->pipe_cfg->num_ents; i++) { | ||
390 | if (vimc->ved[i] && vimc->ved[i]->destroy) | ||
391 | vimc->ved[i]->destroy(vimc->ved[i]); | ||
392 | |||
393 | vimc->ved[i] = NULL; | ||
394 | } | ||
395 | v4l2_device_unregister(&vimc->v4l2_dev); | ||
396 | media_device_cleanup(&vimc->mdev); | ||
397 | } | ||
398 | |||
399 | /* Helper function to allocate and initialize pads */ | ||
400 | struct media_pad *vimc_pads_init(u16 num_pads, const unsigned long *pads_flag) | ||
401 | { | ||
402 | struct media_pad *pads; | ||
403 | unsigned int i; | ||
404 | |||
405 | /* Allocate memory for the pads */ | ||
406 | pads = kcalloc(num_pads, sizeof(*pads), GFP_KERNEL); | ||
407 | if (!pads) | ||
408 | return ERR_PTR(-ENOMEM); | ||
409 | |||
410 | /* Initialize the pads */ | ||
411 | for (i = 0; i < num_pads; i++) { | ||
412 | pads[i].index = i; | ||
413 | pads[i].flags = pads_flag[i]; | ||
414 | } | ||
415 | |||
416 | return pads; | ||
417 | } | ||
418 | |||
419 | /* | ||
420 | * TODO: remove this function when all the | ||
421 | * entities specific code are implemented | ||
422 | */ | ||
423 | static void vimc_raw_destroy(struct vimc_ent_device *ved) | ||
424 | { | ||
425 | media_device_unregister_entity(ved->ent); | ||
426 | |||
427 | media_entity_cleanup(ved->ent); | ||
428 | |||
429 | vimc_pads_cleanup(ved->pads); | ||
430 | |||
431 | kfree(ved->ent); | ||
432 | |||
433 | kfree(ved); | ||
434 | } | ||
435 | |||
436 | /* | ||
437 | * TODO: remove this function when all the | ||
438 | * entities specific code are implemented | ||
439 | */ | ||
440 | static struct vimc_ent_device *vimc_raw_create(struct v4l2_device *v4l2_dev, | ||
441 | const char *const name, | ||
442 | u16 num_pads, | ||
443 | const unsigned long *pads_flag) | ||
444 | { | ||
445 | struct vimc_ent_device *ved; | ||
446 | int ret; | ||
447 | |||
448 | /* Allocate the main ved struct */ | ||
449 | ved = kzalloc(sizeof(*ved), GFP_KERNEL); | ||
450 | if (!ved) | ||
451 | return ERR_PTR(-ENOMEM); | ||
452 | |||
453 | /* Allocate the media entity */ | ||
454 | ved->ent = kzalloc(sizeof(*ved->ent), GFP_KERNEL); | ||
455 | if (!ved->ent) { | ||
456 | ret = -ENOMEM; | ||
457 | goto err_free_ved; | ||
458 | } | ||
459 | |||
460 | /* Allocate the pads */ | ||
461 | ved->pads = vimc_pads_init(num_pads, pads_flag); | ||
462 | if (IS_ERR(ved->pads)) { | ||
463 | ret = PTR_ERR(ved->pads); | ||
464 | goto err_free_ent; | ||
465 | } | ||
466 | |||
467 | /* Initialize the media entity */ | ||
468 | ved->ent->name = name; | ||
469 | ved->ent->function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN; | ||
470 | ret = media_entity_pads_init(ved->ent, num_pads, ved->pads); | ||
471 | if (ret) | ||
472 | goto err_cleanup_pads; | ||
473 | |||
474 | /* Register the media entity */ | ||
475 | ret = media_device_register_entity(v4l2_dev->mdev, ved->ent); | ||
476 | if (ret) | ||
477 | goto err_cleanup_entity; | ||
478 | |||
479 | /* Fill out the destroy function and return */ | ||
480 | ved->destroy = vimc_raw_destroy; | ||
481 | return ved; | ||
482 | |||
483 | err_cleanup_entity: | ||
484 | media_entity_cleanup(ved->ent); | ||
485 | err_cleanup_pads: | ||
486 | vimc_pads_cleanup(ved->pads); | ||
487 | err_free_ent: | ||
488 | kfree(ved->ent); | ||
489 | err_free_ved: | ||
490 | kfree(ved); | ||
491 | |||
492 | return ERR_PTR(ret); | ||
493 | } | ||
494 | |||
495 | static int vimc_device_register(struct vimc_device *vimc) | ||
496 | { | ||
497 | unsigned int i; | ||
498 | int ret; | ||
499 | |||
500 | /* Allocate memory for the vimc_ent_devices pointers */ | ||
501 | vimc->ved = devm_kcalloc(vimc->mdev.dev, vimc->pipe_cfg->num_ents, | ||
502 | sizeof(*vimc->ved), GFP_KERNEL); | ||
503 | if (!vimc->ved) | ||
504 | return -ENOMEM; | ||
505 | |||
506 | /* Link the media device within the v4l2_device */ | ||
507 | vimc->v4l2_dev.mdev = &vimc->mdev; | ||
508 | |||
509 | /* Register the v4l2 struct */ | ||
510 | ret = v4l2_device_register(vimc->mdev.dev, &vimc->v4l2_dev); | ||
511 | if (ret) { | ||
512 | dev_err(vimc->mdev.dev, | ||
513 | "v4l2 device register failed (err=%d)\n", ret); | ||
514 | return ret; | ||
515 | } | ||
516 | |||
517 | /* Initialize entities */ | ||
518 | for (i = 0; i < vimc->pipe_cfg->num_ents; i++) { | ||
519 | struct vimc_ent_device *(*create_func)(struct v4l2_device *, | ||
520 | const char *const, | ||
521 | u16, | ||
522 | const unsigned long *); | ||
523 | |||
524 | /* Register the specific node */ | ||
525 | switch (vimc->pipe_cfg->ents[i].node) { | ||
526 | case VIMC_ENT_NODE_SENSOR: | ||
527 | create_func = vimc_sen_create; | ||
528 | break; | ||
529 | |||
530 | case VIMC_ENT_NODE_CAPTURE: | ||
531 | create_func = vimc_cap_create; | ||
532 | break; | ||
533 | |||
534 | /* TODO: Instantiate the specific topology node */ | ||
535 | case VIMC_ENT_NODE_INPUT: | ||
536 | case VIMC_ENT_NODE_DEBAYER: | ||
537 | case VIMC_ENT_NODE_SCALER: | ||
538 | default: | ||
539 | /* | ||
540 | * TODO: remove this when all the entities specific | ||
541 | * code are implemented | ||
542 | */ | ||
543 | create_func = vimc_raw_create; | ||
544 | break; | ||
545 | } | ||
546 | |||
547 | vimc->ved[i] = create_func(&vimc->v4l2_dev, | ||
548 | vimc->pipe_cfg->ents[i].name, | ||
549 | vimc->pipe_cfg->ents[i].pads_qty, | ||
550 | vimc->pipe_cfg->ents[i].pads_flag); | ||
551 | if (IS_ERR(vimc->ved[i])) { | ||
552 | ret = PTR_ERR(vimc->ved[i]); | ||
553 | vimc->ved[i] = NULL; | ||
554 | goto err; | ||
555 | } | ||
556 | } | ||
557 | |||
558 | /* Initialize the links between entities */ | ||
559 | for (i = 0; i < vimc->pipe_cfg->num_links; i++) { | ||
560 | const struct vimc_ent_link *link = &vimc->pipe_cfg->links[i]; | ||
561 | |||
562 | ret = media_create_pad_link(vimc->ved[link->src_ent]->ent, | ||
563 | link->src_pad, | ||
564 | vimc->ved[link->sink_ent]->ent, | ||
565 | link->sink_pad, | ||
566 | link->flags); | ||
567 | if (ret) | ||
568 | goto err; | ||
569 | } | ||
570 | |||
571 | /* Register the media device */ | ||
572 | ret = media_device_register(&vimc->mdev); | ||
573 | if (ret) { | ||
574 | dev_err(vimc->mdev.dev, | ||
575 | "media device register failed (err=%d)\n", ret); | ||
576 | return ret; | ||
577 | } | ||
578 | |||
579 | /* Expose all subdev's nodes*/ | ||
580 | ret = v4l2_device_register_subdev_nodes(&vimc->v4l2_dev); | ||
581 | if (ret) { | ||
582 | dev_err(vimc->mdev.dev, | ||
583 | "vimc subdev nodes registration failed (err=%d)\n", | ||
584 | ret); | ||
585 | goto err; | ||
586 | } | ||
587 | |||
588 | return 0; | ||
589 | |||
590 | err: | ||
591 | /* Destroy the so far created topology */ | ||
592 | vimc_device_unregister(vimc); | ||
593 | |||
594 | return ret; | ||
595 | } | ||
596 | |||
597 | static int vimc_probe(struct platform_device *pdev) | ||
598 | { | ||
599 | struct vimc_device *vimc; | ||
600 | int ret; | ||
601 | |||
602 | /* Prepare the vimc topology structure */ | ||
603 | |||
604 | /* Allocate memory for the vimc structure */ | ||
605 | vimc = kzalloc(sizeof(*vimc), GFP_KERNEL); | ||
606 | if (!vimc) | ||
607 | return -ENOMEM; | ||
608 | |||
609 | /* Set the pipeline configuration struct */ | ||
610 | vimc->pipe_cfg = &pipe_cfg; | ||
611 | |||
612 | /* Initialize media device */ | ||
613 | strlcpy(vimc->mdev.model, VIMC_MDEV_MODEL_NAME, | ||
614 | sizeof(vimc->mdev.model)); | ||
615 | vimc->mdev.dev = &pdev->dev; | ||
616 | media_device_init(&vimc->mdev); | ||
617 | |||
618 | /* Create vimc topology */ | ||
619 | ret = vimc_device_register(vimc); | ||
620 | if (ret) { | ||
621 | dev_err(vimc->mdev.dev, | ||
622 | "vimc device registration failed (err=%d)\n", ret); | ||
623 | kfree(vimc); | ||
624 | return ret; | ||
625 | } | ||
626 | |||
627 | /* Link the topology object with the platform device object */ | ||
628 | platform_set_drvdata(pdev, vimc); | ||
629 | |||
630 | return 0; | ||
631 | } | ||
632 | |||
633 | static int vimc_remove(struct platform_device *pdev) | ||
634 | { | ||
635 | struct vimc_device *vimc = platform_get_drvdata(pdev); | ||
636 | |||
637 | /* Destroy all the topology */ | ||
638 | vimc_device_unregister(vimc); | ||
639 | kfree(vimc); | ||
640 | |||
641 | return 0; | ||
642 | } | ||
643 | |||
644 | static void vimc_dev_release(struct device *dev) | ||
645 | { | ||
646 | } | ||
647 | |||
648 | static struct platform_device vimc_pdev = { | ||
649 | .name = VIMC_PDEV_NAME, | ||
650 | .dev.release = vimc_dev_release, | ||
651 | }; | ||
652 | |||
653 | static struct platform_driver vimc_pdrv = { | ||
654 | .probe = vimc_probe, | ||
655 | .remove = vimc_remove, | ||
656 | .driver = { | ||
657 | .name = VIMC_PDEV_NAME, | ||
658 | }, | ||
659 | }; | ||
660 | |||
661 | static int __init vimc_init(void) | ||
662 | { | ||
663 | int ret; | ||
664 | |||
665 | ret = platform_device_register(&vimc_pdev); | ||
666 | if (ret) { | ||
667 | dev_err(&vimc_pdev.dev, | ||
668 | "platform device registration failed (err=%d)\n", ret); | ||
669 | return ret; | ||
670 | } | ||
671 | |||
672 | ret = platform_driver_register(&vimc_pdrv); | ||
673 | if (ret) { | ||
674 | dev_err(&vimc_pdev.dev, | ||
675 | "platform driver registration failed (err=%d)\n", ret); | ||
676 | |||
677 | platform_device_unregister(&vimc_pdev); | ||
678 | } | ||
679 | |||
680 | return ret; | ||
681 | } | ||
682 | |||
683 | static void __exit vimc_exit(void) | ||
684 | { | ||
685 | platform_driver_unregister(&vimc_pdrv); | ||
686 | |||
687 | platform_device_unregister(&vimc_pdev); | ||
688 | } | ||
689 | |||
690 | module_init(vimc_init); | ||
691 | module_exit(vimc_exit); | ||
692 | |||
693 | MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC)"); | ||
694 | MODULE_AUTHOR("Helen Fornazier <helen.fornazier@gmail.com>"); | ||
695 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/platform/vimc/vimc-core.h b/drivers/media/platform/vimc/vimc-core.h new file mode 100644 index 000000000000..4525d23211ca --- /dev/null +++ b/drivers/media/platform/vimc/vimc-core.h | |||
@@ -0,0 +1,112 @@ | |||
1 | /* | ||
2 | * vimc-core.h Virtual Media Controller Driver | ||
3 | * | ||
4 | * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #ifndef _VIMC_CORE_H_ | ||
19 | #define _VIMC_CORE_H_ | ||
20 | |||
21 | #include <linux/slab.h> | ||
22 | #include <media/v4l2-device.h> | ||
23 | |||
24 | /** | ||
25 | * struct vimc_pix_map - maps media bus code with v4l2 pixel format | ||
26 | * | ||
27 | * @code: media bus format code defined by MEDIA_BUS_FMT_* macros | ||
28 | * @bbp: number of bytes each pixel occupies | ||
29 | * @pixelformat: pixel format devined by V4L2_PIX_FMT_* macros | ||
30 | * | ||
31 | * Struct which matches the MEDIA_BUS_FMT_* codes with the corresponding | ||
32 | * V4L2_PIX_FMT_* fourcc pixelformat and its bytes per pixel (bpp) | ||
33 | */ | ||
34 | struct vimc_pix_map { | ||
35 | unsigned int code; | ||
36 | unsigned int bpp; | ||
37 | u32 pixelformat; | ||
38 | }; | ||
39 | |||
40 | /** | ||
41 | * struct vimc_ent_device - core struct that represents a node in the topology | ||
42 | * | ||
43 | * @ent: the pointer to struct media_entity for the node | ||
44 | * @pads: the list of pads of the node | ||
45 | * @destroy: callback to destroy the node | ||
46 | * @process_frame: callback send a frame to that node | ||
47 | * | ||
48 | * Each node of the topology must create a vimc_ent_device struct. Depending on | ||
49 | * the node it will be of an instance of v4l2_subdev or video_device struct | ||
50 | * where both contains a struct media_entity. | ||
51 | * Those structures should embedded the vimc_ent_device struct through | ||
52 | * v4l2_set_subdevdata() and video_set_drvdata() respectivaly, allowing the | ||
53 | * vimc_ent_device struct to be retrieved from the corresponding struct | ||
54 | * media_entity | ||
55 | */ | ||
56 | struct vimc_ent_device { | ||
57 | struct media_entity *ent; | ||
58 | struct media_pad *pads; | ||
59 | void (*destroy)(struct vimc_ent_device *); | ||
60 | void (*process_frame)(struct vimc_ent_device *ved, | ||
61 | struct media_pad *sink, const void *frame); | ||
62 | }; | ||
63 | |||
64 | /** | ||
65 | * vimc_propagate_frame - propagate a frame through the topology | ||
66 | * | ||
67 | * @src: the source pad where the frame is being originated | ||
68 | * @frame: the frame to be propagated | ||
69 | * | ||
70 | * This function will call the process_frame callback from the vimc_ent_device | ||
71 | * struct of the nodes directly connected to the @src pad | ||
72 | */ | ||
73 | int vimc_propagate_frame(struct media_pad *src, const void *frame); | ||
74 | |||
75 | /** | ||
76 | * vimc_pads_init - initialize pads | ||
77 | * | ||
78 | * @num_pads: number of pads to initialize | ||
79 | * @pads_flags: flags to use in each pad | ||
80 | * | ||
81 | * Helper functions to allocate/initialize pads | ||
82 | */ | ||
83 | struct media_pad *vimc_pads_init(u16 num_pads, | ||
84 | const unsigned long *pads_flag); | ||
85 | |||
86 | /** | ||
87 | * vimc_pads_cleanup - free pads | ||
88 | * | ||
89 | * @pads: pointer to the pads | ||
90 | * | ||
91 | * Helper function to free the pads initialized with vimc_pads_init | ||
92 | */ | ||
93 | static inline void vimc_pads_cleanup(struct media_pad *pads) | ||
94 | { | ||
95 | kfree(pads); | ||
96 | } | ||
97 | |||
98 | /** | ||
99 | * vimc_pix_map_by_code - get vimc_pix_map struct by media bus code | ||
100 | * | ||
101 | * @code: media bus format code defined by MEDIA_BUS_FMT_* macros | ||
102 | */ | ||
103 | const struct vimc_pix_map *vimc_pix_map_by_code(u32 code); | ||
104 | |||
105 | /** | ||
106 | * vimc_pix_map_by_pixelformat - get vimc_pix_map struct by v4l2 pixel format | ||
107 | * | ||
108 | * @pixelformat: pixel format devined by V4L2_PIX_FMT_* macros | ||
109 | */ | ||
110 | const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat); | ||
111 | |||
112 | #endif | ||
diff --git a/drivers/media/platform/vimc/vimc-sensor.c b/drivers/media/platform/vimc/vimc-sensor.c new file mode 100644 index 000000000000..591f6a4f8bd3 --- /dev/null +++ b/drivers/media/platform/vimc/vimc-sensor.c | |||
@@ -0,0 +1,276 @@ | |||
1 | /* | ||
2 | * vimc-sensor.c Virtual Media Controller Driver | ||
3 | * | ||
4 | * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/freezer.h> | ||
19 | #include <linux/kthread.h> | ||
20 | #include <linux/v4l2-mediabus.h> | ||
21 | #include <linux/vmalloc.h> | ||
22 | #include <media/v4l2-subdev.h> | ||
23 | |||
24 | #include "vimc-sensor.h" | ||
25 | |||
26 | struct vimc_sen_device { | ||
27 | struct vimc_ent_device ved; | ||
28 | struct v4l2_subdev sd; | ||
29 | struct task_struct *kthread_sen; | ||
30 | u8 *frame; | ||
31 | /* The active format */ | ||
32 | struct v4l2_mbus_framefmt mbus_format; | ||
33 | int frame_size; | ||
34 | }; | ||
35 | |||
36 | static int vimc_sen_enum_mbus_code(struct v4l2_subdev *sd, | ||
37 | struct v4l2_subdev_pad_config *cfg, | ||
38 | struct v4l2_subdev_mbus_code_enum *code) | ||
39 | { | ||
40 | struct vimc_sen_device *vsen = | ||
41 | container_of(sd, struct vimc_sen_device, sd); | ||
42 | |||
43 | /* TODO: Add support for other codes */ | ||
44 | if (code->index) | ||
45 | return -EINVAL; | ||
46 | |||
47 | code->code = vsen->mbus_format.code; | ||
48 | |||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | static int vimc_sen_enum_frame_size(struct v4l2_subdev *sd, | ||
53 | struct v4l2_subdev_pad_config *cfg, | ||
54 | struct v4l2_subdev_frame_size_enum *fse) | ||
55 | { | ||
56 | struct vimc_sen_device *vsen = | ||
57 | container_of(sd, struct vimc_sen_device, sd); | ||
58 | |||
59 | /* TODO: Add support to other formats */ | ||
60 | if (fse->index) | ||
61 | return -EINVAL; | ||
62 | |||
63 | /* TODO: Add support for other codes */ | ||
64 | if (fse->code != vsen->mbus_format.code) | ||
65 | return -EINVAL; | ||
66 | |||
67 | fse->min_width = vsen->mbus_format.width; | ||
68 | fse->max_width = vsen->mbus_format.width; | ||
69 | fse->min_height = vsen->mbus_format.height; | ||
70 | fse->max_height = vsen->mbus_format.height; | ||
71 | |||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | static int vimc_sen_get_fmt(struct v4l2_subdev *sd, | ||
76 | struct v4l2_subdev_pad_config *cfg, | ||
77 | struct v4l2_subdev_format *format) | ||
78 | { | ||
79 | struct vimc_sen_device *vsen = | ||
80 | container_of(sd, struct vimc_sen_device, sd); | ||
81 | |||
82 | format->format = vsen->mbus_format; | ||
83 | |||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | static const struct v4l2_subdev_pad_ops vimc_sen_pad_ops = { | ||
88 | .enum_mbus_code = vimc_sen_enum_mbus_code, | ||
89 | .enum_frame_size = vimc_sen_enum_frame_size, | ||
90 | .get_fmt = vimc_sen_get_fmt, | ||
91 | /* TODO: Add support to other formats */ | ||
92 | .set_fmt = vimc_sen_get_fmt, | ||
93 | }; | ||
94 | |||
95 | /* media operations */ | ||
96 | static const struct media_entity_operations vimc_sen_mops = { | ||
97 | .link_validate = v4l2_subdev_link_validate, | ||
98 | }; | ||
99 | |||
100 | static int vimc_thread_sen(void *data) | ||
101 | { | ||
102 | struct vimc_sen_device *vsen = data; | ||
103 | unsigned int i; | ||
104 | |||
105 | set_freezable(); | ||
106 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
107 | |||
108 | for (;;) { | ||
109 | try_to_freeze(); | ||
110 | if (kthread_should_stop()) | ||
111 | break; | ||
112 | |||
113 | memset(vsen->frame, 100, vsen->frame_size); | ||
114 | |||
115 | /* Send the frame to all source pads */ | ||
116 | for (i = 0; i < vsen->sd.entity.num_pads; i++) | ||
117 | vimc_propagate_frame(&vsen->sd.entity.pads[i], | ||
118 | vsen->frame); | ||
119 | |||
120 | /* 60 frames per second */ | ||
121 | schedule_timeout(HZ/60); | ||
122 | } | ||
123 | |||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) | ||
128 | { | ||
129 | struct vimc_sen_device *vsen = | ||
130 | container_of(sd, struct vimc_sen_device, sd); | ||
131 | int ret; | ||
132 | |||
133 | if (enable) { | ||
134 | const struct vimc_pix_map *vpix; | ||
135 | |||
136 | if (vsen->kthread_sen) | ||
137 | return -EINVAL; | ||
138 | |||
139 | /* Calculate the frame size */ | ||
140 | vpix = vimc_pix_map_by_code(vsen->mbus_format.code); | ||
141 | vsen->frame_size = vsen->mbus_format.width * vpix->bpp * | ||
142 | vsen->mbus_format.height; | ||
143 | |||
144 | /* | ||
145 | * Allocate the frame buffer. Use vmalloc to be able to | ||
146 | * allocate a large amount of memory | ||
147 | */ | ||
148 | vsen->frame = vmalloc(vsen->frame_size); | ||
149 | if (!vsen->frame) | ||
150 | return -ENOMEM; | ||
151 | |||
152 | /* Initialize the image generator thread */ | ||
153 | vsen->kthread_sen = kthread_run(vimc_thread_sen, vsen, "%s-sen", | ||
154 | vsen->sd.v4l2_dev->name); | ||
155 | if (IS_ERR(vsen->kthread_sen)) { | ||
156 | dev_err(vsen->sd.v4l2_dev->dev, | ||
157 | "%s: kernel_thread() failed\n", vsen->sd.name); | ||
158 | vfree(vsen->frame); | ||
159 | vsen->frame = NULL; | ||
160 | return PTR_ERR(vsen->kthread_sen); | ||
161 | } | ||
162 | } else { | ||
163 | if (!vsen->kthread_sen) | ||
164 | return -EINVAL; | ||
165 | |||
166 | /* Stop image generator */ | ||
167 | ret = kthread_stop(vsen->kthread_sen); | ||
168 | vsen->kthread_sen = NULL; | ||
169 | |||
170 | vfree(vsen->frame); | ||
171 | vsen->frame = NULL; | ||
172 | return ret; | ||
173 | } | ||
174 | |||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | struct v4l2_subdev_video_ops vimc_sen_video_ops = { | ||
179 | .s_stream = vimc_sen_s_stream, | ||
180 | }; | ||
181 | |||
182 | static const struct v4l2_subdev_ops vimc_sen_ops = { | ||
183 | .pad = &vimc_sen_pad_ops, | ||
184 | .video = &vimc_sen_video_ops, | ||
185 | }; | ||
186 | |||
187 | static void vimc_sen_destroy(struct vimc_ent_device *ved) | ||
188 | { | ||
189 | struct vimc_sen_device *vsen = | ||
190 | container_of(ved, struct vimc_sen_device, ved); | ||
191 | |||
192 | v4l2_device_unregister_subdev(&vsen->sd); | ||
193 | media_entity_cleanup(ved->ent); | ||
194 | kfree(vsen); | ||
195 | } | ||
196 | |||
197 | struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev, | ||
198 | const char *const name, | ||
199 | u16 num_pads, | ||
200 | const unsigned long *pads_flag) | ||
201 | { | ||
202 | struct vimc_sen_device *vsen; | ||
203 | unsigned int i; | ||
204 | int ret; | ||
205 | |||
206 | /* NOTE: a sensor node may be created with more then one pad */ | ||
207 | if (!name || !num_pads || !pads_flag) | ||
208 | return ERR_PTR(-EINVAL); | ||
209 | |||
210 | /* check if all pads are sources */ | ||
211 | for (i = 0; i < num_pads; i++) | ||
212 | if (!(pads_flag[i] & MEDIA_PAD_FL_SOURCE)) | ||
213 | return ERR_PTR(-EINVAL); | ||
214 | |||
215 | /* Allocate the vsen struct */ | ||
216 | vsen = kzalloc(sizeof(*vsen), GFP_KERNEL); | ||
217 | if (!vsen) | ||
218 | return ERR_PTR(-ENOMEM); | ||
219 | |||
220 | /* Allocate the pads */ | ||
221 | vsen->ved.pads = vimc_pads_init(num_pads, pads_flag); | ||
222 | if (IS_ERR(vsen->ved.pads)) { | ||
223 | ret = PTR_ERR(vsen->ved.pads); | ||
224 | goto err_free_vsen; | ||
225 | } | ||
226 | |||
227 | /* Fill the vimc_ent_device struct */ | ||
228 | vsen->ved.destroy = vimc_sen_destroy; | ||
229 | vsen->ved.ent = &vsen->sd.entity; | ||
230 | |||
231 | /* Initialize the subdev */ | ||
232 | v4l2_subdev_init(&vsen->sd, &vimc_sen_ops); | ||
233 | vsen->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; | ||
234 | vsen->sd.entity.ops = &vimc_sen_mops; | ||
235 | vsen->sd.owner = THIS_MODULE; | ||
236 | strlcpy(vsen->sd.name, name, sizeof(vsen->sd.name)); | ||
237 | v4l2_set_subdevdata(&vsen->sd, &vsen->ved); | ||
238 | |||
239 | /* Expose this subdev to user space */ | ||
240 | vsen->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
241 | |||
242 | /* Initialize the media entity */ | ||
243 | ret = media_entity_pads_init(&vsen->sd.entity, | ||
244 | num_pads, vsen->ved.pads); | ||
245 | if (ret) | ||
246 | goto err_clean_pads; | ||
247 | |||
248 | /* Set the active frame format (this is hardcoded for now) */ | ||
249 | vsen->mbus_format.width = 640; | ||
250 | vsen->mbus_format.height = 480; | ||
251 | vsen->mbus_format.code = MEDIA_BUS_FMT_RGB888_1X24; | ||
252 | vsen->mbus_format.field = V4L2_FIELD_NONE; | ||
253 | vsen->mbus_format.colorspace = V4L2_COLORSPACE_SRGB; | ||
254 | vsen->mbus_format.quantization = V4L2_QUANTIZATION_FULL_RANGE; | ||
255 | vsen->mbus_format.xfer_func = V4L2_XFER_FUNC_SRGB; | ||
256 | |||
257 | /* Register the subdev with the v4l2 and the media framework */ | ||
258 | ret = v4l2_device_register_subdev(v4l2_dev, &vsen->sd); | ||
259 | if (ret) { | ||
260 | dev_err(vsen->sd.v4l2_dev->dev, | ||
261 | "%s: subdev register failed (err=%d)\n", | ||
262 | vsen->sd.name, ret); | ||
263 | goto err_clean_m_ent; | ||
264 | } | ||
265 | |||
266 | return &vsen->ved; | ||
267 | |||
268 | err_clean_m_ent: | ||
269 | media_entity_cleanup(&vsen->sd.entity); | ||
270 | err_clean_pads: | ||
271 | vimc_pads_cleanup(vsen->ved.pads); | ||
272 | err_free_vsen: | ||
273 | kfree(vsen); | ||
274 | |||
275 | return ERR_PTR(ret); | ||
276 | } | ||
diff --git a/drivers/media/platform/vimc/vimc-sensor.h b/drivers/media/platform/vimc/vimc-sensor.h new file mode 100644 index 000000000000..505310e8aeb7 --- /dev/null +++ b/drivers/media/platform/vimc/vimc-sensor.h | |||
@@ -0,0 +1,28 @@ | |||
1 | /* | ||
2 | * vimc-sensor.h Virtual Media Controller Driver | ||
3 | * | ||
4 | * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #ifndef _VIMC_SENSOR_H_ | ||
19 | #define _VIMC_SENSOR_H_ | ||
20 | |||
21 | #include "vimc-core.h" | ||
22 | |||
23 | struct vimc_ent_device *vimc_sen_create(struct v4l2_device *v4l2_dev, | ||
24 | const char *const name, | ||
25 | u16 num_pads, | ||
26 | const unsigned long *pads_flag); | ||
27 | |||
28 | #endif | ||
diff --git a/drivers/media/platform/vivid/Kconfig b/drivers/media/platform/vivid/Kconfig index db0dd19d227a..b36ac19dc6e4 100644 --- a/drivers/media/platform/vivid/Kconfig +++ b/drivers/media/platform/vivid/Kconfig | |||
@@ -1,13 +1,14 @@ | |||
1 | config VIDEO_VIVID | 1 | config VIDEO_VIVID |
2 | tristate "Virtual Video Test Driver" | 2 | tristate "Virtual Video Test Driver" |
3 | depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64 && FB | 3 | depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64 && FB |
4 | depends on HAS_DMA | ||
4 | select FONT_SUPPORT | 5 | select FONT_SUPPORT |
5 | select FONT_8x16 | 6 | select FONT_8x16 |
6 | select FB_CFB_FILLRECT | 7 | select FB_CFB_FILLRECT |
7 | select FB_CFB_COPYAREA | 8 | select FB_CFB_COPYAREA |
8 | select FB_CFB_IMAGEBLIT | 9 | select FB_CFB_IMAGEBLIT |
9 | select MEDIA_CEC_EDID | ||
10 | select VIDEOBUF2_VMALLOC | 10 | select VIDEOBUF2_VMALLOC |
11 | select VIDEOBUF2_DMA_CONTIG | ||
11 | select VIDEO_V4L2_TPG | 12 | select VIDEO_V4L2_TPG |
12 | default n | 13 | default n |
13 | ---help--- | 14 | ---help--- |
@@ -25,7 +26,7 @@ config VIDEO_VIVID | |||
25 | 26 | ||
26 | config VIDEO_VIVID_CEC | 27 | config VIDEO_VIVID_CEC |
27 | bool "Enable CEC emulation support" | 28 | bool "Enable CEC emulation support" |
28 | depends on VIDEO_VIVID && MEDIA_CEC_SUPPORT | 29 | depends on VIDEO_VIVID && CEC_CORE |
29 | ---help--- | 30 | ---help--- |
30 | When selected the vivid module will emulate the optional | 31 | When selected the vivid module will emulate the optional |
31 | HDMI CEC feature. | 32 | HDMI CEC feature. |
diff --git a/drivers/media/platform/vivid/vivid-cec.c b/drivers/media/platform/vivid/vivid-cec.c index cb4933592a3c..653f4099f737 100644 --- a/drivers/media/platform/vivid/vivid-cec.c +++ b/drivers/media/platform/vivid/vivid-cec.c | |||
@@ -135,7 +135,7 @@ static int vivid_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr) | |||
135 | static int vivid_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, | 135 | static int vivid_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, |
136 | u32 signal_free_time, struct cec_msg *msg) | 136 | u32 signal_free_time, struct cec_msg *msg) |
137 | { | 137 | { |
138 | struct vivid_dev *dev = adap->priv; | 138 | struct vivid_dev *dev = cec_get_drvdata(adap); |
139 | struct vivid_cec_work *cw = kzalloc(sizeof(*cw), GFP_KERNEL); | 139 | struct vivid_cec_work *cw = kzalloc(sizeof(*cw), GFP_KERNEL); |
140 | long delta_jiffies = 0; | 140 | long delta_jiffies = 0; |
141 | 141 | ||
@@ -166,7 +166,7 @@ static int vivid_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, | |||
166 | 166 | ||
167 | static int vivid_received(struct cec_adapter *adap, struct cec_msg *msg) | 167 | static int vivid_received(struct cec_adapter *adap, struct cec_msg *msg) |
168 | { | 168 | { |
169 | struct vivid_dev *dev = adap->priv; | 169 | struct vivid_dev *dev = cec_get_drvdata(adap); |
170 | struct cec_msg reply; | 170 | struct cec_msg reply; |
171 | u8 dest = cec_msg_destination(msg); | 171 | u8 dest = cec_msg_destination(msg); |
172 | u8 disp_ctl; | 172 | u8 disp_ctl; |
diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index 51e37812ec98..ef344b9a48af 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/videodev2.h> | 30 | #include <linux/videodev2.h> |
31 | #include <linux/v4l2-dv-timings.h> | 31 | #include <linux/v4l2-dv-timings.h> |
32 | #include <media/videobuf2-vmalloc.h> | 32 | #include <media/videobuf2-vmalloc.h> |
33 | #include <media/videobuf2-dma-contig.h> | ||
33 | #include <media/v4l2-dv-timings.h> | 34 | #include <media/v4l2-dv-timings.h> |
34 | #include <media/v4l2-ioctl.h> | 35 | #include <media/v4l2-ioctl.h> |
35 | #include <media/v4l2-fh.h> | 36 | #include <media/v4l2-fh.h> |
@@ -151,6 +152,12 @@ static bool no_error_inj; | |||
151 | module_param(no_error_inj, bool, 0444); | 152 | module_param(no_error_inj, bool, 0444); |
152 | MODULE_PARM_DESC(no_error_inj, " if set disable the error injecting controls"); | 153 | MODULE_PARM_DESC(no_error_inj, " if set disable the error injecting controls"); |
153 | 154 | ||
155 | static unsigned int allocators[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 0 }; | ||
156 | module_param_array(allocators, uint, NULL, 0444); | ||
157 | MODULE_PARM_DESC(allocators, " memory allocator selection, default is 0.\n" | ||
158 | "\t\t 0 == vmalloc\n" | ||
159 | "\t\t 1 == dma-contig"); | ||
160 | |||
154 | static struct vivid_dev *vivid_devs[VIVID_MAX_DEVS]; | 161 | static struct vivid_dev *vivid_devs[VIVID_MAX_DEVS]; |
155 | 162 | ||
156 | const struct v4l2_rect vivid_min_rect = { | 163 | const struct v4l2_rect vivid_min_rect = { |
@@ -636,6 +643,10 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) | |||
636 | { | 643 | { |
637 | static const struct v4l2_dv_timings def_dv_timings = | 644 | static const struct v4l2_dv_timings def_dv_timings = |
638 | V4L2_DV_BT_CEA_1280X720P60; | 645 | V4L2_DV_BT_CEA_1280X720P60; |
646 | static const struct vb2_mem_ops * const vivid_mem_ops[2] = { | ||
647 | &vb2_vmalloc_memops, | ||
648 | &vb2_dma_contig_memops, | ||
649 | }; | ||
639 | unsigned in_type_counter[4] = { 0, 0, 0, 0 }; | 650 | unsigned in_type_counter[4] = { 0, 0, 0, 0 }; |
640 | unsigned out_type_counter[4] = { 0, 0, 0, 0 }; | 651 | unsigned out_type_counter[4] = { 0, 0, 0, 0 }; |
641 | int ccs_cap = ccs_cap_mode[inst]; | 652 | int ccs_cap = ccs_cap_mode[inst]; |
@@ -646,6 +657,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) | |||
646 | struct video_device *vfd; | 657 | struct video_device *vfd; |
647 | struct vb2_queue *q; | 658 | struct vb2_queue *q; |
648 | unsigned node_type = node_types[inst]; | 659 | unsigned node_type = node_types[inst]; |
660 | unsigned int allocator = allocators[inst]; | ||
649 | v4l2_std_id tvnorms_cap = 0, tvnorms_out = 0; | 661 | v4l2_std_id tvnorms_cap = 0, tvnorms_out = 0; |
650 | int ret; | 662 | int ret; |
651 | int i; | 663 | int i; |
@@ -1039,6 +1051,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) | |||
1039 | goto unreg_dev; | 1051 | goto unreg_dev; |
1040 | } | 1052 | } |
1041 | 1053 | ||
1054 | if (allocator == 1) | ||
1055 | dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); | ||
1056 | else if (allocator >= ARRAY_SIZE(vivid_mem_ops)) | ||
1057 | allocator = 0; | ||
1058 | |||
1042 | /* start creating the vb2 queues */ | 1059 | /* start creating the vb2 queues */ |
1043 | if (dev->has_vid_cap) { | 1060 | if (dev->has_vid_cap) { |
1044 | /* initialize vid_cap queue */ | 1061 | /* initialize vid_cap queue */ |
@@ -1049,10 +1066,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) | |||
1049 | q->drv_priv = dev; | 1066 | q->drv_priv = dev; |
1050 | q->buf_struct_size = sizeof(struct vivid_buffer); | 1067 | q->buf_struct_size = sizeof(struct vivid_buffer); |
1051 | q->ops = &vivid_vid_cap_qops; | 1068 | q->ops = &vivid_vid_cap_qops; |
1052 | q->mem_ops = &vb2_vmalloc_memops; | 1069 | q->mem_ops = vivid_mem_ops[allocator]; |
1053 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | 1070 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
1054 | q->min_buffers_needed = 2; | 1071 | q->min_buffers_needed = 2; |
1055 | q->lock = &dev->mutex; | 1072 | q->lock = &dev->mutex; |
1073 | q->dev = dev->v4l2_dev.dev; | ||
1056 | 1074 | ||
1057 | ret = vb2_queue_init(q); | 1075 | ret = vb2_queue_init(q); |
1058 | if (ret) | 1076 | if (ret) |
@@ -1068,10 +1086,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) | |||
1068 | q->drv_priv = dev; | 1086 | q->drv_priv = dev; |
1069 | q->buf_struct_size = sizeof(struct vivid_buffer); | 1087 | q->buf_struct_size = sizeof(struct vivid_buffer); |
1070 | q->ops = &vivid_vid_out_qops; | 1088 | q->ops = &vivid_vid_out_qops; |
1071 | q->mem_ops = &vb2_vmalloc_memops; | 1089 | q->mem_ops = vivid_mem_ops[allocator]; |
1072 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | 1090 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
1073 | q->min_buffers_needed = 2; | 1091 | q->min_buffers_needed = 2; |
1074 | q->lock = &dev->mutex; | 1092 | q->lock = &dev->mutex; |
1093 | q->dev = dev->v4l2_dev.dev; | ||
1075 | 1094 | ||
1076 | ret = vb2_queue_init(q); | 1095 | ret = vb2_queue_init(q); |
1077 | if (ret) | 1096 | if (ret) |
@@ -1087,10 +1106,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) | |||
1087 | q->drv_priv = dev; | 1106 | q->drv_priv = dev; |
1088 | q->buf_struct_size = sizeof(struct vivid_buffer); | 1107 | q->buf_struct_size = sizeof(struct vivid_buffer); |
1089 | q->ops = &vivid_vbi_cap_qops; | 1108 | q->ops = &vivid_vbi_cap_qops; |
1090 | q->mem_ops = &vb2_vmalloc_memops; | 1109 | q->mem_ops = vivid_mem_ops[allocator]; |
1091 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | 1110 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
1092 | q->min_buffers_needed = 2; | 1111 | q->min_buffers_needed = 2; |
1093 | q->lock = &dev->mutex; | 1112 | q->lock = &dev->mutex; |
1113 | q->dev = dev->v4l2_dev.dev; | ||
1094 | 1114 | ||
1095 | ret = vb2_queue_init(q); | 1115 | ret = vb2_queue_init(q); |
1096 | if (ret) | 1116 | if (ret) |
@@ -1106,10 +1126,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) | |||
1106 | q->drv_priv = dev; | 1126 | q->drv_priv = dev; |
1107 | q->buf_struct_size = sizeof(struct vivid_buffer); | 1127 | q->buf_struct_size = sizeof(struct vivid_buffer); |
1108 | q->ops = &vivid_vbi_out_qops; | 1128 | q->ops = &vivid_vbi_out_qops; |
1109 | q->mem_ops = &vb2_vmalloc_memops; | 1129 | q->mem_ops = vivid_mem_ops[allocator]; |
1110 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | 1130 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
1111 | q->min_buffers_needed = 2; | 1131 | q->min_buffers_needed = 2; |
1112 | q->lock = &dev->mutex; | 1132 | q->lock = &dev->mutex; |
1133 | q->dev = dev->v4l2_dev.dev; | ||
1113 | 1134 | ||
1114 | ret = vb2_queue_init(q); | 1135 | ret = vb2_queue_init(q); |
1115 | if (ret) | 1136 | if (ret) |
@@ -1124,10 +1145,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) | |||
1124 | q->drv_priv = dev; | 1145 | q->drv_priv = dev; |
1125 | q->buf_struct_size = sizeof(struct vivid_buffer); | 1146 | q->buf_struct_size = sizeof(struct vivid_buffer); |
1126 | q->ops = &vivid_sdr_cap_qops; | 1147 | q->ops = &vivid_sdr_cap_qops; |
1127 | q->mem_ops = &vb2_vmalloc_memops; | 1148 | q->mem_ops = vivid_mem_ops[allocator]; |
1128 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | 1149 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
1129 | q->min_buffers_needed = 8; | 1150 | q->min_buffers_needed = 8; |
1130 | q->lock = &dev->mutex; | 1151 | q->lock = &dev->mutex; |
1152 | q->dev = dev->v4l2_dev.dev; | ||
1131 | 1153 | ||
1132 | ret = vb2_queue_init(q); | 1154 | ret = vb2_queue_init(q); |
1133 | if (ret) | 1155 | if (ret) |
diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index a18e6fec219b..01419455e545 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c | |||
@@ -616,7 +616,7 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv, | |||
616 | /* This driver supports custom bytesperline values */ | 616 | /* This driver supports custom bytesperline values */ |
617 | 617 | ||
618 | mp->num_planes = fmt->buffers; | 618 | mp->num_planes = fmt->buffers; |
619 | for (p = 0; p < mp->num_planes; p++) { | 619 | for (p = 0; p < fmt->buffers; p++) { |
620 | /* Calculate the minimum supported bytesperline value */ | 620 | /* Calculate the minimum supported bytesperline value */ |
621 | bytesperline = (mp->width * fmt->bit_depth[p]) >> 3; | 621 | bytesperline = (mp->width * fmt->bit_depth[p]) >> 3; |
622 | /* Calculate the maximum supported bytesperline value */ | 622 | /* Calculate the maximum supported bytesperline value */ |
@@ -626,10 +626,17 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv, | |||
626 | pfmt[p].bytesperline = max_bpl; | 626 | pfmt[p].bytesperline = max_bpl; |
627 | if (pfmt[p].bytesperline < bytesperline) | 627 | if (pfmt[p].bytesperline < bytesperline) |
628 | pfmt[p].bytesperline = bytesperline; | 628 | pfmt[p].bytesperline = bytesperline; |
629 | pfmt[p].sizeimage = tpg_calc_line_width(&dev->tpg, p, pfmt[p].bytesperline) * | 629 | |
630 | mp->height + fmt->data_offset[p]; | 630 | pfmt[p].sizeimage = (pfmt[p].bytesperline * mp->height) / |
631 | fmt->vdownsampling[p] + fmt->data_offset[p]; | ||
632 | |||
631 | memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved)); | 633 | memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved)); |
632 | } | 634 | } |
635 | for (p = fmt->buffers; p < fmt->planes; p++) | ||
636 | pfmt[0].sizeimage += (pfmt[0].bytesperline * mp->height * | ||
637 | (fmt->bit_depth[p] / fmt->vdownsampling[p])) / | ||
638 | (fmt->bit_depth[0] / fmt->vdownsampling[0]); | ||
639 | |||
633 | mp->colorspace = vivid_colorspace_cap(dev); | 640 | mp->colorspace = vivid_colorspace_cap(dev); |
634 | if (fmt->color_enc == TGP_COLOR_ENC_HSV) | 641 | if (fmt->color_enc == TGP_COLOR_ENC_HSV) |
635 | mp->hsv_enc = vivid_hsv_enc_cap(dev); | 642 | mp->hsv_enc = vivid_hsv_enc_cap(dev); |
diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index 5fc010f6ce67..f0f423c7ca41 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c | |||
@@ -858,7 +858,7 @@ int vidioc_g_edid(struct file *file, void *_fh, | |||
858 | return -EINVAL; | 858 | return -EINVAL; |
859 | if (edid->start_block + edid->blocks > dev->edid_blocks) | 859 | if (edid->start_block + edid->blocks > dev->edid_blocks) |
860 | edid->blocks = dev->edid_blocks - edid->start_block; | 860 | edid->blocks = dev->edid_blocks - edid->start_block; |
861 | memcpy(edid->edid, dev->edid, edid->blocks * 128); | 861 | cec_set_edid_phys_addr(dev->edid, dev->edid_blocks * 128, adap->phys_addr); |
862 | cec_set_edid_phys_addr(edid->edid, edid->blocks * 128, adap->phys_addr); | 862 | memcpy(edid->edid, dev->edid + edid->start_block * 128, edid->blocks * 128); |
863 | return 0; | 863 | return 0; |
864 | } | 864 | } |
diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index 7ba52ee98371..0b1b6218ede8 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c | |||
@@ -390,22 +390,28 @@ int vivid_try_fmt_vid_out(struct file *file, void *priv, | |||
390 | 390 | ||
391 | /* This driver supports custom bytesperline values */ | 391 | /* This driver supports custom bytesperline values */ |
392 | 392 | ||
393 | /* Calculate the minimum supported bytesperline value */ | ||
394 | bytesperline = (mp->width * fmt->bit_depth[0]) >> 3; | ||
395 | /* Calculate the maximum supported bytesperline value */ | ||
396 | max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->bit_depth[0]) >> 3; | ||
397 | mp->num_planes = fmt->buffers; | 393 | mp->num_planes = fmt->buffers; |
398 | for (p = 0; p < mp->num_planes; p++) { | 394 | for (p = 0; p < fmt->buffers; p++) { |
395 | /* Calculate the minimum supported bytesperline value */ | ||
396 | bytesperline = (mp->width * fmt->bit_depth[p]) >> 3; | ||
397 | /* Calculate the maximum supported bytesperline value */ | ||
398 | max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->bit_depth[p]) >> 3; | ||
399 | |||
399 | if (pfmt[p].bytesperline > max_bpl) | 400 | if (pfmt[p].bytesperline > max_bpl) |
400 | pfmt[p].bytesperline = max_bpl; | 401 | pfmt[p].bytesperline = max_bpl; |
401 | if (pfmt[p].bytesperline < bytesperline) | 402 | if (pfmt[p].bytesperline < bytesperline) |
402 | pfmt[p].bytesperline = bytesperline; | 403 | pfmt[p].bytesperline = bytesperline; |
403 | pfmt[p].sizeimage = pfmt[p].bytesperline * mp->height; | 404 | |
405 | pfmt[p].sizeimage = (pfmt[p].bytesperline * mp->height) / | ||
406 | fmt->vdownsampling[p]; | ||
407 | |||
404 | memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved)); | 408 | memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved)); |
405 | } | 409 | } |
406 | for (p = fmt->buffers; p < fmt->planes; p++) | 410 | for (p = fmt->buffers; p < fmt->planes; p++) |
407 | pfmt[0].sizeimage += (pfmt[0].bytesperline * fmt->bit_depth[p]) / | 411 | pfmt[0].sizeimage += (pfmt[0].bytesperline * mp->height * |
408 | (fmt->bit_depth[0] * fmt->vdownsampling[p]); | 412 | (fmt->bit_depth[p] / fmt->vdownsampling[p])) / |
413 | (fmt->bit_depth[0] / fmt->vdownsampling[0]); | ||
414 | |||
409 | mp->xfer_func = V4L2_XFER_FUNC_DEFAULT; | 415 | mp->xfer_func = V4L2_XFER_FUNC_DEFAULT; |
410 | mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; | 416 | mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; |
411 | mp->quantization = V4L2_QUANTIZATION_DEFAULT; | 417 | mp->quantization = V4L2_QUANTIZATION_DEFAULT; |
@@ -1172,14 +1178,12 @@ int vidioc_subscribe_event(struct v4l2_fh *fh, | |||
1172 | const struct v4l2_event_subscription *sub) | 1178 | const struct v4l2_event_subscription *sub) |
1173 | { | 1179 | { |
1174 | switch (sub->type) { | 1180 | switch (sub->type) { |
1175 | case V4L2_EVENT_CTRL: | ||
1176 | return v4l2_ctrl_subscribe_event(fh, sub); | ||
1177 | case V4L2_EVENT_SOURCE_CHANGE: | 1181 | case V4L2_EVENT_SOURCE_CHANGE: |
1178 | if (fh->vdev->vfl_dir == VFL_DIR_RX) | 1182 | if (fh->vdev->vfl_dir == VFL_DIR_RX) |
1179 | return v4l2_src_change_event_subscribe(fh, sub); | 1183 | return v4l2_src_change_event_subscribe(fh, sub); |
1180 | break; | 1184 | break; |
1181 | default: | 1185 | default: |
1182 | break; | 1186 | return v4l2_ctrl_subscribe_event(fh, sub); |
1183 | } | 1187 | } |
1184 | return -EINVAL; | 1188 | return -EINVAL; |
1185 | } | 1189 | } |
diff --git a/drivers/media/platform/vsp1/Makefile b/drivers/media/platform/vsp1/Makefile index 1328e1bd2143..a33afc385a48 100644 --- a/drivers/media/platform/vsp1/Makefile +++ b/drivers/media/platform/vsp1/Makefile | |||
@@ -3,6 +3,7 @@ vsp1-y += vsp1_dl.o vsp1_drm.o vsp1_video.o | |||
3 | vsp1-y += vsp1_rpf.o vsp1_rwpf.o vsp1_wpf.o | 3 | vsp1-y += vsp1_rpf.o vsp1_rwpf.o vsp1_wpf.o |
4 | vsp1-y += vsp1_clu.o vsp1_hsit.o vsp1_lut.o | 4 | vsp1-y += vsp1_clu.o vsp1_hsit.o vsp1_lut.o |
5 | vsp1-y += vsp1_bru.o vsp1_sru.o vsp1_uds.o | 5 | vsp1-y += vsp1_bru.o vsp1_sru.o vsp1_uds.o |
6 | vsp1-y += vsp1_hgo.o vsp1_hgt.o vsp1_histo.o | ||
6 | vsp1-y += vsp1_lif.o | 7 | vsp1-y += vsp1_lif.o |
7 | 8 | ||
8 | obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1.o | 9 | obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1.o |
diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h index b23fa879a9aa..85387a64179a 100644 --- a/drivers/media/platform/vsp1/vsp1.h +++ b/drivers/media/platform/vsp1/vsp1.h | |||
@@ -32,6 +32,8 @@ struct vsp1_entity; | |||
32 | struct vsp1_platform_data; | 32 | struct vsp1_platform_data; |
33 | struct vsp1_bru; | 33 | struct vsp1_bru; |
34 | struct vsp1_clu; | 34 | struct vsp1_clu; |
35 | struct vsp1_hgo; | ||
36 | struct vsp1_hgt; | ||
35 | struct vsp1_hsit; | 37 | struct vsp1_hsit; |
36 | struct vsp1_lif; | 38 | struct vsp1_lif; |
37 | struct vsp1_lut; | 39 | struct vsp1_lut; |
@@ -50,6 +52,8 @@ struct vsp1_uds; | |||
50 | #define VSP1_HAS_CLU (1 << 4) | 52 | #define VSP1_HAS_CLU (1 << 4) |
51 | #define VSP1_HAS_WPF_VFLIP (1 << 5) | 53 | #define VSP1_HAS_WPF_VFLIP (1 << 5) |
52 | #define VSP1_HAS_WPF_HFLIP (1 << 6) | 54 | #define VSP1_HAS_WPF_HFLIP (1 << 6) |
55 | #define VSP1_HAS_HGO (1 << 7) | ||
56 | #define VSP1_HAS_HGT (1 << 8) | ||
53 | 57 | ||
54 | struct vsp1_device_info { | 58 | struct vsp1_device_info { |
55 | u32 version; | 59 | u32 version; |
@@ -73,6 +77,8 @@ struct vsp1_device { | |||
73 | 77 | ||
74 | struct vsp1_bru *bru; | 78 | struct vsp1_bru *bru; |
75 | struct vsp1_clu *clu; | 79 | struct vsp1_clu *clu; |
80 | struct vsp1_hgo *hgo; | ||
81 | struct vsp1_hgt *hgt; | ||
76 | struct vsp1_hsit *hsi; | 82 | struct vsp1_hsit *hsi; |
77 | struct vsp1_hsit *hst; | 83 | struct vsp1_hsit *hst; |
78 | struct vsp1_lif *lif; | 84 | struct vsp1_lif *lif; |
diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c index ee8355c28f94..85362c5ef57a 100644 --- a/drivers/media/platform/vsp1/vsp1_bru.c +++ b/drivers/media/platform/vsp1/vsp1_bru.c | |||
@@ -251,7 +251,8 @@ static int bru_set_selection(struct v4l2_subdev *subdev, | |||
251 | sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1); | 251 | sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1); |
252 | sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1); | 252 | sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1); |
253 | 253 | ||
254 | /* Scaling isn't supported, the compose rectangle size must be identical | 254 | /* |
255 | * Scaling isn't supported, the compose rectangle size must be identical | ||
255 | * to the sink format size. | 256 | * to the sink format size. |
256 | */ | 257 | */ |
257 | format = vsp1_entity_get_pad_format(&bru->entity, config, sel->pad); | 258 | format = vsp1_entity_get_pad_format(&bru->entity, config, sel->pad); |
@@ -300,13 +301,15 @@ static void bru_configure(struct vsp1_entity *entity, | |||
300 | format = vsp1_entity_get_pad_format(&bru->entity, bru->entity.config, | 301 | format = vsp1_entity_get_pad_format(&bru->entity, bru->entity.config, |
301 | bru->entity.source_pad); | 302 | bru->entity.source_pad); |
302 | 303 | ||
303 | /* The hardware is extremely flexible but we have no userspace API to | 304 | /* |
305 | * The hardware is extremely flexible but we have no userspace API to | ||
304 | * expose all the parameters, nor is it clear whether we would have use | 306 | * expose all the parameters, nor is it clear whether we would have use |
305 | * cases for all the supported modes. Let's just harcode the parameters | 307 | * cases for all the supported modes. Let's just harcode the parameters |
306 | * to sane default values for now. | 308 | * to sane default values for now. |
307 | */ | 309 | */ |
308 | 310 | ||
309 | /* Disable dithering and enable color data normalization unless the | 311 | /* |
312 | * Disable dithering and enable color data normalization unless the | ||
310 | * format at the pipeline output is premultiplied. | 313 | * format at the pipeline output is premultiplied. |
311 | */ | 314 | */ |
312 | flags = pipe->output ? pipe->output->format.flags : 0; | 315 | flags = pipe->output ? pipe->output->format.flags : 0; |
@@ -314,7 +317,8 @@ static void bru_configure(struct vsp1_entity *entity, | |||
314 | flags & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA ? | 317 | flags & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA ? |
315 | 0 : VI6_BRU_INCTRL_NRM); | 318 | 0 : VI6_BRU_INCTRL_NRM); |
316 | 319 | ||
317 | /* Set the background position to cover the whole output image and | 320 | /* |
321 | * Set the background position to cover the whole output image and | ||
318 | * configure its color. | 322 | * configure its color. |
319 | */ | 323 | */ |
320 | vsp1_bru_write(bru, dl, VI6_BRU_VIRRPF_SIZE, | 324 | vsp1_bru_write(bru, dl, VI6_BRU_VIRRPF_SIZE, |
@@ -325,7 +329,8 @@ static void bru_configure(struct vsp1_entity *entity, | |||
325 | vsp1_bru_write(bru, dl, VI6_BRU_VIRRPF_COL, bru->bgcolor | | 329 | vsp1_bru_write(bru, dl, VI6_BRU_VIRRPF_COL, bru->bgcolor | |
326 | (0xff << VI6_BRU_VIRRPF_COL_A_SHIFT)); | 330 | (0xff << VI6_BRU_VIRRPF_COL_A_SHIFT)); |
327 | 331 | ||
328 | /* Route BRU input 1 as SRC input to the ROP unit and configure the ROP | 332 | /* |
333 | * Route BRU input 1 as SRC input to the ROP unit and configure the ROP | ||
329 | * unit with a NOP operation to make BRU input 1 available as the | 334 | * unit with a NOP operation to make BRU input 1 available as the |
330 | * Blend/ROP unit B SRC input. | 335 | * Blend/ROP unit B SRC input. |
331 | */ | 336 | */ |
@@ -337,7 +342,8 @@ static void bru_configure(struct vsp1_entity *entity, | |||
337 | bool premultiplied = false; | 342 | bool premultiplied = false; |
338 | u32 ctrl = 0; | 343 | u32 ctrl = 0; |
339 | 344 | ||
340 | /* Configure all Blend/ROP units corresponding to an enabled BRU | 345 | /* |
346 | * Configure all Blend/ROP units corresponding to an enabled BRU | ||
341 | * input for alpha blending. Blend/ROP units corresponding to | 347 | * input for alpha blending. Blend/ROP units corresponding to |
342 | * disabled BRU inputs are used in ROP NOP mode to ignore the | 348 | * disabled BRU inputs are used in ROP NOP mode to ignore the |
343 | * SRC input. | 349 | * SRC input. |
@@ -352,13 +358,15 @@ static void bru_configure(struct vsp1_entity *entity, | |||
352 | | VI6_BRU_CTRL_AROP(VI6_ROP_NOP); | 358 | | VI6_BRU_CTRL_AROP(VI6_ROP_NOP); |
353 | } | 359 | } |
354 | 360 | ||
355 | /* Select the virtual RPF as the Blend/ROP unit A DST input to | 361 | /* |
362 | * Select the virtual RPF as the Blend/ROP unit A DST input to | ||
356 | * serve as a background color. | 363 | * serve as a background color. |
357 | */ | 364 | */ |
358 | if (i == 0) | 365 | if (i == 0) |
359 | ctrl |= VI6_BRU_CTRL_DSTSEL_VRPF; | 366 | ctrl |= VI6_BRU_CTRL_DSTSEL_VRPF; |
360 | 367 | ||
361 | /* Route BRU inputs 0 to 3 as SRC inputs to Blend/ROP units A to | 368 | /* |
369 | * Route BRU inputs 0 to 3 as SRC inputs to Blend/ROP units A to | ||
362 | * D in that order. The Blend/ROP unit B SRC is hardwired to the | 370 | * D in that order. The Blend/ROP unit B SRC is hardwired to the |
363 | * ROP unit output, the corresponding register bits must be set | 371 | * ROP unit output, the corresponding register bits must be set |
364 | * to 0. | 372 | * to 0. |
@@ -368,7 +376,8 @@ static void bru_configure(struct vsp1_entity *entity, | |||
368 | 376 | ||
369 | vsp1_bru_write(bru, dl, VI6_BRU_CTRL(i), ctrl); | 377 | vsp1_bru_write(bru, dl, VI6_BRU_CTRL(i), ctrl); |
370 | 378 | ||
371 | /* Harcode the blending formula to | 379 | /* |
380 | * Harcode the blending formula to | ||
372 | * | 381 | * |
373 | * DSTc = DSTc * (1 - SRCa) + SRCc * SRCa | 382 | * DSTc = DSTc * (1 - SRCa) + SRCc * SRCa |
374 | * DSTa = DSTa * (1 - SRCa) + SRCa | 383 | * DSTa = DSTa * (1 - SRCa) + SRCa |
diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c index ad545aff4e35..7d8f37772b56 100644 --- a/drivers/media/platform/vsp1/vsp1_dl.c +++ b/drivers/media/platform/vsp1/vsp1_dl.c | |||
@@ -240,7 +240,8 @@ static struct vsp1_dl_list *vsp1_dl_list_alloc(struct vsp1_dl_manager *dlm) | |||
240 | INIT_LIST_HEAD(&dl->fragments); | 240 | INIT_LIST_HEAD(&dl->fragments); |
241 | dl->dlm = dlm; | 241 | dl->dlm = dlm; |
242 | 242 | ||
243 | /* Initialize the display list body and allocate DMA memory for the body | 243 | /* |
244 | * Initialize the display list body and allocate DMA memory for the body | ||
244 | * and the optional header. Both are allocated together to avoid memory | 245 | * and the optional header. Both are allocated together to avoid memory |
245 | * fragmentation, with the header located right after the body in | 246 | * fragmentation, with the header located right after the body in |
246 | * memory. | 247 | * memory. |
@@ -511,7 +512,8 @@ void vsp1_dl_list_commit(struct vsp1_dl_list *dl) | |||
511 | goto done; | 512 | goto done; |
512 | } | 513 | } |
513 | 514 | ||
514 | /* Once the UPD bit has been set the hardware can start processing the | 515 | /* |
516 | * Once the UPD bit has been set the hardware can start processing the | ||
515 | * display list at any time and we can't touch the address and size | 517 | * display list at any time and we can't touch the address and size |
516 | * registers. In that case mark the update as pending, it will be | 518 | * registers. In that case mark the update as pending, it will be |
517 | * queued up to the hardware by the frame end interrupt handler. | 519 | * queued up to the hardware by the frame end interrupt handler. |
@@ -523,7 +525,8 @@ void vsp1_dl_list_commit(struct vsp1_dl_list *dl) | |||
523 | goto done; | 525 | goto done; |
524 | } | 526 | } |
525 | 527 | ||
526 | /* Program the hardware with the display list body address and size. | 528 | /* |
529 | * Program the hardware with the display list body address and size. | ||
527 | * The UPD bit will be cleared by the device when the display list is | 530 | * The UPD bit will be cleared by the device when the display list is |
528 | * processed. | 531 | * processed. |
529 | */ | 532 | */ |
@@ -547,7 +550,8 @@ void vsp1_dlm_irq_display_start(struct vsp1_dl_manager *dlm) | |||
547 | { | 550 | { |
548 | spin_lock(&dlm->lock); | 551 | spin_lock(&dlm->lock); |
549 | 552 | ||
550 | /* The display start interrupt signals the end of the display list | 553 | /* |
554 | * The display start interrupt signals the end of the display list | ||
551 | * processing by the device. The active display list, if any, won't be | 555 | * processing by the device. The active display list, if any, won't be |
552 | * accessed anymore and can be reused. | 556 | * accessed anymore and can be reused. |
553 | */ | 557 | */ |
@@ -566,14 +570,16 @@ void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm) | |||
566 | __vsp1_dl_list_put(dlm->active); | 570 | __vsp1_dl_list_put(dlm->active); |
567 | dlm->active = NULL; | 571 | dlm->active = NULL; |
568 | 572 | ||
569 | /* Header mode is used for mem-to-mem pipelines only. We don't need to | 573 | /* |
574 | * Header mode is used for mem-to-mem pipelines only. We don't need to | ||
570 | * perform any operation as there can't be any new display list queued | 575 | * perform any operation as there can't be any new display list queued |
571 | * in that case. | 576 | * in that case. |
572 | */ | 577 | */ |
573 | if (dlm->mode == VSP1_DL_MODE_HEADER) | 578 | if (dlm->mode == VSP1_DL_MODE_HEADER) |
574 | goto done; | 579 | goto done; |
575 | 580 | ||
576 | /* The UPD bit set indicates that the commit operation raced with the | 581 | /* |
582 | * The UPD bit set indicates that the commit operation raced with the | ||
577 | * interrupt and occurred after the frame end event and UPD clear but | 583 | * interrupt and occurred after the frame end event and UPD clear but |
578 | * before interrupt processing. The hardware hasn't taken the update | 584 | * before interrupt processing. The hardware hasn't taken the update |
579 | * into account yet, we'll thus skip one frame and retry. | 585 | * into account yet, we'll thus skip one frame and retry. |
@@ -581,7 +587,8 @@ void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm) | |||
581 | if (vsp1_read(vsp1, VI6_DL_BODY_SIZE) & VI6_DL_BODY_SIZE_UPD) | 587 | if (vsp1_read(vsp1, VI6_DL_BODY_SIZE) & VI6_DL_BODY_SIZE_UPD) |
582 | goto done; | 588 | goto done; |
583 | 589 | ||
584 | /* The device starts processing the queued display list right after the | 590 | /* |
591 | * The device starts processing the queued display list right after the | ||
585 | * frame end interrupt. The display list thus becomes active. | 592 | * frame end interrupt. The display list thus becomes active. |
586 | */ | 593 | */ |
587 | if (dlm->queued) { | 594 | if (dlm->queued) { |
@@ -589,7 +596,8 @@ void vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm) | |||
589 | dlm->queued = NULL; | 596 | dlm->queued = NULL; |
590 | } | 597 | } |
591 | 598 | ||
592 | /* Now that the UPD bit has been cleared we can queue the next display | 599 | /* |
600 | * Now that the UPD bit has been cleared we can queue the next display | ||
593 | * list to the hardware if one has been prepared. | 601 | * list to the hardware if one has been prepared. |
594 | */ | 602 | */ |
595 | if (dlm->pending) { | 603 | if (dlm->pending) { |
@@ -615,7 +623,8 @@ void vsp1_dlm_setup(struct vsp1_device *vsp1) | |||
615 | | VI6_DL_CTRL_DC2 | VI6_DL_CTRL_DC1 | VI6_DL_CTRL_DC0 | 623 | | VI6_DL_CTRL_DC2 | VI6_DL_CTRL_DC1 | VI6_DL_CTRL_DC0 |
616 | | VI6_DL_CTRL_DLE; | 624 | | VI6_DL_CTRL_DLE; |
617 | 625 | ||
618 | /* The DRM pipeline operates with display lists in Continuous Frame | 626 | /* |
627 | * The DRM pipeline operates with display lists in Continuous Frame | ||
619 | * Mode, all other pipelines use manual start. | 628 | * Mode, all other pipelines use manual start. |
620 | */ | 629 | */ |
621 | if (vsp1->drm) | 630 | if (vsp1->drm) |
diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c index b4c0f10fc3b0..9d235e830f5a 100644 --- a/drivers/media/platform/vsp1/vsp1_drm.c +++ b/drivers/media/platform/vsp1/vsp1_drm.c | |||
@@ -78,7 +78,8 @@ int vsp1_du_setup_lif(struct device *dev, const struct vsp1_du_lif_config *cfg) | |||
78 | int ret; | 78 | int ret; |
79 | 79 | ||
80 | if (!cfg) { | 80 | if (!cfg) { |
81 | /* NULL configuration means the CRTC is being disabled, stop | 81 | /* |
82 | * NULL configuration means the CRTC is being disabled, stop | ||
82 | * the pipeline and turn the light off. | 83 | * the pipeline and turn the light off. |
83 | */ | 84 | */ |
84 | ret = vsp1_pipeline_stop(pipe); | 85 | ret = vsp1_pipeline_stop(pipe); |
@@ -106,7 +107,8 @@ int vsp1_du_setup_lif(struct device *dev, const struct vsp1_du_lif_config *cfg) | |||
106 | dev_dbg(vsp1->dev, "%s: configuring LIF with format %ux%u\n", | 107 | dev_dbg(vsp1->dev, "%s: configuring LIF with format %ux%u\n", |
107 | __func__, cfg->width, cfg->height); | 108 | __func__, cfg->width, cfg->height); |
108 | 109 | ||
109 | /* Configure the format at the BRU sinks and propagate it through the | 110 | /* |
111 | * Configure the format at the BRU sinks and propagate it through the | ||
110 | * pipeline. | 112 | * pipeline. |
111 | */ | 113 | */ |
112 | memset(&format, 0, sizeof(format)); | 114 | memset(&format, 0, sizeof(format)); |
@@ -175,7 +177,8 @@ int vsp1_du_setup_lif(struct device *dev, const struct vsp1_du_lif_config *cfg) | |||
175 | __func__, format.format.width, format.format.height, | 177 | __func__, format.format.width, format.format.height, |
176 | format.format.code); | 178 | format.format.code); |
177 | 179 | ||
178 | /* Verify that the format at the output of the pipeline matches the | 180 | /* |
181 | * Verify that the format at the output of the pipeline matches the | ||
179 | * requested frame size and media bus code. | 182 | * requested frame size and media bus code. |
180 | */ | 183 | */ |
181 | if (format.format.width != cfg->width || | 184 | if (format.format.width != cfg->width || |
@@ -185,7 +188,8 @@ int vsp1_du_setup_lif(struct device *dev, const struct vsp1_du_lif_config *cfg) | |||
185 | return -EPIPE; | 188 | return -EPIPE; |
186 | } | 189 | } |
187 | 190 | ||
188 | /* Mark the pipeline as streaming and enable the VSP1. This will store | 191 | /* |
192 | * Mark the pipeline as streaming and enable the VSP1. This will store | ||
189 | * the pipeline pointer in all entities, which the s_stream handlers | 193 | * the pipeline pointer in all entities, which the s_stream handlers |
190 | * will need. We don't start the entities themselves right at this point | 194 | * will need. We don't start the entities themselves right at this point |
191 | * as there's no plane configured yet, so we can't start processing | 195 | * as there's no plane configured yet, so we can't start processing |
@@ -219,9 +223,6 @@ void vsp1_du_atomic_begin(struct device *dev) | |||
219 | struct vsp1_pipeline *pipe = &vsp1->drm->pipe; | 223 | struct vsp1_pipeline *pipe = &vsp1->drm->pipe; |
220 | 224 | ||
221 | vsp1->drm->num_inputs = pipe->num_inputs; | 225 | vsp1->drm->num_inputs = pipe->num_inputs; |
222 | |||
223 | /* Prepare the display list. */ | ||
224 | pipe->dl = vsp1_dl_list_get(pipe->output->dlm); | ||
225 | } | 226 | } |
226 | EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin); | 227 | EXPORT_SYMBOL_GPL(vsp1_du_atomic_begin); |
227 | 228 | ||
@@ -320,7 +321,8 @@ static int vsp1_du_setup_rpf_pipe(struct vsp1_device *vsp1, | |||
320 | const struct v4l2_rect *crop; | 321 | const struct v4l2_rect *crop; |
321 | int ret; | 322 | int ret; |
322 | 323 | ||
323 | /* Configure the format on the RPF sink pad and propagate it up to the | 324 | /* |
325 | * Configure the format on the RPF sink pad and propagate it up to the | ||
324 | * BRU sink pad. | 326 | * BRU sink pad. |
325 | */ | 327 | */ |
326 | crop = &vsp1->drm->inputs[rpf->entity.index].crop; | 328 | crop = &vsp1->drm->inputs[rpf->entity.index].crop; |
@@ -359,7 +361,8 @@ static int vsp1_du_setup_rpf_pipe(struct vsp1_device *vsp1, | |||
359 | __func__, sel.r.left, sel.r.top, sel.r.width, sel.r.height, | 361 | __func__, sel.r.left, sel.r.top, sel.r.width, sel.r.height, |
360 | rpf->entity.index); | 362 | rpf->entity.index); |
361 | 363 | ||
362 | /* RPF source, hardcode the format to ARGB8888 to turn on format | 364 | /* |
365 | * RPF source, hardcode the format to ARGB8888 to turn on format | ||
363 | * conversion if needed. | 366 | * conversion if needed. |
364 | */ | 367 | */ |
365 | format.pad = RWPF_PAD_SOURCE; | 368 | format.pad = RWPF_PAD_SOURCE; |
@@ -425,10 +428,14 @@ void vsp1_du_atomic_flush(struct device *dev) | |||
425 | struct vsp1_pipeline *pipe = &vsp1->drm->pipe; | 428 | struct vsp1_pipeline *pipe = &vsp1->drm->pipe; |
426 | struct vsp1_rwpf *inputs[VSP1_MAX_RPF] = { NULL, }; | 429 | struct vsp1_rwpf *inputs[VSP1_MAX_RPF] = { NULL, }; |
427 | struct vsp1_entity *entity; | 430 | struct vsp1_entity *entity; |
431 | struct vsp1_dl_list *dl; | ||
428 | unsigned long flags; | 432 | unsigned long flags; |
429 | unsigned int i; | 433 | unsigned int i; |
430 | int ret; | 434 | int ret; |
431 | 435 | ||
436 | /* Prepare the display list. */ | ||
437 | dl = vsp1_dl_list_get(pipe->output->dlm); | ||
438 | |||
432 | /* Count the number of enabled inputs and sort them by Z-order. */ | 439 | /* Count the number of enabled inputs and sort them by Z-order. */ |
433 | pipe->num_inputs = 0; | 440 | pipe->num_inputs = 0; |
434 | 441 | ||
@@ -483,26 +490,25 @@ void vsp1_du_atomic_flush(struct device *dev) | |||
483 | struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev); | 490 | struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev); |
484 | 491 | ||
485 | if (!pipe->inputs[rpf->entity.index]) { | 492 | if (!pipe->inputs[rpf->entity.index]) { |
486 | vsp1_dl_list_write(pipe->dl, entity->route->reg, | 493 | vsp1_dl_list_write(dl, entity->route->reg, |
487 | VI6_DPR_NODE_UNUSED); | 494 | VI6_DPR_NODE_UNUSED); |
488 | continue; | 495 | continue; |
489 | } | 496 | } |
490 | } | 497 | } |
491 | 498 | ||
492 | vsp1_entity_route_setup(entity, pipe->dl); | 499 | vsp1_entity_route_setup(entity, pipe, dl); |
493 | 500 | ||
494 | if (entity->ops->configure) { | 501 | if (entity->ops->configure) { |
495 | entity->ops->configure(entity, pipe, pipe->dl, | 502 | entity->ops->configure(entity, pipe, dl, |
496 | VSP1_ENTITY_PARAMS_INIT); | 503 | VSP1_ENTITY_PARAMS_INIT); |
497 | entity->ops->configure(entity, pipe, pipe->dl, | 504 | entity->ops->configure(entity, pipe, dl, |
498 | VSP1_ENTITY_PARAMS_RUNTIME); | 505 | VSP1_ENTITY_PARAMS_RUNTIME); |
499 | entity->ops->configure(entity, pipe, pipe->dl, | 506 | entity->ops->configure(entity, pipe, dl, |
500 | VSP1_ENTITY_PARAMS_PARTITION); | 507 | VSP1_ENTITY_PARAMS_PARTITION); |
501 | } | 508 | } |
502 | } | 509 | } |
503 | 510 | ||
504 | vsp1_dl_list_commit(pipe->dl); | 511 | vsp1_dl_list_commit(dl); |
505 | pipe->dl = NULL; | ||
506 | 512 | ||
507 | /* Start or stop the pipeline if needed. */ | 513 | /* Start or stop the pipeline if needed. */ |
508 | if (!vsp1->drm->num_inputs && pipe->num_inputs) { | 514 | if (!vsp1->drm->num_inputs && pipe->num_inputs) { |
@@ -528,7 +534,8 @@ int vsp1_drm_create_links(struct vsp1_device *vsp1) | |||
528 | unsigned int i; | 534 | unsigned int i; |
529 | int ret; | 535 | int ret; |
530 | 536 | ||
531 | /* VSPD instances require a BRU to perform composition and a LIF to | 537 | /* |
538 | * VSPD instances require a BRU to perform composition and a LIF to | ||
532 | * output to the DU. | 539 | * output to the DU. |
533 | */ | 540 | */ |
534 | if (!vsp1->bru || !vsp1->lif) | 541 | if (!vsp1->bru || !vsp1->lif) |
@@ -595,6 +602,7 @@ int vsp1_drm_init(struct vsp1_device *vsp1) | |||
595 | pipe->bru = &vsp1->bru->entity; | 602 | pipe->bru = &vsp1->bru->entity; |
596 | pipe->lif = &vsp1->lif->entity; | 603 | pipe->lif = &vsp1->lif->entity; |
597 | pipe->output = vsp1->wpf[0]; | 604 | pipe->output = vsp1->wpf[0]; |
605 | pipe->output->pipe = pipe; | ||
598 | 606 | ||
599 | return 0; | 607 | return 0; |
600 | } | 608 | } |
diff --git a/drivers/media/platform/vsp1/vsp1_drm.h b/drivers/media/platform/vsp1/vsp1_drm.h index 9e28ab9254ba..c8d2f88fc483 100644 --- a/drivers/media/platform/vsp1/vsp1_drm.h +++ b/drivers/media/platform/vsp1/vsp1_drm.h | |||
@@ -21,7 +21,7 @@ | |||
21 | * vsp1_drm - State for the API exposed to the DRM driver | 21 | * vsp1_drm - State for the API exposed to the DRM driver |
22 | * @pipe: the VSP1 pipeline used for display | 22 | * @pipe: the VSP1 pipeline used for display |
23 | * @num_inputs: number of active pipeline inputs at the beginning of an update | 23 | * @num_inputs: number of active pipeline inputs at the beginning of an update |
24 | * @planes: source crop rectangle, destination compose rectangle and z-order | 24 | * @inputs: source crop rectangle, destination compose rectangle and z-order |
25 | * position for every input | 25 | * position for every input |
26 | */ | 26 | */ |
27 | struct vsp1_drm { | 27 | struct vsp1_drm { |
diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index aa237b48ad55..048446af5ae7 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c | |||
@@ -30,6 +30,8 @@ | |||
30 | #include "vsp1_clu.h" | 30 | #include "vsp1_clu.h" |
31 | #include "vsp1_dl.h" | 31 | #include "vsp1_dl.h" |
32 | #include "vsp1_drm.h" | 32 | #include "vsp1_drm.h" |
33 | #include "vsp1_hgo.h" | ||
34 | #include "vsp1_hgt.h" | ||
33 | #include "vsp1_hsit.h" | 35 | #include "vsp1_hsit.h" |
34 | #include "vsp1_lif.h" | 36 | #include "vsp1_lif.h" |
35 | #include "vsp1_lut.h" | 37 | #include "vsp1_lut.h" |
@@ -105,7 +107,9 @@ static int vsp1_create_sink_links(struct vsp1_device *vsp1, | |||
105 | if (source->type == sink->type) | 107 | if (source->type == sink->type) |
106 | continue; | 108 | continue; |
107 | 109 | ||
108 | if (source->type == VSP1_ENTITY_LIF || | 110 | if (source->type == VSP1_ENTITY_HGO || |
111 | source->type == VSP1_ENTITY_HGT || | ||
112 | source->type == VSP1_ENTITY_LIF || | ||
109 | source->type == VSP1_ENTITY_WPF) | 113 | source->type == VSP1_ENTITY_WPF) |
110 | continue; | 114 | continue; |
111 | 115 | ||
@@ -148,6 +152,26 @@ static int vsp1_uapi_create_links(struct vsp1_device *vsp1) | |||
148 | return ret; | 152 | return ret; |
149 | } | 153 | } |
150 | 154 | ||
155 | if (vsp1->hgo) { | ||
156 | ret = media_create_pad_link(&vsp1->hgo->histo.entity.subdev.entity, | ||
157 | HISTO_PAD_SOURCE, | ||
158 | &vsp1->hgo->histo.video.entity, 0, | ||
159 | MEDIA_LNK_FL_ENABLED | | ||
160 | MEDIA_LNK_FL_IMMUTABLE); | ||
161 | if (ret < 0) | ||
162 | return ret; | ||
163 | } | ||
164 | |||
165 | if (vsp1->hgt) { | ||
166 | ret = media_create_pad_link(&vsp1->hgt->histo.entity.subdev.entity, | ||
167 | HISTO_PAD_SOURCE, | ||
168 | &vsp1->hgt->histo.video.entity, 0, | ||
169 | MEDIA_LNK_FL_ENABLED | | ||
170 | MEDIA_LNK_FL_IMMUTABLE); | ||
171 | if (ret < 0) | ||
172 | return ret; | ||
173 | } | ||
174 | |||
151 | if (vsp1->lif) { | 175 | if (vsp1->lif) { |
152 | ret = media_create_pad_link(&vsp1->wpf[0]->entity.subdev.entity, | 176 | ret = media_create_pad_link(&vsp1->wpf[0]->entity.subdev.entity, |
153 | RWPF_PAD_SOURCE, | 177 | RWPF_PAD_SOURCE, |
@@ -170,7 +194,8 @@ static int vsp1_uapi_create_links(struct vsp1_device *vsp1) | |||
170 | } | 194 | } |
171 | 195 | ||
172 | for (i = 0; i < vsp1->info->wpf_count; ++i) { | 196 | for (i = 0; i < vsp1->info->wpf_count; ++i) { |
173 | /* Connect the video device to the WPF. All connections are | 197 | /* |
198 | * Connect the video device to the WPF. All connections are | ||
174 | * immutable. | 199 | * immutable. |
175 | */ | 200 | */ |
176 | struct vsp1_rwpf *wpf = vsp1->wpf[i]; | 201 | struct vsp1_rwpf *wpf = vsp1->wpf[i]; |
@@ -227,7 +252,8 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) | |||
227 | media_device_init(mdev); | 252 | media_device_init(mdev); |
228 | 253 | ||
229 | vsp1->media_ops.link_setup = vsp1_entity_link_setup; | 254 | vsp1->media_ops.link_setup = vsp1_entity_link_setup; |
230 | /* Don't perform link validation when the userspace API is disabled as | 255 | /* |
256 | * Don't perform link validation when the userspace API is disabled as | ||
231 | * the pipeline is configured internally by the driver in that case, and | 257 | * the pipeline is configured internally by the driver in that case, and |
232 | * its configuration can thus be trusted. | 258 | * its configuration can thus be trusted. |
233 | */ | 259 | */ |
@@ -279,7 +305,30 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) | |||
279 | 305 | ||
280 | list_add_tail(&vsp1->hst->entity.list_dev, &vsp1->entities); | 306 | list_add_tail(&vsp1->hst->entity.list_dev, &vsp1->entities); |
281 | 307 | ||
282 | /* The LIF is only supported when used in conjunction with the DU, in | 308 | if (vsp1->info->features & VSP1_HAS_HGO && vsp1->info->uapi) { |
309 | vsp1->hgo = vsp1_hgo_create(vsp1); | ||
310 | if (IS_ERR(vsp1->hgo)) { | ||
311 | ret = PTR_ERR(vsp1->hgo); | ||
312 | goto done; | ||
313 | } | ||
314 | |||
315 | list_add_tail(&vsp1->hgo->histo.entity.list_dev, | ||
316 | &vsp1->entities); | ||
317 | } | ||
318 | |||
319 | if (vsp1->info->features & VSP1_HAS_HGT && vsp1->info->uapi) { | ||
320 | vsp1->hgt = vsp1_hgt_create(vsp1); | ||
321 | if (IS_ERR(vsp1->hgt)) { | ||
322 | ret = PTR_ERR(vsp1->hgt); | ||
323 | goto done; | ||
324 | } | ||
325 | |||
326 | list_add_tail(&vsp1->hgt->histo.entity.list_dev, | ||
327 | &vsp1->entities); | ||
328 | } | ||
329 | |||
330 | /* | ||
331 | * The LIF is only supported when used in conjunction with the DU, in | ||
283 | * which case the userspace API is disabled. If the userspace API is | 332 | * which case the userspace API is disabled. If the userspace API is |
284 | * enabled skip the LIF, even when present. | 333 | * enabled skip the LIF, even when present. |
285 | */ | 334 | */ |
@@ -391,7 +440,8 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) | |||
391 | if (ret < 0) | 440 | if (ret < 0) |
392 | goto done; | 441 | goto done; |
393 | 442 | ||
394 | /* Register subdev nodes if the userspace API is enabled or initialize | 443 | /* |
444 | * Register subdev nodes if the userspace API is enabled or initialize | ||
395 | * the DRM pipeline otherwise. | 445 | * the DRM pipeline otherwise. |
396 | */ | 446 | */ |
397 | if (vsp1->info->uapi) { | 447 | if (vsp1->info->uapi) { |
@@ -562,8 +612,9 @@ static const struct vsp1_device_info vsp1_device_infos[] = { | |||
562 | .version = VI6_IP_VERSION_MODEL_VSPS_H2, | 612 | .version = VI6_IP_VERSION_MODEL_VSPS_H2, |
563 | .model = "VSP1-S", | 613 | .model = "VSP1-S", |
564 | .gen = 2, | 614 | .gen = 2, |
565 | .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT | 615 | .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_HGO |
566 | | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP, | 616 | | VSP1_HAS_HGT | VSP1_HAS_LUT | VSP1_HAS_SRU |
617 | | VSP1_HAS_WPF_VFLIP, | ||
567 | .rpf_count = 5, | 618 | .rpf_count = 5, |
568 | .uds_count = 3, | 619 | .uds_count = 3, |
569 | .wpf_count = 4, | 620 | .wpf_count = 4, |
@@ -583,7 +634,8 @@ static const struct vsp1_device_info vsp1_device_infos[] = { | |||
583 | .version = VI6_IP_VERSION_MODEL_VSPD_GEN2, | 634 | .version = VI6_IP_VERSION_MODEL_VSPD_GEN2, |
584 | .model = "VSP1-D", | 635 | .model = "VSP1-D", |
585 | .gen = 2, | 636 | .gen = 2, |
586 | .features = VSP1_HAS_BRU | VSP1_HAS_LIF | VSP1_HAS_LUT, | 637 | .features = VSP1_HAS_BRU | VSP1_HAS_HGO | VSP1_HAS_LIF |
638 | | VSP1_HAS_LUT, | ||
587 | .rpf_count = 4, | 639 | .rpf_count = 4, |
588 | .uds_count = 1, | 640 | .uds_count = 1, |
589 | .wpf_count = 1, | 641 | .wpf_count = 1, |
@@ -593,8 +645,9 @@ static const struct vsp1_device_info vsp1_device_infos[] = { | |||
593 | .version = VI6_IP_VERSION_MODEL_VSPS_M2, | 645 | .version = VI6_IP_VERSION_MODEL_VSPS_M2, |
594 | .model = "VSP1-S", | 646 | .model = "VSP1-S", |
595 | .gen = 2, | 647 | .gen = 2, |
596 | .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT | 648 | .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_HGO |
597 | | VSP1_HAS_SRU | VSP1_HAS_WPF_VFLIP, | 649 | | VSP1_HAS_HGT | VSP1_HAS_LUT | VSP1_HAS_SRU |
650 | | VSP1_HAS_WPF_VFLIP, | ||
598 | .rpf_count = 5, | 651 | .rpf_count = 5, |
599 | .uds_count = 1, | 652 | .uds_count = 1, |
600 | .wpf_count = 4, | 653 | .wpf_count = 4, |
@@ -626,8 +679,9 @@ static const struct vsp1_device_info vsp1_device_infos[] = { | |||
626 | .version = VI6_IP_VERSION_MODEL_VSPI_GEN3, | 679 | .version = VI6_IP_VERSION_MODEL_VSPI_GEN3, |
627 | .model = "VSP2-I", | 680 | .model = "VSP2-I", |
628 | .gen = 3, | 681 | .gen = 3, |
629 | .features = VSP1_HAS_CLU | VSP1_HAS_LUT | VSP1_HAS_SRU | 682 | .features = VSP1_HAS_CLU | VSP1_HAS_HGO | VSP1_HAS_HGT |
630 | | VSP1_HAS_WPF_HFLIP | VSP1_HAS_WPF_VFLIP, | 683 | | VSP1_HAS_LUT | VSP1_HAS_SRU | VSP1_HAS_WPF_HFLIP |
684 | | VSP1_HAS_WPF_VFLIP, | ||
631 | .rpf_count = 1, | 685 | .rpf_count = 1, |
632 | .uds_count = 1, | 686 | .uds_count = 1, |
633 | .wpf_count = 1, | 687 | .wpf_count = 1, |
@@ -645,8 +699,8 @@ static const struct vsp1_device_info vsp1_device_infos[] = { | |||
645 | .version = VI6_IP_VERSION_MODEL_VSPBC_GEN3, | 699 | .version = VI6_IP_VERSION_MODEL_VSPBC_GEN3, |
646 | .model = "VSP2-BC", | 700 | .model = "VSP2-BC", |
647 | .gen = 3, | 701 | .gen = 3, |
648 | .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_LUT | 702 | .features = VSP1_HAS_BRU | VSP1_HAS_CLU | VSP1_HAS_HGO |
649 | | VSP1_HAS_WPF_VFLIP, | 703 | | VSP1_HAS_LUT | VSP1_HAS_WPF_VFLIP, |
650 | .rpf_count = 5, | 704 | .rpf_count = 5, |
651 | .wpf_count = 1, | 705 | .wpf_count = 1, |
652 | .num_bru_inputs = 5, | 706 | .num_bru_inputs = 5, |
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c index da673495c222..4bdb3b141611 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.c +++ b/drivers/media/platform/vsp1/vsp1_entity.c | |||
@@ -21,6 +21,8 @@ | |||
21 | #include "vsp1.h" | 21 | #include "vsp1.h" |
22 | #include "vsp1_dl.h" | 22 | #include "vsp1_dl.h" |
23 | #include "vsp1_entity.h" | 23 | #include "vsp1_entity.h" |
24 | #include "vsp1_pipe.h" | ||
25 | #include "vsp1_rwpf.h" | ||
24 | 26 | ||
25 | static inline struct vsp1_entity * | 27 | static inline struct vsp1_entity * |
26 | media_entity_to_vsp1_entity(struct media_entity *entity) | 28 | media_entity_to_vsp1_entity(struct media_entity *entity) |
@@ -28,11 +30,42 @@ media_entity_to_vsp1_entity(struct media_entity *entity) | |||
28 | return container_of(entity, struct vsp1_entity, subdev.entity); | 30 | return container_of(entity, struct vsp1_entity, subdev.entity); |
29 | } | 31 | } |
30 | 32 | ||
31 | void vsp1_entity_route_setup(struct vsp1_entity *source, | 33 | void vsp1_entity_route_setup(struct vsp1_entity *entity, |
34 | struct vsp1_pipeline *pipe, | ||
32 | struct vsp1_dl_list *dl) | 35 | struct vsp1_dl_list *dl) |
33 | { | 36 | { |
37 | struct vsp1_entity *source; | ||
34 | struct vsp1_entity *sink; | 38 | struct vsp1_entity *sink; |
35 | 39 | ||
40 | if (entity->type == VSP1_ENTITY_HGO) { | ||
41 | u32 smppt; | ||
42 | |||
43 | /* | ||
44 | * The HGO is a special case, its routing is configured on the | ||
45 | * sink pad. | ||
46 | */ | ||
47 | source = media_entity_to_vsp1_entity(entity->sources[0]); | ||
48 | smppt = (pipe->output->entity.index << VI6_DPR_SMPPT_TGW_SHIFT) | ||
49 | | (source->route->output << VI6_DPR_SMPPT_PT_SHIFT); | ||
50 | |||
51 | vsp1_dl_list_write(dl, VI6_DPR_HGO_SMPPT, smppt); | ||
52 | return; | ||
53 | } else if (entity->type == VSP1_ENTITY_HGT) { | ||
54 | u32 smppt; | ||
55 | |||
56 | /* | ||
57 | * The HGT is a special case, its routing is configured on the | ||
58 | * sink pad. | ||
59 | */ | ||
60 | source = media_entity_to_vsp1_entity(entity->sources[0]); | ||
61 | smppt = (pipe->output->entity.index << VI6_DPR_SMPPT_TGW_SHIFT) | ||
62 | | (source->route->output << VI6_DPR_SMPPT_PT_SHIFT); | ||
63 | |||
64 | vsp1_dl_list_write(dl, VI6_DPR_HGT_SMPPT, smppt); | ||
65 | return; | ||
66 | } | ||
67 | |||
68 | source = entity; | ||
36 | if (source->route->reg == 0) | 69 | if (source->route->reg == 0) |
37 | return; | 70 | return; |
38 | 71 | ||
@@ -199,7 +232,8 @@ int vsp1_subdev_enum_mbus_code(struct v4l2_subdev *subdev, | |||
199 | struct v4l2_subdev_pad_config *config; | 232 | struct v4l2_subdev_pad_config *config; |
200 | struct v4l2_mbus_framefmt *format; | 233 | struct v4l2_mbus_framefmt *format; |
201 | 234 | ||
202 | /* The entity can't perform format conversion, the sink format | 235 | /* |
236 | * The entity can't perform format conversion, the sink format | ||
203 | * is always identical to the source format. | 237 | * is always identical to the source format. |
204 | */ | 238 | */ |
205 | if (code->index) | 239 | if (code->index) |
@@ -263,7 +297,8 @@ int vsp1_subdev_enum_frame_size(struct v4l2_subdev *subdev, | |||
263 | fse->min_height = min_height; | 297 | fse->min_height = min_height; |
264 | fse->max_height = max_height; | 298 | fse->max_height = max_height; |
265 | } else { | 299 | } else { |
266 | /* The size on the source pad are fixed and always identical to | 300 | /* |
301 | * The size on the source pad are fixed and always identical to | ||
267 | * the size on the sink pad. | 302 | * the size on the sink pad. |
268 | */ | 303 | */ |
269 | fse->min_width = format->width; | 304 | fse->min_width = format->width; |
@@ -281,25 +316,32 @@ done: | |||
281 | * Media Operations | 316 | * Media Operations |
282 | */ | 317 | */ |
283 | 318 | ||
284 | int vsp1_entity_link_setup(struct media_entity *entity, | 319 | static int vsp1_entity_link_setup_source(const struct media_pad *source_pad, |
285 | const struct media_pad *local, | 320 | const struct media_pad *sink_pad, |
286 | const struct media_pad *remote, u32 flags) | 321 | u32 flags) |
287 | { | 322 | { |
288 | struct vsp1_entity *source; | 323 | struct vsp1_entity *source; |
289 | 324 | ||
290 | if (!(local->flags & MEDIA_PAD_FL_SOURCE)) | 325 | source = media_entity_to_vsp1_entity(source_pad->entity); |
291 | return 0; | ||
292 | |||
293 | source = media_entity_to_vsp1_entity(local->entity); | ||
294 | 326 | ||
295 | if (!source->route) | 327 | if (!source->route) |
296 | return 0; | 328 | return 0; |
297 | 329 | ||
298 | if (flags & MEDIA_LNK_FL_ENABLED) { | 330 | if (flags & MEDIA_LNK_FL_ENABLED) { |
299 | if (source->sink) | 331 | struct vsp1_entity *sink |
300 | return -EBUSY; | 332 | = media_entity_to_vsp1_entity(sink_pad->entity); |
301 | source->sink = remote->entity; | 333 | |
302 | source->sink_pad = remote->index; | 334 | /* |
335 | * Fan-out is limited to one for the normal data path plus | ||
336 | * optional HGO and HGT. We ignore the HGO and HGT here. | ||
337 | */ | ||
338 | if (sink->type != VSP1_ENTITY_HGO && | ||
339 | sink->type != VSP1_ENTITY_HGT) { | ||
340 | if (source->sink) | ||
341 | return -EBUSY; | ||
342 | source->sink = sink_pad->entity; | ||
343 | source->sink_pad = sink_pad->index; | ||
344 | } | ||
303 | } else { | 345 | } else { |
304 | source->sink = NULL; | 346 | source->sink = NULL; |
305 | source->sink_pad = 0; | 347 | source->sink_pad = 0; |
@@ -308,6 +350,85 @@ int vsp1_entity_link_setup(struct media_entity *entity, | |||
308 | return 0; | 350 | return 0; |
309 | } | 351 | } |
310 | 352 | ||
353 | static int vsp1_entity_link_setup_sink(const struct media_pad *source_pad, | ||
354 | const struct media_pad *sink_pad, | ||
355 | u32 flags) | ||
356 | { | ||
357 | struct vsp1_entity *sink; | ||
358 | |||
359 | sink = media_entity_to_vsp1_entity(sink_pad->entity); | ||
360 | |||
361 | if (flags & MEDIA_LNK_FL_ENABLED) { | ||
362 | /* Fan-in is limited to one. */ | ||
363 | if (sink->sources[sink_pad->index]) | ||
364 | return -EBUSY; | ||
365 | |||
366 | sink->sources[sink_pad->index] = source_pad->entity; | ||
367 | } else { | ||
368 | sink->sources[sink_pad->index] = NULL; | ||
369 | } | ||
370 | |||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | int vsp1_entity_link_setup(struct media_entity *entity, | ||
375 | const struct media_pad *local, | ||
376 | const struct media_pad *remote, u32 flags) | ||
377 | { | ||
378 | if (local->flags & MEDIA_PAD_FL_SOURCE) | ||
379 | return vsp1_entity_link_setup_source(local, remote, flags); | ||
380 | else | ||
381 | return vsp1_entity_link_setup_sink(remote, local, flags); | ||
382 | } | ||
383 | |||
384 | /** | ||
385 | * vsp1_entity_remote_pad - Find the pad at the remote end of a link | ||
386 | * @pad: Pad at the local end of the link | ||
387 | * | ||
388 | * Search for a remote pad connected to the given pad by iterating over all | ||
389 | * links originating or terminating at that pad until an enabled link is found. | ||
390 | * | ||
391 | * Our link setup implementation guarantees that the output fan-out will not be | ||
392 | * higher than one for the data pipelines, except for the links to the HGO and | ||
393 | * HGT that can be enabled in addition to a regular data link. When traversing | ||
394 | * outgoing links this function ignores HGO and HGT entities and should thus be | ||
395 | * used in place of the generic media_entity_remote_pad() function to traverse | ||
396 | * data pipelines. | ||
397 | * | ||
398 | * Return a pointer to the pad at the remote end of the first found enabled | ||
399 | * link, or NULL if no enabled link has been found. | ||
400 | */ | ||
401 | struct media_pad *vsp1_entity_remote_pad(struct media_pad *pad) | ||
402 | { | ||
403 | struct media_link *link; | ||
404 | |||
405 | list_for_each_entry(link, &pad->entity->links, list) { | ||
406 | struct vsp1_entity *entity; | ||
407 | |||
408 | if (!(link->flags & MEDIA_LNK_FL_ENABLED)) | ||
409 | continue; | ||
410 | |||
411 | /* If we're the sink the source will never be an HGO or HGT. */ | ||
412 | if (link->sink == pad) | ||
413 | return link->source; | ||
414 | |||
415 | if (link->source != pad) | ||
416 | continue; | ||
417 | |||
418 | /* If the sink isn't a subdevice it can't be an HGO or HGT. */ | ||
419 | if (!is_media_entity_v4l2_subdev(link->sink->entity)) | ||
420 | return link->sink; | ||
421 | |||
422 | entity = media_entity_to_vsp1_entity(link->sink->entity); | ||
423 | if (entity->type != VSP1_ENTITY_HGO && | ||
424 | entity->type != VSP1_ENTITY_HGT) | ||
425 | return link->sink; | ||
426 | } | ||
427 | |||
428 | return NULL; | ||
429 | |||
430 | } | ||
431 | |||
311 | /* ----------------------------------------------------------------------------- | 432 | /* ----------------------------------------------------------------------------- |
312 | * Initialization | 433 | * Initialization |
313 | */ | 434 | */ |
@@ -334,6 +455,8 @@ static const struct vsp1_route vsp1_routes[] = { | |||
334 | VI6_DPR_NODE_BRU_IN(2), VI6_DPR_NODE_BRU_IN(3), | 455 | VI6_DPR_NODE_BRU_IN(2), VI6_DPR_NODE_BRU_IN(3), |
335 | VI6_DPR_NODE_BRU_IN(4) }, VI6_DPR_NODE_BRU_OUT }, | 456 | VI6_DPR_NODE_BRU_IN(4) }, VI6_DPR_NODE_BRU_OUT }, |
336 | VSP1_ENTITY_ROUTE(CLU), | 457 | VSP1_ENTITY_ROUTE(CLU), |
458 | { VSP1_ENTITY_HGO, 0, 0, { 0, }, 0 }, | ||
459 | { VSP1_ENTITY_HGT, 0, 0, { 0, }, 0 }, | ||
337 | VSP1_ENTITY_ROUTE(HSI), | 460 | VSP1_ENTITY_ROUTE(HSI), |
338 | VSP1_ENTITY_ROUTE(HST), | 461 | VSP1_ENTITY_ROUTE(HST), |
339 | { VSP1_ENTITY_LIF, 0, 0, { VI6_DPR_NODE_LIF, }, VI6_DPR_NODE_LIF }, | 462 | { VSP1_ENTITY_LIF, 0, 0, { VI6_DPR_NODE_LIF, }, VI6_DPR_NODE_LIF }, |
@@ -386,7 +509,14 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, | |||
386 | for (i = 0; i < num_pads - 1; ++i) | 509 | for (i = 0; i < num_pads - 1; ++i) |
387 | entity->pads[i].flags = MEDIA_PAD_FL_SINK; | 510 | entity->pads[i].flags = MEDIA_PAD_FL_SINK; |
388 | 511 | ||
389 | entity->pads[num_pads - 1].flags = MEDIA_PAD_FL_SOURCE; | 512 | entity->sources = devm_kcalloc(vsp1->dev, max(num_pads - 1, 1U), |
513 | sizeof(*entity->sources), GFP_KERNEL); | ||
514 | if (entity->sources == NULL) | ||
515 | return -ENOMEM; | ||
516 | |||
517 | /* Single-pad entities only have a sink. */ | ||
518 | entity->pads[num_pads - 1].flags = num_pads > 1 ? MEDIA_PAD_FL_SOURCE | ||
519 | : MEDIA_PAD_FL_SINK; | ||
390 | 520 | ||
391 | /* Initialize the media entity. */ | 521 | /* Initialize the media entity. */ |
392 | ret = media_entity_pads_init(&entity->subdev.entity, num_pads, | 522 | ret = media_entity_pads_init(&entity->subdev.entity, num_pads, |
@@ -407,7 +537,8 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, | |||
407 | 537 | ||
408 | vsp1_entity_init_cfg(subdev, NULL); | 538 | vsp1_entity_init_cfg(subdev, NULL); |
409 | 539 | ||
410 | /* Allocate the pad configuration to store formats and selection | 540 | /* |
541 | * Allocate the pad configuration to store formats and selection | ||
411 | * rectangles. | 542 | * rectangles. |
412 | */ | 543 | */ |
413 | entity->config = v4l2_subdev_alloc_pad_config(&entity->subdev); | 544 | entity->config = v4l2_subdev_alloc_pad_config(&entity->subdev); |
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h index 901146f807b9..c169a060b6d2 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.h +++ b/drivers/media/platform/vsp1/vsp1_entity.h | |||
@@ -25,6 +25,8 @@ struct vsp1_pipeline; | |||
25 | enum vsp1_entity_type { | 25 | enum vsp1_entity_type { |
26 | VSP1_ENTITY_BRU, | 26 | VSP1_ENTITY_BRU, |
27 | VSP1_ENTITY_CLU, | 27 | VSP1_ENTITY_CLU, |
28 | VSP1_ENTITY_HGO, | ||
29 | VSP1_ENTITY_HGT, | ||
28 | VSP1_ENTITY_HSI, | 30 | VSP1_ENTITY_HSI, |
29 | VSP1_ENTITY_HST, | 31 | VSP1_ENTITY_HST, |
30 | VSP1_ENTITY_LIF, | 32 | VSP1_ENTITY_LIF, |
@@ -102,6 +104,7 @@ struct vsp1_entity { | |||
102 | struct media_pad *pads; | 104 | struct media_pad *pads; |
103 | unsigned int source_pad; | 105 | unsigned int source_pad; |
104 | 106 | ||
107 | struct media_entity **sources; | ||
105 | struct media_entity *sink; | 108 | struct media_entity *sink; |
106 | unsigned int sink_pad; | 109 | unsigned int sink_pad; |
107 | 110 | ||
@@ -142,9 +145,12 @@ vsp1_entity_get_pad_selection(struct vsp1_entity *entity, | |||
142 | int vsp1_entity_init_cfg(struct v4l2_subdev *subdev, | 145 | int vsp1_entity_init_cfg(struct v4l2_subdev *subdev, |
143 | struct v4l2_subdev_pad_config *cfg); | 146 | struct v4l2_subdev_pad_config *cfg); |
144 | 147 | ||
145 | void vsp1_entity_route_setup(struct vsp1_entity *source, | 148 | void vsp1_entity_route_setup(struct vsp1_entity *entity, |
149 | struct vsp1_pipeline *pipe, | ||
146 | struct vsp1_dl_list *dl); | 150 | struct vsp1_dl_list *dl); |
147 | 151 | ||
152 | struct media_pad *vsp1_entity_remote_pad(struct media_pad *pad); | ||
153 | |||
148 | int vsp1_subdev_get_pad_format(struct v4l2_subdev *subdev, | 154 | int vsp1_subdev_get_pad_format(struct v4l2_subdev *subdev, |
149 | struct v4l2_subdev_pad_config *cfg, | 155 | struct v4l2_subdev_pad_config *cfg, |
150 | struct v4l2_subdev_format *fmt); | 156 | struct v4l2_subdev_format *fmt); |
diff --git a/drivers/media/platform/vsp1/vsp1_hgo.c b/drivers/media/platform/vsp1/vsp1_hgo.c new file mode 100644 index 000000000000..50309c053b78 --- /dev/null +++ b/drivers/media/platform/vsp1/vsp1_hgo.c | |||
@@ -0,0 +1,230 @@ | |||
1 | /* | ||
2 | * vsp1_hgo.c -- R-Car VSP1 Histogram Generator 1D | ||
3 | * | ||
4 | * Copyright (C) 2016 Renesas Electronics Corporation | ||
5 | * | ||
6 | * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/device.h> | ||
15 | #include <linux/gfp.h> | ||
16 | |||
17 | #include <media/v4l2-subdev.h> | ||
18 | #include <media/videobuf2-vmalloc.h> | ||
19 | |||
20 | #include "vsp1.h" | ||
21 | #include "vsp1_dl.h" | ||
22 | #include "vsp1_hgo.h" | ||
23 | |||
24 | #define HGO_DATA_SIZE ((2 + 256) * 4) | ||
25 | |||
26 | /* ----------------------------------------------------------------------------- | ||
27 | * Device Access | ||
28 | */ | ||
29 | |||
30 | static inline u32 vsp1_hgo_read(struct vsp1_hgo *hgo, u32 reg) | ||
31 | { | ||
32 | return vsp1_read(hgo->histo.entity.vsp1, reg); | ||
33 | } | ||
34 | |||
35 | static inline void vsp1_hgo_write(struct vsp1_hgo *hgo, struct vsp1_dl_list *dl, | ||
36 | u32 reg, u32 data) | ||
37 | { | ||
38 | vsp1_dl_list_write(dl, reg, data); | ||
39 | } | ||
40 | |||
41 | /* ----------------------------------------------------------------------------- | ||
42 | * Frame End Handler | ||
43 | */ | ||
44 | |||
45 | void vsp1_hgo_frame_end(struct vsp1_entity *entity) | ||
46 | { | ||
47 | struct vsp1_hgo *hgo = to_hgo(&entity->subdev); | ||
48 | struct vsp1_histogram_buffer *buf; | ||
49 | unsigned int i; | ||
50 | size_t size; | ||
51 | u32 *data; | ||
52 | |||
53 | buf = vsp1_histogram_buffer_get(&hgo->histo); | ||
54 | if (!buf) | ||
55 | return; | ||
56 | |||
57 | data = buf->addr; | ||
58 | |||
59 | if (hgo->num_bins == 256) { | ||
60 | *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_MAXMIN); | ||
61 | *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_SUM); | ||
62 | |||
63 | for (i = 0; i < 256; ++i) { | ||
64 | vsp1_write(hgo->histo.entity.vsp1, | ||
65 | VI6_HGO_EXT_HIST_ADDR, i); | ||
66 | *data++ = vsp1_hgo_read(hgo, VI6_HGO_EXT_HIST_DATA); | ||
67 | } | ||
68 | |||
69 | size = (2 + 256) * sizeof(u32); | ||
70 | } else if (hgo->max_rgb) { | ||
71 | *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_MAXMIN); | ||
72 | *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_SUM); | ||
73 | |||
74 | for (i = 0; i < 64; ++i) | ||
75 | *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_HISTO(i)); | ||
76 | |||
77 | size = (2 + 64) * sizeof(u32); | ||
78 | } else { | ||
79 | *data++ = vsp1_hgo_read(hgo, VI6_HGO_R_MAXMIN); | ||
80 | *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_MAXMIN); | ||
81 | *data++ = vsp1_hgo_read(hgo, VI6_HGO_B_MAXMIN); | ||
82 | |||
83 | *data++ = vsp1_hgo_read(hgo, VI6_HGO_R_SUM); | ||
84 | *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_SUM); | ||
85 | *data++ = vsp1_hgo_read(hgo, VI6_HGO_B_SUM); | ||
86 | |||
87 | for (i = 0; i < 64; ++i) { | ||
88 | data[i] = vsp1_hgo_read(hgo, VI6_HGO_R_HISTO(i)); | ||
89 | data[i+64] = vsp1_hgo_read(hgo, VI6_HGO_G_HISTO(i)); | ||
90 | data[i+128] = vsp1_hgo_read(hgo, VI6_HGO_B_HISTO(i)); | ||
91 | } | ||
92 | |||
93 | size = (6 + 64 * 3) * sizeof(u32); | ||
94 | } | ||
95 | |||
96 | vsp1_histogram_buffer_complete(&hgo->histo, buf, size); | ||
97 | } | ||
98 | |||
99 | /* ----------------------------------------------------------------------------- | ||
100 | * Controls | ||
101 | */ | ||
102 | |||
103 | #define V4L2_CID_VSP1_HGO_MAX_RGB (V4L2_CID_USER_BASE | 0x1001) | ||
104 | #define V4L2_CID_VSP1_HGO_NUM_BINS (V4L2_CID_USER_BASE | 0x1002) | ||
105 | |||
106 | static const struct v4l2_ctrl_config hgo_max_rgb_control = { | ||
107 | .id = V4L2_CID_VSP1_HGO_MAX_RGB, | ||
108 | .name = "Maximum RGB Mode", | ||
109 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
110 | .min = 0, | ||
111 | .max = 1, | ||
112 | .def = 0, | ||
113 | .step = 1, | ||
114 | .flags = V4L2_CTRL_FLAG_MODIFY_LAYOUT, | ||
115 | }; | ||
116 | |||
117 | static const s64 hgo_num_bins[] = { | ||
118 | 64, 256, | ||
119 | }; | ||
120 | |||
121 | static const struct v4l2_ctrl_config hgo_num_bins_control = { | ||
122 | .id = V4L2_CID_VSP1_HGO_NUM_BINS, | ||
123 | .name = "Number of Bins", | ||
124 | .type = V4L2_CTRL_TYPE_INTEGER_MENU, | ||
125 | .min = 0, | ||
126 | .max = 1, | ||
127 | .def = 0, | ||
128 | .qmenu_int = hgo_num_bins, | ||
129 | .flags = V4L2_CTRL_FLAG_MODIFY_LAYOUT, | ||
130 | }; | ||
131 | |||
132 | /* ----------------------------------------------------------------------------- | ||
133 | * VSP1 Entity Operations | ||
134 | */ | ||
135 | |||
136 | static void hgo_configure(struct vsp1_entity *entity, | ||
137 | struct vsp1_pipeline *pipe, | ||
138 | struct vsp1_dl_list *dl, | ||
139 | enum vsp1_entity_params params) | ||
140 | { | ||
141 | struct vsp1_hgo *hgo = to_hgo(&entity->subdev); | ||
142 | struct v4l2_rect *compose; | ||
143 | struct v4l2_rect *crop; | ||
144 | unsigned int hratio; | ||
145 | unsigned int vratio; | ||
146 | |||
147 | if (params != VSP1_ENTITY_PARAMS_INIT) | ||
148 | return; | ||
149 | |||
150 | crop = vsp1_entity_get_pad_selection(entity, entity->config, | ||
151 | HISTO_PAD_SINK, V4L2_SEL_TGT_CROP); | ||
152 | compose = vsp1_entity_get_pad_selection(entity, entity->config, | ||
153 | HISTO_PAD_SINK, | ||
154 | V4L2_SEL_TGT_COMPOSE); | ||
155 | |||
156 | vsp1_hgo_write(hgo, dl, VI6_HGO_REGRST, VI6_HGO_REGRST_RCLEA); | ||
157 | |||
158 | vsp1_hgo_write(hgo, dl, VI6_HGO_OFFSET, | ||
159 | (crop->left << VI6_HGO_OFFSET_HOFFSET_SHIFT) | | ||
160 | (crop->top << VI6_HGO_OFFSET_VOFFSET_SHIFT)); | ||
161 | vsp1_hgo_write(hgo, dl, VI6_HGO_SIZE, | ||
162 | (crop->width << VI6_HGO_SIZE_HSIZE_SHIFT) | | ||
163 | (crop->height << VI6_HGO_SIZE_VSIZE_SHIFT)); | ||
164 | |||
165 | mutex_lock(hgo->ctrls.handler.lock); | ||
166 | hgo->max_rgb = hgo->ctrls.max_rgb->cur.val; | ||
167 | if (hgo->ctrls.num_bins) | ||
168 | hgo->num_bins = hgo_num_bins[hgo->ctrls.num_bins->cur.val]; | ||
169 | mutex_unlock(hgo->ctrls.handler.lock); | ||
170 | |||
171 | hratio = crop->width * 2 / compose->width / 3; | ||
172 | vratio = crop->height * 2 / compose->height / 3; | ||
173 | vsp1_hgo_write(hgo, dl, VI6_HGO_MODE, | ||
174 | (hgo->num_bins == 256 ? VI6_HGO_MODE_STEP : 0) | | ||
175 | (hgo->max_rgb ? VI6_HGO_MODE_MAXRGB : 0) | | ||
176 | (hratio << VI6_HGO_MODE_HRATIO_SHIFT) | | ||
177 | (vratio << VI6_HGO_MODE_VRATIO_SHIFT)); | ||
178 | } | ||
179 | |||
180 | static const struct vsp1_entity_operations hgo_entity_ops = { | ||
181 | .configure = hgo_configure, | ||
182 | .destroy = vsp1_histogram_destroy, | ||
183 | }; | ||
184 | |||
185 | /* ----------------------------------------------------------------------------- | ||
186 | * Initialization and Cleanup | ||
187 | */ | ||
188 | |||
189 | static const unsigned int hgo_mbus_formats[] = { | ||
190 | MEDIA_BUS_FMT_AYUV8_1X32, | ||
191 | MEDIA_BUS_FMT_ARGB8888_1X32, | ||
192 | MEDIA_BUS_FMT_AHSV8888_1X32, | ||
193 | }; | ||
194 | |||
195 | struct vsp1_hgo *vsp1_hgo_create(struct vsp1_device *vsp1) | ||
196 | { | ||
197 | struct vsp1_hgo *hgo; | ||
198 | int ret; | ||
199 | |||
200 | hgo = devm_kzalloc(vsp1->dev, sizeof(*hgo), GFP_KERNEL); | ||
201 | if (hgo == NULL) | ||
202 | return ERR_PTR(-ENOMEM); | ||
203 | |||
204 | /* Initialize the control handler. */ | ||
205 | v4l2_ctrl_handler_init(&hgo->ctrls.handler, | ||
206 | vsp1->info->gen == 3 ? 2 : 1); | ||
207 | hgo->ctrls.max_rgb = v4l2_ctrl_new_custom(&hgo->ctrls.handler, | ||
208 | &hgo_max_rgb_control, NULL); | ||
209 | if (vsp1->info->gen == 3) | ||
210 | hgo->ctrls.num_bins = | ||
211 | v4l2_ctrl_new_custom(&hgo->ctrls.handler, | ||
212 | &hgo_num_bins_control, NULL); | ||
213 | |||
214 | hgo->max_rgb = false; | ||
215 | hgo->num_bins = 64; | ||
216 | |||
217 | hgo->histo.entity.subdev.ctrl_handler = &hgo->ctrls.handler; | ||
218 | |||
219 | /* Initialize the video device and queue for statistics data. */ | ||
220 | ret = vsp1_histogram_init(vsp1, &hgo->histo, VSP1_ENTITY_HGO, "hgo", | ||
221 | &hgo_entity_ops, hgo_mbus_formats, | ||
222 | ARRAY_SIZE(hgo_mbus_formats), | ||
223 | HGO_DATA_SIZE, V4L2_META_FMT_VSP1_HGO); | ||
224 | if (ret < 0) { | ||
225 | vsp1_entity_destroy(&hgo->histo.entity); | ||
226 | return ERR_PTR(ret); | ||
227 | } | ||
228 | |||
229 | return hgo; | ||
230 | } | ||
diff --git a/drivers/media/platform/vsp1/vsp1_hgo.h b/drivers/media/platform/vsp1/vsp1_hgo.h new file mode 100644 index 000000000000..c6c0b7a80e0c --- /dev/null +++ b/drivers/media/platform/vsp1/vsp1_hgo.h | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | * vsp1_hgo.h -- R-Car VSP1 Histogram Generator 1D | ||
3 | * | ||
4 | * Copyright (C) 2016 Renesas Electronics Corporation | ||
5 | * | ||
6 | * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | */ | ||
13 | #ifndef __VSP1_HGO_H__ | ||
14 | #define __VSP1_HGO_H__ | ||
15 | |||
16 | #include <media/media-entity.h> | ||
17 | #include <media/v4l2-ctrls.h> | ||
18 | #include <media/v4l2-subdev.h> | ||
19 | |||
20 | #include "vsp1_histo.h" | ||
21 | |||
22 | struct vsp1_device; | ||
23 | |||
24 | struct vsp1_hgo { | ||
25 | struct vsp1_histogram histo; | ||
26 | |||
27 | struct { | ||
28 | struct v4l2_ctrl_handler handler; | ||
29 | struct v4l2_ctrl *max_rgb; | ||
30 | struct v4l2_ctrl *num_bins; | ||
31 | } ctrls; | ||
32 | |||
33 | bool max_rgb; | ||
34 | unsigned int num_bins; | ||
35 | }; | ||
36 | |||
37 | static inline struct vsp1_hgo *to_hgo(struct v4l2_subdev *subdev) | ||
38 | { | ||
39 | return container_of(subdev, struct vsp1_hgo, histo.entity.subdev); | ||
40 | } | ||
41 | |||
42 | struct vsp1_hgo *vsp1_hgo_create(struct vsp1_device *vsp1); | ||
43 | void vsp1_hgo_frame_end(struct vsp1_entity *hgo); | ||
44 | |||
45 | #endif /* __VSP1_HGO_H__ */ | ||
diff --git a/drivers/media/platform/vsp1/vsp1_hgt.c b/drivers/media/platform/vsp1/vsp1_hgt.c new file mode 100644 index 000000000000..b5ce305e3e6f --- /dev/null +++ b/drivers/media/platform/vsp1/vsp1_hgt.c | |||
@@ -0,0 +1,222 @@ | |||
1 | /* | ||
2 | * vsp1_hgt.c -- R-Car VSP1 Histogram Generator 2D | ||
3 | * | ||
4 | * Copyright (C) 2016 Renesas Electronics Corporation | ||
5 | * | ||
6 | * Contact: Niklas Söderlund (niklas.soderlund@ragnatech.se) | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/device.h> | ||
15 | #include <linux/gfp.h> | ||
16 | |||
17 | #include <media/v4l2-subdev.h> | ||
18 | #include <media/videobuf2-vmalloc.h> | ||
19 | |||
20 | #include "vsp1.h" | ||
21 | #include "vsp1_dl.h" | ||
22 | #include "vsp1_hgt.h" | ||
23 | |||
24 | #define HGT_DATA_SIZE ((2 + 6 * 32) * 4) | ||
25 | |||
26 | /* ----------------------------------------------------------------------------- | ||
27 | * Device Access | ||
28 | */ | ||
29 | |||
30 | static inline u32 vsp1_hgt_read(struct vsp1_hgt *hgt, u32 reg) | ||
31 | { | ||
32 | return vsp1_read(hgt->histo.entity.vsp1, reg); | ||
33 | } | ||
34 | |||
35 | static inline void vsp1_hgt_write(struct vsp1_hgt *hgt, struct vsp1_dl_list *dl, | ||
36 | u32 reg, u32 data) | ||
37 | { | ||
38 | vsp1_dl_list_write(dl, reg, data); | ||
39 | } | ||
40 | |||
41 | /* ----------------------------------------------------------------------------- | ||
42 | * Frame End Handler | ||
43 | */ | ||
44 | |||
45 | void vsp1_hgt_frame_end(struct vsp1_entity *entity) | ||
46 | { | ||
47 | struct vsp1_hgt *hgt = to_hgt(&entity->subdev); | ||
48 | struct vsp1_histogram_buffer *buf; | ||
49 | unsigned int m; | ||
50 | unsigned int n; | ||
51 | u32 *data; | ||
52 | |||
53 | buf = vsp1_histogram_buffer_get(&hgt->histo); | ||
54 | if (!buf) | ||
55 | return; | ||
56 | |||
57 | data = buf->addr; | ||
58 | |||
59 | *data++ = vsp1_hgt_read(hgt, VI6_HGT_MAXMIN); | ||
60 | *data++ = vsp1_hgt_read(hgt, VI6_HGT_SUM); | ||
61 | |||
62 | for (m = 0; m < 6; ++m) | ||
63 | for (n = 0; n < 32; ++n) | ||
64 | *data++ = vsp1_hgt_read(hgt, VI6_HGT_HISTO(m, n)); | ||
65 | |||
66 | vsp1_histogram_buffer_complete(&hgt->histo, buf, HGT_DATA_SIZE); | ||
67 | } | ||
68 | |||
69 | /* ----------------------------------------------------------------------------- | ||
70 | * Controls | ||
71 | */ | ||
72 | |||
73 | #define V4L2_CID_VSP1_HGT_HUE_AREAS (V4L2_CID_USER_BASE | 0x1001) | ||
74 | |||
75 | static int hgt_hue_areas_try_ctrl(struct v4l2_ctrl *ctrl) | ||
76 | { | ||
77 | const u8 *values = ctrl->p_new.p_u8; | ||
78 | unsigned int i; | ||
79 | |||
80 | /* | ||
81 | * The hardware has constraints on the hue area boundaries beyond the | ||
82 | * control min, max and step. The values must match one of the following | ||
83 | * expressions. | ||
84 | * | ||
85 | * 0L <= 0U <= 1L <= 1U <= 2L <= 2U <= 3L <= 3U <= 4L <= 4U <= 5L <= 5U | ||
86 | * 0U <= 1L <= 1U <= 2L <= 2U <= 3L <= 3U <= 4L <= 4U <= 5L <= 5U <= 0L | ||
87 | * | ||
88 | * Start by verifying the common part... | ||
89 | */ | ||
90 | for (i = 1; i < (HGT_NUM_HUE_AREAS * 2) - 1; ++i) { | ||
91 | if (values[i] > values[i+1]) | ||
92 | return -EINVAL; | ||
93 | } | ||
94 | |||
95 | /* ... and handle 0L separately. */ | ||
96 | if (values[0] > values[1] && values[11] > values[0]) | ||
97 | return -EINVAL; | ||
98 | |||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static int hgt_hue_areas_s_ctrl(struct v4l2_ctrl *ctrl) | ||
103 | { | ||
104 | struct vsp1_hgt *hgt = container_of(ctrl->handler, struct vsp1_hgt, | ||
105 | ctrls); | ||
106 | |||
107 | memcpy(hgt->hue_areas, ctrl->p_new.p_u8, sizeof(hgt->hue_areas)); | ||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | static const struct v4l2_ctrl_ops hgt_hue_areas_ctrl_ops = { | ||
112 | .try_ctrl = hgt_hue_areas_try_ctrl, | ||
113 | .s_ctrl = hgt_hue_areas_s_ctrl, | ||
114 | }; | ||
115 | |||
116 | static const struct v4l2_ctrl_config hgt_hue_areas = { | ||
117 | .ops = &hgt_hue_areas_ctrl_ops, | ||
118 | .id = V4L2_CID_VSP1_HGT_HUE_AREAS, | ||
119 | .name = "Boundary Values for Hue Area", | ||
120 | .type = V4L2_CTRL_TYPE_U8, | ||
121 | .min = 0, | ||
122 | .max = 255, | ||
123 | .def = 0, | ||
124 | .step = 1, | ||
125 | .dims = { 12 }, | ||
126 | }; | ||
127 | |||
128 | /* ----------------------------------------------------------------------------- | ||
129 | * VSP1 Entity Operations | ||
130 | */ | ||
131 | |||
132 | static void hgt_configure(struct vsp1_entity *entity, | ||
133 | struct vsp1_pipeline *pipe, | ||
134 | struct vsp1_dl_list *dl, | ||
135 | enum vsp1_entity_params params) | ||
136 | { | ||
137 | struct vsp1_hgt *hgt = to_hgt(&entity->subdev); | ||
138 | struct v4l2_rect *compose; | ||
139 | struct v4l2_rect *crop; | ||
140 | unsigned int hratio; | ||
141 | unsigned int vratio; | ||
142 | u8 lower; | ||
143 | u8 upper; | ||
144 | unsigned int i; | ||
145 | |||
146 | if (params != VSP1_ENTITY_PARAMS_INIT) | ||
147 | return; | ||
148 | |||
149 | crop = vsp1_entity_get_pad_selection(entity, entity->config, | ||
150 | HISTO_PAD_SINK, V4L2_SEL_TGT_CROP); | ||
151 | compose = vsp1_entity_get_pad_selection(entity, entity->config, | ||
152 | HISTO_PAD_SINK, | ||
153 | V4L2_SEL_TGT_COMPOSE); | ||
154 | |||
155 | vsp1_hgt_write(hgt, dl, VI6_HGT_REGRST, VI6_HGT_REGRST_RCLEA); | ||
156 | |||
157 | vsp1_hgt_write(hgt, dl, VI6_HGT_OFFSET, | ||
158 | (crop->left << VI6_HGT_OFFSET_HOFFSET_SHIFT) | | ||
159 | (crop->top << VI6_HGT_OFFSET_VOFFSET_SHIFT)); | ||
160 | vsp1_hgt_write(hgt, dl, VI6_HGT_SIZE, | ||
161 | (crop->width << VI6_HGT_SIZE_HSIZE_SHIFT) | | ||
162 | (crop->height << VI6_HGT_SIZE_VSIZE_SHIFT)); | ||
163 | |||
164 | mutex_lock(hgt->ctrls.lock); | ||
165 | for (i = 0; i < HGT_NUM_HUE_AREAS; ++i) { | ||
166 | lower = hgt->hue_areas[i*2 + 0]; | ||
167 | upper = hgt->hue_areas[i*2 + 1]; | ||
168 | vsp1_hgt_write(hgt, dl, VI6_HGT_HUE_AREA(i), | ||
169 | (lower << VI6_HGT_HUE_AREA_LOWER_SHIFT) | | ||
170 | (upper << VI6_HGT_HUE_AREA_UPPER_SHIFT)); | ||
171 | } | ||
172 | mutex_unlock(hgt->ctrls.lock); | ||
173 | |||
174 | hratio = crop->width * 2 / compose->width / 3; | ||
175 | vratio = crop->height * 2 / compose->height / 3; | ||
176 | vsp1_hgt_write(hgt, dl, VI6_HGT_MODE, | ||
177 | (hratio << VI6_HGT_MODE_HRATIO_SHIFT) | | ||
178 | (vratio << VI6_HGT_MODE_VRATIO_SHIFT)); | ||
179 | } | ||
180 | |||
181 | static const struct vsp1_entity_operations hgt_entity_ops = { | ||
182 | .configure = hgt_configure, | ||
183 | .destroy = vsp1_histogram_destroy, | ||
184 | }; | ||
185 | |||
186 | /* ----------------------------------------------------------------------------- | ||
187 | * Initialization and Cleanup | ||
188 | */ | ||
189 | |||
190 | static const unsigned int hgt_mbus_formats[] = { | ||
191 | MEDIA_BUS_FMT_AHSV8888_1X32, | ||
192 | }; | ||
193 | |||
194 | struct vsp1_hgt *vsp1_hgt_create(struct vsp1_device *vsp1) | ||
195 | { | ||
196 | struct vsp1_hgt *hgt; | ||
197 | int ret; | ||
198 | |||
199 | hgt = devm_kzalloc(vsp1->dev, sizeof(*hgt), GFP_KERNEL); | ||
200 | if (hgt == NULL) | ||
201 | return ERR_PTR(-ENOMEM); | ||
202 | |||
203 | /* Initialize the control handler. */ | ||
204 | v4l2_ctrl_handler_init(&hgt->ctrls, 1); | ||
205 | v4l2_ctrl_new_custom(&hgt->ctrls, &hgt_hue_areas, NULL); | ||
206 | |||
207 | hgt->histo.entity.subdev.ctrl_handler = &hgt->ctrls; | ||
208 | |||
209 | /* Initialize the video device and queue for statistics data. */ | ||
210 | ret = vsp1_histogram_init(vsp1, &hgt->histo, VSP1_ENTITY_HGT, "hgt", | ||
211 | &hgt_entity_ops, hgt_mbus_formats, | ||
212 | ARRAY_SIZE(hgt_mbus_formats), | ||
213 | HGT_DATA_SIZE, V4L2_META_FMT_VSP1_HGT); | ||
214 | if (ret < 0) { | ||
215 | vsp1_entity_destroy(&hgt->histo.entity); | ||
216 | return ERR_PTR(ret); | ||
217 | } | ||
218 | |||
219 | v4l2_ctrl_handler_setup(&hgt->ctrls); | ||
220 | |||
221 | return hgt; | ||
222 | } | ||
diff --git a/drivers/media/platform/vsp1/vsp1_hgt.h b/drivers/media/platform/vsp1/vsp1_hgt.h new file mode 100644 index 000000000000..83f2e130942a --- /dev/null +++ b/drivers/media/platform/vsp1/vsp1_hgt.h | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | * vsp1_hgt.h -- R-Car VSP1 Histogram Generator 2D | ||
3 | * | ||
4 | * Copyright (C) 2016 Renesas Electronics Corporation | ||
5 | * | ||
6 | * Contact: Niklas Söderlund (niklas.soderlund@ragnatech.se) | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | */ | ||
13 | #ifndef __VSP1_HGT_H__ | ||
14 | #define __VSP1_HGT_H__ | ||
15 | |||
16 | #include <media/media-entity.h> | ||
17 | #include <media/v4l2-ctrls.h> | ||
18 | #include <media/v4l2-subdev.h> | ||
19 | |||
20 | #include "vsp1_histo.h" | ||
21 | |||
22 | struct vsp1_device; | ||
23 | |||
24 | #define HGT_NUM_HUE_AREAS 6 | ||
25 | |||
26 | struct vsp1_hgt { | ||
27 | struct vsp1_histogram histo; | ||
28 | |||
29 | struct v4l2_ctrl_handler ctrls; | ||
30 | |||
31 | u8 hue_areas[HGT_NUM_HUE_AREAS * 2]; | ||
32 | }; | ||
33 | |||
34 | static inline struct vsp1_hgt *to_hgt(struct v4l2_subdev *subdev) | ||
35 | { | ||
36 | return container_of(subdev, struct vsp1_hgt, histo.entity.subdev); | ||
37 | } | ||
38 | |||
39 | struct vsp1_hgt *vsp1_hgt_create(struct vsp1_device *vsp1); | ||
40 | void vsp1_hgt_frame_end(struct vsp1_entity *hgt); | ||
41 | |||
42 | #endif /* __VSP1_HGT_H__ */ | ||
diff --git a/drivers/media/platform/vsp1/vsp1_histo.c b/drivers/media/platform/vsp1/vsp1_histo.c new file mode 100644 index 000000000000..afab77cf4fa5 --- /dev/null +++ b/drivers/media/platform/vsp1/vsp1_histo.c | |||
@@ -0,0 +1,646 @@ | |||
1 | /* | ||
2 | * vsp1_histo.c -- R-Car VSP1 Histogram API | ||
3 | * | ||
4 | * Copyright (C) 2016 Renesas Electronics Corporation | ||
5 | * Copyright (C) 2016 Laurent Pinchart | ||
6 | * | ||
7 | * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | */ | ||
14 | |||
15 | #include <linux/device.h> | ||
16 | #include <linux/gfp.h> | ||
17 | |||
18 | #include <media/v4l2-ioctl.h> | ||
19 | #include <media/v4l2-subdev.h> | ||
20 | #include <media/videobuf2-vmalloc.h> | ||
21 | |||
22 | #include "vsp1.h" | ||
23 | #include "vsp1_histo.h" | ||
24 | #include "vsp1_pipe.h" | ||
25 | |||
26 | #define HISTO_MIN_SIZE 4U | ||
27 | #define HISTO_MAX_SIZE 8192U | ||
28 | |||
29 | /* ----------------------------------------------------------------------------- | ||
30 | * Buffer Operations | ||
31 | */ | ||
32 | |||
33 | static inline struct vsp1_histogram_buffer * | ||
34 | to_vsp1_histogram_buffer(struct vb2_v4l2_buffer *vbuf) | ||
35 | { | ||
36 | return container_of(vbuf, struct vsp1_histogram_buffer, buf); | ||
37 | } | ||
38 | |||
39 | struct vsp1_histogram_buffer * | ||
40 | vsp1_histogram_buffer_get(struct vsp1_histogram *histo) | ||
41 | { | ||
42 | struct vsp1_histogram_buffer *buf = NULL; | ||
43 | unsigned long flags; | ||
44 | |||
45 | spin_lock_irqsave(&histo->irqlock, flags); | ||
46 | |||
47 | if (list_empty(&histo->irqqueue)) | ||
48 | goto done; | ||
49 | |||
50 | buf = list_first_entry(&histo->irqqueue, struct vsp1_histogram_buffer, | ||
51 | queue); | ||
52 | list_del(&buf->queue); | ||
53 | histo->readout = true; | ||
54 | |||
55 | done: | ||
56 | spin_unlock_irqrestore(&histo->irqlock, flags); | ||
57 | return buf; | ||
58 | } | ||
59 | |||
60 | void vsp1_histogram_buffer_complete(struct vsp1_histogram *histo, | ||
61 | struct vsp1_histogram_buffer *buf, | ||
62 | size_t size) | ||
63 | { | ||
64 | struct vsp1_pipeline *pipe = histo->pipe; | ||
65 | unsigned long flags; | ||
66 | |||
67 | /* | ||
68 | * The pipeline pointer is guaranteed to be valid as this function is | ||
69 | * called from the frame completion interrupt handler, which can only | ||
70 | * occur when video streaming is active. | ||
71 | */ | ||
72 | buf->buf.sequence = pipe->sequence; | ||
73 | buf->buf.vb2_buf.timestamp = ktime_get_ns(); | ||
74 | vb2_set_plane_payload(&buf->buf.vb2_buf, 0, size); | ||
75 | vb2_buffer_done(&buf->buf.vb2_buf, VB2_BUF_STATE_DONE); | ||
76 | |||
77 | spin_lock_irqsave(&histo->irqlock, flags); | ||
78 | histo->readout = false; | ||
79 | wake_up(&histo->wait_queue); | ||
80 | spin_unlock_irqrestore(&histo->irqlock, flags); | ||
81 | } | ||
82 | |||
83 | /* ----------------------------------------------------------------------------- | ||
84 | * videobuf2 Queue Operations | ||
85 | */ | ||
86 | |||
87 | static int histo_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, | ||
88 | unsigned int *nplanes, unsigned int sizes[], | ||
89 | struct device *alloc_devs[]) | ||
90 | { | ||
91 | struct vsp1_histogram *histo = vb2_get_drv_priv(vq); | ||
92 | |||
93 | if (*nplanes) { | ||
94 | if (*nplanes != 1) | ||
95 | return -EINVAL; | ||
96 | |||
97 | if (sizes[0] < histo->data_size) | ||
98 | return -EINVAL; | ||
99 | |||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | *nplanes = 1; | ||
104 | sizes[0] = histo->data_size; | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static int histo_buffer_prepare(struct vb2_buffer *vb) | ||
110 | { | ||
111 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | ||
112 | struct vsp1_histogram *histo = vb2_get_drv_priv(vb->vb2_queue); | ||
113 | struct vsp1_histogram_buffer *buf = to_vsp1_histogram_buffer(vbuf); | ||
114 | |||
115 | if (vb->num_planes != 1) | ||
116 | return -EINVAL; | ||
117 | |||
118 | if (vb2_plane_size(vb, 0) < histo->data_size) | ||
119 | return -EINVAL; | ||
120 | |||
121 | buf->addr = vb2_plane_vaddr(vb, 0); | ||
122 | |||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | static void histo_buffer_queue(struct vb2_buffer *vb) | ||
127 | { | ||
128 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | ||
129 | struct vsp1_histogram *histo = vb2_get_drv_priv(vb->vb2_queue); | ||
130 | struct vsp1_histogram_buffer *buf = to_vsp1_histogram_buffer(vbuf); | ||
131 | unsigned long flags; | ||
132 | |||
133 | spin_lock_irqsave(&histo->irqlock, flags); | ||
134 | list_add_tail(&buf->queue, &histo->irqqueue); | ||
135 | spin_unlock_irqrestore(&histo->irqlock, flags); | ||
136 | } | ||
137 | |||
138 | static int histo_start_streaming(struct vb2_queue *vq, unsigned int count) | ||
139 | { | ||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | static void histo_stop_streaming(struct vb2_queue *vq) | ||
144 | { | ||
145 | struct vsp1_histogram *histo = vb2_get_drv_priv(vq); | ||
146 | struct vsp1_histogram_buffer *buffer; | ||
147 | unsigned long flags; | ||
148 | |||
149 | spin_lock_irqsave(&histo->irqlock, flags); | ||
150 | |||
151 | /* Remove all buffers from the IRQ queue. */ | ||
152 | list_for_each_entry(buffer, &histo->irqqueue, queue) | ||
153 | vb2_buffer_done(&buffer->buf.vb2_buf, VB2_BUF_STATE_ERROR); | ||
154 | INIT_LIST_HEAD(&histo->irqqueue); | ||
155 | |||
156 | /* Wait for the buffer being read out (if any) to complete. */ | ||
157 | wait_event_lock_irq(histo->wait_queue, !histo->readout, histo->irqlock); | ||
158 | |||
159 | spin_unlock_irqrestore(&histo->irqlock, flags); | ||
160 | } | ||
161 | |||
162 | static const struct vb2_ops histo_video_queue_qops = { | ||
163 | .queue_setup = histo_queue_setup, | ||
164 | .buf_prepare = histo_buffer_prepare, | ||
165 | .buf_queue = histo_buffer_queue, | ||
166 | .wait_prepare = vb2_ops_wait_prepare, | ||
167 | .wait_finish = vb2_ops_wait_finish, | ||
168 | .start_streaming = histo_start_streaming, | ||
169 | .stop_streaming = histo_stop_streaming, | ||
170 | }; | ||
171 | |||
172 | /* ----------------------------------------------------------------------------- | ||
173 | * V4L2 Subdevice Operations | ||
174 | */ | ||
175 | |||
176 | static int histo_enum_mbus_code(struct v4l2_subdev *subdev, | ||
177 | struct v4l2_subdev_pad_config *cfg, | ||
178 | struct v4l2_subdev_mbus_code_enum *code) | ||
179 | { | ||
180 | struct vsp1_histogram *histo = subdev_to_histo(subdev); | ||
181 | |||
182 | if (code->pad == HISTO_PAD_SOURCE) { | ||
183 | code->code = MEDIA_BUS_FMT_FIXED; | ||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | return vsp1_subdev_enum_mbus_code(subdev, cfg, code, histo->formats, | ||
188 | histo->num_formats); | ||
189 | } | ||
190 | |||
191 | static int histo_enum_frame_size(struct v4l2_subdev *subdev, | ||
192 | struct v4l2_subdev_pad_config *cfg, | ||
193 | struct v4l2_subdev_frame_size_enum *fse) | ||
194 | { | ||
195 | if (fse->pad != HISTO_PAD_SINK) | ||
196 | return -EINVAL; | ||
197 | |||
198 | return vsp1_subdev_enum_frame_size(subdev, cfg, fse, HISTO_MIN_SIZE, | ||
199 | HISTO_MIN_SIZE, HISTO_MAX_SIZE, | ||
200 | HISTO_MAX_SIZE); | ||
201 | } | ||
202 | |||
203 | static int histo_get_selection(struct v4l2_subdev *subdev, | ||
204 | struct v4l2_subdev_pad_config *cfg, | ||
205 | struct v4l2_subdev_selection *sel) | ||
206 | { | ||
207 | struct vsp1_histogram *histo = subdev_to_histo(subdev); | ||
208 | struct v4l2_subdev_pad_config *config; | ||
209 | struct v4l2_mbus_framefmt *format; | ||
210 | struct v4l2_rect *crop; | ||
211 | int ret = 0; | ||
212 | |||
213 | if (sel->pad != HISTO_PAD_SINK) | ||
214 | return -EINVAL; | ||
215 | |||
216 | mutex_lock(&histo->entity.lock); | ||
217 | |||
218 | config = vsp1_entity_get_pad_config(&histo->entity, cfg, sel->which); | ||
219 | if (!config) { | ||
220 | ret = -EINVAL; | ||
221 | goto done; | ||
222 | } | ||
223 | |||
224 | switch (sel->target) { | ||
225 | case V4L2_SEL_TGT_COMPOSE_BOUNDS: | ||
226 | case V4L2_SEL_TGT_COMPOSE_DEFAULT: | ||
227 | crop = vsp1_entity_get_pad_selection(&histo->entity, config, | ||
228 | HISTO_PAD_SINK, | ||
229 | V4L2_SEL_TGT_CROP); | ||
230 | sel->r.left = 0; | ||
231 | sel->r.top = 0; | ||
232 | sel->r.width = crop->width; | ||
233 | sel->r.height = crop->height; | ||
234 | break; | ||
235 | |||
236 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
237 | case V4L2_SEL_TGT_CROP_DEFAULT: | ||
238 | format = vsp1_entity_get_pad_format(&histo->entity, config, | ||
239 | HISTO_PAD_SINK); | ||
240 | sel->r.left = 0; | ||
241 | sel->r.top = 0; | ||
242 | sel->r.width = format->width; | ||
243 | sel->r.height = format->height; | ||
244 | break; | ||
245 | |||
246 | case V4L2_SEL_TGT_COMPOSE: | ||
247 | case V4L2_SEL_TGT_CROP: | ||
248 | sel->r = *vsp1_entity_get_pad_selection(&histo->entity, config, | ||
249 | sel->pad, sel->target); | ||
250 | break; | ||
251 | |||
252 | default: | ||
253 | ret = -EINVAL; | ||
254 | break; | ||
255 | } | ||
256 | |||
257 | done: | ||
258 | mutex_unlock(&histo->entity.lock); | ||
259 | return ret; | ||
260 | } | ||
261 | |||
262 | static int histo_set_crop(struct v4l2_subdev *subdev, | ||
263 | struct v4l2_subdev_pad_config *config, | ||
264 | struct v4l2_subdev_selection *sel) | ||
265 | { | ||
266 | struct vsp1_histogram *histo = subdev_to_histo(subdev); | ||
267 | struct v4l2_mbus_framefmt *format; | ||
268 | struct v4l2_rect *selection; | ||
269 | |||
270 | /* The crop rectangle must be inside the input frame. */ | ||
271 | format = vsp1_entity_get_pad_format(&histo->entity, config, | ||
272 | HISTO_PAD_SINK); | ||
273 | sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1); | ||
274 | sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1); | ||
275 | sel->r.width = clamp_t(unsigned int, sel->r.width, HISTO_MIN_SIZE, | ||
276 | format->width - sel->r.left); | ||
277 | sel->r.height = clamp_t(unsigned int, sel->r.height, HISTO_MIN_SIZE, | ||
278 | format->height - sel->r.top); | ||
279 | |||
280 | /* Set the crop rectangle and reset the compose rectangle. */ | ||
281 | selection = vsp1_entity_get_pad_selection(&histo->entity, config, | ||
282 | sel->pad, V4L2_SEL_TGT_CROP); | ||
283 | *selection = sel->r; | ||
284 | |||
285 | selection = vsp1_entity_get_pad_selection(&histo->entity, config, | ||
286 | sel->pad, | ||
287 | V4L2_SEL_TGT_COMPOSE); | ||
288 | *selection = sel->r; | ||
289 | |||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | static int histo_set_compose(struct v4l2_subdev *subdev, | ||
294 | struct v4l2_subdev_pad_config *config, | ||
295 | struct v4l2_subdev_selection *sel) | ||
296 | { | ||
297 | struct vsp1_histogram *histo = subdev_to_histo(subdev); | ||
298 | struct v4l2_rect *compose; | ||
299 | struct v4l2_rect *crop; | ||
300 | unsigned int ratio; | ||
301 | |||
302 | /* | ||
303 | * The compose rectangle is used to configure downscaling, the top left | ||
304 | * corner is fixed to (0,0) and the size to 1/2 or 1/4 of the crop | ||
305 | * rectangle. | ||
306 | */ | ||
307 | sel->r.left = 0; | ||
308 | sel->r.top = 0; | ||
309 | |||
310 | crop = vsp1_entity_get_pad_selection(&histo->entity, config, sel->pad, | ||
311 | V4L2_SEL_TGT_CROP); | ||
312 | |||
313 | /* | ||
314 | * Clamp the width and height to acceptable values first and then | ||
315 | * compute the closest rounded dividing ratio. | ||
316 | * | ||
317 | * Ratio Rounded ratio | ||
318 | * -------------------------- | ||
319 | * [1.0 1.5[ 1 | ||
320 | * [1.5 3.0[ 2 | ||
321 | * [3.0 4.0] 4 | ||
322 | * | ||
323 | * The rounded ratio can be computed using | ||
324 | * | ||
325 | * 1 << (ceil(ratio * 2) / 3) | ||
326 | */ | ||
327 | sel->r.width = clamp(sel->r.width, crop->width / 4, crop->width); | ||
328 | ratio = 1 << (crop->width * 2 / sel->r.width / 3); | ||
329 | sel->r.width = crop->width / ratio; | ||
330 | |||
331 | |||
332 | sel->r.height = clamp(sel->r.height, crop->height / 4, crop->height); | ||
333 | ratio = 1 << (crop->height * 2 / sel->r.height / 3); | ||
334 | sel->r.height = crop->height / ratio; | ||
335 | |||
336 | compose = vsp1_entity_get_pad_selection(&histo->entity, config, | ||
337 | sel->pad, | ||
338 | V4L2_SEL_TGT_COMPOSE); | ||
339 | *compose = sel->r; | ||
340 | |||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | static int histo_set_selection(struct v4l2_subdev *subdev, | ||
345 | struct v4l2_subdev_pad_config *cfg, | ||
346 | struct v4l2_subdev_selection *sel) | ||
347 | { | ||
348 | struct vsp1_histogram *histo = subdev_to_histo(subdev); | ||
349 | struct v4l2_subdev_pad_config *config; | ||
350 | int ret; | ||
351 | |||
352 | if (sel->pad != HISTO_PAD_SINK) | ||
353 | return -EINVAL; | ||
354 | |||
355 | mutex_lock(&histo->entity.lock); | ||
356 | |||
357 | config = vsp1_entity_get_pad_config(&histo->entity, cfg, sel->which); | ||
358 | if (!config) { | ||
359 | ret = -EINVAL; | ||
360 | goto done; | ||
361 | } | ||
362 | |||
363 | if (sel->target == V4L2_SEL_TGT_CROP) | ||
364 | ret = histo_set_crop(subdev, config, sel); | ||
365 | else if (sel->target == V4L2_SEL_TGT_COMPOSE) | ||
366 | ret = histo_set_compose(subdev, config, sel); | ||
367 | else | ||
368 | ret = -EINVAL; | ||
369 | |||
370 | done: | ||
371 | mutex_unlock(&histo->entity.lock); | ||
372 | return ret; | ||
373 | } | ||
374 | |||
375 | static int histo_get_format(struct v4l2_subdev *subdev, | ||
376 | struct v4l2_subdev_pad_config *cfg, | ||
377 | struct v4l2_subdev_format *fmt) | ||
378 | { | ||
379 | if (fmt->pad == HISTO_PAD_SOURCE) { | ||
380 | fmt->format.code = MEDIA_BUS_FMT_FIXED; | ||
381 | fmt->format.width = 0; | ||
382 | fmt->format.height = 0; | ||
383 | fmt->format.field = V4L2_FIELD_NONE; | ||
384 | fmt->format.colorspace = V4L2_COLORSPACE_RAW; | ||
385 | return 0; | ||
386 | } | ||
387 | |||
388 | return vsp1_subdev_get_pad_format(subdev, cfg, fmt); | ||
389 | } | ||
390 | |||
391 | static int histo_set_format(struct v4l2_subdev *subdev, | ||
392 | struct v4l2_subdev_pad_config *cfg, | ||
393 | struct v4l2_subdev_format *fmt) | ||
394 | { | ||
395 | struct vsp1_histogram *histo = subdev_to_histo(subdev); | ||
396 | struct v4l2_subdev_pad_config *config; | ||
397 | struct v4l2_mbus_framefmt *format; | ||
398 | struct v4l2_rect *selection; | ||
399 | unsigned int i; | ||
400 | int ret = 0; | ||
401 | |||
402 | if (fmt->pad != HISTO_PAD_SINK) | ||
403 | return histo_get_format(subdev, cfg, fmt); | ||
404 | |||
405 | mutex_lock(&histo->entity.lock); | ||
406 | |||
407 | config = vsp1_entity_get_pad_config(&histo->entity, cfg, fmt->which); | ||
408 | if (!config) { | ||
409 | ret = -EINVAL; | ||
410 | goto done; | ||
411 | } | ||
412 | |||
413 | /* | ||
414 | * Default to the first format if the requested format is not | ||
415 | * supported. | ||
416 | */ | ||
417 | for (i = 0; i < histo->num_formats; ++i) { | ||
418 | if (fmt->format.code == histo->formats[i]) | ||
419 | break; | ||
420 | } | ||
421 | if (i == histo->num_formats) | ||
422 | fmt->format.code = histo->formats[0]; | ||
423 | |||
424 | format = vsp1_entity_get_pad_format(&histo->entity, config, fmt->pad); | ||
425 | |||
426 | format->code = fmt->format.code; | ||
427 | format->width = clamp_t(unsigned int, fmt->format.width, | ||
428 | HISTO_MIN_SIZE, HISTO_MAX_SIZE); | ||
429 | format->height = clamp_t(unsigned int, fmt->format.height, | ||
430 | HISTO_MIN_SIZE, HISTO_MAX_SIZE); | ||
431 | format->field = V4L2_FIELD_NONE; | ||
432 | format->colorspace = V4L2_COLORSPACE_SRGB; | ||
433 | |||
434 | fmt->format = *format; | ||
435 | |||
436 | /* Reset the crop and compose rectangles */ | ||
437 | selection = vsp1_entity_get_pad_selection(&histo->entity, config, | ||
438 | fmt->pad, V4L2_SEL_TGT_CROP); | ||
439 | selection->left = 0; | ||
440 | selection->top = 0; | ||
441 | selection->width = format->width; | ||
442 | selection->height = format->height; | ||
443 | |||
444 | selection = vsp1_entity_get_pad_selection(&histo->entity, config, | ||
445 | fmt->pad, | ||
446 | V4L2_SEL_TGT_COMPOSE); | ||
447 | selection->left = 0; | ||
448 | selection->top = 0; | ||
449 | selection->width = format->width; | ||
450 | selection->height = format->height; | ||
451 | |||
452 | done: | ||
453 | mutex_unlock(&histo->entity.lock); | ||
454 | return ret; | ||
455 | } | ||
456 | |||
457 | static const struct v4l2_subdev_pad_ops histo_pad_ops = { | ||
458 | .enum_mbus_code = histo_enum_mbus_code, | ||
459 | .enum_frame_size = histo_enum_frame_size, | ||
460 | .get_fmt = histo_get_format, | ||
461 | .set_fmt = histo_set_format, | ||
462 | .get_selection = histo_get_selection, | ||
463 | .set_selection = histo_set_selection, | ||
464 | }; | ||
465 | |||
466 | static const struct v4l2_subdev_ops histo_ops = { | ||
467 | .pad = &histo_pad_ops, | ||
468 | }; | ||
469 | |||
470 | /* ----------------------------------------------------------------------------- | ||
471 | * V4L2 ioctls | ||
472 | */ | ||
473 | |||
474 | static int histo_v4l2_querycap(struct file *file, void *fh, | ||
475 | struct v4l2_capability *cap) | ||
476 | { | ||
477 | struct v4l2_fh *vfh = file->private_data; | ||
478 | struct vsp1_histogram *histo = vdev_to_histo(vfh->vdev); | ||
479 | |||
480 | cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING | ||
481 | | V4L2_CAP_VIDEO_CAPTURE_MPLANE | ||
482 | | V4L2_CAP_VIDEO_OUTPUT_MPLANE | ||
483 | | V4L2_CAP_META_CAPTURE; | ||
484 | cap->device_caps = V4L2_CAP_META_CAPTURE | ||
485 | | V4L2_CAP_STREAMING; | ||
486 | |||
487 | strlcpy(cap->driver, "vsp1", sizeof(cap->driver)); | ||
488 | strlcpy(cap->card, histo->video.name, sizeof(cap->card)); | ||
489 | snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", | ||
490 | dev_name(histo->entity.vsp1->dev)); | ||
491 | |||
492 | return 0; | ||
493 | } | ||
494 | |||
495 | static int histo_v4l2_enum_format(struct file *file, void *fh, | ||
496 | struct v4l2_fmtdesc *f) | ||
497 | { | ||
498 | struct v4l2_fh *vfh = file->private_data; | ||
499 | struct vsp1_histogram *histo = vdev_to_histo(vfh->vdev); | ||
500 | |||
501 | if (f->index > 0 || f->type != histo->queue.type) | ||
502 | return -EINVAL; | ||
503 | |||
504 | f->pixelformat = histo->meta_format; | ||
505 | |||
506 | return 0; | ||
507 | } | ||
508 | |||
509 | static int histo_v4l2_get_format(struct file *file, void *fh, | ||
510 | struct v4l2_format *format) | ||
511 | { | ||
512 | struct v4l2_fh *vfh = file->private_data; | ||
513 | struct vsp1_histogram *histo = vdev_to_histo(vfh->vdev); | ||
514 | struct v4l2_meta_format *meta = &format->fmt.meta; | ||
515 | |||
516 | if (format->type != histo->queue.type) | ||
517 | return -EINVAL; | ||
518 | |||
519 | memset(meta, 0, sizeof(*meta)); | ||
520 | |||
521 | meta->dataformat = histo->meta_format; | ||
522 | meta->buffersize = histo->data_size; | ||
523 | |||
524 | return 0; | ||
525 | } | ||
526 | |||
527 | static const struct v4l2_ioctl_ops histo_v4l2_ioctl_ops = { | ||
528 | .vidioc_querycap = histo_v4l2_querycap, | ||
529 | .vidioc_enum_fmt_meta_cap = histo_v4l2_enum_format, | ||
530 | .vidioc_g_fmt_meta_cap = histo_v4l2_get_format, | ||
531 | .vidioc_s_fmt_meta_cap = histo_v4l2_get_format, | ||
532 | .vidioc_try_fmt_meta_cap = histo_v4l2_get_format, | ||
533 | .vidioc_reqbufs = vb2_ioctl_reqbufs, | ||
534 | .vidioc_querybuf = vb2_ioctl_querybuf, | ||
535 | .vidioc_qbuf = vb2_ioctl_qbuf, | ||
536 | .vidioc_dqbuf = vb2_ioctl_dqbuf, | ||
537 | .vidioc_create_bufs = vb2_ioctl_create_bufs, | ||
538 | .vidioc_prepare_buf = vb2_ioctl_prepare_buf, | ||
539 | .vidioc_streamon = vb2_ioctl_streamon, | ||
540 | .vidioc_streamoff = vb2_ioctl_streamoff, | ||
541 | }; | ||
542 | |||
543 | /* ----------------------------------------------------------------------------- | ||
544 | * V4L2 File Operations | ||
545 | */ | ||
546 | |||
547 | static const struct v4l2_file_operations histo_v4l2_fops = { | ||
548 | .owner = THIS_MODULE, | ||
549 | .unlocked_ioctl = video_ioctl2, | ||
550 | .open = v4l2_fh_open, | ||
551 | .release = vb2_fop_release, | ||
552 | .poll = vb2_fop_poll, | ||
553 | .mmap = vb2_fop_mmap, | ||
554 | }; | ||
555 | |||
556 | static void vsp1_histogram_cleanup(struct vsp1_histogram *histo) | ||
557 | { | ||
558 | if (video_is_registered(&histo->video)) | ||
559 | video_unregister_device(&histo->video); | ||
560 | |||
561 | media_entity_cleanup(&histo->video.entity); | ||
562 | } | ||
563 | |||
564 | void vsp1_histogram_destroy(struct vsp1_entity *entity) | ||
565 | { | ||
566 | struct vsp1_histogram *histo = subdev_to_histo(&entity->subdev); | ||
567 | |||
568 | vsp1_histogram_cleanup(histo); | ||
569 | } | ||
570 | |||
571 | int vsp1_histogram_init(struct vsp1_device *vsp1, struct vsp1_histogram *histo, | ||
572 | enum vsp1_entity_type type, const char *name, | ||
573 | const struct vsp1_entity_operations *ops, | ||
574 | const unsigned int *formats, unsigned int num_formats, | ||
575 | size_t data_size, u32 meta_format) | ||
576 | { | ||
577 | int ret; | ||
578 | |||
579 | histo->formats = formats; | ||
580 | histo->num_formats = num_formats; | ||
581 | histo->data_size = data_size; | ||
582 | histo->meta_format = meta_format; | ||
583 | |||
584 | histo->pad.flags = MEDIA_PAD_FL_SINK; | ||
585 | histo->video.vfl_dir = VFL_DIR_RX; | ||
586 | |||
587 | mutex_init(&histo->lock); | ||
588 | spin_lock_init(&histo->irqlock); | ||
589 | INIT_LIST_HEAD(&histo->irqqueue); | ||
590 | init_waitqueue_head(&histo->wait_queue); | ||
591 | |||
592 | /* Initialize the VSP entity... */ | ||
593 | histo->entity.ops = ops; | ||
594 | histo->entity.type = type; | ||
595 | |||
596 | ret = vsp1_entity_init(vsp1, &histo->entity, name, 2, &histo_ops, | ||
597 | MEDIA_ENT_F_PROC_VIDEO_STATISTICS); | ||
598 | if (ret < 0) | ||
599 | return ret; | ||
600 | |||
601 | /* ... and the media entity... */ | ||
602 | ret = media_entity_pads_init(&histo->video.entity, 1, &histo->pad); | ||
603 | if (ret < 0) | ||
604 | return ret; | ||
605 | |||
606 | /* ... and the video node... */ | ||
607 | histo->video.v4l2_dev = &vsp1->v4l2_dev; | ||
608 | histo->video.fops = &histo_v4l2_fops; | ||
609 | snprintf(histo->video.name, sizeof(histo->video.name), | ||
610 | "%s histo", histo->entity.subdev.name); | ||
611 | histo->video.vfl_type = VFL_TYPE_GRABBER; | ||
612 | histo->video.release = video_device_release_empty; | ||
613 | histo->video.ioctl_ops = &histo_v4l2_ioctl_ops; | ||
614 | |||
615 | video_set_drvdata(&histo->video, histo); | ||
616 | |||
617 | /* ... and the buffers queue... */ | ||
618 | histo->queue.type = V4L2_BUF_TYPE_META_CAPTURE; | ||
619 | histo->queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; | ||
620 | histo->queue.lock = &histo->lock; | ||
621 | histo->queue.drv_priv = histo; | ||
622 | histo->queue.buf_struct_size = sizeof(struct vsp1_histogram_buffer); | ||
623 | histo->queue.ops = &histo_video_queue_qops; | ||
624 | histo->queue.mem_ops = &vb2_vmalloc_memops; | ||
625 | histo->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; | ||
626 | histo->queue.dev = vsp1->dev; | ||
627 | ret = vb2_queue_init(&histo->queue); | ||
628 | if (ret < 0) { | ||
629 | dev_err(vsp1->dev, "failed to initialize vb2 queue\n"); | ||
630 | goto error; | ||
631 | } | ||
632 | |||
633 | /* ... and register the video device. */ | ||
634 | histo->video.queue = &histo->queue; | ||
635 | ret = video_register_device(&histo->video, VFL_TYPE_GRABBER, -1); | ||
636 | if (ret < 0) { | ||
637 | dev_err(vsp1->dev, "failed to register video device\n"); | ||
638 | goto error; | ||
639 | } | ||
640 | |||
641 | return 0; | ||
642 | |||
643 | error: | ||
644 | vsp1_histogram_cleanup(histo); | ||
645 | return ret; | ||
646 | } | ||
diff --git a/drivers/media/platform/vsp1/vsp1_histo.h b/drivers/media/platform/vsp1/vsp1_histo.h new file mode 100644 index 000000000000..af2874f6031d --- /dev/null +++ b/drivers/media/platform/vsp1/vsp1_histo.h | |||
@@ -0,0 +1,84 @@ | |||
1 | /* | ||
2 | * vsp1_histo.h -- R-Car VSP1 Histogram API | ||
3 | * | ||
4 | * Copyright (C) 2016 Renesas Electronics Corporation | ||
5 | * Copyright (C) 2016 Laurent Pinchart | ||
6 | * | ||
7 | * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | */ | ||
14 | #ifndef __VSP1_HISTO_H__ | ||
15 | #define __VSP1_HISTO_H__ | ||
16 | |||
17 | #include <linux/list.h> | ||
18 | #include <linux/mutex.h> | ||
19 | #include <linux/spinlock.h> | ||
20 | |||
21 | #include <media/media-entity.h> | ||
22 | #include <media/v4l2-dev.h> | ||
23 | #include <media/videobuf2-v4l2.h> | ||
24 | |||
25 | #include "vsp1_entity.h" | ||
26 | |||
27 | struct vsp1_device; | ||
28 | struct vsp1_pipeline; | ||
29 | |||
30 | #define HISTO_PAD_SINK 0 | ||
31 | #define HISTO_PAD_SOURCE 1 | ||
32 | |||
33 | struct vsp1_histogram_buffer { | ||
34 | struct vb2_v4l2_buffer buf; | ||
35 | struct list_head queue; | ||
36 | void *addr; | ||
37 | }; | ||
38 | |||
39 | struct vsp1_histogram { | ||
40 | struct vsp1_pipeline *pipe; | ||
41 | |||
42 | struct vsp1_entity entity; | ||
43 | struct video_device video; | ||
44 | struct media_pad pad; | ||
45 | |||
46 | const u32 *formats; | ||
47 | unsigned int num_formats; | ||
48 | size_t data_size; | ||
49 | u32 meta_format; | ||
50 | |||
51 | struct mutex lock; | ||
52 | struct vb2_queue queue; | ||
53 | |||
54 | spinlock_t irqlock; | ||
55 | struct list_head irqqueue; | ||
56 | |||
57 | wait_queue_head_t wait_queue; | ||
58 | bool readout; | ||
59 | }; | ||
60 | |||
61 | static inline struct vsp1_histogram *vdev_to_histo(struct video_device *vdev) | ||
62 | { | ||
63 | return container_of(vdev, struct vsp1_histogram, video); | ||
64 | } | ||
65 | |||
66 | static inline struct vsp1_histogram *subdev_to_histo(struct v4l2_subdev *subdev) | ||
67 | { | ||
68 | return container_of(subdev, struct vsp1_histogram, entity.subdev); | ||
69 | } | ||
70 | |||
71 | int vsp1_histogram_init(struct vsp1_device *vsp1, struct vsp1_histogram *histo, | ||
72 | enum vsp1_entity_type type, const char *name, | ||
73 | const struct vsp1_entity_operations *ops, | ||
74 | const unsigned int *formats, unsigned int num_formats, | ||
75 | size_t data_size, u32 meta_format); | ||
76 | void vsp1_histogram_destroy(struct vsp1_entity *entity); | ||
77 | |||
78 | struct vsp1_histogram_buffer * | ||
79 | vsp1_histogram_buffer_get(struct vsp1_histogram *histo); | ||
80 | void vsp1_histogram_buffer_complete(struct vsp1_histogram *histo, | ||
81 | struct vsp1_histogram_buffer *buf, | ||
82 | size_t size); | ||
83 | |||
84 | #endif /* __VSP1_HISTO_H__ */ | ||
diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c index 94316afc54ff..764d405345ee 100644 --- a/drivers/media/platform/vsp1/vsp1_hsit.c +++ b/drivers/media/platform/vsp1/vsp1_hsit.c | |||
@@ -84,7 +84,8 @@ static int hsit_set_format(struct v4l2_subdev *subdev, | |||
84 | format = vsp1_entity_get_pad_format(&hsit->entity, config, fmt->pad); | 84 | format = vsp1_entity_get_pad_format(&hsit->entity, config, fmt->pad); |
85 | 85 | ||
86 | if (fmt->pad == HSIT_PAD_SOURCE) { | 86 | if (fmt->pad == HSIT_PAD_SOURCE) { |
87 | /* The HST and HSI output format code and resolution can't be | 87 | /* |
88 | * The HST and HSI output format code and resolution can't be | ||
88 | * modified. | 89 | * modified. |
89 | */ | 90 | */ |
90 | fmt->format = *format; | 91 | fmt->format = *format; |
diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c index e32acae1fc6e..702487f895b3 100644 --- a/drivers/media/platform/vsp1/vsp1_lif.c +++ b/drivers/media/platform/vsp1/vsp1_lif.c | |||
@@ -84,7 +84,8 @@ static int lif_set_format(struct v4l2_subdev *subdev, | |||
84 | format = vsp1_entity_get_pad_format(&lif->entity, config, fmt->pad); | 84 | format = vsp1_entity_get_pad_format(&lif->entity, config, fmt->pad); |
85 | 85 | ||
86 | if (fmt->pad == LIF_PAD_SOURCE) { | 86 | if (fmt->pad == LIF_PAD_SOURCE) { |
87 | /* The LIF source format is always identical to its sink | 87 | /* |
88 | * The LIF source format is always identical to its sink | ||
88 | * format. | 89 | * format. |
89 | */ | 90 | */ |
90 | fmt->format = *format; | 91 | fmt->format = *format; |
@@ -176,7 +177,8 @@ struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1) | |||
176 | lif->entity.ops = &lif_entity_ops; | 177 | lif->entity.ops = &lif_entity_ops; |
177 | lif->entity.type = VSP1_ENTITY_LIF; | 178 | lif->entity.type = VSP1_ENTITY_LIF; |
178 | 179 | ||
179 | /* The LIF is never exposed to userspace, but media entity registration | 180 | /* |
181 | * The LIF is never exposed to userspace, but media entity registration | ||
180 | * requires a function to be set. Use PROC_VIDEO_PIXEL_FORMATTER just to | 182 | * requires a function to be set. Use PROC_VIDEO_PIXEL_FORMATTER just to |
181 | * avoid triggering a WARN_ON(), the value won't be seen anywhere. | 183 | * avoid triggering a WARN_ON(), the value won't be seen anywhere. |
182 | */ | 184 | */ |
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c index 280ba0804699..edebf3fa926f 100644 --- a/drivers/media/platform/vsp1/vsp1_pipe.c +++ b/drivers/media/platform/vsp1/vsp1_pipe.c | |||
@@ -23,6 +23,8 @@ | |||
23 | #include "vsp1_bru.h" | 23 | #include "vsp1_bru.h" |
24 | #include "vsp1_dl.h" | 24 | #include "vsp1_dl.h" |
25 | #include "vsp1_entity.h" | 25 | #include "vsp1_entity.h" |
26 | #include "vsp1_hgo.h" | ||
27 | #include "vsp1_hgt.h" | ||
26 | #include "vsp1_pipe.h" | 28 | #include "vsp1_pipe.h" |
27 | #include "vsp1_rwpf.h" | 29 | #include "vsp1_rwpf.h" |
28 | #include "vsp1_uds.h" | 30 | #include "vsp1_uds.h" |
@@ -157,9 +159,15 @@ const struct vsp1_format_info *vsp1_get_format_info(struct vsp1_device *vsp1, | |||
157 | { | 159 | { |
158 | unsigned int i; | 160 | unsigned int i; |
159 | 161 | ||
160 | /* Special case, the VYUY format is supported on Gen2 only. */ | 162 | /* Special case, the VYUY and HSV formats are supported on Gen2 only. */ |
161 | if (vsp1->info->gen != 2 && fourcc == V4L2_PIX_FMT_VYUY) | 163 | if (vsp1->info->gen != 2) { |
162 | return NULL; | 164 | switch (fourcc) { |
165 | case V4L2_PIX_FMT_VYUY: | ||
166 | case V4L2_PIX_FMT_HSV24: | ||
167 | case V4L2_PIX_FMT_HSV32: | ||
168 | return NULL; | ||
169 | } | ||
170 | } | ||
163 | 171 | ||
164 | for (i = 0; i < ARRAY_SIZE(vsp1_video_formats); ++i) { | 172 | for (i = 0; i < ARRAY_SIZE(vsp1_video_formats); ++i) { |
165 | const struct vsp1_format_info *info = &vsp1_video_formats[i]; | 173 | const struct vsp1_format_info *info = &vsp1_video_formats[i]; |
@@ -198,11 +206,25 @@ void vsp1_pipeline_reset(struct vsp1_pipeline *pipe) | |||
198 | pipe->output = NULL; | 206 | pipe->output = NULL; |
199 | } | 207 | } |
200 | 208 | ||
209 | if (pipe->hgo) { | ||
210 | struct vsp1_hgo *hgo = to_hgo(&pipe->hgo->subdev); | ||
211 | |||
212 | hgo->histo.pipe = NULL; | ||
213 | } | ||
214 | |||
215 | if (pipe->hgt) { | ||
216 | struct vsp1_hgt *hgt = to_hgt(&pipe->hgt->subdev); | ||
217 | |||
218 | hgt->histo.pipe = NULL; | ||
219 | } | ||
220 | |||
201 | INIT_LIST_HEAD(&pipe->entities); | 221 | INIT_LIST_HEAD(&pipe->entities); |
202 | pipe->state = VSP1_PIPELINE_STOPPED; | 222 | pipe->state = VSP1_PIPELINE_STOPPED; |
203 | pipe->buffers_ready = 0; | 223 | pipe->buffers_ready = 0; |
204 | pipe->num_inputs = 0; | 224 | pipe->num_inputs = 0; |
205 | pipe->bru = NULL; | 225 | pipe->bru = NULL; |
226 | pipe->hgo = NULL; | ||
227 | pipe->hgt = NULL; | ||
206 | pipe->lif = NULL; | 228 | pipe->lif = NULL; |
207 | pipe->uds = NULL; | 229 | pipe->uds = NULL; |
208 | } | 230 | } |
@@ -246,16 +268,17 @@ bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe) | |||
246 | 268 | ||
247 | int vsp1_pipeline_stop(struct vsp1_pipeline *pipe) | 269 | int vsp1_pipeline_stop(struct vsp1_pipeline *pipe) |
248 | { | 270 | { |
271 | struct vsp1_device *vsp1 = pipe->output->entity.vsp1; | ||
249 | struct vsp1_entity *entity; | 272 | struct vsp1_entity *entity; |
250 | unsigned long flags; | 273 | unsigned long flags; |
251 | int ret; | 274 | int ret; |
252 | 275 | ||
253 | if (pipe->lif) { | 276 | if (pipe->lif) { |
254 | /* When using display lists in continuous frame mode the only | 277 | /* |
278 | * When using display lists in continuous frame mode the only | ||
255 | * way to stop the pipeline is to reset the hardware. | 279 | * way to stop the pipeline is to reset the hardware. |
256 | */ | 280 | */ |
257 | ret = vsp1_reset_wpf(pipe->output->entity.vsp1, | 281 | ret = vsp1_reset_wpf(vsp1, pipe->output->entity.index); |
258 | pipe->output->entity.index); | ||
259 | if (ret == 0) { | 282 | if (ret == 0) { |
260 | spin_lock_irqsave(&pipe->irqlock, flags); | 283 | spin_lock_irqsave(&pipe->irqlock, flags); |
261 | pipe->state = VSP1_PIPELINE_STOPPED; | 284 | pipe->state = VSP1_PIPELINE_STOPPED; |
@@ -275,10 +298,20 @@ int vsp1_pipeline_stop(struct vsp1_pipeline *pipe) | |||
275 | 298 | ||
276 | list_for_each_entry(entity, &pipe->entities, list_pipe) { | 299 | list_for_each_entry(entity, &pipe->entities, list_pipe) { |
277 | if (entity->route && entity->route->reg) | 300 | if (entity->route && entity->route->reg) |
278 | vsp1_write(entity->vsp1, entity->route->reg, | 301 | vsp1_write(vsp1, entity->route->reg, |
279 | VI6_DPR_NODE_UNUSED); | 302 | VI6_DPR_NODE_UNUSED); |
280 | } | 303 | } |
281 | 304 | ||
305 | if (pipe->hgo) | ||
306 | vsp1_write(vsp1, VI6_DPR_HGO_SMPPT, | ||
307 | (7 << VI6_DPR_SMPPT_TGW_SHIFT) | | ||
308 | (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT)); | ||
309 | |||
310 | if (pipe->hgt) | ||
311 | vsp1_write(vsp1, VI6_DPR_HGT_SMPPT, | ||
312 | (7 << VI6_DPR_SMPPT_TGW_SHIFT) | | ||
313 | (VI6_DPR_NODE_UNUSED << VI6_DPR_SMPPT_PT_SHIFT)); | ||
314 | |||
282 | v4l2_subdev_call(&pipe->output->entity.subdev, video, s_stream, 0); | 315 | v4l2_subdev_call(&pipe->output->entity.subdev, video, s_stream, 0); |
283 | 316 | ||
284 | return ret; | 317 | return ret; |
@@ -302,6 +335,12 @@ void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe) | |||
302 | 335 | ||
303 | vsp1_dlm_irq_frame_end(pipe->output->dlm); | 336 | vsp1_dlm_irq_frame_end(pipe->output->dlm); |
304 | 337 | ||
338 | if (pipe->hgo) | ||
339 | vsp1_hgo_frame_end(pipe->hgo); | ||
340 | |||
341 | if (pipe->hgt) | ||
342 | vsp1_hgt_frame_end(pipe->hgt); | ||
343 | |||
305 | if (pipe->frame_end) | 344 | if (pipe->frame_end) |
306 | pipe->frame_end(pipe); | 345 | pipe->frame_end(pipe); |
307 | 346 | ||
@@ -322,7 +361,8 @@ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, | |||
322 | if (!pipe->uds) | 361 | if (!pipe->uds) |
323 | return; | 362 | return; |
324 | 363 | ||
325 | /* The BRU background color has a fixed alpha value set to 255, the | 364 | /* |
365 | * The BRU background color has a fixed alpha value set to 255, the | ||
326 | * output alpha value is thus always equal to 255. | 366 | * output alpha value is thus always equal to 255. |
327 | */ | 367 | */ |
328 | if (pipe->uds_input->type == VSP1_ENTITY_BRU) | 368 | if (pipe->uds_input->type == VSP1_ENTITY_BRU) |
@@ -337,7 +377,8 @@ void vsp1_pipelines_suspend(struct vsp1_device *vsp1) | |||
337 | unsigned int i; | 377 | unsigned int i; |
338 | int ret; | 378 | int ret; |
339 | 379 | ||
340 | /* To avoid increasing the system suspend time needlessly, loop over the | 380 | /* |
381 | * To avoid increasing the system suspend time needlessly, loop over the | ||
341 | * pipelines twice, first to set them all to the stopping state, and | 382 | * pipelines twice, first to set them all to the stopping state, and |
342 | * then to wait for the stop to complete. | 383 | * then to wait for the stop to complete. |
343 | */ | 384 | */ |
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h b/drivers/media/platform/vsp1/vsp1_pipe.h index ac4ad2655551..91a784a13422 100644 --- a/drivers/media/platform/vsp1/vsp1_pipe.h +++ b/drivers/media/platform/vsp1/vsp1_pipe.h | |||
@@ -25,11 +25,12 @@ struct vsp1_rwpf; | |||
25 | 25 | ||
26 | /* | 26 | /* |
27 | * struct vsp1_format_info - VSP1 video format description | 27 | * struct vsp1_format_info - VSP1 video format description |
28 | * @mbus: media bus format code | ||
29 | * @fourcc: V4L2 pixel format FCC identifier | 28 | * @fourcc: V4L2 pixel format FCC identifier |
29 | * @mbus: media bus format code | ||
30 | * @hwfmt: VSP1 hardware format | ||
31 | * @swap: swap register control | ||
30 | * @planes: number of planes | 32 | * @planes: number of planes |
31 | * @bpp: bits per pixel | 33 | * @bpp: bits per pixel |
32 | * @hwfmt: VSP1 hardware format | ||
33 | * @swap_yc: the Y and C components are swapped (Y comes before C) | 34 | * @swap_yc: the Y and C components are swapped (Y comes before C) |
34 | * @swap_uv: the U and V components are swapped (V comes before U) | 35 | * @swap_uv: the U and V components are swapped (V comes before U) |
35 | * @hsub: horizontal subsampling factor | 36 | * @hsub: horizontal subsampling factor |
@@ -72,6 +73,8 @@ enum vsp1_pipeline_state { | |||
72 | * @inputs: array of RPFs in the pipeline (indexed by RPF index) | 73 | * @inputs: array of RPFs in the pipeline (indexed by RPF index) |
73 | * @output: WPF at the output of the pipeline | 74 | * @output: WPF at the output of the pipeline |
74 | * @bru: BRU entity, if present | 75 | * @bru: BRU entity, if present |
76 | * @hgo: HGO entity, if present | ||
77 | * @hgt: HGT entity, if present | ||
75 | * @lif: LIF entity, if present | 78 | * @lif: LIF entity, if present |
76 | * @uds: UDS entity, if present | 79 | * @uds: UDS entity, if present |
77 | * @uds_input: entity at the input of the UDS, if the UDS is present | 80 | * @uds_input: entity at the input of the UDS, if the UDS is present |
@@ -100,6 +103,8 @@ struct vsp1_pipeline { | |||
100 | struct vsp1_rwpf *inputs[VSP1_MAX_RPF]; | 103 | struct vsp1_rwpf *inputs[VSP1_MAX_RPF]; |
101 | struct vsp1_rwpf *output; | 104 | struct vsp1_rwpf *output; |
102 | struct vsp1_entity *bru; | 105 | struct vsp1_entity *bru; |
106 | struct vsp1_entity *hgo; | ||
107 | struct vsp1_entity *hgt; | ||
103 | struct vsp1_entity *lif; | 108 | struct vsp1_entity *lif; |
104 | struct vsp1_entity *uds; | 109 | struct vsp1_entity *uds; |
105 | struct vsp1_entity *uds_input; | 110 | struct vsp1_entity *uds_input; |
diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h index 47b1dee044fb..cd3e32af6e3b 100644 --- a/drivers/media/platform/vsp1/vsp1_regs.h +++ b/drivers/media/platform/vsp1/vsp1_regs.h | |||
@@ -328,8 +328,8 @@ | |||
328 | #define VI6_DPR_ROUTE_RT_MASK (0x3f << 0) | 328 | #define VI6_DPR_ROUTE_RT_MASK (0x3f << 0) |
329 | #define VI6_DPR_ROUTE_RT_SHIFT 0 | 329 | #define VI6_DPR_ROUTE_RT_SHIFT 0 |
330 | 330 | ||
331 | #define VI6_DPR_HGO_SMPPT 0x2050 | 331 | #define VI6_DPR_HGO_SMPPT 0x2054 |
332 | #define VI6_DPR_HGT_SMPPT 0x2054 | 332 | #define VI6_DPR_HGT_SMPPT 0x2058 |
333 | #define VI6_DPR_SMPPT_TGW_MASK (7 << 8) | 333 | #define VI6_DPR_SMPPT_TGW_MASK (7 << 8) |
334 | #define VI6_DPR_SMPPT_TGW_SHIFT 8 | 334 | #define VI6_DPR_SMPPT_TGW_SHIFT 8 |
335 | #define VI6_DPR_SMPPT_PT_MASK (0x3f << 0) | 335 | #define VI6_DPR_SMPPT_PT_MASK (0x3f << 0) |
@@ -590,33 +590,55 @@ | |||
590 | */ | 590 | */ |
591 | 591 | ||
592 | #define VI6_HGO_OFFSET 0x3000 | 592 | #define VI6_HGO_OFFSET 0x3000 |
593 | #define VI6_HGO_OFFSET_HOFFSET_SHIFT 16 | ||
594 | #define VI6_HGO_OFFSET_VOFFSET_SHIFT 0 | ||
593 | #define VI6_HGO_SIZE 0x3004 | 595 | #define VI6_HGO_SIZE 0x3004 |
596 | #define VI6_HGO_SIZE_HSIZE_SHIFT 16 | ||
597 | #define VI6_HGO_SIZE_VSIZE_SHIFT 0 | ||
594 | #define VI6_HGO_MODE 0x3008 | 598 | #define VI6_HGO_MODE 0x3008 |
599 | #define VI6_HGO_MODE_STEP (1 << 10) | ||
600 | #define VI6_HGO_MODE_MAXRGB (1 << 7) | ||
601 | #define VI6_HGO_MODE_OFSB_R (1 << 6) | ||
602 | #define VI6_HGO_MODE_OFSB_G (1 << 5) | ||
603 | #define VI6_HGO_MODE_OFSB_B (1 << 4) | ||
604 | #define VI6_HGO_MODE_HRATIO_SHIFT 2 | ||
605 | #define VI6_HGO_MODE_VRATIO_SHIFT 0 | ||
595 | #define VI6_HGO_LB_TH 0x300c | 606 | #define VI6_HGO_LB_TH 0x300c |
596 | #define VI6_HGO_LBn_H(n) (0x3010 + (n) * 8) | 607 | #define VI6_HGO_LBn_H(n) (0x3010 + (n) * 8) |
597 | #define VI6_HGO_LBn_V(n) (0x3014 + (n) * 8) | 608 | #define VI6_HGO_LBn_V(n) (0x3014 + (n) * 8) |
598 | #define VI6_HGO_R_HISTO 0x3030 | 609 | #define VI6_HGO_R_HISTO(n) (0x3030 + (n) * 4) |
599 | #define VI6_HGO_R_MAXMIN 0x3130 | 610 | #define VI6_HGO_R_MAXMIN 0x3130 |
600 | #define VI6_HGO_R_SUM 0x3134 | 611 | #define VI6_HGO_R_SUM 0x3134 |
601 | #define VI6_HGO_R_LB_DET 0x3138 | 612 | #define VI6_HGO_R_LB_DET 0x3138 |
602 | #define VI6_HGO_G_HISTO 0x3140 | 613 | #define VI6_HGO_G_HISTO(n) (0x3140 + (n) * 4) |
603 | #define VI6_HGO_G_MAXMIN 0x3240 | 614 | #define VI6_HGO_G_MAXMIN 0x3240 |
604 | #define VI6_HGO_G_SUM 0x3244 | 615 | #define VI6_HGO_G_SUM 0x3244 |
605 | #define VI6_HGO_G_LB_DET 0x3248 | 616 | #define VI6_HGO_G_LB_DET 0x3248 |
606 | #define VI6_HGO_B_HISTO 0x3250 | 617 | #define VI6_HGO_B_HISTO(n) (0x3250 + (n) * 4) |
607 | #define VI6_HGO_B_MAXMIN 0x3350 | 618 | #define VI6_HGO_B_MAXMIN 0x3350 |
608 | #define VI6_HGO_B_SUM 0x3354 | 619 | #define VI6_HGO_B_SUM 0x3354 |
609 | #define VI6_HGO_B_LB_DET 0x3358 | 620 | #define VI6_HGO_B_LB_DET 0x3358 |
621 | #define VI6_HGO_EXT_HIST_ADDR 0x335c | ||
622 | #define VI6_HGO_EXT_HIST_DATA 0x3360 | ||
610 | #define VI6_HGO_REGRST 0x33fc | 623 | #define VI6_HGO_REGRST 0x33fc |
624 | #define VI6_HGO_REGRST_RCLEA (1 << 0) | ||
611 | 625 | ||
612 | /* ----------------------------------------------------------------------------- | 626 | /* ----------------------------------------------------------------------------- |
613 | * HGT Control Registers | 627 | * HGT Control Registers |
614 | */ | 628 | */ |
615 | 629 | ||
616 | #define VI6_HGT_OFFSET 0x3400 | 630 | #define VI6_HGT_OFFSET 0x3400 |
631 | #define VI6_HGT_OFFSET_HOFFSET_SHIFT 16 | ||
632 | #define VI6_HGT_OFFSET_VOFFSET_SHIFT 0 | ||
617 | #define VI6_HGT_SIZE 0x3404 | 633 | #define VI6_HGT_SIZE 0x3404 |
634 | #define VI6_HGT_SIZE_HSIZE_SHIFT 16 | ||
635 | #define VI6_HGT_SIZE_VSIZE_SHIFT 0 | ||
618 | #define VI6_HGT_MODE 0x3408 | 636 | #define VI6_HGT_MODE 0x3408 |
637 | #define VI6_HGT_MODE_HRATIO_SHIFT 2 | ||
638 | #define VI6_HGT_MODE_VRATIO_SHIFT 0 | ||
619 | #define VI6_HGT_HUE_AREA(n) (0x340c + (n) * 4) | 639 | #define VI6_HGT_HUE_AREA(n) (0x340c + (n) * 4) |
640 | #define VI6_HGT_HUE_AREA_LOWER_SHIFT 16 | ||
641 | #define VI6_HGT_HUE_AREA_UPPER_SHIFT 0 | ||
620 | #define VI6_HGT_LB_TH 0x3424 | 642 | #define VI6_HGT_LB_TH 0x3424 |
621 | #define VI6_HGT_LBn_H(n) (0x3438 + (n) * 8) | 643 | #define VI6_HGT_LBn_H(n) (0x3438 + (n) * 8) |
622 | #define VI6_HGT_LBn_V(n) (0x342c + (n) * 8) | 644 | #define VI6_HGT_LBn_V(n) (0x342c + (n) * 8) |
@@ -625,6 +647,7 @@ | |||
625 | #define VI6_HGT_SUM 0x3754 | 647 | #define VI6_HGT_SUM 0x3754 |
626 | #define VI6_HGT_LB_DET 0x3758 | 648 | #define VI6_HGT_LB_DET 0x3758 |
627 | #define VI6_HGT_REGRST 0x37fc | 649 | #define VI6_HGT_REGRST 0x37fc |
650 | #define VI6_HGT_REGRST_RCLEA (1 << 0) | ||
628 | 651 | ||
629 | /* ----------------------------------------------------------------------------- | 652 | /* ----------------------------------------------------------------------------- |
630 | * LIF Control Registers | 653 | * LIF Control Registers |
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c index b2e34a800ffa..8feddd59cf8d 100644 --- a/drivers/media/platform/vsp1/vsp1_rpf.c +++ b/drivers/media/platform/vsp1/vsp1_rpf.c | |||
@@ -72,7 +72,8 @@ static void rpf_configure(struct vsp1_entity *entity, | |||
72 | } | 72 | } |
73 | 73 | ||
74 | if (params == VSP1_ENTITY_PARAMS_PARTITION) { | 74 | if (params == VSP1_ENTITY_PARAMS_PARTITION) { |
75 | unsigned int offsets[2]; | 75 | struct vsp1_device *vsp1 = rpf->entity.vsp1; |
76 | struct vsp1_rwpf_memory mem = rpf->mem; | ||
76 | struct v4l2_rect crop; | 77 | struct v4l2_rect crop; |
77 | 78 | ||
78 | /* | 79 | /* |
@@ -105,7 +106,7 @@ static void rpf_configure(struct vsp1_entity *entity, | |||
105 | * of the pipeline. | 106 | * of the pipeline. |
106 | */ | 107 | */ |
107 | output = vsp1_entity_get_pad_format(wpf, wpf->config, | 108 | output = vsp1_entity_get_pad_format(wpf, wpf->config, |
108 | RWPF_PAD_SOURCE); | 109 | RWPF_PAD_SINK); |
109 | 110 | ||
110 | crop.width = pipe->partition.width * input_width | 111 | crop.width = pipe->partition.width * input_width |
111 | / output->width; | 112 | / output->width; |
@@ -120,22 +121,30 @@ static void rpf_configure(struct vsp1_entity *entity, | |||
120 | (crop.width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) | | 121 | (crop.width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) | |
121 | (crop.height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT)); | 122 | (crop.height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT)); |
122 | 123 | ||
123 | offsets[0] = crop.top * format->plane_fmt[0].bytesperline | 124 | mem.addr[0] += crop.top * format->plane_fmt[0].bytesperline |
124 | + crop.left * fmtinfo->bpp[0] / 8; | 125 | + crop.left * fmtinfo->bpp[0] / 8; |
125 | 126 | ||
126 | if (format->num_planes > 1) | 127 | if (format->num_planes > 1) { |
127 | offsets[1] = crop.top * format->plane_fmt[1].bytesperline | 128 | unsigned int offset; |
128 | + crop.left / fmtinfo->hsub | 129 | |
129 | * fmtinfo->bpp[1] / 8; | 130 | offset = crop.top * format->plane_fmt[1].bytesperline |
130 | else | 131 | + crop.left / fmtinfo->hsub |
131 | offsets[1] = 0; | 132 | * fmtinfo->bpp[1] / 8; |
132 | 133 | mem.addr[1] += offset; | |
133 | vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_Y, | 134 | mem.addr[2] += offset; |
134 | rpf->mem.addr[0] + offsets[0]); | 135 | } |
135 | vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_C0, | 136 | |
136 | rpf->mem.addr[1] + offsets[1]); | 137 | /* |
137 | vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_C1, | 138 | * On Gen3 hardware the SPUVS bit has no effect on 3-planar |
138 | rpf->mem.addr[2] + offsets[1]); | 139 | * formats. Swap the U and V planes manually in that case. |
140 | */ | ||
141 | if (vsp1->info->gen == 3 && format->num_planes == 3 && | ||
142 | fmtinfo->swap_uv) | ||
143 | swap(mem.addr[1], mem.addr[2]); | ||
144 | |||
145 | vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_Y, mem.addr[0]); | ||
146 | vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_C0, mem.addr[1]); | ||
147 | vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_C1, mem.addr[2]); | ||
139 | return; | 148 | return; |
140 | } | 149 | } |
141 | 150 | ||
@@ -186,7 +195,8 @@ static void rpf_configure(struct vsp1_entity *entity, | |||
186 | (left << VI6_RPF_LOC_HCOORD_SHIFT) | | 195 | (left << VI6_RPF_LOC_HCOORD_SHIFT) | |
187 | (top << VI6_RPF_LOC_VCOORD_SHIFT)); | 196 | (top << VI6_RPF_LOC_VCOORD_SHIFT)); |
188 | 197 | ||
189 | /* On Gen2 use the alpha channel (extended to 8 bits) when available or | 198 | /* |
199 | * On Gen2 use the alpha channel (extended to 8 bits) when available or | ||
190 | * a fixed alpha value set through the V4L2_CID_ALPHA_COMPONENT control | 200 | * a fixed alpha value set through the V4L2_CID_ALPHA_COMPONENT control |
191 | * otherwise. | 201 | * otherwise. |
192 | * | 202 | * |
@@ -216,7 +226,8 @@ static void rpf_configure(struct vsp1_entity *entity, | |||
216 | u32 mult; | 226 | u32 mult; |
217 | 227 | ||
218 | if (fmtinfo->alpha) { | 228 | if (fmtinfo->alpha) { |
219 | /* When the input contains an alpha channel enable the | 229 | /* |
230 | * When the input contains an alpha channel enable the | ||
220 | * alpha multiplier. If the input is premultiplied we | 231 | * alpha multiplier. If the input is premultiplied we |
221 | * need to multiply both the alpha channel and the pixel | 232 | * need to multiply both the alpha channel and the pixel |
222 | * components by the global alpha value to keep them | 233 | * components by the global alpha value to keep them |
@@ -231,7 +242,8 @@ static void rpf_configure(struct vsp1_entity *entity, | |||
231 | VI6_RPF_MULT_ALPHA_P_MMD_RATIO : | 242 | VI6_RPF_MULT_ALPHA_P_MMD_RATIO : |
232 | VI6_RPF_MULT_ALPHA_P_MMD_NONE); | 243 | VI6_RPF_MULT_ALPHA_P_MMD_NONE); |
233 | } else { | 244 | } else { |
234 | /* When the input doesn't contain an alpha channel the | 245 | /* |
246 | * When the input doesn't contain an alpha channel the | ||
235 | * global alpha value is applied in the unpacking unit, | 247 | * global alpha value is applied in the unpacking unit, |
236 | * the alpha multiplier isn't needed and must be | 248 | * the alpha multiplier isn't needed and must be |
237 | * disabled. | 249 | * disabled. |
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c index 04104ef28fb5..cfd8f1904fa6 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.c +++ b/drivers/media/platform/vsp1/vsp1_rwpf.c | |||
@@ -86,7 +86,8 @@ static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, | |||
86 | format = vsp1_entity_get_pad_format(&rwpf->entity, config, fmt->pad); | 86 | format = vsp1_entity_get_pad_format(&rwpf->entity, config, fmt->pad); |
87 | 87 | ||
88 | if (fmt->pad == RWPF_PAD_SOURCE) { | 88 | if (fmt->pad == RWPF_PAD_SOURCE) { |
89 | /* The RWPF performs format conversion but can't scale, only the | 89 | /* |
90 | * The RWPF performs format conversion but can't scale, only the | ||
90 | * format code can be changed on the source pad. | 91 | * format code can be changed on the source pad. |
91 | */ | 92 | */ |
92 | format->code = fmt->format.code; | 93 | format->code = fmt->format.code; |
@@ -120,6 +121,11 @@ static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, | |||
120 | RWPF_PAD_SOURCE); | 121 | RWPF_PAD_SOURCE); |
121 | *format = fmt->format; | 122 | *format = fmt->format; |
122 | 123 | ||
124 | if (rwpf->flip.rotate) { | ||
125 | format->width = fmt->format.height; | ||
126 | format->height = fmt->format.width; | ||
127 | } | ||
128 | |||
123 | done: | 129 | done: |
124 | mutex_unlock(&rwpf->entity.lock); | 130 | mutex_unlock(&rwpf->entity.lock); |
125 | return ret; | 131 | return ret; |
@@ -205,7 +211,8 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, | |||
205 | format = vsp1_entity_get_pad_format(&rwpf->entity, config, | 211 | format = vsp1_entity_get_pad_format(&rwpf->entity, config, |
206 | RWPF_PAD_SINK); | 212 | RWPF_PAD_SINK); |
207 | 213 | ||
208 | /* Restrict the crop rectangle coordinates to multiples of 2 to avoid | 214 | /* |
215 | * Restrict the crop rectangle coordinates to multiples of 2 to avoid | ||
209 | * shifting the color plane. | 216 | * shifting the color plane. |
210 | */ | 217 | */ |
211 | if (format->code == MEDIA_BUS_FMT_AYUV8_1X32) { | 218 | if (format->code == MEDIA_BUS_FMT_AYUV8_1X32) { |
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h index 1c98aff3da5d..58215a7ab631 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.h +++ b/drivers/media/platform/vsp1/vsp1_rwpf.h | |||
@@ -56,9 +56,14 @@ struct vsp1_rwpf { | |||
56 | 56 | ||
57 | struct { | 57 | struct { |
58 | spinlock_t lock; | 58 | spinlock_t lock; |
59 | struct v4l2_ctrl *ctrls[2]; | 59 | struct { |
60 | struct v4l2_ctrl *vflip; | ||
61 | struct v4l2_ctrl *hflip; | ||
62 | struct v4l2_ctrl *rotate; | ||
63 | } ctrls; | ||
60 | unsigned int pending; | 64 | unsigned int pending; |
61 | unsigned int active; | 65 | unsigned int active; |
66 | bool rotate; | ||
62 | } flip; | 67 | } flip; |
63 | 68 | ||
64 | struct vsp1_rwpf_memory mem; | 69 | struct vsp1_rwpf_memory mem; |
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c index b4e568a3b4ed..30142793dfcd 100644 --- a/drivers/media/platform/vsp1/vsp1_sru.c +++ b/drivers/media/platform/vsp1/vsp1_sru.c | |||
@@ -191,7 +191,8 @@ static void sru_try_format(struct vsp1_sru *sru, | |||
191 | SRU_PAD_SINK); | 191 | SRU_PAD_SINK); |
192 | fmt->code = format->code; | 192 | fmt->code = format->code; |
193 | 193 | ||
194 | /* We can upscale by 2 in both direction, but not independently. | 194 | /* |
195 | * We can upscale by 2 in both direction, but not independently. | ||
195 | * Compare the input and output rectangles areas (avoiding | 196 | * Compare the input and output rectangles areas (avoiding |
196 | * integer overflows on the output): if the requested output | 197 | * integer overflows on the output): if the requested output |
197 | * area is larger than 1.5^2 the input area upscale by two, | 198 | * area is larger than 1.5^2 the input area upscale by two, |
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c index da8f89a31ea4..4226403ad235 100644 --- a/drivers/media/platform/vsp1/vsp1_uds.c +++ b/drivers/media/platform/vsp1/vsp1_uds.c | |||
@@ -293,7 +293,8 @@ static void uds_configure(struct vsp1_entity *entity, | |||
293 | 293 | ||
294 | dev_dbg(uds->entity.vsp1->dev, "hscale %u vscale %u\n", hscale, vscale); | 294 | dev_dbg(uds->entity.vsp1->dev, "hscale %u vscale %u\n", hscale, vscale); |
295 | 295 | ||
296 | /* Multi-tap scaling can't be enabled along with alpha scaling when | 296 | /* |
297 | * Multi-tap scaling can't be enabled along with alpha scaling when | ||
297 | * scaling down with a factor lower than or equal to 1/2 in either | 298 | * scaling down with a factor lower than or equal to 1/2 in either |
298 | * direction. | 299 | * direction. |
299 | */ | 300 | */ |
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index 3eaadbf7a876..eab3c3ea85d7 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c | |||
@@ -31,6 +31,8 @@ | |||
31 | #include "vsp1_bru.h" | 31 | #include "vsp1_bru.h" |
32 | #include "vsp1_dl.h" | 32 | #include "vsp1_dl.h" |
33 | #include "vsp1_entity.h" | 33 | #include "vsp1_entity.h" |
34 | #include "vsp1_hgo.h" | ||
35 | #include "vsp1_hgt.h" | ||
34 | #include "vsp1_pipe.h" | 36 | #include "vsp1_pipe.h" |
35 | #include "vsp1_rwpf.h" | 37 | #include "vsp1_rwpf.h" |
36 | #include "vsp1_uds.h" | 38 | #include "vsp1_uds.h" |
@@ -103,7 +105,8 @@ static int __vsp1_video_try_format(struct vsp1_video *video, | |||
103 | unsigned int height = pix->height; | 105 | unsigned int height = pix->height; |
104 | unsigned int i; | 106 | unsigned int i; |
105 | 107 | ||
106 | /* Backward compatibility: replace deprecated RGB formats by their XRGB | 108 | /* |
109 | * Backward compatibility: replace deprecated RGB formats by their XRGB | ||
107 | * equivalent. This selects the format older userspace applications want | 110 | * equivalent. This selects the format older userspace applications want |
108 | * while still exposing the new format. | 111 | * while still exposing the new format. |
109 | */ | 112 | */ |
@@ -114,7 +117,8 @@ static int __vsp1_video_try_format(struct vsp1_video *video, | |||
114 | } | 117 | } |
115 | } | 118 | } |
116 | 119 | ||
117 | /* Retrieve format information and select the default format if the | 120 | /* |
121 | * Retrieve format information and select the default format if the | ||
118 | * requested format isn't supported. | 122 | * requested format isn't supported. |
119 | */ | 123 | */ |
120 | info = vsp1_get_format_info(video->vsp1, pix->pixelformat); | 124 | info = vsp1_get_format_info(video->vsp1, pix->pixelformat); |
@@ -140,7 +144,8 @@ static int __vsp1_video_try_format(struct vsp1_video *video, | |||
140 | pix->height = clamp(height, VSP1_VIDEO_MIN_HEIGHT, | 144 | pix->height = clamp(height, VSP1_VIDEO_MIN_HEIGHT, |
141 | VSP1_VIDEO_MAX_HEIGHT); | 145 | VSP1_VIDEO_MAX_HEIGHT); |
142 | 146 | ||
143 | /* Compute and clamp the stride and image size. While not documented in | 147 | /* |
148 | * Compute and clamp the stride and image size. While not documented in | ||
144 | * the datasheet, strides not aligned to a multiple of 128 bytes result | 149 | * the datasheet, strides not aligned to a multiple of 128 bytes result |
145 | * in image corruption. | 150 | * in image corruption. |
146 | */ | 151 | */ |
@@ -184,9 +189,13 @@ static void vsp1_video_pipeline_setup_partitions(struct vsp1_pipeline *pipe) | |||
184 | struct vsp1_entity *entity; | 189 | struct vsp1_entity *entity; |
185 | unsigned int div_size; | 190 | unsigned int div_size; |
186 | 191 | ||
192 | /* | ||
193 | * Partitions are computed on the size before rotation, use the format | ||
194 | * at the WPF sink. | ||
195 | */ | ||
187 | format = vsp1_entity_get_pad_format(&pipe->output->entity, | 196 | format = vsp1_entity_get_pad_format(&pipe->output->entity, |
188 | pipe->output->entity.config, | 197 | pipe->output->entity.config, |
189 | RWPF_PAD_SOURCE); | 198 | RWPF_PAD_SINK); |
190 | div_size = format->width; | 199 | div_size = format->width; |
191 | 200 | ||
192 | /* Gen2 hardware doesn't require image partitioning. */ | 201 | /* Gen2 hardware doesn't require image partitioning. */ |
@@ -226,9 +235,13 @@ static struct v4l2_rect vsp1_video_partition(struct vsp1_pipeline *pipe, | |||
226 | struct v4l2_rect partition; | 235 | struct v4l2_rect partition; |
227 | unsigned int modulus; | 236 | unsigned int modulus; |
228 | 237 | ||
238 | /* | ||
239 | * Partitions are computed on the size before rotation, use the format | ||
240 | * at the WPF sink. | ||
241 | */ | ||
229 | format = vsp1_entity_get_pad_format(&pipe->output->entity, | 242 | format = vsp1_entity_get_pad_format(&pipe->output->entity, |
230 | pipe->output->entity.config, | 243 | pipe->output->entity.config, |
231 | RWPF_PAD_SOURCE); | 244 | RWPF_PAD_SINK); |
232 | 245 | ||
233 | /* A single partition simply processes the output size in full. */ | 246 | /* A single partition simply processes the output size in full. */ |
234 | if (pipe->partitions <= 1) { | 247 | if (pipe->partitions <= 1) { |
@@ -449,7 +462,8 @@ static void vsp1_video_pipeline_frame_end(struct vsp1_pipeline *pipe) | |||
449 | state = pipe->state; | 462 | state = pipe->state; |
450 | pipe->state = VSP1_PIPELINE_STOPPED; | 463 | pipe->state = VSP1_PIPELINE_STOPPED; |
451 | 464 | ||
452 | /* If a stop has been requested, mark the pipeline as stopped and | 465 | /* |
466 | * If a stop has been requested, mark the pipeline as stopped and | ||
453 | * return. Otherwise restart the pipeline if ready. | 467 | * return. Otherwise restart the pipeline if ready. |
454 | */ | 468 | */ |
455 | if (state == VSP1_PIPELINE_STOPPING) | 469 | if (state == VSP1_PIPELINE_STOPPING) |
@@ -474,7 +488,12 @@ static int vsp1_video_pipeline_build_branch(struct vsp1_pipeline *pipe, | |||
474 | if (ret < 0) | 488 | if (ret < 0) |
475 | return ret; | 489 | return ret; |
476 | 490 | ||
477 | pad = media_entity_remote_pad(&input->entity.pads[RWPF_PAD_SOURCE]); | 491 | /* |
492 | * The main data path doesn't include the HGO or HGT, use | ||
493 | * vsp1_entity_remote_pad() to traverse the graph. | ||
494 | */ | ||
495 | |||
496 | pad = vsp1_entity_remote_pad(&input->entity.pads[RWPF_PAD_SOURCE]); | ||
478 | 497 | ||
479 | while (1) { | 498 | while (1) { |
480 | if (pad == NULL) { | 499 | if (pad == NULL) { |
@@ -491,7 +510,8 @@ static int vsp1_video_pipeline_build_branch(struct vsp1_pipeline *pipe, | |||
491 | entity = to_vsp1_entity( | 510 | entity = to_vsp1_entity( |
492 | media_entity_to_v4l2_subdev(pad->entity)); | 511 | media_entity_to_v4l2_subdev(pad->entity)); |
493 | 512 | ||
494 | /* A BRU is present in the pipeline, store the BRU input pad | 513 | /* |
514 | * A BRU is present in the pipeline, store the BRU input pad | ||
495 | * number in the input RPF for use when configuring the RPF. | 515 | * number in the input RPF for use when configuring the RPF. |
496 | */ | 516 | */ |
497 | if (entity->type == VSP1_ENTITY_BRU) { | 517 | if (entity->type == VSP1_ENTITY_BRU) { |
@@ -526,13 +546,9 @@ static int vsp1_video_pipeline_build_branch(struct vsp1_pipeline *pipe, | |||
526 | : &input->entity; | 546 | : &input->entity; |
527 | } | 547 | } |
528 | 548 | ||
529 | /* Follow the source link. The link setup operations ensure | 549 | /* Follow the source link, ignoring any HGO or HGT. */ |
530 | * that the output fan-out can't be more than one, there is thus | ||
531 | * no need to verify here that only a single source link is | ||
532 | * activated. | ||
533 | */ | ||
534 | pad = &entity->pads[entity->source_pad]; | 550 | pad = &entity->pads[entity->source_pad]; |
535 | pad = media_entity_remote_pad(pad); | 551 | pad = vsp1_entity_remote_pad(pad); |
536 | } | 552 | } |
537 | 553 | ||
538 | /* The last entity must be the output WPF. */ | 554 | /* The last entity must be the output WPF. */ |
@@ -587,6 +603,16 @@ static int vsp1_video_pipeline_build(struct vsp1_pipeline *pipe, | |||
587 | pipe->lif = e; | 603 | pipe->lif = e; |
588 | } else if (e->type == VSP1_ENTITY_BRU) { | 604 | } else if (e->type == VSP1_ENTITY_BRU) { |
589 | pipe->bru = e; | 605 | pipe->bru = e; |
606 | } else if (e->type == VSP1_ENTITY_HGO) { | ||
607 | struct vsp1_hgo *hgo = to_hgo(subdev); | ||
608 | |||
609 | pipe->hgo = e; | ||
610 | hgo->histo.pipe = pipe; | ||
611 | } else if (e->type == VSP1_ENTITY_HGT) { | ||
612 | struct vsp1_hgt *hgt = to_hgt(subdev); | ||
613 | |||
614 | pipe->hgt = e; | ||
615 | hgt->histo.pipe = pipe; | ||
590 | } | 616 | } |
591 | } | 617 | } |
592 | 618 | ||
@@ -596,7 +622,8 @@ static int vsp1_video_pipeline_build(struct vsp1_pipeline *pipe, | |||
596 | if (pipe->num_inputs == 0 || !pipe->output) | 622 | if (pipe->num_inputs == 0 || !pipe->output) |
597 | return -EPIPE; | 623 | return -EPIPE; |
598 | 624 | ||
599 | /* Follow links downstream for each input and make sure the graph | 625 | /* |
626 | * Follow links downstream for each input and make sure the graph | ||
600 | * contains no loop and that all branches end at the output WPF. | 627 | * contains no loop and that all branches end at the output WPF. |
601 | */ | 628 | */ |
602 | for (i = 0; i < video->vsp1->info->rpf_count; ++i) { | 629 | for (i = 0; i < video->vsp1->info->rpf_count; ++i) { |
@@ -627,7 +654,8 @@ static struct vsp1_pipeline *vsp1_video_pipeline_get(struct vsp1_video *video) | |||
627 | struct vsp1_pipeline *pipe; | 654 | struct vsp1_pipeline *pipe; |
628 | int ret; | 655 | int ret; |
629 | 656 | ||
630 | /* Get a pipeline object for the video node. If a pipeline has already | 657 | /* |
658 | * Get a pipeline object for the video node. If a pipeline has already | ||
631 | * been allocated just increment its reference count and return it. | 659 | * been allocated just increment its reference count and return it. |
632 | * Otherwise allocate a new pipeline and initialize it, it will be freed | 660 | * Otherwise allocate a new pipeline and initialize it, it will be freed |
633 | * when the last reference is released. | 661 | * when the last reference is released. |
@@ -767,7 +795,8 @@ static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe) | |||
767 | if (pipe->uds) { | 795 | if (pipe->uds) { |
768 | struct vsp1_uds *uds = to_uds(&pipe->uds->subdev); | 796 | struct vsp1_uds *uds = to_uds(&pipe->uds->subdev); |
769 | 797 | ||
770 | /* If a BRU is present in the pipeline before the UDS, the alpha | 798 | /* |
799 | * If a BRU is present in the pipeline before the UDS, the alpha | ||
771 | * component doesn't need to be scaled as the BRU output alpha | 800 | * component doesn't need to be scaled as the BRU output alpha |
772 | * value is fixed to 255. Otherwise we need to scale the alpha | 801 | * value is fixed to 255. Otherwise we need to scale the alpha |
773 | * component only when available at the input RPF. | 802 | * component only when available at the input RPF. |
@@ -783,7 +812,7 @@ static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe) | |||
783 | } | 812 | } |
784 | 813 | ||
785 | list_for_each_entry(entity, &pipe->entities, list_pipe) { | 814 | list_for_each_entry(entity, &pipe->entities, list_pipe) { |
786 | vsp1_entity_route_setup(entity, pipe->dl); | 815 | vsp1_entity_route_setup(entity, pipe, pipe->dl); |
787 | 816 | ||
788 | if (entity->ops->configure) | 817 | if (entity->ops->configure) |
789 | entity->ops->configure(entity, pipe, pipe->dl, | 818 | entity->ops->configure(entity, pipe, pipe->dl, |
@@ -797,6 +826,7 @@ static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count) | |||
797 | { | 826 | { |
798 | struct vsp1_video *video = vb2_get_drv_priv(vq); | 827 | struct vsp1_video *video = vb2_get_drv_priv(vq); |
799 | struct vsp1_pipeline *pipe = video->rwpf->pipe; | 828 | struct vsp1_pipeline *pipe = video->rwpf->pipe; |
829 | bool start_pipeline = false; | ||
800 | unsigned long flags; | 830 | unsigned long flags; |
801 | int ret; | 831 | int ret; |
802 | 832 | ||
@@ -807,11 +837,23 @@ static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count) | |||
807 | mutex_unlock(&pipe->lock); | 837 | mutex_unlock(&pipe->lock); |
808 | return ret; | 838 | return ret; |
809 | } | 839 | } |
840 | |||
841 | start_pipeline = true; | ||
810 | } | 842 | } |
811 | 843 | ||
812 | pipe->stream_count++; | 844 | pipe->stream_count++; |
813 | mutex_unlock(&pipe->lock); | 845 | mutex_unlock(&pipe->lock); |
814 | 846 | ||
847 | /* | ||
848 | * vsp1_pipeline_ready() is not sufficient to establish that all streams | ||
849 | * are prepared and the pipeline is configured, as multiple streams | ||
850 | * can race through streamon with buffers already queued; Therefore we | ||
851 | * don't even attempt to start the pipeline until the last stream has | ||
852 | * called through here. | ||
853 | */ | ||
854 | if (!start_pipeline) | ||
855 | return 0; | ||
856 | |||
815 | spin_lock_irqsave(&pipe->irqlock, flags); | 857 | spin_lock_irqsave(&pipe->irqlock, flags); |
816 | if (vsp1_pipeline_ready(pipe)) | 858 | if (vsp1_pipeline_ready(pipe)) |
817 | vsp1_video_pipeline_run(pipe); | 859 | vsp1_video_pipeline_run(pipe); |
@@ -968,7 +1010,8 @@ vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) | |||
968 | if (video->queue.owner && video->queue.owner != file->private_data) | 1010 | if (video->queue.owner && video->queue.owner != file->private_data) |
969 | return -EBUSY; | 1011 | return -EBUSY; |
970 | 1012 | ||
971 | /* Get a pipeline for the video node and start streaming on it. No link | 1013 | /* |
1014 | * Get a pipeline for the video node and start streaming on it. No link | ||
972 | * touching an entity in the pipeline can be activated or deactivated | 1015 | * touching an entity in the pipeline can be activated or deactivated |
973 | * once streaming is started. | 1016 | * once streaming is started. |
974 | */ | 1017 | */ |
@@ -988,7 +1031,8 @@ vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) | |||
988 | 1031 | ||
989 | mutex_unlock(&mdev->graph_mutex); | 1032 | mutex_unlock(&mdev->graph_mutex); |
990 | 1033 | ||
991 | /* Verify that the configured format matches the output of the connected | 1034 | /* |
1035 | * Verify that the configured format matches the output of the connected | ||
992 | * subdev. | 1036 | * subdev. |
993 | */ | 1037 | */ |
994 | ret = vsp1_video_verify_format(video); | 1038 | ret = vsp1_video_verify_format(video); |
@@ -1050,6 +1094,7 @@ static int vsp1_video_open(struct file *file) | |||
1050 | ret = vsp1_device_get(video->vsp1); | 1094 | ret = vsp1_device_get(video->vsp1); |
1051 | if (ret < 0) { | 1095 | if (ret < 0) { |
1052 | v4l2_fh_del(vfh); | 1096 | v4l2_fh_del(vfh); |
1097 | v4l2_fh_exit(vfh); | ||
1053 | kfree(vfh); | 1098 | kfree(vfh); |
1054 | } | 1099 | } |
1055 | 1100 | ||
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c index 7c48f81cd5c1..32df109b119f 100644 --- a/drivers/media/platform/vsp1/vsp1_wpf.c +++ b/drivers/media/platform/vsp1/vsp1_wpf.c | |||
@@ -43,32 +43,90 @@ static inline void vsp1_wpf_write(struct vsp1_rwpf *wpf, | |||
43 | enum wpf_flip_ctrl { | 43 | enum wpf_flip_ctrl { |
44 | WPF_CTRL_VFLIP = 0, | 44 | WPF_CTRL_VFLIP = 0, |
45 | WPF_CTRL_HFLIP = 1, | 45 | WPF_CTRL_HFLIP = 1, |
46 | WPF_CTRL_MAX, | ||
47 | }; | 46 | }; |
48 | 47 | ||
48 | static int vsp1_wpf_set_rotation(struct vsp1_rwpf *wpf, unsigned int rotation) | ||
49 | { | ||
50 | struct vsp1_video *video = wpf->video; | ||
51 | struct v4l2_mbus_framefmt *sink_format; | ||
52 | struct v4l2_mbus_framefmt *source_format; | ||
53 | bool rotate; | ||
54 | int ret = 0; | ||
55 | |||
56 | /* | ||
57 | * Only consider the 0°/180° from/to 90°/270° modifications, the rest | ||
58 | * is taken care of by the flipping configuration. | ||
59 | */ | ||
60 | rotate = rotation == 90 || rotation == 270; | ||
61 | if (rotate == wpf->flip.rotate) | ||
62 | return 0; | ||
63 | |||
64 | /* Changing rotation isn't allowed when buffers are allocated. */ | ||
65 | mutex_lock(&video->lock); | ||
66 | |||
67 | if (vb2_is_busy(&video->queue)) { | ||
68 | ret = -EBUSY; | ||
69 | goto done; | ||
70 | } | ||
71 | |||
72 | sink_format = vsp1_entity_get_pad_format(&wpf->entity, | ||
73 | wpf->entity.config, | ||
74 | RWPF_PAD_SINK); | ||
75 | source_format = vsp1_entity_get_pad_format(&wpf->entity, | ||
76 | wpf->entity.config, | ||
77 | RWPF_PAD_SOURCE); | ||
78 | |||
79 | mutex_lock(&wpf->entity.lock); | ||
80 | |||
81 | if (rotate) { | ||
82 | source_format->width = sink_format->height; | ||
83 | source_format->height = sink_format->width; | ||
84 | } else { | ||
85 | source_format->width = sink_format->width; | ||
86 | source_format->height = sink_format->height; | ||
87 | } | ||
88 | |||
89 | wpf->flip.rotate = rotate; | ||
90 | |||
91 | mutex_unlock(&wpf->entity.lock); | ||
92 | |||
93 | done: | ||
94 | mutex_unlock(&video->lock); | ||
95 | return ret; | ||
96 | } | ||
97 | |||
49 | static int vsp1_wpf_s_ctrl(struct v4l2_ctrl *ctrl) | 98 | static int vsp1_wpf_s_ctrl(struct v4l2_ctrl *ctrl) |
50 | { | 99 | { |
51 | struct vsp1_rwpf *wpf = | 100 | struct vsp1_rwpf *wpf = |
52 | container_of(ctrl->handler, struct vsp1_rwpf, ctrls); | 101 | container_of(ctrl->handler, struct vsp1_rwpf, ctrls); |
53 | unsigned int i; | 102 | unsigned int rotation; |
54 | u32 flip = 0; | 103 | u32 flip = 0; |
104 | int ret; | ||
55 | 105 | ||
56 | switch (ctrl->id) { | 106 | /* Update the rotation. */ |
57 | case V4L2_CID_HFLIP: | 107 | rotation = wpf->flip.ctrls.rotate ? wpf->flip.ctrls.rotate->val : 0; |
58 | case V4L2_CID_VFLIP: | 108 | ret = vsp1_wpf_set_rotation(wpf, rotation); |
59 | for (i = 0; i < WPF_CTRL_MAX; ++i) { | 109 | if (ret < 0) |
60 | if (wpf->flip.ctrls[i]) | 110 | return ret; |
61 | flip |= wpf->flip.ctrls[i]->val ? BIT(i) : 0; | ||
62 | } | ||
63 | 111 | ||
64 | spin_lock_irq(&wpf->flip.lock); | 112 | /* |
65 | wpf->flip.pending = flip; | 113 | * Compute the flip value resulting from all three controls, with |
66 | spin_unlock_irq(&wpf->flip.lock); | 114 | * rotation by 180° flipping the image in both directions. Store the |
67 | break; | 115 | * result in the pending flip field for the next frame that will be |
116 | * processed. | ||
117 | */ | ||
118 | if (wpf->flip.ctrls.vflip->val) | ||
119 | flip |= BIT(WPF_CTRL_VFLIP); | ||
68 | 120 | ||
69 | default: | 121 | if (wpf->flip.ctrls.hflip && wpf->flip.ctrls.hflip->val) |
70 | return -EINVAL; | 122 | flip |= BIT(WPF_CTRL_HFLIP); |
71 | } | 123 | |
124 | if (rotation == 180 || rotation == 270) | ||
125 | flip ^= BIT(WPF_CTRL_VFLIP) | BIT(WPF_CTRL_HFLIP); | ||
126 | |||
127 | spin_lock_irq(&wpf->flip.lock); | ||
128 | wpf->flip.pending = flip; | ||
129 | spin_unlock_irq(&wpf->flip.lock); | ||
72 | 130 | ||
73 | return 0; | 131 | return 0; |
74 | } | 132 | } |
@@ -88,12 +146,14 @@ static int wpf_init_controls(struct vsp1_rwpf *wpf) | |||
88 | /* Only WPF0 supports flipping. */ | 146 | /* Only WPF0 supports flipping. */ |
89 | num_flip_ctrls = 0; | 147 | num_flip_ctrls = 0; |
90 | } else if (vsp1->info->features & VSP1_HAS_WPF_HFLIP) { | 148 | } else if (vsp1->info->features & VSP1_HAS_WPF_HFLIP) { |
91 | /* When horizontal flip is supported the WPF implements two | 149 | /* |
92 | * controls (horizontal flip and vertical flip). | 150 | * When horizontal flip is supported the WPF implements three |
151 | * controls (horizontal flip, vertical flip and rotation). | ||
93 | */ | 152 | */ |
94 | num_flip_ctrls = 2; | 153 | num_flip_ctrls = 3; |
95 | } else if (vsp1->info->features & VSP1_HAS_WPF_VFLIP) { | 154 | } else if (vsp1->info->features & VSP1_HAS_WPF_VFLIP) { |
96 | /* When only vertical flip is supported the WPF implements a | 155 | /* |
156 | * When only vertical flip is supported the WPF implements a | ||
97 | * single control (vertical flip). | 157 | * single control (vertical flip). |
98 | */ | 158 | */ |
99 | num_flip_ctrls = 1; | 159 | num_flip_ctrls = 1; |
@@ -105,17 +165,19 @@ static int wpf_init_controls(struct vsp1_rwpf *wpf) | |||
105 | vsp1_rwpf_init_ctrls(wpf, num_flip_ctrls); | 165 | vsp1_rwpf_init_ctrls(wpf, num_flip_ctrls); |
106 | 166 | ||
107 | if (num_flip_ctrls >= 1) { | 167 | if (num_flip_ctrls >= 1) { |
108 | wpf->flip.ctrls[WPF_CTRL_VFLIP] = | 168 | wpf->flip.ctrls.vflip = |
109 | v4l2_ctrl_new_std(&wpf->ctrls, &vsp1_wpf_ctrl_ops, | 169 | v4l2_ctrl_new_std(&wpf->ctrls, &vsp1_wpf_ctrl_ops, |
110 | V4L2_CID_VFLIP, 0, 1, 1, 0); | 170 | V4L2_CID_VFLIP, 0, 1, 1, 0); |
111 | } | 171 | } |
112 | 172 | ||
113 | if (num_flip_ctrls == 2) { | 173 | if (num_flip_ctrls == 3) { |
114 | wpf->flip.ctrls[WPF_CTRL_HFLIP] = | 174 | wpf->flip.ctrls.hflip = |
115 | v4l2_ctrl_new_std(&wpf->ctrls, &vsp1_wpf_ctrl_ops, | 175 | v4l2_ctrl_new_std(&wpf->ctrls, &vsp1_wpf_ctrl_ops, |
116 | V4L2_CID_HFLIP, 0, 1, 1, 0); | 176 | V4L2_CID_HFLIP, 0, 1, 1, 0); |
117 | 177 | wpf->flip.ctrls.rotate = | |
118 | v4l2_ctrl_cluster(2, wpf->flip.ctrls); | 178 | v4l2_ctrl_new_std(&wpf->ctrls, &vsp1_wpf_ctrl_ops, |
179 | V4L2_CID_ROTATE, 0, 270, 90, 0); | ||
180 | v4l2_ctrl_cluster(3, &wpf->flip.ctrls.vflip); | ||
119 | } | 181 | } |
120 | 182 | ||
121 | if (wpf->ctrls.error) { | 183 | if (wpf->ctrls.error) { |
@@ -139,7 +201,8 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable) | |||
139 | if (enable) | 201 | if (enable) |
140 | return 0; | 202 | return 0; |
141 | 203 | ||
142 | /* Write to registers directly when stopping the stream as there will be | 204 | /* |
205 | * Write to registers directly when stopping the stream as there will be | ||
143 | * no pipeline run to apply the display list. | 206 | * no pipeline run to apply the display list. |
144 | */ | 207 | */ |
145 | vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index), 0); | 208 | vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index), 0); |
@@ -216,10 +279,11 @@ static void wpf_configure(struct vsp1_entity *entity, | |||
216 | 279 | ||
217 | if (params == VSP1_ENTITY_PARAMS_PARTITION) { | 280 | if (params == VSP1_ENTITY_PARAMS_PARTITION) { |
218 | const struct v4l2_pix_format_mplane *format = &wpf->format; | 281 | const struct v4l2_pix_format_mplane *format = &wpf->format; |
282 | const struct vsp1_format_info *fmtinfo = wpf->fmtinfo; | ||
219 | struct vsp1_rwpf_memory mem = wpf->mem; | 283 | struct vsp1_rwpf_memory mem = wpf->mem; |
220 | unsigned int flip = wpf->flip.active; | 284 | unsigned int flip = wpf->flip.active; |
221 | unsigned int width = source_format->width; | 285 | unsigned int width = sink_format->width; |
222 | unsigned int height = source_format->height; | 286 | unsigned int height = sink_format->height; |
223 | unsigned int offset; | 287 | unsigned int offset; |
224 | 288 | ||
225 | /* | 289 | /* |
@@ -242,45 +306,86 @@ static void wpf_configure(struct vsp1_entity *entity, | |||
242 | /* | 306 | /* |
243 | * Update the memory offsets based on flipping configuration. | 307 | * Update the memory offsets based on flipping configuration. |
244 | * The destination addresses point to the locations where the | 308 | * The destination addresses point to the locations where the |
245 | * VSP starts writing to memory, which can be different corners | 309 | * VSP starts writing to memory, which can be any corner of the |
246 | * of the image depending on vertical flipping. | 310 | * image depending on the combination of flipping and rotation. |
247 | */ | 311 | */ |
248 | if (pipe->partitions > 1) { | ||
249 | const struct vsp1_format_info *fmtinfo = wpf->fmtinfo; | ||
250 | 312 | ||
251 | /* | 313 | /* |
252 | * Horizontal flipping is handled through a line buffer | 314 | * First take the partition left coordinate into account. |
253 | * and doesn't modify the start address, but still needs | 315 | * Compute the offset to order the partitions correctly on the |
254 | * to be handled when image partitioning is in effect to | 316 | * output based on whether flipping is enabled. Consider |
255 | * order the partitions correctly. | 317 | * horizontal flipping when rotation is disabled but vertical |
256 | */ | 318 | * flipping when rotation is enabled, as rotating the image |
257 | if (flip & BIT(WPF_CTRL_HFLIP)) | 319 | * switches the horizontal and vertical directions. The offset |
258 | offset = format->width - pipe->partition.left | 320 | * is applied horizontally or vertically accordingly. |
259 | - pipe->partition.width; | 321 | */ |
322 | if (flip & BIT(WPF_CTRL_HFLIP) && !wpf->flip.rotate) | ||
323 | offset = format->width - pipe->partition.left | ||
324 | - pipe->partition.width; | ||
325 | else if (flip & BIT(WPF_CTRL_VFLIP) && wpf->flip.rotate) | ||
326 | offset = format->height - pipe->partition.left | ||
327 | - pipe->partition.width; | ||
328 | else | ||
329 | offset = pipe->partition.left; | ||
330 | |||
331 | for (i = 0; i < format->num_planes; ++i) { | ||
332 | unsigned int hsub = i > 0 ? fmtinfo->hsub : 1; | ||
333 | unsigned int vsub = i > 0 ? fmtinfo->vsub : 1; | ||
334 | |||
335 | if (wpf->flip.rotate) | ||
336 | mem.addr[i] += offset / vsub | ||
337 | * format->plane_fmt[i].bytesperline; | ||
260 | else | 338 | else |
261 | offset = pipe->partition.left; | 339 | mem.addr[i] += offset / hsub |
262 | 340 | * fmtinfo->bpp[i] / 8; | |
263 | mem.addr[0] += offset * fmtinfo->bpp[0] / 8; | ||
264 | if (format->num_planes > 1) { | ||
265 | mem.addr[1] += offset / fmtinfo->hsub | ||
266 | * fmtinfo->bpp[1] / 8; | ||
267 | mem.addr[2] += offset / fmtinfo->hsub | ||
268 | * fmtinfo->bpp[2] / 8; | ||
269 | } | ||
270 | } | 341 | } |
271 | 342 | ||
272 | if (flip & BIT(WPF_CTRL_VFLIP)) { | 343 | if (flip & BIT(WPF_CTRL_VFLIP)) { |
273 | mem.addr[0] += (format->height - 1) | 344 | /* |
345 | * When rotating the output (after rotation) image | ||
346 | * height is equal to the partition width (before | ||
347 | * rotation). Otherwise it is equal to the output | ||
348 | * image height. | ||
349 | */ | ||
350 | if (wpf->flip.rotate) | ||
351 | height = pipe->partition.width; | ||
352 | else | ||
353 | height = format->height; | ||
354 | |||
355 | mem.addr[0] += (height - 1) | ||
274 | * format->plane_fmt[0].bytesperline; | 356 | * format->plane_fmt[0].bytesperline; |
275 | 357 | ||
276 | if (format->num_planes > 1) { | 358 | if (format->num_planes > 1) { |
277 | offset = (format->height / wpf->fmtinfo->vsub - 1) | 359 | offset = (height / fmtinfo->vsub - 1) |
278 | * format->plane_fmt[1].bytesperline; | 360 | * format->plane_fmt[1].bytesperline; |
279 | mem.addr[1] += offset; | 361 | mem.addr[1] += offset; |
280 | mem.addr[2] += offset; | 362 | mem.addr[2] += offset; |
281 | } | 363 | } |
282 | } | 364 | } |
283 | 365 | ||
366 | if (wpf->flip.rotate && !(flip & BIT(WPF_CTRL_HFLIP))) { | ||
367 | unsigned int hoffset = max(0, (int)format->width - 16); | ||
368 | |||
369 | /* | ||
370 | * Compute the output coordinate. The partition | ||
371 | * horizontal (left) offset becomes a vertical offset. | ||
372 | */ | ||
373 | for (i = 0; i < format->num_planes; ++i) { | ||
374 | unsigned int hsub = i > 0 ? fmtinfo->hsub : 1; | ||
375 | |||
376 | mem.addr[i] += hoffset / hsub | ||
377 | * fmtinfo->bpp[i] / 8; | ||
378 | } | ||
379 | } | ||
380 | |||
381 | /* | ||
382 | * On Gen3 hardware the SPUVS bit has no effect on 3-planar | ||
383 | * formats. Swap the U and V planes manually in that case. | ||
384 | */ | ||
385 | if (vsp1->info->gen == 3 && format->num_planes == 3 && | ||
386 | fmtinfo->swap_uv) | ||
387 | swap(mem.addr[1], mem.addr[2]); | ||
388 | |||
284 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_Y, mem.addr[0]); | 389 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_Y, mem.addr[0]); |
285 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C0, mem.addr[1]); | 390 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C0, mem.addr[1]); |
286 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C1, mem.addr[2]); | 391 | vsp1_wpf_write(wpf, dl, VI6_WPF_DSTM_ADDR_C1, mem.addr[2]); |
@@ -294,6 +399,9 @@ static void wpf_configure(struct vsp1_entity *entity, | |||
294 | 399 | ||
295 | outfmt = fmtinfo->hwfmt << VI6_WPF_OUTFMT_WRFMT_SHIFT; | 400 | outfmt = fmtinfo->hwfmt << VI6_WPF_OUTFMT_WRFMT_SHIFT; |
296 | 401 | ||
402 | if (wpf->flip.rotate) | ||
403 | outfmt |= VI6_WPF_OUTFMT_ROT; | ||
404 | |||
297 | if (fmtinfo->alpha) | 405 | if (fmtinfo->alpha) |
298 | outfmt |= VI6_WPF_OUTFMT_PXA; | 406 | outfmt |= VI6_WPF_OUTFMT_PXA; |
299 | if (fmtinfo->swap_yc) | 407 | if (fmtinfo->swap_yc) |
@@ -327,7 +435,8 @@ static void wpf_configure(struct vsp1_entity *entity, | |||
327 | 435 | ||
328 | vsp1_dl_list_write(dl, VI6_WPF_WRBCK_CTRL, 0); | 436 | vsp1_dl_list_write(dl, VI6_WPF_WRBCK_CTRL, 0); |
329 | 437 | ||
330 | /* Sources. If the pipeline has a single input and BRU is not used, | 438 | /* |
439 | * Sources. If the pipeline has a single input and BRU is not used, | ||
331 | * configure it as the master layer. Otherwise configure all | 440 | * configure it as the master layer. Otherwise configure all |
332 | * inputs as sub-layers and select the virtual RPF as the master | 441 | * inputs as sub-layers and select the virtual RPF as the master |
333 | * layer. | 442 | * layer. |
@@ -354,9 +463,18 @@ static void wpf_configure(struct vsp1_entity *entity, | |||
354 | VI6_WFP_IRQ_ENB_DFEE); | 463 | VI6_WFP_IRQ_ENB_DFEE); |
355 | } | 464 | } |
356 | 465 | ||
466 | static unsigned int wpf_max_width(struct vsp1_entity *entity, | ||
467 | struct vsp1_pipeline *pipe) | ||
468 | { | ||
469 | struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev); | ||
470 | |||
471 | return wpf->flip.rotate ? 256 : wpf->max_width; | ||
472 | } | ||
473 | |||
357 | static const struct vsp1_entity_operations wpf_entity_ops = { | 474 | static const struct vsp1_entity_operations wpf_entity_ops = { |
358 | .destroy = vsp1_wpf_destroy, | 475 | .destroy = vsp1_wpf_destroy, |
359 | .configure = wpf_configure, | 476 | .configure = wpf_configure, |
477 | .max_width = wpf_max_width, | ||
360 | }; | 478 | }; |
361 | 479 | ||
362 | /* ----------------------------------------------------------------------------- | 480 | /* ----------------------------------------------------------------------------- |
diff --git a/drivers/media/radio/si4713/si4713.c b/drivers/media/radio/si4713/si4713.c index 60f026a58076..f4a53f1e856e 100644 --- a/drivers/media/radio/si4713/si4713.c +++ b/drivers/media/radio/si4713/si4713.c | |||
@@ -1656,9 +1656,18 @@ static const struct i2c_device_id si4713_id[] = { | |||
1656 | }; | 1656 | }; |
1657 | MODULE_DEVICE_TABLE(i2c, si4713_id); | 1657 | MODULE_DEVICE_TABLE(i2c, si4713_id); |
1658 | 1658 | ||
1659 | #if IS_ENABLED(CONFIG_OF) | ||
1660 | static const struct of_device_id si4713_of_match[] = { | ||
1661 | { .compatible = "silabs,si4713" }, | ||
1662 | { }, | ||
1663 | }; | ||
1664 | MODULE_DEVICE_TABLE(of, si4713_of_match); | ||
1665 | #endif | ||
1666 | |||
1659 | static struct i2c_driver si4713_i2c_driver = { | 1667 | static struct i2c_driver si4713_i2c_driver = { |
1660 | .driver = { | 1668 | .driver = { |
1661 | .name = "si4713", | 1669 | .name = "si4713", |
1670 | .of_match_table = of_match_ptr(si4713_of_match), | ||
1662 | }, | 1671 | }, |
1663 | .probe = si4713_probe, | 1672 | .probe = si4713_probe, |
1664 | .remove = si4713_remove, | 1673 | .remove = si4713_remove, |
diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c index 74a1b3ecb30a..588e2d61c3b4 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.c +++ b/drivers/media/radio/wl128x/fmdrv_common.c | |||
@@ -1550,9 +1550,8 @@ int fmc_prepare(struct fmdev *fmdev) | |||
1550 | atomic_set(&fmdev->tx_cnt, 1); | 1550 | atomic_set(&fmdev->tx_cnt, 1); |
1551 | fmdev->resp_comp = NULL; | 1551 | fmdev->resp_comp = NULL; |
1552 | 1552 | ||
1553 | init_timer(&fmdev->irq_info.timer); | 1553 | setup_timer(&fmdev->irq_info.timer, &int_timeout_handler, |
1554 | fmdev->irq_info.timer.function = &int_timeout_handler; | 1554 | (unsigned long)fmdev); |
1555 | fmdev->irq_info.timer.data = (unsigned long)fmdev; | ||
1556 | /*TODO: add FM_STIC_EVENT later */ | 1555 | /*TODO: add FM_STIC_EVENT later */ |
1557 | fmdev->irq_info.mask = FM_MAL_EVENT; | 1556 | fmdev->irq_info.mask = FM_MAL_EVENT; |
1558 | 1557 | ||
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index d1d3fd00ed89..e422f3d56f76 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig | |||
@@ -426,4 +426,13 @@ config IR_SERIAL_TRANSMITTER | |||
426 | ---help--- | 426 | ---help--- |
427 | Serial Port Transmitter support | 427 | Serial Port Transmitter support |
428 | 428 | ||
429 | config IR_SIR | ||
430 | tristate "Built-in SIR IrDA port" | ||
431 | depends on RC_CORE | ||
432 | ---help--- | ||
433 | Say Y if you want to use a IrDA SIR port Transceivers. | ||
434 | |||
435 | To compile this driver as a module, choose M here: the module will | ||
436 | be called sir-ir. | ||
437 | |||
429 | endif #RC_DEVICES | 438 | endif #RC_DEVICES |
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index 679aa0af85cd..245e2c2d0b22 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile | |||
@@ -39,4 +39,5 @@ obj-$(CONFIG_RC_ST) += st_rc.o | |||
39 | obj-$(CONFIG_IR_SUNXI) += sunxi-cir.o | 39 | obj-$(CONFIG_IR_SUNXI) += sunxi-cir.o |
40 | obj-$(CONFIG_IR_IMG) += img-ir/ | 40 | obj-$(CONFIG_IR_IMG) += img-ir/ |
41 | obj-$(CONFIG_IR_SERIAL) += serial_ir.o | 41 | obj-$(CONFIG_IR_SERIAL) += serial_ir.o |
42 | obj-$(CONFIG_IR_SIR) += sir_ir.o | ||
42 | obj-$(CONFIG_IR_MTK) += mtk-cir.o | 43 | obj-$(CONFIG_IR_MTK) += mtk-cir.o |
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c index 4a4895e4d599..b4f773b9dc1d 100644 --- a/drivers/media/rc/gpio-ir-recv.c +++ b/drivers/media/rc/gpio-ir-recv.c | |||
@@ -158,7 +158,7 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) | |||
158 | rcdev->input_id.version = 0x0100; | 158 | rcdev->input_id.version = 0x0100; |
159 | rcdev->dev.parent = &pdev->dev; | 159 | rcdev->dev.parent = &pdev->dev; |
160 | rcdev->driver_name = GPIO_IR_DRIVER_NAME; | 160 | rcdev->driver_name = GPIO_IR_DRIVER_NAME; |
161 | rcdev->min_timeout = 0; | 161 | rcdev->min_timeout = 1; |
162 | rcdev->timeout = IR_DEFAULT_TIMEOUT; | 162 | rcdev->timeout = IR_DEFAULT_TIMEOUT; |
163 | rcdev->max_timeout = 10 * IR_DEFAULT_TIMEOUT; | 163 | rcdev->max_timeout = 10 * IR_DEFAULT_TIMEOUT; |
164 | if (pdata->allowed_protos) | 164 | if (pdata->allowed_protos) |
diff --git a/drivers/media/rc/igorplugusb.c b/drivers/media/rc/igorplugusb.c index 0f0ed4ea4d06..cb6d4f1247da 100644 --- a/drivers/media/rc/igorplugusb.c +++ b/drivers/media/rc/igorplugusb.c | |||
@@ -205,7 +205,7 @@ static int igorplugusb_probe(struct usb_interface *intf, | |||
205 | rc->allowed_protocols = RC_BIT_ALL_IR_DECODER & ~(RC_BIT_NEC | | 205 | rc->allowed_protocols = RC_BIT_ALL_IR_DECODER & ~(RC_BIT_NEC | |
206 | RC_BIT_NECX | RC_BIT_NEC32 | RC_BIT_RC6_6A_20 | | 206 | RC_BIT_NECX | RC_BIT_NEC32 | RC_BIT_RC6_6A_20 | |
207 | RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE | | 207 | RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE | |
208 | RC_BIT_SONY20 | RC_BIT_MCE_KBD | RC_BIT_SANYO); | 208 | RC_BIT_SONY20 | RC_BIT_SANYO); |
209 | 209 | ||
210 | rc->priv = ir; | 210 | rc->priv = ir; |
211 | rc->driver_name = DRIVER_NAME; | 211 | rc->driver_name = DRIVER_NAME; |
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 89823d24a384..3489010601b5 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c | |||
@@ -2412,9 +2412,8 @@ static struct imon_context *imon_init_intf1(struct usb_interface *intf, | |||
2412 | mutex_lock(&ictx->lock); | 2412 | mutex_lock(&ictx->lock); |
2413 | 2413 | ||
2414 | if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) { | 2414 | if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) { |
2415 | init_timer(&ictx->ttimer); | 2415 | setup_timer(&ictx->ttimer, imon_touch_display_timeout, |
2416 | ictx->ttimer.data = (unsigned long)ictx; | 2416 | (unsigned long)ictx); |
2417 | ictx->ttimer.function = imon_touch_display_timeout; | ||
2418 | } | 2417 | } |
2419 | 2418 | ||
2420 | ictx->usbdev_intf1 = usb_get_dev(interface_to_usbdev(intf)); | 2419 | ictx->usbdev_intf1 = usb_get_dev(interface_to_usbdev(intf)); |
diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index 8517d5153fcf..de85f1d7ce43 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c | |||
@@ -139,7 +139,7 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, | |||
139 | } | 139 | } |
140 | 140 | ||
141 | if (!dev->tx_ir) { | 141 | if (!dev->tx_ir) { |
142 | ret = -ENOSYS; | 142 | ret = -EINVAL; |
143 | goto out; | 143 | goto out; |
144 | } | 144 | } |
145 | 145 | ||
@@ -221,19 +221,19 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, | |||
221 | /* TX settings */ | 221 | /* TX settings */ |
222 | case LIRC_SET_TRANSMITTER_MASK: | 222 | case LIRC_SET_TRANSMITTER_MASK: |
223 | if (!dev->s_tx_mask) | 223 | if (!dev->s_tx_mask) |
224 | return -ENOSYS; | 224 | return -ENOTTY; |
225 | 225 | ||
226 | return dev->s_tx_mask(dev, val); | 226 | return dev->s_tx_mask(dev, val); |
227 | 227 | ||
228 | case LIRC_SET_SEND_CARRIER: | 228 | case LIRC_SET_SEND_CARRIER: |
229 | if (!dev->s_tx_carrier) | 229 | if (!dev->s_tx_carrier) |
230 | return -ENOSYS; | 230 | return -ENOTTY; |
231 | 231 | ||
232 | return dev->s_tx_carrier(dev, val); | 232 | return dev->s_tx_carrier(dev, val); |
233 | 233 | ||
234 | case LIRC_SET_SEND_DUTY_CYCLE: | 234 | case LIRC_SET_SEND_DUTY_CYCLE: |
235 | if (!dev->s_tx_duty_cycle) | 235 | if (!dev->s_tx_duty_cycle) |
236 | return -ENOSYS; | 236 | return -ENOTTY; |
237 | 237 | ||
238 | if (val <= 0 || val >= 100) | 238 | if (val <= 0 || val >= 100) |
239 | return -EINVAL; | 239 | return -EINVAL; |
@@ -243,7 +243,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, | |||
243 | /* RX settings */ | 243 | /* RX settings */ |
244 | case LIRC_SET_REC_CARRIER: | 244 | case LIRC_SET_REC_CARRIER: |
245 | if (!dev->s_rx_carrier_range) | 245 | if (!dev->s_rx_carrier_range) |
246 | return -ENOSYS; | 246 | return -ENOTTY; |
247 | 247 | ||
248 | if (val <= 0) | 248 | if (val <= 0) |
249 | return -EINVAL; | 249 | return -EINVAL; |
@@ -253,6 +253,9 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, | |||
253 | val); | 253 | val); |
254 | 254 | ||
255 | case LIRC_SET_REC_CARRIER_RANGE: | 255 | case LIRC_SET_REC_CARRIER_RANGE: |
256 | if (!dev->s_rx_carrier_range) | ||
257 | return -ENOTTY; | ||
258 | |||
256 | if (val <= 0) | 259 | if (val <= 0) |
257 | return -EINVAL; | 260 | return -EINVAL; |
258 | 261 | ||
@@ -260,37 +263,40 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, | |||
260 | return 0; | 263 | return 0; |
261 | 264 | ||
262 | case LIRC_GET_REC_RESOLUTION: | 265 | case LIRC_GET_REC_RESOLUTION: |
266 | if (!dev->rx_resolution) | ||
267 | return -ENOTTY; | ||
268 | |||
263 | val = dev->rx_resolution; | 269 | val = dev->rx_resolution; |
264 | break; | 270 | break; |
265 | 271 | ||
266 | case LIRC_SET_WIDEBAND_RECEIVER: | 272 | case LIRC_SET_WIDEBAND_RECEIVER: |
267 | if (!dev->s_learning_mode) | 273 | if (!dev->s_learning_mode) |
268 | return -ENOSYS; | 274 | return -ENOTTY; |
269 | 275 | ||
270 | return dev->s_learning_mode(dev, !!val); | 276 | return dev->s_learning_mode(dev, !!val); |
271 | 277 | ||
272 | case LIRC_SET_MEASURE_CARRIER_MODE: | 278 | case LIRC_SET_MEASURE_CARRIER_MODE: |
273 | if (!dev->s_carrier_report) | 279 | if (!dev->s_carrier_report) |
274 | return -ENOSYS; | 280 | return -ENOTTY; |
275 | 281 | ||
276 | return dev->s_carrier_report(dev, !!val); | 282 | return dev->s_carrier_report(dev, !!val); |
277 | 283 | ||
278 | /* Generic timeout support */ | 284 | /* Generic timeout support */ |
279 | case LIRC_GET_MIN_TIMEOUT: | 285 | case LIRC_GET_MIN_TIMEOUT: |
280 | if (!dev->max_timeout) | 286 | if (!dev->max_timeout) |
281 | return -ENOSYS; | 287 | return -ENOTTY; |
282 | val = DIV_ROUND_UP(dev->min_timeout, 1000); | 288 | val = DIV_ROUND_UP(dev->min_timeout, 1000); |
283 | break; | 289 | break; |
284 | 290 | ||
285 | case LIRC_GET_MAX_TIMEOUT: | 291 | case LIRC_GET_MAX_TIMEOUT: |
286 | if (!dev->max_timeout) | 292 | if (!dev->max_timeout) |
287 | return -ENOSYS; | 293 | return -ENOTTY; |
288 | val = dev->max_timeout / 1000; | 294 | val = dev->max_timeout / 1000; |
289 | break; | 295 | break; |
290 | 296 | ||
291 | case LIRC_SET_REC_TIMEOUT: | 297 | case LIRC_SET_REC_TIMEOUT: |
292 | if (!dev->max_timeout) | 298 | if (!dev->max_timeout) |
293 | return -ENOSYS; | 299 | return -ENOTTY; |
294 | 300 | ||
295 | tmp = val * 1000; | 301 | tmp = val * 1000; |
296 | 302 | ||
@@ -305,6 +311,9 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, | |||
305 | break; | 311 | break; |
306 | 312 | ||
307 | case LIRC_SET_REC_TIMEOUT_REPORTS: | 313 | case LIRC_SET_REC_TIMEOUT_REPORTS: |
314 | if (!dev->timeout) | ||
315 | return -ENOTTY; | ||
316 | |||
308 | lirc->send_timeout_reports = !!val; | 317 | lirc->send_timeout_reports = !!val; |
309 | break; | 318 | break; |
310 | 319 | ||
@@ -361,8 +370,11 @@ static int ir_lirc_register(struct rc_dev *dev) | |||
361 | if (rc) | 370 | if (rc) |
362 | goto rbuf_init_failed; | 371 | goto rbuf_init_failed; |
363 | 372 | ||
364 | if (dev->driver_type != RC_DRIVER_IR_RAW_TX) | 373 | if (dev->driver_type != RC_DRIVER_IR_RAW_TX) { |
365 | features |= LIRC_CAN_REC_MODE2; | 374 | features |= LIRC_CAN_REC_MODE2; |
375 | if (dev->rx_resolution) | ||
376 | features |= LIRC_CAN_GET_REC_RESOLUTION; | ||
377 | } | ||
366 | if (dev->tx_ir) { | 378 | if (dev->tx_ir) { |
367 | features |= LIRC_CAN_SEND_PULSE; | 379 | features |= LIRC_CAN_SEND_PULSE; |
368 | if (dev->s_tx_mask) | 380 | if (dev->s_tx_mask) |
diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c index 5226d510e847..6a4d58b88d91 100644 --- a/drivers/media/rc/ir-mce_kbd-decoder.c +++ b/drivers/media/rc/ir-mce_kbd-decoder.c | |||
@@ -23,7 +23,7 @@ | |||
23 | * - MCIR-2 29-bit IR signals used for mouse movement and buttons | 23 | * - MCIR-2 29-bit IR signals used for mouse movement and buttons |
24 | * - MCIR-2 32-bit IR signals used for standard keyboard keys | 24 | * - MCIR-2 32-bit IR signals used for standard keyboard keys |
25 | * | 25 | * |
26 | * The media keys on the keyboard send RC-6 signals that are inditinguishable | 26 | * The media keys on the keyboard send RC-6 signals that are indistinguishable |
27 | * from the keys of the same name on the stock MCE remote, and will be handled | 27 | * from the keys of the same name on the stock MCE remote, and will be handled |
28 | * by the standard RC-6 decoder, and be made available to the system via the | 28 | * by the standard RC-6 decoder, and be made available to the system via the |
29 | * input device for the remote, rather than the keyboard/mouse one. | 29 | * input device for the remote, rather than the keyboard/mouse one. |
@@ -339,6 +339,7 @@ again: | |||
339 | } | 339 | } |
340 | 340 | ||
341 | data->state = STATE_INACTIVE; | 341 | data->state = STATE_INACTIVE; |
342 | input_event(data->idev, EV_MSC, MSC_SCAN, scancode); | ||
342 | input_sync(data->idev); | 343 | input_sync(data->idev); |
343 | return 0; | 344 | return 0; |
344 | } | 345 | } |
@@ -418,9 +419,53 @@ static int ir_mce_kbd_unregister(struct rc_dev *dev) | |||
418 | return 0; | 419 | return 0; |
419 | } | 420 | } |
420 | 421 | ||
422 | static const struct ir_raw_timings_manchester ir_mce_kbd_timings = { | ||
423 | .leader = MCIR2_PREFIX_PULSE, | ||
424 | .invert = 1, | ||
425 | .clock = MCIR2_UNIT, | ||
426 | .trailer_space = MCIR2_UNIT * 10, | ||
427 | }; | ||
428 | |||
429 | /** | ||
430 | * ir_mce_kbd_encode() - Encode a scancode as a stream of raw events | ||
431 | * | ||
432 | * @protocol: protocol to encode | ||
433 | * @scancode: scancode to encode | ||
434 | * @events: array of raw ir events to write into | ||
435 | * @max: maximum size of @events | ||
436 | * | ||
437 | * Returns: The number of events written. | ||
438 | * -ENOBUFS if there isn't enough space in the array to fit the | ||
439 | * encoding. In this case all @max events will have been written. | ||
440 | */ | ||
441 | static int ir_mce_kbd_encode(enum rc_type protocol, u32 scancode, | ||
442 | struct ir_raw_event *events, unsigned int max) | ||
443 | { | ||
444 | struct ir_raw_event *e = events; | ||
445 | int len, ret; | ||
446 | u64 raw; | ||
447 | |||
448 | if (protocol == RC_TYPE_MCIR2_KBD) { | ||
449 | raw = scancode | | ||
450 | ((u64)MCIR2_KEYBOARD_HEADER << MCIR2_KEYBOARD_NBITS); | ||
451 | len = MCIR2_KEYBOARD_NBITS + MCIR2_HEADER_NBITS + 1; | ||
452 | } else { | ||
453 | raw = scancode | | ||
454 | ((u64)MCIR2_MOUSE_HEADER << MCIR2_MOUSE_NBITS); | ||
455 | len = MCIR2_MOUSE_NBITS + MCIR2_HEADER_NBITS + 1; | ||
456 | } | ||
457 | |||
458 | ret = ir_raw_gen_manchester(&e, max, &ir_mce_kbd_timings, len, raw); | ||
459 | if (ret < 0) | ||
460 | return ret; | ||
461 | |||
462 | return e - events; | ||
463 | } | ||
464 | |||
421 | static struct ir_raw_handler mce_kbd_handler = { | 465 | static struct ir_raw_handler mce_kbd_handler = { |
422 | .protocols = RC_BIT_MCE_KBD, | 466 | .protocols = RC_BIT_MCIR2_KBD | RC_BIT_MCIR2_MSE, |
423 | .decode = ir_mce_kbd_decode, | 467 | .decode = ir_mce_kbd_decode, |
468 | .encode = ir_mce_kbd_encode, | ||
424 | .raw_register = ir_mce_kbd_register, | 469 | .raw_register = ir_mce_kbd_register, |
425 | .raw_unregister = ir_mce_kbd_unregister, | 470 | .raw_unregister = ir_mce_kbd_unregister, |
426 | }; | 471 | }; |
diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index ffe9e612f8d6..2945f99907b5 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile | |||
@@ -57,7 +57,6 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ | |||
57 | rc-kworld-pc150u.o \ | 57 | rc-kworld-pc150u.o \ |
58 | rc-kworld-plus-tv-analog.o \ | 58 | rc-kworld-plus-tv-analog.o \ |
59 | rc-leadtek-y04g0051.o \ | 59 | rc-leadtek-y04g0051.o \ |
60 | rc-lirc.o \ | ||
61 | rc-lme2510.o \ | 60 | rc-lme2510.o \ |
62 | rc-manli.o \ | 61 | rc-manli.o \ |
63 | rc-medion-x10.o \ | 62 | rc-medion-x10.o \ |
diff --git a/drivers/media/rc/keymaps/rc-dvico-mce.c b/drivers/media/rc/keymaps/rc-dvico-mce.c index e5f098c50235..d1e861f4d095 100644 --- a/drivers/media/rc/keymaps/rc-dvico-mce.c +++ b/drivers/media/rc/keymaps/rc-dvico-mce.c | |||
@@ -12,58 +12,58 @@ | |||
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | 13 | ||
14 | static struct rc_map_table rc_map_dvico_mce_table[] = { | 14 | static struct rc_map_table rc_map_dvico_mce_table[] = { |
15 | { 0xfe02, KEY_TV }, | 15 | { 0x0102, KEY_TV }, |
16 | { 0xfe0e, KEY_MP3 }, | 16 | { 0x010e, KEY_MP3 }, |
17 | { 0xfe1a, KEY_DVD }, | 17 | { 0x011a, KEY_DVD }, |
18 | { 0xfe1e, KEY_FAVORITES }, | 18 | { 0x011e, KEY_FAVORITES }, |
19 | { 0xfe16, KEY_SETUP }, | 19 | { 0x0116, KEY_SETUP }, |
20 | { 0xfe46, KEY_POWER2 }, | 20 | { 0x0146, KEY_POWER2 }, |
21 | { 0xfe0a, KEY_EPG }, | 21 | { 0x010a, KEY_EPG }, |
22 | { 0xfe49, KEY_BACK }, | 22 | { 0x0149, KEY_BACK }, |
23 | { 0xfe4d, KEY_MENU }, | 23 | { 0x014d, KEY_MENU }, |
24 | { 0xfe51, KEY_UP }, | 24 | { 0x0151, KEY_UP }, |
25 | { 0xfe5b, KEY_LEFT }, | 25 | { 0x015b, KEY_LEFT }, |
26 | { 0xfe5f, KEY_RIGHT }, | 26 | { 0x015f, KEY_RIGHT }, |
27 | { 0xfe53, KEY_DOWN }, | 27 | { 0x0153, KEY_DOWN }, |
28 | { 0xfe5e, KEY_OK }, | 28 | { 0x015e, KEY_OK }, |
29 | { 0xfe59, KEY_INFO }, | 29 | { 0x0159, KEY_INFO }, |
30 | { 0xfe55, KEY_TAB }, | 30 | { 0x0155, KEY_TAB }, |
31 | { 0xfe0f, KEY_PREVIOUSSONG },/* Replay */ | 31 | { 0x010f, KEY_PREVIOUSSONG },/* Replay */ |
32 | { 0xfe12, KEY_NEXTSONG }, /* Skip */ | 32 | { 0x0112, KEY_NEXTSONG }, /* Skip */ |
33 | { 0xfe42, KEY_ENTER }, /* Windows/Start */ | 33 | { 0x0142, KEY_ENTER }, /* Windows/Start */ |
34 | { 0xfe15, KEY_VOLUMEUP }, | 34 | { 0x0115, KEY_VOLUMEUP }, |
35 | { 0xfe05, KEY_VOLUMEDOWN }, | 35 | { 0x0105, KEY_VOLUMEDOWN }, |
36 | { 0xfe11, KEY_CHANNELUP }, | 36 | { 0x0111, KEY_CHANNELUP }, |
37 | { 0xfe09, KEY_CHANNELDOWN }, | 37 | { 0x0109, KEY_CHANNELDOWN }, |
38 | { 0xfe52, KEY_CAMERA }, | 38 | { 0x0152, KEY_CAMERA }, |
39 | { 0xfe5a, KEY_TUNER }, /* Live */ | 39 | { 0x015a, KEY_TUNER }, /* Live */ |
40 | { 0xfe19, KEY_OPEN }, | 40 | { 0x0119, KEY_OPEN }, |
41 | { 0xfe0b, KEY_1 }, | 41 | { 0x010b, KEY_1 }, |
42 | { 0xfe17, KEY_2 }, | 42 | { 0x0117, KEY_2 }, |
43 | { 0xfe1b, KEY_3 }, | 43 | { 0x011b, KEY_3 }, |
44 | { 0xfe07, KEY_4 }, | 44 | { 0x0107, KEY_4 }, |
45 | { 0xfe50, KEY_5 }, | 45 | { 0x0150, KEY_5 }, |
46 | { 0xfe54, KEY_6 }, | 46 | { 0x0154, KEY_6 }, |
47 | { 0xfe48, KEY_7 }, | 47 | { 0x0148, KEY_7 }, |
48 | { 0xfe4c, KEY_8 }, | 48 | { 0x014c, KEY_8 }, |
49 | { 0xfe58, KEY_9 }, | 49 | { 0x0158, KEY_9 }, |
50 | { 0xfe13, KEY_ANGLE }, /* Aspect */ | 50 | { 0x0113, KEY_ANGLE }, /* Aspect */ |
51 | { 0xfe03, KEY_0 }, | 51 | { 0x0103, KEY_0 }, |
52 | { 0xfe1f, KEY_ZOOM }, | 52 | { 0x011f, KEY_ZOOM }, |
53 | { 0xfe43, KEY_REWIND }, | 53 | { 0x0143, KEY_REWIND }, |
54 | { 0xfe47, KEY_PLAYPAUSE }, | 54 | { 0x0147, KEY_PLAYPAUSE }, |
55 | { 0xfe4f, KEY_FASTFORWARD }, | 55 | { 0x014f, KEY_FASTFORWARD }, |
56 | { 0xfe57, KEY_MUTE }, | 56 | { 0x0157, KEY_MUTE }, |
57 | { 0xfe0d, KEY_STOP }, | 57 | { 0x010d, KEY_STOP }, |
58 | { 0xfe01, KEY_RECORD }, | 58 | { 0x0101, KEY_RECORD }, |
59 | { 0xfe4e, KEY_POWER }, | 59 | { 0x014e, KEY_POWER }, |
60 | }; | 60 | }; |
61 | 61 | ||
62 | static struct rc_map_list dvico_mce_map = { | 62 | static struct rc_map_list dvico_mce_map = { |
63 | .map = { | 63 | .map = { |
64 | .scan = rc_map_dvico_mce_table, | 64 | .scan = rc_map_dvico_mce_table, |
65 | .size = ARRAY_SIZE(rc_map_dvico_mce_table), | 65 | .size = ARRAY_SIZE(rc_map_dvico_mce_table), |
66 | .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ | 66 | .rc_type = RC_TYPE_NEC, |
67 | .name = RC_MAP_DVICO_MCE, | 67 | .name = RC_MAP_DVICO_MCE, |
68 | } | 68 | } |
69 | }; | 69 | }; |
diff --git a/drivers/media/rc/keymaps/rc-dvico-portable.c b/drivers/media/rc/keymaps/rc-dvico-portable.c index 94ceeee94b3f..ac4cb515cbf1 100644 --- a/drivers/media/rc/keymaps/rc-dvico-portable.c +++ b/drivers/media/rc/keymaps/rc-dvico-portable.c | |||
@@ -12,49 +12,49 @@ | |||
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | 13 | ||
14 | static struct rc_map_table rc_map_dvico_portable_table[] = { | 14 | static struct rc_map_table rc_map_dvico_portable_table[] = { |
15 | { 0xfc02, KEY_SETUP }, /* Profile */ | 15 | { 0x0302, KEY_SETUP }, /* Profile */ |
16 | { 0xfc43, KEY_POWER2 }, | 16 | { 0x0343, KEY_POWER2 }, |
17 | { 0xfc06, KEY_EPG }, | 17 | { 0x0306, KEY_EPG }, |
18 | { 0xfc5a, KEY_BACK }, | 18 | { 0x035a, KEY_BACK }, |
19 | { 0xfc05, KEY_MENU }, | 19 | { 0x0305, KEY_MENU }, |
20 | { 0xfc47, KEY_INFO }, | 20 | { 0x0347, KEY_INFO }, |
21 | { 0xfc01, KEY_TAB }, | 21 | { 0x0301, KEY_TAB }, |
22 | { 0xfc42, KEY_PREVIOUSSONG },/* Replay */ | 22 | { 0x0342, KEY_PREVIOUSSONG },/* Replay */ |
23 | { 0xfc49, KEY_VOLUMEUP }, | 23 | { 0x0349, KEY_VOLUMEUP }, |
24 | { 0xfc09, KEY_VOLUMEDOWN }, | 24 | { 0x0309, KEY_VOLUMEDOWN }, |
25 | { 0xfc54, KEY_CHANNELUP }, | 25 | { 0x0354, KEY_CHANNELUP }, |
26 | { 0xfc0b, KEY_CHANNELDOWN }, | 26 | { 0x030b, KEY_CHANNELDOWN }, |
27 | { 0xfc16, KEY_CAMERA }, | 27 | { 0x0316, KEY_CAMERA }, |
28 | { 0xfc40, KEY_TUNER }, /* ATV/DTV */ | 28 | { 0x0340, KEY_TUNER }, /* ATV/DTV */ |
29 | { 0xfc45, KEY_OPEN }, | 29 | { 0x0345, KEY_OPEN }, |
30 | { 0xfc19, KEY_1 }, | 30 | { 0x0319, KEY_1 }, |
31 | { 0xfc18, KEY_2 }, | 31 | { 0x0318, KEY_2 }, |
32 | { 0xfc1b, KEY_3 }, | 32 | { 0x031b, KEY_3 }, |
33 | { 0xfc1a, KEY_4 }, | 33 | { 0x031a, KEY_4 }, |
34 | { 0xfc58, KEY_5 }, | 34 | { 0x0358, KEY_5 }, |
35 | { 0xfc59, KEY_6 }, | 35 | { 0x0359, KEY_6 }, |
36 | { 0xfc15, KEY_7 }, | 36 | { 0x0315, KEY_7 }, |
37 | { 0xfc14, KEY_8 }, | 37 | { 0x0314, KEY_8 }, |
38 | { 0xfc17, KEY_9 }, | 38 | { 0x0317, KEY_9 }, |
39 | { 0xfc44, KEY_ANGLE }, /* Aspect */ | 39 | { 0x0344, KEY_ANGLE }, /* Aspect */ |
40 | { 0xfc55, KEY_0 }, | 40 | { 0x0355, KEY_0 }, |
41 | { 0xfc07, KEY_ZOOM }, | 41 | { 0x0307, KEY_ZOOM }, |
42 | { 0xfc0a, KEY_REWIND }, | 42 | { 0x030a, KEY_REWIND }, |
43 | { 0xfc08, KEY_PLAYPAUSE }, | 43 | { 0x0308, KEY_PLAYPAUSE }, |
44 | { 0xfc4b, KEY_FASTFORWARD }, | 44 | { 0x034b, KEY_FASTFORWARD }, |
45 | { 0xfc5b, KEY_MUTE }, | 45 | { 0x035b, KEY_MUTE }, |
46 | { 0xfc04, KEY_STOP }, | 46 | { 0x0304, KEY_STOP }, |
47 | { 0xfc56, KEY_RECORD }, | 47 | { 0x0356, KEY_RECORD }, |
48 | { 0xfc57, KEY_POWER }, | 48 | { 0x0357, KEY_POWER }, |
49 | { 0xfc41, KEY_UNKNOWN }, /* INPUT */ | 49 | { 0x0341, KEY_UNKNOWN }, /* INPUT */ |
50 | { 0xfc00, KEY_UNKNOWN }, /* HD */ | 50 | { 0x0300, KEY_UNKNOWN }, /* HD */ |
51 | }; | 51 | }; |
52 | 52 | ||
53 | static struct rc_map_list dvico_portable_map = { | 53 | static struct rc_map_list dvico_portable_map = { |
54 | .map = { | 54 | .map = { |
55 | .scan = rc_map_dvico_portable_table, | 55 | .scan = rc_map_dvico_portable_table, |
56 | .size = ARRAY_SIZE(rc_map_dvico_portable_table), | 56 | .size = ARRAY_SIZE(rc_map_dvico_portable_table), |
57 | .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ | 57 | .rc_type = RC_TYPE_NEC, |
58 | .name = RC_MAP_DVICO_PORTABLE, | 58 | .name = RC_MAP_DVICO_PORTABLE, |
59 | } | 59 | } |
60 | }; | 60 | }; |
diff --git a/drivers/media/rc/keymaps/rc-lirc.c b/drivers/media/rc/keymaps/rc-lirc.c deleted file mode 100644 index e172f5db5803..000000000000 --- a/drivers/media/rc/keymaps/rc-lirc.c +++ /dev/null | |||
@@ -1,42 +0,0 @@ | |||
1 | /* rc-lirc.c - Empty dummy keytable, for use when its preferred to pass | ||
2 | * all raw IR data to the lirc userspace decoder. | ||
3 | * | ||
4 | * Copyright (c) 2010 by Jarod Wilson <jarod@redhat.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <media/rc-core.h> | ||
13 | #include <linux/module.h> | ||
14 | |||
15 | static struct rc_map_table lirc[] = { | ||
16 | { }, | ||
17 | }; | ||
18 | |||
19 | static struct rc_map_list lirc_map = { | ||
20 | .map = { | ||
21 | .scan = lirc, | ||
22 | .size = ARRAY_SIZE(lirc), | ||
23 | .rc_type = RC_TYPE_OTHER, | ||
24 | .name = RC_MAP_LIRC, | ||
25 | } | ||
26 | }; | ||
27 | |||
28 | static int __init init_rc_map_lirc(void) | ||
29 | { | ||
30 | return rc_map_register(&lirc_map); | ||
31 | } | ||
32 | |||
33 | static void __exit exit_rc_map_lirc(void) | ||
34 | { | ||
35 | rc_map_unregister(&lirc_map); | ||
36 | } | ||
37 | |||
38 | module_init(init_rc_map_lirc) | ||
39 | module_exit(exit_rc_map_lirc) | ||
40 | |||
41 | MODULE_LICENSE("GPL"); | ||
42 | MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>"); | ||
diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index 1688893a65bb..8d60c9f00df9 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c | |||
@@ -54,7 +54,8 @@ struct irctl { | |||
54 | struct lirc_buffer *buf; | 54 | struct lirc_buffer *buf; |
55 | unsigned int chunk_size; | 55 | unsigned int chunk_size; |
56 | 56 | ||
57 | struct cdev *cdev; | 57 | struct device dev; |
58 | struct cdev cdev; | ||
58 | 59 | ||
59 | struct task_struct *task; | 60 | struct task_struct *task; |
60 | long jiffies_to_wait; | 61 | long jiffies_to_wait; |
@@ -76,15 +77,21 @@ static void lirc_irctl_init(struct irctl *ir) | |||
76 | ir->d.minor = NOPLUG; | 77 | ir->d.minor = NOPLUG; |
77 | } | 78 | } |
78 | 79 | ||
79 | static void lirc_irctl_cleanup(struct irctl *ir) | 80 | static void lirc_release(struct device *ld) |
80 | { | 81 | { |
81 | device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor)); | 82 | struct irctl *ir = container_of(ld, struct irctl, dev); |
83 | |||
84 | put_device(ir->dev.parent); | ||
82 | 85 | ||
83 | if (ir->buf != ir->d.rbuf) { | 86 | if (ir->buf != ir->d.rbuf) { |
84 | lirc_buffer_free(ir->buf); | 87 | lirc_buffer_free(ir->buf); |
85 | kfree(ir->buf); | 88 | kfree(ir->buf); |
86 | } | 89 | } |
87 | ir->buf = NULL; | 90 | |
91 | mutex_lock(&lirc_dev_lock); | ||
92 | irctls[ir->d.minor] = NULL; | ||
93 | mutex_unlock(&lirc_dev_lock); | ||
94 | kfree(ir); | ||
88 | } | 95 | } |
89 | 96 | ||
90 | /* helper function | 97 | /* helper function |
@@ -157,32 +164,21 @@ static int lirc_cdev_add(struct irctl *ir) | |||
157 | struct cdev *cdev; | 164 | struct cdev *cdev; |
158 | int retval; | 165 | int retval; |
159 | 166 | ||
160 | cdev = cdev_alloc(); | 167 | cdev = &ir->cdev; |
161 | if (!cdev) | ||
162 | return -ENOMEM; | ||
163 | 168 | ||
164 | if (d->fops) { | 169 | if (d->fops) { |
165 | cdev->ops = d->fops; | 170 | cdev_init(cdev, d->fops); |
166 | cdev->owner = d->owner; | 171 | cdev->owner = d->owner; |
167 | } else { | 172 | } else { |
168 | cdev->ops = &lirc_dev_fops; | 173 | cdev_init(cdev, &lirc_dev_fops); |
169 | cdev->owner = THIS_MODULE; | 174 | cdev->owner = THIS_MODULE; |
170 | } | 175 | } |
171 | retval = kobject_set_name(&cdev->kobj, "lirc%d", d->minor); | 176 | retval = kobject_set_name(&cdev->kobj, "lirc%d", d->minor); |
172 | if (retval) | 177 | if (retval) |
173 | goto err_out; | 178 | return retval; |
174 | |||
175 | retval = cdev_add(cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1); | ||
176 | if (retval) | ||
177 | goto err_out; | ||
178 | |||
179 | ir->cdev = cdev; | ||
180 | |||
181 | return 0; | ||
182 | 179 | ||
183 | err_out: | 180 | cdev->kobj.parent = &ir->dev.kobj; |
184 | cdev_del(cdev); | 181 | return cdev_add(cdev, ir->dev.devt, 1); |
185 | return retval; | ||
186 | } | 182 | } |
187 | 183 | ||
188 | static int lirc_allocate_buffer(struct irctl *ir) | 184 | static int lirc_allocate_buffer(struct irctl *ir) |
@@ -304,9 +300,12 @@ static int lirc_allocate_driver(struct lirc_driver *d) | |||
304 | 300 | ||
305 | ir->d = *d; | 301 | ir->d = *d; |
306 | 302 | ||
307 | device_create(lirc_class, ir->d.dev, | 303 | ir->dev.devt = MKDEV(MAJOR(lirc_base_dev), ir->d.minor); |
308 | MKDEV(MAJOR(lirc_base_dev), ir->d.minor), NULL, | 304 | ir->dev.class = lirc_class; |
309 | "lirc%u", ir->d.minor); | 305 | ir->dev.parent = d->dev; |
306 | ir->dev.release = lirc_release; | ||
307 | dev_set_name(&ir->dev, "lirc%d", ir->d.minor); | ||
308 | device_initialize(&ir->dev); | ||
310 | 309 | ||
311 | if (d->sample_rate) { | 310 | if (d->sample_rate) { |
312 | ir->jiffies_to_wait = HZ / d->sample_rate; | 311 | ir->jiffies_to_wait = HZ / d->sample_rate; |
@@ -329,14 +328,22 @@ static int lirc_allocate_driver(struct lirc_driver *d) | |||
329 | goto out_sysfs; | 328 | goto out_sysfs; |
330 | 329 | ||
331 | ir->attached = 1; | 330 | ir->attached = 1; |
331 | |||
332 | err = device_add(&ir->dev); | ||
333 | if (err) | ||
334 | goto out_cdev; | ||
335 | |||
332 | mutex_unlock(&lirc_dev_lock); | 336 | mutex_unlock(&lirc_dev_lock); |
333 | 337 | ||
338 | get_device(ir->dev.parent); | ||
339 | |||
334 | dev_info(ir->d.dev, "lirc_dev: driver %s registered at minor = %d\n", | 340 | dev_info(ir->d.dev, "lirc_dev: driver %s registered at minor = %d\n", |
335 | ir->d.name, ir->d.minor); | 341 | ir->d.name, ir->d.minor); |
336 | return minor; | 342 | return minor; |
337 | 343 | out_cdev: | |
344 | cdev_del(&ir->cdev); | ||
338 | out_sysfs: | 345 | out_sysfs: |
339 | device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor)); | 346 | put_device(&ir->dev); |
340 | out_lock: | 347 | out_lock: |
341 | mutex_unlock(&lirc_dev_lock); | 348 | mutex_unlock(&lirc_dev_lock); |
342 | 349 | ||
@@ -364,7 +371,6 @@ EXPORT_SYMBOL(lirc_register_driver); | |||
364 | int lirc_unregister_driver(int minor) | 371 | int lirc_unregister_driver(int minor) |
365 | { | 372 | { |
366 | struct irctl *ir; | 373 | struct irctl *ir; |
367 | struct cdev *cdev; | ||
368 | 374 | ||
369 | if (minor < 0 || minor >= MAX_IRCTL_DEVICES) { | 375 | if (minor < 0 || minor >= MAX_IRCTL_DEVICES) { |
370 | pr_err("minor (%d) must be between 0 and %d!\n", | 376 | pr_err("minor (%d) must be between 0 and %d!\n", |
@@ -378,8 +384,6 @@ int lirc_unregister_driver(int minor) | |||
378 | return -ENOENT; | 384 | return -ENOENT; |
379 | } | 385 | } |
380 | 386 | ||
381 | cdev = ir->cdev; | ||
382 | |||
383 | mutex_lock(&lirc_dev_lock); | 387 | mutex_lock(&lirc_dev_lock); |
384 | 388 | ||
385 | if (ir->d.minor != minor) { | 389 | if (ir->d.minor != minor) { |
@@ -401,22 +405,20 @@ int lirc_unregister_driver(int minor) | |||
401 | dev_dbg(ir->d.dev, LOGHEAD "releasing opened driver\n", | 405 | dev_dbg(ir->d.dev, LOGHEAD "releasing opened driver\n", |
402 | ir->d.name, ir->d.minor); | 406 | ir->d.name, ir->d.minor); |
403 | wake_up_interruptible(&ir->buf->wait_poll); | 407 | wake_up_interruptible(&ir->buf->wait_poll); |
404 | mutex_lock(&ir->irctl_lock); | 408 | } |
405 | 409 | ||
406 | if (ir->d.set_use_dec) | 410 | mutex_lock(&ir->irctl_lock); |
407 | ir->d.set_use_dec(ir->d.data); | ||
408 | 411 | ||
409 | module_put(cdev->owner); | 412 | if (ir->d.set_use_dec) |
410 | mutex_unlock(&ir->irctl_lock); | 413 | ir->d.set_use_dec(ir->d.data); |
411 | } else { | ||
412 | lirc_irctl_cleanup(ir); | ||
413 | cdev_del(cdev); | ||
414 | kfree(ir); | ||
415 | irctls[minor] = NULL; | ||
416 | } | ||
417 | 414 | ||
415 | mutex_unlock(&ir->irctl_lock); | ||
418 | mutex_unlock(&lirc_dev_lock); | 416 | mutex_unlock(&lirc_dev_lock); |
419 | 417 | ||
418 | device_del(&ir->dev); | ||
419 | cdev_del(&ir->cdev); | ||
420 | put_device(&ir->dev); | ||
421 | |||
420 | return 0; | 422 | return 0; |
421 | } | 423 | } |
422 | EXPORT_SYMBOL(lirc_unregister_driver); | 424 | EXPORT_SYMBOL(lirc_unregister_driver); |
@@ -424,7 +426,6 @@ EXPORT_SYMBOL(lirc_unregister_driver); | |||
424 | int lirc_dev_fop_open(struct inode *inode, struct file *file) | 426 | int lirc_dev_fop_open(struct inode *inode, struct file *file) |
425 | { | 427 | { |
426 | struct irctl *ir; | 428 | struct irctl *ir; |
427 | struct cdev *cdev; | ||
428 | int retval = 0; | 429 | int retval = 0; |
429 | 430 | ||
430 | if (iminor(inode) >= MAX_IRCTL_DEVICES) { | 431 | if (iminor(inode) >= MAX_IRCTL_DEVICES) { |
@@ -461,18 +462,14 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file) | |||
461 | goto error; | 462 | goto error; |
462 | } | 463 | } |
463 | 464 | ||
464 | cdev = ir->cdev; | 465 | ir->open++; |
465 | if (try_module_get(cdev->owner)) { | 466 | if (ir->d.set_use_inc) |
466 | ir->open++; | 467 | retval = ir->d.set_use_inc(ir->d.data); |
467 | if (ir->d.set_use_inc) | 468 | if (retval) { |
468 | retval = ir->d.set_use_inc(ir->d.data); | 469 | ir->open--; |
469 | 470 | } else { | |
470 | if (retval) { | 471 | if (ir->buf) |
471 | module_put(cdev->owner); | ||
472 | ir->open--; | ||
473 | } else if (ir->buf) { | ||
474 | lirc_buffer_clear(ir->buf); | 472 | lirc_buffer_clear(ir->buf); |
475 | } | ||
476 | if (ir->task) | 473 | if (ir->task) |
477 | wake_up_process(ir->task); | 474 | wake_up_process(ir->task); |
478 | } | 475 | } |
@@ -487,7 +484,6 @@ EXPORT_SYMBOL(lirc_dev_fop_open); | |||
487 | int lirc_dev_fop_close(struct inode *inode, struct file *file) | 484 | int lirc_dev_fop_close(struct inode *inode, struct file *file) |
488 | { | 485 | { |
489 | struct irctl *ir = irctls[iminor(inode)]; | 486 | struct irctl *ir = irctls[iminor(inode)]; |
490 | struct cdev *cdev; | ||
491 | int ret; | 487 | int ret; |
492 | 488 | ||
493 | if (!ir) { | 489 | if (!ir) { |
@@ -495,25 +491,14 @@ int lirc_dev_fop_close(struct inode *inode, struct file *file) | |||
495 | return -EINVAL; | 491 | return -EINVAL; |
496 | } | 492 | } |
497 | 493 | ||
498 | cdev = ir->cdev; | ||
499 | |||
500 | ret = mutex_lock_killable(&lirc_dev_lock); | 494 | ret = mutex_lock_killable(&lirc_dev_lock); |
501 | WARN_ON(ret); | 495 | WARN_ON(ret); |
502 | 496 | ||
503 | rc_close(ir->d.rdev); | 497 | rc_close(ir->d.rdev); |
504 | 498 | ||
505 | ir->open--; | 499 | ir->open--; |
506 | if (ir->attached) { | 500 | if (ir->d.set_use_dec) |
507 | if (ir->d.set_use_dec) | 501 | ir->d.set_use_dec(ir->d.data); |
508 | ir->d.set_use_dec(ir->d.data); | ||
509 | module_put(cdev->owner); | ||
510 | } else { | ||
511 | lirc_irctl_cleanup(ir); | ||
512 | cdev_del(cdev); | ||
513 | irctls[ir->d.minor] = NULL; | ||
514 | kfree(ir); | ||
515 | } | ||
516 | |||
517 | if (!ret) | 502 | if (!ret) |
518 | mutex_unlock(&lirc_dev_lock); | 503 | mutex_unlock(&lirc_dev_lock); |
519 | 504 | ||
@@ -623,7 +608,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
623 | result = put_user(ir->d.max_timeout, (__u32 __user *)arg); | 608 | result = put_user(ir->d.max_timeout, (__u32 __user *)arg); |
624 | break; | 609 | break; |
625 | default: | 610 | default: |
626 | result = -EINVAL; | 611 | result = -ENOTTY; |
627 | } | 612 | } |
628 | 613 | ||
629 | mutex_unlock(&ir->irctl_lock); | 614 | mutex_unlock(&ir->irctl_lock); |
@@ -780,15 +765,12 @@ static int __init lirc_dev_init(void) | |||
780 | return retval; | 765 | return retval; |
781 | } | 766 | } |
782 | 767 | ||
783 | |||
784 | pr_info("IR Remote Control driver registered, major %d\n", | 768 | pr_info("IR Remote Control driver registered, major %d\n", |
785 | MAJOR(lirc_base_dev)); | 769 | MAJOR(lirc_base_dev)); |
786 | 770 | ||
787 | return 0; | 771 | return 0; |
788 | } | 772 | } |
789 | 773 | ||
790 | |||
791 | |||
792 | static void __exit lirc_dev_exit(void) | 774 | static void __exit lirc_dev_exit(void) |
793 | { | 775 | { |
794 | class_destroy(lirc_class); | 776 | class_destroy(lirc_class); |
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 238d8eaf7d94..93b16fe3ab38 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c | |||
@@ -1288,8 +1288,8 @@ static int mceusb_dev_probe(struct usb_interface *intf, | |||
1288 | } | 1288 | } |
1289 | } | 1289 | } |
1290 | } | 1290 | } |
1291 | if (ep_in == NULL) { | 1291 | if (!ep_in || !ep_out) { |
1292 | dev_dbg(&intf->dev, "inbound and/or endpoint not found"); | 1292 | dev_dbg(&intf->dev, "required endpoints not found\n"); |
1293 | return -ENODEV; | 1293 | return -ENODEV; |
1294 | } | 1294 | } |
1295 | 1295 | ||
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index a70a5c557434..0455b273c2fc 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h | |||
@@ -185,7 +185,7 @@ struct ir_raw_timings_manchester { | |||
185 | 185 | ||
186 | int ir_raw_gen_manchester(struct ir_raw_event **ev, unsigned int max, | 186 | int ir_raw_gen_manchester(struct ir_raw_event **ev, unsigned int max, |
187 | const struct ir_raw_timings_manchester *timings, | 187 | const struct ir_raw_timings_manchester *timings, |
188 | unsigned int n, unsigned int data); | 188 | unsigned int n, u64 data); |
189 | 189 | ||
190 | /** | 190 | /** |
191 | * ir_raw_gen_pulse_space() - generate pulse and space raw events. | 191 | * ir_raw_gen_pulse_space() - generate pulse and space raw events. |
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c index 7fa84b64a2ae..90f66dc7c0d7 100644 --- a/drivers/media/rc/rc-ir-raw.c +++ b/drivers/media/rc/rc-ir-raw.c | |||
@@ -258,13 +258,13 @@ static void ir_raw_disable_protocols(struct rc_dev *dev, u64 protocols) | |||
258 | */ | 258 | */ |
259 | int ir_raw_gen_manchester(struct ir_raw_event **ev, unsigned int max, | 259 | int ir_raw_gen_manchester(struct ir_raw_event **ev, unsigned int max, |
260 | const struct ir_raw_timings_manchester *timings, | 260 | const struct ir_raw_timings_manchester *timings, |
261 | unsigned int n, unsigned int data) | 261 | unsigned int n, u64 data) |
262 | { | 262 | { |
263 | bool need_pulse; | 263 | bool need_pulse; |
264 | unsigned int i; | 264 | u64 i; |
265 | int ret = -ENOBUFS; | 265 | int ret = -ENOBUFS; |
266 | 266 | ||
267 | i = 1 << (n - 1); | 267 | i = BIT_ULL(n - 1); |
268 | 268 | ||
269 | if (timings->leader) { | 269 | if (timings->leader) { |
270 | if (!max--) | 270 | if (!max--) |
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index d84533699668..6ec73357fa47 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c | |||
@@ -746,6 +746,8 @@ static int rc_validate_filter(struct rc_dev *dev, | |||
746 | [RC_TYPE_NECX] = 0xffffff, | 746 | [RC_TYPE_NECX] = 0xffffff, |
747 | [RC_TYPE_NEC32] = 0xffffffff, | 747 | [RC_TYPE_NEC32] = 0xffffffff, |
748 | [RC_TYPE_SANYO] = 0x1fffff, | 748 | [RC_TYPE_SANYO] = 0x1fffff, |
749 | [RC_TYPE_MCIR2_KBD] = 0xffff, | ||
750 | [RC_TYPE_MCIR2_MSE] = 0x1fffff, | ||
749 | [RC_TYPE_RC6_0] = 0xffff, | 751 | [RC_TYPE_RC6_0] = 0xffff, |
750 | [RC_TYPE_RC6_6A_20] = 0xfffff, | 752 | [RC_TYPE_RC6_6A_20] = 0xfffff, |
751 | [RC_TYPE_RC6_6A_24] = 0xffffff, | 753 | [RC_TYPE_RC6_6A_24] = 0xffffff, |
@@ -878,7 +880,8 @@ static const struct { | |||
878 | { RC_BIT_RC5_SZ, "rc-5-sz", "ir-rc5-decoder" }, | 880 | { RC_BIT_RC5_SZ, "rc-5-sz", "ir-rc5-decoder" }, |
879 | { RC_BIT_SANYO, "sanyo", "ir-sanyo-decoder" }, | 881 | { RC_BIT_SANYO, "sanyo", "ir-sanyo-decoder" }, |
880 | { RC_BIT_SHARP, "sharp", "ir-sharp-decoder" }, | 882 | { RC_BIT_SHARP, "sharp", "ir-sharp-decoder" }, |
881 | { RC_BIT_MCE_KBD, "mce_kbd", "ir-mce_kbd-decoder" }, | 883 | { RC_BIT_MCIR2_KBD | |
884 | RC_BIT_MCIR2_MSE, "mce_kbd", "ir-mce_kbd-decoder" }, | ||
882 | { RC_BIT_XMP, "xmp", "ir-xmp-decoder" }, | 885 | { RC_BIT_XMP, "xmp", "ir-xmp-decoder" }, |
883 | { RC_BIT_CEC, "cec", NULL }, | 886 | { RC_BIT_CEC, "cec", NULL }, |
884 | }; | 887 | }; |
@@ -1346,7 +1349,8 @@ static const char * const proto_variant_names[] = { | |||
1346 | [RC_TYPE_NECX] = "nec-x", | 1349 | [RC_TYPE_NECX] = "nec-x", |
1347 | [RC_TYPE_NEC32] = "nec-32", | 1350 | [RC_TYPE_NEC32] = "nec-32", |
1348 | [RC_TYPE_SANYO] = "sanyo", | 1351 | [RC_TYPE_SANYO] = "sanyo", |
1349 | [RC_TYPE_MCE_KBD] = "mce_kbd", | 1352 | [RC_TYPE_MCIR2_KBD] = "mcir2-kbd", |
1353 | [RC_TYPE_MCIR2_MSE] = "mcir2-mse", | ||
1350 | [RC_TYPE_RC6_0] = "rc-6-0", | 1354 | [RC_TYPE_RC6_0] = "rc-6-0", |
1351 | [RC_TYPE_RC6_6A_20] = "rc-6-6a-20", | 1355 | [RC_TYPE_RC6_6A_20] = "rc-6-6a-20", |
1352 | [RC_TYPE_RC6_6A_24] = "rc-6-6a-24", | 1356 | [RC_TYPE_RC6_6A_24] = "rc-6-6a-24", |
diff --git a/drivers/media/rc/serial_ir.c b/drivers/media/rc/serial_ir.c index 41b54e40176c..2f0a0d248936 100644 --- a/drivers/media/rc/serial_ir.c +++ b/drivers/media/rc/serial_ir.c | |||
@@ -56,7 +56,7 @@ struct serial_ir_hw { | |||
56 | static int type; | 56 | static int type; |
57 | static int io; | 57 | static int io; |
58 | static int irq; | 58 | static int irq; |
59 | static bool iommap; | 59 | static ulong iommap; |
60 | static int ioshift; | 60 | static int ioshift; |
61 | static bool softcarrier = true; | 61 | static bool softcarrier = true; |
62 | static bool share_irq; | 62 | static bool share_irq; |
@@ -837,7 +837,7 @@ module_param(io, int, 0444); | |||
837 | MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)"); | 837 | MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)"); |
838 | 838 | ||
839 | /* some architectures (e.g. intel xscale) have memory mapped registers */ | 839 | /* some architectures (e.g. intel xscale) have memory mapped registers */ |
840 | module_param(iommap, bool, 0444); | 840 | module_param(iommap, ulong, 0444); |
841 | MODULE_PARM_DESC(iommap, "physical base for memory mapped I/O (0 = no memory mapped io)"); | 841 | MODULE_PARM_DESC(iommap, "physical base for memory mapped I/O (0 = no memory mapped io)"); |
842 | 842 | ||
843 | /* | 843 | /* |
diff --git a/drivers/media/rc/sir_ir.c b/drivers/media/rc/sir_ir.c new file mode 100644 index 000000000000..e12ec50bf0bf --- /dev/null +++ b/drivers/media/rc/sir_ir.c | |||
@@ -0,0 +1,438 @@ | |||
1 | /* | ||
2 | * IR SIR driver, (C) 2000 Milan Pikula <www@fornax.sk> | ||
3 | * | ||
4 | * sir_ir - Device driver for use with SIR (serial infra red) | ||
5 | * mode of IrDA on many notebooks. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/serial_reg.h> | ||
19 | #include <linux/ktime.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | |||
23 | #include <media/rc-core.h> | ||
24 | |||
25 | /* SECTION: Definitions */ | ||
26 | #define PULSE '[' | ||
27 | |||
28 | /* 9bit * 1s/115200bit in milli seconds = 78.125ms*/ | ||
29 | #define TIME_CONST (9000000ul / 115200ul) | ||
30 | |||
31 | /* timeout for sequences in jiffies (=5/100s), must be longer than TIME_CONST */ | ||
32 | #define SIR_TIMEOUT (HZ * 5 / 100) | ||
33 | |||
34 | /* onboard sir ports are typically com3 */ | ||
35 | static int io = 0x3e8; | ||
36 | static int irq = 4; | ||
37 | static int threshold = 3; | ||
38 | |||
39 | static DEFINE_SPINLOCK(timer_lock); | ||
40 | static struct timer_list timerlist; | ||
41 | /* time of last signal change detected */ | ||
42 | static ktime_t last; | ||
43 | /* time of last UART data ready interrupt */ | ||
44 | static ktime_t last_intr_time; | ||
45 | static int last_value; | ||
46 | static struct rc_dev *rcdev; | ||
47 | |||
48 | static struct platform_device *sir_ir_dev; | ||
49 | |||
50 | static DEFINE_SPINLOCK(hardware_lock); | ||
51 | |||
52 | /* SECTION: Prototypes */ | ||
53 | |||
54 | /* Communication with user-space */ | ||
55 | static void add_read_queue(int flag, unsigned long val); | ||
56 | static int init_chrdev(void); | ||
57 | /* Hardware */ | ||
58 | static irqreturn_t sir_interrupt(int irq, void *dev_id); | ||
59 | static void send_space(unsigned long len); | ||
60 | static void send_pulse(unsigned long len); | ||
61 | static int init_hardware(void); | ||
62 | static void drop_hardware(void); | ||
63 | /* Initialisation */ | ||
64 | static int init_port(void); | ||
65 | static void drop_port(void); | ||
66 | |||
67 | static inline unsigned int sinp(int offset) | ||
68 | { | ||
69 | return inb(io + offset); | ||
70 | } | ||
71 | |||
72 | static inline void soutp(int offset, int value) | ||
73 | { | ||
74 | outb(value, io + offset); | ||
75 | } | ||
76 | |||
77 | /* SECTION: Communication with user-space */ | ||
78 | static int sir_tx_ir(struct rc_dev *dev, unsigned int *tx_buf, | ||
79 | unsigned int count) | ||
80 | { | ||
81 | unsigned long flags; | ||
82 | int i; | ||
83 | |||
84 | local_irq_save(flags); | ||
85 | for (i = 0; i < count;) { | ||
86 | if (tx_buf[i]) | ||
87 | send_pulse(tx_buf[i]); | ||
88 | i++; | ||
89 | if (i >= count) | ||
90 | break; | ||
91 | if (tx_buf[i]) | ||
92 | send_space(tx_buf[i]); | ||
93 | i++; | ||
94 | } | ||
95 | local_irq_restore(flags); | ||
96 | |||
97 | return count; | ||
98 | } | ||
99 | |||
100 | static void add_read_queue(int flag, unsigned long val) | ||
101 | { | ||
102 | DEFINE_IR_RAW_EVENT(ev); | ||
103 | |||
104 | pr_debug("add flag %d with val %lu\n", flag, val); | ||
105 | |||
106 | /* | ||
107 | * statistically, pulses are ~TIME_CONST/2 too long. we could | ||
108 | * maybe make this more exact, but this is good enough | ||
109 | */ | ||
110 | if (flag) { | ||
111 | /* pulse */ | ||
112 | if (val > TIME_CONST / 2) | ||
113 | val -= TIME_CONST / 2; | ||
114 | else /* should not ever happen */ | ||
115 | val = 1; | ||
116 | ev.pulse = true; | ||
117 | } else { | ||
118 | val += TIME_CONST / 2; | ||
119 | } | ||
120 | ev.duration = US_TO_NS(val); | ||
121 | |||
122 | ir_raw_event_store_with_filter(rcdev, &ev); | ||
123 | } | ||
124 | |||
125 | static int init_chrdev(void) | ||
126 | { | ||
127 | rcdev = devm_rc_allocate_device(&sir_ir_dev->dev, RC_DRIVER_IR_RAW); | ||
128 | if (!rcdev) | ||
129 | return -ENOMEM; | ||
130 | |||
131 | rcdev->input_name = "SIR IrDA port"; | ||
132 | rcdev->input_phys = KBUILD_MODNAME "/input0"; | ||
133 | rcdev->input_id.bustype = BUS_HOST; | ||
134 | rcdev->input_id.vendor = 0x0001; | ||
135 | rcdev->input_id.product = 0x0001; | ||
136 | rcdev->input_id.version = 0x0100; | ||
137 | rcdev->tx_ir = sir_tx_ir; | ||
138 | rcdev->allowed_protocols = RC_BIT_ALL_IR_DECODER; | ||
139 | rcdev->driver_name = KBUILD_MODNAME; | ||
140 | rcdev->map_name = RC_MAP_RC6_MCE; | ||
141 | rcdev->timeout = IR_DEFAULT_TIMEOUT; | ||
142 | rcdev->dev.parent = &sir_ir_dev->dev; | ||
143 | |||
144 | return devm_rc_register_device(&sir_ir_dev->dev, rcdev); | ||
145 | } | ||
146 | |||
147 | /* SECTION: Hardware */ | ||
148 | static void sir_timeout(unsigned long data) | ||
149 | { | ||
150 | /* | ||
151 | * if last received signal was a pulse, but receiving stopped | ||
152 | * within the 9 bit frame, we need to finish this pulse and | ||
153 | * simulate a signal change to from pulse to space. Otherwise | ||
154 | * upper layers will receive two sequences next time. | ||
155 | */ | ||
156 | |||
157 | unsigned long flags; | ||
158 | unsigned long pulse_end; | ||
159 | |||
160 | /* avoid interference with interrupt */ | ||
161 | spin_lock_irqsave(&timer_lock, flags); | ||
162 | if (last_value) { | ||
163 | /* clear unread bits in UART and restart */ | ||
164 | outb(UART_FCR_CLEAR_RCVR, io + UART_FCR); | ||
165 | /* determine 'virtual' pulse end: */ | ||
166 | pulse_end = min_t(unsigned long, | ||
167 | ktime_us_delta(last, last_intr_time), | ||
168 | IR_MAX_DURATION); | ||
169 | dev_dbg(&sir_ir_dev->dev, "timeout add %d for %lu usec\n", | ||
170 | last_value, pulse_end); | ||
171 | add_read_queue(last_value, pulse_end); | ||
172 | last_value = 0; | ||
173 | last = last_intr_time; | ||
174 | } | ||
175 | spin_unlock_irqrestore(&timer_lock, flags); | ||
176 | ir_raw_event_handle(rcdev); | ||
177 | } | ||
178 | |||
179 | static irqreturn_t sir_interrupt(int irq, void *dev_id) | ||
180 | { | ||
181 | unsigned char data; | ||
182 | ktime_t curr_time; | ||
183 | static unsigned long delt; | ||
184 | unsigned long deltintr; | ||
185 | unsigned long flags; | ||
186 | int iir, lsr; | ||
187 | |||
188 | while ((iir = inb(io + UART_IIR) & UART_IIR_ID)) { | ||
189 | switch (iir & UART_IIR_ID) { /* FIXME toto treba preriedit */ | ||
190 | case UART_IIR_MSI: | ||
191 | (void)inb(io + UART_MSR); | ||
192 | break; | ||
193 | case UART_IIR_RLSI: | ||
194 | case UART_IIR_THRI: | ||
195 | (void)inb(io + UART_LSR); | ||
196 | break; | ||
197 | case UART_IIR_RDI: | ||
198 | /* avoid interference with timer */ | ||
199 | spin_lock_irqsave(&timer_lock, flags); | ||
200 | do { | ||
201 | del_timer(&timerlist); | ||
202 | data = inb(io + UART_RX); | ||
203 | curr_time = ktime_get(); | ||
204 | delt = min_t(unsigned long, | ||
205 | ktime_us_delta(last, curr_time), | ||
206 | IR_MAX_DURATION); | ||
207 | deltintr = min_t(unsigned long, | ||
208 | ktime_us_delta(last_intr_time, | ||
209 | curr_time), | ||
210 | IR_MAX_DURATION); | ||
211 | dev_dbg(&sir_ir_dev->dev, "t %lu, d %d\n", | ||
212 | deltintr, (int)data); | ||
213 | /* | ||
214 | * if nothing came in last X cycles, | ||
215 | * it was gap | ||
216 | */ | ||
217 | if (deltintr > TIME_CONST * threshold) { | ||
218 | if (last_value) { | ||
219 | dev_dbg(&sir_ir_dev->dev, "GAP\n"); | ||
220 | /* simulate signal change */ | ||
221 | add_read_queue(last_value, | ||
222 | delt - | ||
223 | deltintr); | ||
224 | last_value = 0; | ||
225 | last = last_intr_time; | ||
226 | delt = deltintr; | ||
227 | } | ||
228 | } | ||
229 | data = 1; | ||
230 | if (data ^ last_value) { | ||
231 | /* | ||
232 | * deltintr > 2*TIME_CONST, remember? | ||
233 | * the other case is timeout | ||
234 | */ | ||
235 | add_read_queue(last_value, | ||
236 | delt - TIME_CONST); | ||
237 | last_value = data; | ||
238 | last = curr_time; | ||
239 | last = ktime_sub_us(last, | ||
240 | TIME_CONST); | ||
241 | } | ||
242 | last_intr_time = curr_time; | ||
243 | if (data) { | ||
244 | /* | ||
245 | * start timer for end of | ||
246 | * sequence detection | ||
247 | */ | ||
248 | timerlist.expires = jiffies + | ||
249 | SIR_TIMEOUT; | ||
250 | add_timer(&timerlist); | ||
251 | } | ||
252 | |||
253 | lsr = inb(io + UART_LSR); | ||
254 | } while (lsr & UART_LSR_DR); /* data ready */ | ||
255 | spin_unlock_irqrestore(&timer_lock, flags); | ||
256 | break; | ||
257 | default: | ||
258 | break; | ||
259 | } | ||
260 | } | ||
261 | ir_raw_event_handle(rcdev); | ||
262 | return IRQ_RETVAL(IRQ_HANDLED); | ||
263 | } | ||
264 | |||
265 | static void send_space(unsigned long len) | ||
266 | { | ||
267 | usleep_range(len, len + 25); | ||
268 | } | ||
269 | |||
270 | static void send_pulse(unsigned long len) | ||
271 | { | ||
272 | long bytes_out = len / TIME_CONST; | ||
273 | |||
274 | if (bytes_out == 0) | ||
275 | bytes_out++; | ||
276 | |||
277 | while (bytes_out--) { | ||
278 | outb(PULSE, io + UART_TX); | ||
279 | /* FIXME treba seriozne cakanie z char/serial.c */ | ||
280 | while (!(inb(io + UART_LSR) & UART_LSR_THRE)) | ||
281 | ; | ||
282 | } | ||
283 | } | ||
284 | |||
285 | static int init_hardware(void) | ||
286 | { | ||
287 | unsigned long flags; | ||
288 | |||
289 | spin_lock_irqsave(&hardware_lock, flags); | ||
290 | /* reset UART */ | ||
291 | outb(0, io + UART_MCR); | ||
292 | outb(0, io + UART_IER); | ||
293 | /* init UART */ | ||
294 | /* set DLAB, speed = 115200 */ | ||
295 | outb(UART_LCR_DLAB | UART_LCR_WLEN7, io + UART_LCR); | ||
296 | outb(1, io + UART_DLL); outb(0, io + UART_DLM); | ||
297 | /* 7N1+start = 9 bits at 115200 ~ 3 bits at 44000 */ | ||
298 | outb(UART_LCR_WLEN7, io + UART_LCR); | ||
299 | /* FIFO operation */ | ||
300 | outb(UART_FCR_ENABLE_FIFO, io + UART_FCR); | ||
301 | /* interrupts */ | ||
302 | /* outb(UART_IER_RLSI|UART_IER_RDI|UART_IER_THRI, io + UART_IER); */ | ||
303 | outb(UART_IER_RDI, io + UART_IER); | ||
304 | /* turn on UART */ | ||
305 | outb(UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2, io + UART_MCR); | ||
306 | spin_unlock_irqrestore(&hardware_lock, flags); | ||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | static void drop_hardware(void) | ||
311 | { | ||
312 | unsigned long flags; | ||
313 | |||
314 | spin_lock_irqsave(&hardware_lock, flags); | ||
315 | |||
316 | /* turn off interrupts */ | ||
317 | outb(0, io + UART_IER); | ||
318 | |||
319 | spin_unlock_irqrestore(&hardware_lock, flags); | ||
320 | } | ||
321 | |||
322 | /* SECTION: Initialisation */ | ||
323 | |||
324 | static int init_port(void) | ||
325 | { | ||
326 | int retval; | ||
327 | |||
328 | setup_timer(&timerlist, sir_timeout, 0); | ||
329 | |||
330 | /* get I/O port access and IRQ line */ | ||
331 | if (!request_region(io, 8, KBUILD_MODNAME)) { | ||
332 | pr_err("i/o port 0x%.4x already in use.\n", io); | ||
333 | return -EBUSY; | ||
334 | } | ||
335 | retval = request_irq(irq, sir_interrupt, 0, | ||
336 | KBUILD_MODNAME, NULL); | ||
337 | if (retval < 0) { | ||
338 | release_region(io, 8); | ||
339 | pr_err("IRQ %d already in use.\n", irq); | ||
340 | return retval; | ||
341 | } | ||
342 | pr_info("I/O port 0x%.4x, IRQ %d.\n", io, irq); | ||
343 | |||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | static void drop_port(void) | ||
348 | { | ||
349 | free_irq(irq, NULL); | ||
350 | del_timer_sync(&timerlist); | ||
351 | release_region(io, 8); | ||
352 | } | ||
353 | |||
354 | static int init_sir_ir(void) | ||
355 | { | ||
356 | int retval; | ||
357 | |||
358 | retval = init_port(); | ||
359 | if (retval < 0) | ||
360 | return retval; | ||
361 | init_hardware(); | ||
362 | return 0; | ||
363 | } | ||
364 | |||
365 | static int sir_ir_probe(struct platform_device *dev) | ||
366 | { | ||
367 | int retval; | ||
368 | |||
369 | retval = init_chrdev(); | ||
370 | if (retval < 0) | ||
371 | return retval; | ||
372 | |||
373 | return init_sir_ir(); | ||
374 | } | ||
375 | |||
376 | static int sir_ir_remove(struct platform_device *dev) | ||
377 | { | ||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | static struct platform_driver sir_ir_driver = { | ||
382 | .probe = sir_ir_probe, | ||
383 | .remove = sir_ir_remove, | ||
384 | .driver = { | ||
385 | .name = "sir_ir", | ||
386 | }, | ||
387 | }; | ||
388 | |||
389 | static int __init sir_ir_init(void) | ||
390 | { | ||
391 | int retval; | ||
392 | |||
393 | retval = platform_driver_register(&sir_ir_driver); | ||
394 | if (retval) | ||
395 | return retval; | ||
396 | |||
397 | sir_ir_dev = platform_device_alloc("sir_ir", 0); | ||
398 | if (!sir_ir_dev) { | ||
399 | retval = -ENOMEM; | ||
400 | goto pdev_alloc_fail; | ||
401 | } | ||
402 | |||
403 | retval = platform_device_add(sir_ir_dev); | ||
404 | if (retval) | ||
405 | goto pdev_add_fail; | ||
406 | |||
407 | return 0; | ||
408 | |||
409 | pdev_add_fail: | ||
410 | platform_device_put(sir_ir_dev); | ||
411 | pdev_alloc_fail: | ||
412 | platform_driver_unregister(&sir_ir_driver); | ||
413 | return retval; | ||
414 | } | ||
415 | |||
416 | static void __exit sir_ir_exit(void) | ||
417 | { | ||
418 | drop_hardware(); | ||
419 | drop_port(); | ||
420 | platform_device_unregister(sir_ir_dev); | ||
421 | platform_driver_unregister(&sir_ir_driver); | ||
422 | } | ||
423 | |||
424 | module_init(sir_ir_init); | ||
425 | module_exit(sir_ir_exit); | ||
426 | |||
427 | MODULE_DESCRIPTION("Infrared receiver driver for SIR type serial ports"); | ||
428 | MODULE_AUTHOR("Milan Pikula"); | ||
429 | MODULE_LICENSE("GPL"); | ||
430 | |||
431 | module_param(io, int, 0444); | ||
432 | MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)"); | ||
433 | |||
434 | module_param(irq, int, 0444); | ||
435 | MODULE_PARM_DESC(irq, "Interrupt (4 or 3)"); | ||
436 | |||
437 | module_param(threshold, int, 0444); | ||
438 | MODULE_PARM_DESC(threshold, "space detection threshold (3)"); | ||
diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c index f0d7190e3919..a08e1dd06124 100644 --- a/drivers/media/rc/st_rc.c +++ b/drivers/media/rc/st_rc.c | |||
@@ -165,8 +165,7 @@ static void st_rc_hardware_init(struct st_rc_device *dev) | |||
165 | unsigned int rx_sampling_freq_div; | 165 | unsigned int rx_sampling_freq_div; |
166 | 166 | ||
167 | /* Enable the IP */ | 167 | /* Enable the IP */ |
168 | if (dev->rstc) | 168 | reset_control_deassert(dev->rstc); |
169 | reset_control_deassert(dev->rstc); | ||
170 | 169 | ||
171 | clk_prepare_enable(dev->sys_clock); | 170 | clk_prepare_enable(dev->sys_clock); |
172 | baseclock = clk_get_rate(dev->sys_clock); | 171 | baseclock = clk_get_rate(dev->sys_clock); |
@@ -281,10 +280,11 @@ static int st_rc_probe(struct platform_device *pdev) | |||
281 | else | 280 | else |
282 | rc_dev->rx_base = rc_dev->base; | 281 | rc_dev->rx_base = rc_dev->base; |
283 | 282 | ||
284 | |||
285 | rc_dev->rstc = reset_control_get_optional(dev, NULL); | 283 | rc_dev->rstc = reset_control_get_optional(dev, NULL); |
286 | if (IS_ERR(rc_dev->rstc)) | 284 | if (IS_ERR(rc_dev->rstc)) { |
287 | rc_dev->rstc = NULL; | 285 | ret = PTR_ERR(rc_dev->rstc); |
286 | goto err; | ||
287 | } | ||
288 | 288 | ||
289 | rc_dev->dev = dev; | 289 | rc_dev->dev = dev; |
290 | platform_set_drvdata(pdev, rc_dev); | 290 | platform_set_drvdata(pdev, rc_dev); |
@@ -298,7 +298,7 @@ static int st_rc_probe(struct platform_device *pdev) | |||
298 | rdev->open = st_rc_open; | 298 | rdev->open = st_rc_open; |
299 | rdev->close = st_rc_close; | 299 | rdev->close = st_rc_close; |
300 | rdev->driver_name = IR_ST_NAME; | 300 | rdev->driver_name = IR_ST_NAME; |
301 | rdev->map_name = RC_MAP_LIRC; | 301 | rdev->map_name = RC_MAP_EMPTY; |
302 | rdev->input_name = "ST Remote Control Receiver"; | 302 | rdev->input_name = "ST Remote Control Receiver"; |
303 | 303 | ||
304 | ret = rc_register_device(rdev); | 304 | ret = rc_register_device(rdev); |
@@ -352,8 +352,7 @@ static int st_rc_suspend(struct device *dev) | |||
352 | writel(0x00, rc_dev->rx_base + IRB_RX_EN); | 352 | writel(0x00, rc_dev->rx_base + IRB_RX_EN); |
353 | writel(0x00, rc_dev->rx_base + IRB_RX_INT_EN); | 353 | writel(0x00, rc_dev->rx_base + IRB_RX_INT_EN); |
354 | clk_disable_unprepare(rc_dev->sys_clock); | 354 | clk_disable_unprepare(rc_dev->sys_clock); |
355 | if (rc_dev->rstc) | 355 | reset_control_assert(rc_dev->rstc); |
356 | reset_control_assert(rc_dev->rstc); | ||
357 | } | 356 | } |
358 | 357 | ||
359 | return 0; | 358 | return 0; |
diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c index 25b006167810..4b785dd775c1 100644 --- a/drivers/media/rc/sunxi-cir.c +++ b/drivers/media/rc/sunxi-cir.c | |||
@@ -174,16 +174,11 @@ static int sunxi_ir_probe(struct platform_device *pdev) | |||
174 | 174 | ||
175 | /* Reset (optional) */ | 175 | /* Reset (optional) */ |
176 | ir->rst = devm_reset_control_get_optional(dev, NULL); | 176 | ir->rst = devm_reset_control_get_optional(dev, NULL); |
177 | if (IS_ERR(ir->rst)) { | 177 | if (IS_ERR(ir->rst)) |
178 | ret = PTR_ERR(ir->rst); | 178 | return PTR_ERR(ir->rst); |
179 | if (ret == -EPROBE_DEFER) | 179 | ret = reset_control_deassert(ir->rst); |
180 | return ret; | 180 | if (ret) |
181 | ir->rst = NULL; | 181 | return ret; |
182 | } else { | ||
183 | ret = reset_control_deassert(ir->rst); | ||
184 | if (ret) | ||
185 | return ret; | ||
186 | } | ||
187 | 182 | ||
188 | ret = clk_set_rate(ir->clk, SUNXI_IR_BASE_CLK); | 183 | ret = clk_set_rate(ir->clk, SUNXI_IR_BASE_CLK); |
189 | if (ret) { | 184 | if (ret) { |
@@ -291,8 +286,7 @@ exit_clkdisable_clk: | |||
291 | exit_clkdisable_apb_clk: | 286 | exit_clkdisable_apb_clk: |
292 | clk_disable_unprepare(ir->apb_clk); | 287 | clk_disable_unprepare(ir->apb_clk); |
293 | exit_reset_assert: | 288 | exit_reset_assert: |
294 | if (ir->rst) | 289 | reset_control_assert(ir->rst); |
295 | reset_control_assert(ir->rst); | ||
296 | 290 | ||
297 | return ret; | 291 | return ret; |
298 | } | 292 | } |
@@ -304,8 +298,7 @@ static int sunxi_ir_remove(struct platform_device *pdev) | |||
304 | 298 | ||
305 | clk_disable_unprepare(ir->clk); | 299 | clk_disable_unprepare(ir->clk); |
306 | clk_disable_unprepare(ir->apb_clk); | 300 | clk_disable_unprepare(ir->apb_clk); |
307 | if (ir->rst) | 301 | reset_control_assert(ir->rst); |
308 | reset_control_assert(ir->rst); | ||
309 | 302 | ||
310 | spin_lock_irqsave(&ir->ir_lock, flags); | 303 | spin_lock_irqsave(&ir->ir_lock, flags); |
311 | /* disable IR IRQ */ | 304 | /* disable IR IRQ */ |
diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c index dc1c8305ad23..5a4d4a611197 100644 --- a/drivers/media/rc/winbond-cir.c +++ b/drivers/media/rc/winbond-cir.c | |||
@@ -1082,7 +1082,9 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id) | |||
1082 | data->dev->tx_ir = wbcir_tx; | 1082 | data->dev->tx_ir = wbcir_tx; |
1083 | data->dev->priv = data; | 1083 | data->dev->priv = data; |
1084 | data->dev->dev.parent = &device->dev; | 1084 | data->dev->dev.parent = &device->dev; |
1085 | data->dev->timeout = MS_TO_NS(100); | 1085 | data->dev->min_timeout = 1; |
1086 | data->dev->timeout = IR_DEFAULT_TIMEOUT; | ||
1087 | data->dev->max_timeout = 10 * IR_DEFAULT_TIMEOUT; | ||
1086 | data->dev->rx_resolution = US_TO_NS(2); | 1088 | data->dev->rx_resolution = US_TO_NS(2); |
1087 | data->dev->allowed_protocols = RC_BIT_ALL_IR_DECODER; | 1089 | data->dev->allowed_protocols = RC_BIT_ALL_IR_DECODER; |
1088 | data->dev->allowed_wakeup_protocols = RC_BIT_NEC | RC_BIT_NECX | | 1090 | data->dev->allowed_wakeup_protocols = RC_BIT_NEC | RC_BIT_NECX | |
diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c index 57b250847cd3..e35b1faf0ddc 100644 --- a/drivers/media/tuners/si2157.c +++ b/drivers/media/tuners/si2157.c | |||
@@ -106,6 +106,9 @@ static int si2157_init(struct dvb_frontend *fe) | |||
106 | if (dev->chiptype == SI2157_CHIPTYPE_SI2146) { | 106 | if (dev->chiptype == SI2157_CHIPTYPE_SI2146) { |
107 | memcpy(cmd.args, "\xc0\x05\x01\x00\x00\x0b\x00\x00\x01", 9); | 107 | memcpy(cmd.args, "\xc0\x05\x01\x00\x00\x0b\x00\x00\x01", 9); |
108 | cmd.wlen = 9; | 108 | cmd.wlen = 9; |
109 | } else if (dev->chiptype == SI2157_CHIPTYPE_SI2141) { | ||
110 | memcpy(cmd.args, "\xc0\x00\x0d\x0e\x00\x01\x01\x01\x01\x03", 10); | ||
111 | cmd.wlen = 10; | ||
109 | } else { | 112 | } else { |
110 | memcpy(cmd.args, "\xc0\x00\x0c\x00\x00\x01\x01\x01\x01\x01\x01\x02\x00\x00\x01", 15); | 113 | memcpy(cmd.args, "\xc0\x00\x0c\x00\x00\x01\x01\x01\x01\x01\x01\x02\x00\x00\x01", 15); |
111 | cmd.wlen = 15; | 114 | cmd.wlen = 15; |
@@ -115,6 +118,15 @@ static int si2157_init(struct dvb_frontend *fe) | |||
115 | if (ret) | 118 | if (ret) |
116 | goto err; | 119 | goto err; |
117 | 120 | ||
121 | /* Si2141 needs a second command before it answers the revision query */ | ||
122 | if (dev->chiptype == SI2157_CHIPTYPE_SI2141) { | ||
123 | memcpy(cmd.args, "\xc0\x08\x01\x02\x00\x00\x01", 7); | ||
124 | cmd.wlen = 7; | ||
125 | ret = si2157_cmd_execute(client, &cmd); | ||
126 | if (ret) | ||
127 | goto err; | ||
128 | } | ||
129 | |||
118 | /* query chip revision */ | 130 | /* query chip revision */ |
119 | memcpy(cmd.args, "\x02", 1); | 131 | memcpy(cmd.args, "\x02", 1); |
120 | cmd.wlen = 1; | 132 | cmd.wlen = 1; |
@@ -131,12 +143,16 @@ static int si2157_init(struct dvb_frontend *fe) | |||
131 | #define SI2157_A30 ('A' << 24 | 57 << 16 | '3' << 8 | '0' << 0) | 143 | #define SI2157_A30 ('A' << 24 | 57 << 16 | '3' << 8 | '0' << 0) |
132 | #define SI2147_A30 ('A' << 24 | 47 << 16 | '3' << 8 | '0' << 0) | 144 | #define SI2147_A30 ('A' << 24 | 47 << 16 | '3' << 8 | '0' << 0) |
133 | #define SI2146_A10 ('A' << 24 | 46 << 16 | '1' << 8 | '0' << 0) | 145 | #define SI2146_A10 ('A' << 24 | 46 << 16 | '1' << 8 | '0' << 0) |
146 | #define SI2141_A10 ('A' << 24 | 41 << 16 | '1' << 8 | '0' << 0) | ||
134 | 147 | ||
135 | switch (chip_id) { | 148 | switch (chip_id) { |
136 | case SI2158_A20: | 149 | case SI2158_A20: |
137 | case SI2148_A20: | 150 | case SI2148_A20: |
138 | fw_name = SI2158_A20_FIRMWARE; | 151 | fw_name = SI2158_A20_FIRMWARE; |
139 | break; | 152 | break; |
153 | case SI2141_A10: | ||
154 | fw_name = SI2141_A10_FIRMWARE; | ||
155 | break; | ||
140 | case SI2157_A30: | 156 | case SI2157_A30: |
141 | case SI2147_A30: | 157 | case SI2147_A30: |
142 | case SI2146_A10: | 158 | case SI2146_A10: |
@@ -371,7 +387,7 @@ static int si2157_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) | |||
371 | 387 | ||
372 | static const struct dvb_tuner_ops si2157_ops = { | 388 | static const struct dvb_tuner_ops si2157_ops = { |
373 | .info = { | 389 | .info = { |
374 | .name = "Silicon Labs Si2146/2147/2148/2157/2158", | 390 | .name = "Silicon Labs Si2141/Si2146/2147/2148/2157/2158", |
375 | .frequency_min = 42000000, | 391 | .frequency_min = 42000000, |
376 | .frequency_max = 870000000, | 392 | .frequency_max = 870000000, |
377 | }, | 393 | }, |
@@ -471,6 +487,7 @@ static int si2157_probe(struct i2c_client *client, | |||
471 | #endif | 487 | #endif |
472 | 488 | ||
473 | dev_info(&client->dev, "Silicon Labs %s successfully attached\n", | 489 | dev_info(&client->dev, "Silicon Labs %s successfully attached\n", |
490 | dev->chiptype == SI2157_CHIPTYPE_SI2141 ? "Si2141" : | ||
474 | dev->chiptype == SI2157_CHIPTYPE_SI2146 ? | 491 | dev->chiptype == SI2157_CHIPTYPE_SI2146 ? |
475 | "Si2146" : "Si2147/2148/2157/2158"); | 492 | "Si2146" : "Si2147/2148/2157/2158"); |
476 | 493 | ||
@@ -508,6 +525,7 @@ static int si2157_remove(struct i2c_client *client) | |||
508 | static const struct i2c_device_id si2157_id_table[] = { | 525 | static const struct i2c_device_id si2157_id_table[] = { |
509 | {"si2157", SI2157_CHIPTYPE_SI2157}, | 526 | {"si2157", SI2157_CHIPTYPE_SI2157}, |
510 | {"si2146", SI2157_CHIPTYPE_SI2146}, | 527 | {"si2146", SI2157_CHIPTYPE_SI2146}, |
528 | {"si2141", SI2157_CHIPTYPE_SI2141}, | ||
511 | {} | 529 | {} |
512 | }; | 530 | }; |
513 | MODULE_DEVICE_TABLE(i2c, si2157_id_table); | 531 | MODULE_DEVICE_TABLE(i2c, si2157_id_table); |
@@ -524,7 +542,8 @@ static struct i2c_driver si2157_driver = { | |||
524 | 542 | ||
525 | module_i2c_driver(si2157_driver); | 543 | module_i2c_driver(si2157_driver); |
526 | 544 | ||
527 | MODULE_DESCRIPTION("Silicon Labs Si2146/2147/2148/2157/2158 silicon tuner driver"); | 545 | MODULE_DESCRIPTION("Silicon Labs Si2141/Si2146/2147/2148/2157/2158 silicon tuner driver"); |
528 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | 546 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); |
529 | MODULE_LICENSE("GPL"); | 547 | MODULE_LICENSE("GPL"); |
530 | MODULE_FIRMWARE(SI2158_A20_FIRMWARE); | 548 | MODULE_FIRMWARE(SI2158_A20_FIRMWARE); |
549 | MODULE_FIRMWARE(SI2141_A10_FIRMWARE); | ||
diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h index d6b2c7b44053..e6436f74abaa 100644 --- a/drivers/media/tuners/si2157_priv.h +++ b/drivers/media/tuners/si2157_priv.h | |||
@@ -42,6 +42,7 @@ struct si2157_dev { | |||
42 | 42 | ||
43 | #define SI2157_CHIPTYPE_SI2157 0 | 43 | #define SI2157_CHIPTYPE_SI2157 0 |
44 | #define SI2157_CHIPTYPE_SI2146 1 | 44 | #define SI2157_CHIPTYPE_SI2146 1 |
45 | #define SI2157_CHIPTYPE_SI2141 2 | ||
45 | 46 | ||
46 | /* firmware command struct */ | 47 | /* firmware command struct */ |
47 | #define SI2157_ARGLEN 30 | 48 | #define SI2157_ARGLEN 30 |
@@ -52,5 +53,6 @@ struct si2157_cmd { | |||
52 | }; | 53 | }; |
53 | 54 | ||
54 | #define SI2158_A20_FIRMWARE "dvb-tuner-si2158-a20-01.fw" | 55 | #define SI2158_A20_FIRMWARE "dvb-tuner-si2158-a20-01.fw" |
56 | #define SI2141_A10_FIRMWARE "dvb-tuner-si2141-a10-01.fw" | ||
55 | 57 | ||
56 | #endif | 58 | #endif |
diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c index 91947cf1950e..e823aafce276 100644 --- a/drivers/media/tuners/xc5000.c +++ b/drivers/media/tuners/xc5000.c | |||
@@ -1184,8 +1184,7 @@ static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force) | |||
1184 | /* Start the tuner self-calibration process */ | 1184 | /* Start the tuner self-calibration process */ |
1185 | ret = xc_initialize(priv); | 1185 | ret = xc_initialize(priv); |
1186 | if (ret) { | 1186 | if (ret) { |
1187 | printk(KERN_ERR | 1187 | printk(KERN_ERR "xc5000: Can't request self-calibration."); |
1188 | "xc5000: Can't request Self-callibration."); | ||
1189 | continue; | 1188 | continue; |
1190 | } | 1189 | } |
1191 | 1190 | ||
diff --git a/drivers/media/usb/Kconfig b/drivers/media/usb/Kconfig index c9644b62f91a..b24e753c4766 100644 --- a/drivers/media/usb/Kconfig +++ b/drivers/media/usb/Kconfig | |||
@@ -63,6 +63,7 @@ endif | |||
63 | if MEDIA_CEC_SUPPORT | 63 | if MEDIA_CEC_SUPPORT |
64 | comment "USB HDMI CEC adapters" | 64 | comment "USB HDMI CEC adapters" |
65 | source "drivers/media/usb/pulse8-cec/Kconfig" | 65 | source "drivers/media/usb/pulse8-cec/Kconfig" |
66 | source "drivers/media/usb/rainshadow-cec/Kconfig" | ||
66 | endif | 67 | endif |
67 | 68 | ||
68 | endif #MEDIA_USB_SUPPORT | 69 | endif #MEDIA_USB_SUPPORT |
diff --git a/drivers/media/usb/Makefile b/drivers/media/usb/Makefile index 0f15e3351ddc..738b993ec8b0 100644 --- a/drivers/media/usb/Makefile +++ b/drivers/media/usb/Makefile | |||
@@ -25,3 +25,4 @@ obj-$(CONFIG_VIDEO_USBTV) += usbtv/ | |||
25 | obj-$(CONFIG_VIDEO_GO7007) += go7007/ | 25 | obj-$(CONFIG_VIDEO_GO7007) += go7007/ |
26 | obj-$(CONFIG_DVB_AS102) += as102/ | 26 | obj-$(CONFIG_DVB_AS102) += as102/ |
27 | obj-$(CONFIG_USB_PULSE8_CEC) += pulse8-cec/ | 27 | obj-$(CONFIG_USB_PULSE8_CEC) += pulse8-cec/ |
28 | obj-$(CONFIG_USB_RAINSHADOW_CEC) += rainshadow-cec/ | ||
diff --git a/drivers/media/usb/au0828/au0828-cards.c b/drivers/media/usb/au0828/au0828-cards.c index 313f659f0bfb..43bfa778b070 100644 --- a/drivers/media/usb/au0828/au0828-cards.c +++ b/drivers/media/usb/au0828/au0828-cards.c | |||
@@ -153,7 +153,7 @@ static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data) | |||
153 | { | 153 | { |
154 | struct tveeprom tv; | 154 | struct tveeprom tv; |
155 | 155 | ||
156 | tveeprom_hauppauge_analog(&dev->i2c_client, &tv, eeprom_data); | 156 | tveeprom_hauppauge_analog(&tv, eeprom_data); |
157 | dev->board.tuner_type = tv.tuner_type; | 157 | dev->board.tuner_type = tv.tuner_type; |
158 | 158 | ||
159 | /* Make sure we support the board model */ | 159 | /* Make sure we support the board model */ |
diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 16f9125a985a..2a255bd32bb3 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c | |||
@@ -809,16 +809,9 @@ static void au0828_analog_stream_reset(struct au0828_dev *dev) | |||
809 | */ | 809 | */ |
810 | static int au0828_stream_interrupt(struct au0828_dev *dev) | 810 | static int au0828_stream_interrupt(struct au0828_dev *dev) |
811 | { | 811 | { |
812 | int ret = 0; | ||
813 | |||
814 | dev->stream_state = STREAM_INTERRUPT; | 812 | dev->stream_state = STREAM_INTERRUPT; |
815 | if (test_bit(DEV_DISCONNECTED, &dev->dev_state)) | 813 | if (test_bit(DEV_DISCONNECTED, &dev->dev_state)) |
816 | return -ENODEV; | 814 | return -ENODEV; |
817 | else if (ret) { | ||
818 | set_bit(DEV_MISCONFIGURED, &dev->dev_state); | ||
819 | dprintk(1, "%s device is misconfigured!\n", __func__); | ||
820 | return ret; | ||
821 | } | ||
822 | return 0; | 815 | return 0; |
823 | } | 816 | } |
824 | 817 | ||
diff --git a/drivers/media/usb/cx231xx/cx231xx-audio.c b/drivers/media/usb/cx231xx/cx231xx-audio.c index cf80842dfa08..a050d125934c 100644 --- a/drivers/media/usb/cx231xx/cx231xx-audio.c +++ b/drivers/media/usb/cx231xx/cx231xx-audio.c | |||
@@ -670,10 +670,8 @@ static int cx231xx_audio_init(struct cx231xx *dev) | |||
670 | 670 | ||
671 | spin_lock_init(&adev->slock); | 671 | spin_lock_init(&adev->slock); |
672 | err = snd_pcm_new(card, "Cx231xx Audio", 0, 0, 1, &pcm); | 672 | err = snd_pcm_new(card, "Cx231xx Audio", 0, 0, 1, &pcm); |
673 | if (err < 0) { | 673 | if (err < 0) |
674 | snd_card_free(card); | 674 | goto err_free_card; |
675 | return err; | ||
676 | } | ||
677 | 675 | ||
678 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, | 676 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, |
679 | &snd_cx231xx_pcm_capture); | 677 | &snd_cx231xx_pcm_capture); |
@@ -687,10 +685,9 @@ static int cx231xx_audio_init(struct cx231xx *dev) | |||
687 | INIT_WORK(&dev->wq_trigger, audio_trigger); | 685 | INIT_WORK(&dev->wq_trigger, audio_trigger); |
688 | 686 | ||
689 | err = snd_card_register(card); | 687 | err = snd_card_register(card); |
690 | if (err < 0) { | 688 | if (err < 0) |
691 | snd_card_free(card); | 689 | goto err_free_card; |
692 | return err; | 690 | |
693 | } | ||
694 | adev->sndcard = card; | 691 | adev->sndcard = card; |
695 | adev->udev = dev->udev; | 692 | adev->udev = dev->udev; |
696 | 693 | ||
@@ -700,6 +697,11 @@ static int cx231xx_audio_init(struct cx231xx *dev) | |||
700 | hs_config_info[0].interface_info. | 697 | hs_config_info[0].interface_info. |
701 | audio_index + 1]; | 698 | audio_index + 1]; |
702 | 699 | ||
700 | if (uif->altsetting[0].desc.bNumEndpoints < isoc_pipe + 1) { | ||
701 | err = -ENODEV; | ||
702 | goto err_free_card; | ||
703 | } | ||
704 | |||
703 | adev->end_point_addr = | 705 | adev->end_point_addr = |
704 | uif->altsetting[0].endpoint[isoc_pipe].desc. | 706 | uif->altsetting[0].endpoint[isoc_pipe].desc. |
705 | bEndpointAddress; | 707 | bEndpointAddress; |
@@ -709,13 +711,20 @@ static int cx231xx_audio_init(struct cx231xx *dev) | |||
709 | "audio EndPoint Addr 0x%x, Alternate settings: %i\n", | 711 | "audio EndPoint Addr 0x%x, Alternate settings: %i\n", |
710 | adev->end_point_addr, adev->num_alt); | 712 | adev->end_point_addr, adev->num_alt); |
711 | adev->alt_max_pkt_size = kmalloc(32 * adev->num_alt, GFP_KERNEL); | 713 | adev->alt_max_pkt_size = kmalloc(32 * adev->num_alt, GFP_KERNEL); |
712 | 714 | if (!adev->alt_max_pkt_size) { | |
713 | if (adev->alt_max_pkt_size == NULL) | 715 | err = -ENOMEM; |
714 | return -ENOMEM; | 716 | goto err_free_card; |
717 | } | ||
715 | 718 | ||
716 | for (i = 0; i < adev->num_alt; i++) { | 719 | for (i = 0; i < adev->num_alt; i++) { |
717 | u16 tmp = | 720 | u16 tmp; |
718 | le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc. | 721 | |
722 | if (uif->altsetting[i].desc.bNumEndpoints < isoc_pipe + 1) { | ||
723 | err = -ENODEV; | ||
724 | goto err_free_pkt_size; | ||
725 | } | ||
726 | |||
727 | tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc. | ||
719 | wMaxPacketSize); | 728 | wMaxPacketSize); |
720 | adev->alt_max_pkt_size[i] = | 729 | adev->alt_max_pkt_size[i] = |
721 | (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); | 730 | (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); |
@@ -725,6 +734,13 @@ static int cx231xx_audio_init(struct cx231xx *dev) | |||
725 | } | 734 | } |
726 | 735 | ||
727 | return 0; | 736 | return 0; |
737 | |||
738 | err_free_pkt_size: | ||
739 | kfree(adev->alt_max_pkt_size); | ||
740 | err_free_card: | ||
741 | snd_card_free(card); | ||
742 | |||
743 | return err; | ||
728 | } | 744 | } |
729 | 745 | ||
730 | static int cx231xx_audio_fini(struct cx231xx *dev) | 746 | static int cx231xx_audio_fini(struct cx231xx *dev) |
diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index f730fdbc9156..a1007d005290 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c | |||
@@ -1165,8 +1165,7 @@ void cx231xx_card_setup(struct cx231xx *dev) | |||
1165 | e->client.addr = 0xa0 >> 1; | 1165 | e->client.addr = 0xa0 >> 1; |
1166 | 1166 | ||
1167 | read_eeprom(dev, &e->client, e->eeprom, sizeof(e->eeprom)); | 1167 | read_eeprom(dev, &e->client, e->eeprom, sizeof(e->eeprom)); |
1168 | tveeprom_hauppauge_analog(&e->client, | 1168 | tveeprom_hauppauge_analog(&e->tvee, e->eeprom + 0xc0); |
1169 | &e->tvee, e->eeprom + 0xc0); | ||
1170 | kfree(e); | 1169 | kfree(e); |
1171 | break; | 1170 | break; |
1172 | } | 1171 | } |
@@ -1426,6 +1425,9 @@ static int cx231xx_init_v4l2(struct cx231xx *dev, | |||
1426 | 1425 | ||
1427 | uif = udev->actconfig->interface[idx]; | 1426 | uif = udev->actconfig->interface[idx]; |
1428 | 1427 | ||
1428 | if (uif->altsetting[0].desc.bNumEndpoints < isoc_pipe + 1) | ||
1429 | return -ENODEV; | ||
1430 | |||
1429 | dev->video_mode.end_point_addr = uif->altsetting[0].endpoint[isoc_pipe].desc.bEndpointAddress; | 1431 | dev->video_mode.end_point_addr = uif->altsetting[0].endpoint[isoc_pipe].desc.bEndpointAddress; |
1430 | dev->video_mode.num_alt = uif->num_altsetting; | 1432 | dev->video_mode.num_alt = uif->num_altsetting; |
1431 | 1433 | ||
@@ -1439,7 +1441,12 @@ static int cx231xx_init_v4l2(struct cx231xx *dev, | |||
1439 | return -ENOMEM; | 1441 | return -ENOMEM; |
1440 | 1442 | ||
1441 | for (i = 0; i < dev->video_mode.num_alt; i++) { | 1443 | for (i = 0; i < dev->video_mode.num_alt; i++) { |
1442 | u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc.wMaxPacketSize); | 1444 | u16 tmp; |
1445 | |||
1446 | if (uif->altsetting[i].desc.bNumEndpoints < isoc_pipe + 1) | ||
1447 | return -ENODEV; | ||
1448 | |||
1449 | tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc.wMaxPacketSize); | ||
1443 | dev->video_mode.alt_max_pkt_size[i] = (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); | 1450 | dev->video_mode.alt_max_pkt_size[i] = (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); |
1444 | dev_dbg(dev->dev, | 1451 | dev_dbg(dev->dev, |
1445 | "Alternate setting %i, max size= %i\n", i, | 1452 | "Alternate setting %i, max size= %i\n", i, |
@@ -1456,6 +1463,9 @@ static int cx231xx_init_v4l2(struct cx231xx *dev, | |||
1456 | } | 1463 | } |
1457 | uif = udev->actconfig->interface[idx]; | 1464 | uif = udev->actconfig->interface[idx]; |
1458 | 1465 | ||
1466 | if (uif->altsetting[0].desc.bNumEndpoints < isoc_pipe + 1) | ||
1467 | return -ENODEV; | ||
1468 | |||
1459 | dev->vbi_mode.end_point_addr = | 1469 | dev->vbi_mode.end_point_addr = |
1460 | uif->altsetting[0].endpoint[isoc_pipe].desc. | 1470 | uif->altsetting[0].endpoint[isoc_pipe].desc. |
1461 | bEndpointAddress; | 1471 | bEndpointAddress; |
@@ -1472,8 +1482,12 @@ static int cx231xx_init_v4l2(struct cx231xx *dev, | |||
1472 | return -ENOMEM; | 1482 | return -ENOMEM; |
1473 | 1483 | ||
1474 | for (i = 0; i < dev->vbi_mode.num_alt; i++) { | 1484 | for (i = 0; i < dev->vbi_mode.num_alt; i++) { |
1475 | u16 tmp = | 1485 | u16 tmp; |
1476 | le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe]. | 1486 | |
1487 | if (uif->altsetting[i].desc.bNumEndpoints < isoc_pipe + 1) | ||
1488 | return -ENODEV; | ||
1489 | |||
1490 | tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe]. | ||
1477 | desc.wMaxPacketSize); | 1491 | desc.wMaxPacketSize); |
1478 | dev->vbi_mode.alt_max_pkt_size[i] = | 1492 | dev->vbi_mode.alt_max_pkt_size[i] = |
1479 | (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); | 1493 | (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); |
@@ -1493,6 +1507,9 @@ static int cx231xx_init_v4l2(struct cx231xx *dev, | |||
1493 | } | 1507 | } |
1494 | uif = udev->actconfig->interface[idx]; | 1508 | uif = udev->actconfig->interface[idx]; |
1495 | 1509 | ||
1510 | if (uif->altsetting[0].desc.bNumEndpoints < isoc_pipe + 1) | ||
1511 | return -ENODEV; | ||
1512 | |||
1496 | dev->sliced_cc_mode.end_point_addr = | 1513 | dev->sliced_cc_mode.end_point_addr = |
1497 | uif->altsetting[0].endpoint[isoc_pipe].desc. | 1514 | uif->altsetting[0].endpoint[isoc_pipe].desc. |
1498 | bEndpointAddress; | 1515 | bEndpointAddress; |
@@ -1507,7 +1524,12 @@ static int cx231xx_init_v4l2(struct cx231xx *dev, | |||
1507 | return -ENOMEM; | 1524 | return -ENOMEM; |
1508 | 1525 | ||
1509 | for (i = 0; i < dev->sliced_cc_mode.num_alt; i++) { | 1526 | for (i = 0; i < dev->sliced_cc_mode.num_alt; i++) { |
1510 | u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe]. | 1527 | u16 tmp; |
1528 | |||
1529 | if (uif->altsetting[i].desc.bNumEndpoints < isoc_pipe + 1) | ||
1530 | return -ENODEV; | ||
1531 | |||
1532 | tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe]. | ||
1511 | desc.wMaxPacketSize); | 1533 | desc.wMaxPacketSize); |
1512 | dev->sliced_cc_mode.alt_max_pkt_size[i] = | 1534 | dev->sliced_cc_mode.alt_max_pkt_size[i] = |
1513 | (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); | 1535 | (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); |
@@ -1676,6 +1698,11 @@ static int cx231xx_usb_probe(struct usb_interface *interface, | |||
1676 | } | 1698 | } |
1677 | uif = udev->actconfig->interface[idx]; | 1699 | uif = udev->actconfig->interface[idx]; |
1678 | 1700 | ||
1701 | if (uif->altsetting[0].desc.bNumEndpoints < isoc_pipe + 1) { | ||
1702 | retval = -ENODEV; | ||
1703 | goto err_video_alt; | ||
1704 | } | ||
1705 | |||
1679 | dev->ts1_mode.end_point_addr = | 1706 | dev->ts1_mode.end_point_addr = |
1680 | uif->altsetting[0].endpoint[isoc_pipe]. | 1707 | uif->altsetting[0].endpoint[isoc_pipe]. |
1681 | desc.bEndpointAddress; | 1708 | desc.bEndpointAddress; |
@@ -1693,7 +1720,14 @@ static int cx231xx_usb_probe(struct usb_interface *interface, | |||
1693 | } | 1720 | } |
1694 | 1721 | ||
1695 | for (i = 0; i < dev->ts1_mode.num_alt; i++) { | 1722 | for (i = 0; i < dev->ts1_mode.num_alt; i++) { |
1696 | u16 tmp = le16_to_cpu(uif->altsetting[i]. | 1723 | u16 tmp; |
1724 | |||
1725 | if (uif->altsetting[i].desc.bNumEndpoints < isoc_pipe + 1) { | ||
1726 | retval = -ENODEV; | ||
1727 | goto err_video_alt; | ||
1728 | } | ||
1729 | |||
1730 | tmp = le16_to_cpu(uif->altsetting[i]. | ||
1697 | endpoint[isoc_pipe].desc. | 1731 | endpoint[isoc_pipe].desc. |
1698 | wMaxPacketSize); | 1732 | wMaxPacketSize); |
1699 | dev->ts1_mode.alt_max_pkt_size[i] = | 1733 | dev->ts1_mode.alt_max_pkt_size[i] = |
diff --git a/drivers/media/usb/cx231xx/cx231xx-i2c.c b/drivers/media/usb/cx231xx/cx231xx-i2c.c index dff514e147da..8d95b1154e12 100644 --- a/drivers/media/usb/cx231xx/cx231xx-i2c.c +++ b/drivers/media/usb/cx231xx/cx231xx-i2c.c | |||
@@ -491,20 +491,24 @@ void cx231xx_do_i2c_scan(struct cx231xx *dev, int i2c_port) | |||
491 | { | 491 | { |
492 | unsigned char buf; | 492 | unsigned char buf; |
493 | int i, rc; | 493 | int i, rc; |
494 | struct i2c_client client; | 494 | struct i2c_adapter *adap; |
495 | struct i2c_msg msg = { | ||
496 | .flags = I2C_M_RD, | ||
497 | .len = 1, | ||
498 | .buf = &buf, | ||
499 | }; | ||
495 | 500 | ||
496 | if (!i2c_scan) | 501 | if (!i2c_scan) |
497 | return; | 502 | return; |
498 | 503 | ||
499 | /* Don't generate I2C errors during scan */ | 504 | /* Don't generate I2C errors during scan */ |
500 | dev->i2c_scan_running = true; | 505 | dev->i2c_scan_running = true; |
501 | 506 | adap = cx231xx_get_i2c_adap(dev, i2c_port); | |
502 | memset(&client, 0, sizeof(client)); | ||
503 | client.adapter = cx231xx_get_i2c_adap(dev, i2c_port); | ||
504 | 507 | ||
505 | for (i = 0; i < 128; i++) { | 508 | for (i = 0; i < 128; i++) { |
506 | client.addr = i; | 509 | msg.addr = i; |
507 | rc = i2c_master_recv(&client, &buf, 0); | 510 | rc = i2c_transfer(adap, &msg, 1); |
511 | |||
508 | if (rc < 0) | 512 | if (rc < 0) |
509 | continue; | 513 | continue; |
510 | dev_info(dev->dev, | 514 | dev_info(dev->dev, |
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.c b/drivers/media/usb/dvb-usb-v2/mxl111sf.c index 80c635980526..abf69d8fa469 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c | |||
@@ -919,7 +919,12 @@ static int mxl111sf_init(struct dvb_usb_device *d) | |||
919 | struct mxl111sf_state *state = d_to_priv(d); | 919 | struct mxl111sf_state *state = d_to_priv(d); |
920 | int ret; | 920 | int ret; |
921 | static u8 eeprom[256]; | 921 | static u8 eeprom[256]; |
922 | struct i2c_client c; | 922 | u8 reg = 0; |
923 | struct i2c_msg msg[2] = { | ||
924 | { .addr = 0xa0 >> 1, .len = 1, .buf = ® }, | ||
925 | { .addr = 0xa0 >> 1, .flags = I2C_M_RD, | ||
926 | .len = sizeof(eeprom), .buf = eeprom }, | ||
927 | }; | ||
923 | 928 | ||
924 | ret = get_chip_info(state); | 929 | ret = get_chip_info(state); |
925 | if (mxl_fail(ret)) | 930 | if (mxl_fail(ret)) |
@@ -930,14 +935,11 @@ static int mxl111sf_init(struct dvb_usb_device *d) | |||
930 | if (state->chip_rev > MXL111SF_V6) | 935 | if (state->chip_rev > MXL111SF_V6) |
931 | mxl111sf_config_pin_mux_modes(state, PIN_MUX_TS_SPI_IN_MODE_1); | 936 | mxl111sf_config_pin_mux_modes(state, PIN_MUX_TS_SPI_IN_MODE_1); |
932 | 937 | ||
933 | c.adapter = &d->i2c_adap; | 938 | ret = i2c_transfer(&d->i2c_adap, msg, 2); |
934 | c.addr = 0xa0 >> 1; | ||
935 | |||
936 | ret = tveeprom_read(&c, eeprom, sizeof(eeprom)); | ||
937 | if (mxl_fail(ret)) | 939 | if (mxl_fail(ret)) |
938 | return 0; | 940 | return 0; |
939 | tveeprom_hauppauge_analog(&c, &state->tv, (0x84 == eeprom[0xa0]) ? | 941 | tveeprom_hauppauge_analog(&state->tv, (0x84 == eeprom[0xa0]) ? |
940 | eeprom + 0xa0 : eeprom + 0x80); | 942 | eeprom + 0xa0 : eeprom + 0x80); |
941 | #if 0 | 943 | #if 0 |
942 | switch (state->tv.model) { | 944 | switch (state->tv.model) { |
943 | case 117001: | 945 | case 117001: |
diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c index 51620e02292f..99a3f3625944 100644 --- a/drivers/media/usb/dvb-usb/cxusb.c +++ b/drivers/media/usb/dvb-usb/cxusb.c | |||
@@ -458,8 +458,8 @@ static int cxusb_rc_query(struct dvb_usb_device *d) | |||
458 | cxusb_ctrl_msg(d, CMD_GET_IR_CODE, NULL, 0, ircode, 4); | 458 | cxusb_ctrl_msg(d, CMD_GET_IR_CODE, NULL, 0, ircode, 4); |
459 | 459 | ||
460 | if (ircode[2] || ircode[3]) | 460 | if (ircode[2] || ircode[3]) |
461 | rc_keydown(d->rc_dev, RC_TYPE_UNKNOWN, | 461 | rc_keydown(d->rc_dev, RC_TYPE_NEC, |
462 | RC_SCANCODE_RC5(ircode[2], ircode[3]), 0); | 462 | RC_SCANCODE_NEC(~ircode[2] & 0xff, ircode[3]), 0); |
463 | return 0; | 463 | return 0; |
464 | } | 464 | } |
465 | 465 | ||
@@ -473,8 +473,8 @@ static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d) | |||
473 | return 0; | 473 | return 0; |
474 | 474 | ||
475 | if (ircode[1] || ircode[2]) | 475 | if (ircode[1] || ircode[2]) |
476 | rc_keydown(d->rc_dev, RC_TYPE_UNKNOWN, | 476 | rc_keydown(d->rc_dev, RC_TYPE_NEC, |
477 | RC_SCANCODE_RC5(ircode[1], ircode[2]), 0); | 477 | RC_SCANCODE_NEC(~ircode[1] & 0xff, ircode[2]), 0); |
478 | return 0; | 478 | return 0; |
479 | } | 479 | } |
480 | 480 | ||
@@ -1239,6 +1239,82 @@ static int cxusb_mygica_t230_frontend_attach(struct dvb_usb_adapter *adap) | |||
1239 | return 0; | 1239 | return 0; |
1240 | } | 1240 | } |
1241 | 1241 | ||
1242 | static int cxusb_mygica_t230c_frontend_attach(struct dvb_usb_adapter *adap) | ||
1243 | { | ||
1244 | struct dvb_usb_device *d = adap->dev; | ||
1245 | struct cxusb_state *st = d->priv; | ||
1246 | struct i2c_adapter *adapter; | ||
1247 | struct i2c_client *client_demod; | ||
1248 | struct i2c_client *client_tuner; | ||
1249 | struct i2c_board_info info; | ||
1250 | struct si2168_config si2168_config; | ||
1251 | struct si2157_config si2157_config; | ||
1252 | |||
1253 | /* Select required USB configuration */ | ||
1254 | if (usb_set_interface(d->udev, 0, 0) < 0) | ||
1255 | err("set interface failed"); | ||
1256 | |||
1257 | /* Unblock all USB pipes */ | ||
1258 | usb_clear_halt(d->udev, | ||
1259 | usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); | ||
1260 | usb_clear_halt(d->udev, | ||
1261 | usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); | ||
1262 | usb_clear_halt(d->udev, | ||
1263 | usb_rcvbulkpipe(d->udev, d->props.adapter[0].fe[0].stream.endpoint)); | ||
1264 | |||
1265 | /* attach frontend */ | ||
1266 | memset(&si2168_config, 0, sizeof(si2168_config)); | ||
1267 | si2168_config.i2c_adapter = &adapter; | ||
1268 | si2168_config.fe = &adap->fe_adap[0].fe; | ||
1269 | si2168_config.ts_mode = SI2168_TS_PARALLEL; | ||
1270 | si2168_config.ts_clock_inv = 1; | ||
1271 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
1272 | strlcpy(info.type, "si2168", I2C_NAME_SIZE); | ||
1273 | info.addr = 0x64; | ||
1274 | info.platform_data = &si2168_config; | ||
1275 | request_module(info.type); | ||
1276 | client_demod = i2c_new_device(&d->i2c_adap, &info); | ||
1277 | if (client_demod == NULL || client_demod->dev.driver == NULL) | ||
1278 | return -ENODEV; | ||
1279 | |||
1280 | if (!try_module_get(client_demod->dev.driver->owner)) { | ||
1281 | i2c_unregister_device(client_demod); | ||
1282 | return -ENODEV; | ||
1283 | } | ||
1284 | |||
1285 | /* attach tuner */ | ||
1286 | memset(&si2157_config, 0, sizeof(si2157_config)); | ||
1287 | si2157_config.fe = adap->fe_adap[0].fe; | ||
1288 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
1289 | strlcpy(info.type, "si2141", I2C_NAME_SIZE); | ||
1290 | info.addr = 0x60; | ||
1291 | info.platform_data = &si2157_config; | ||
1292 | request_module("si2157"); | ||
1293 | client_tuner = i2c_new_device(adapter, &info); | ||
1294 | if (client_tuner == NULL || client_tuner->dev.driver == NULL) { | ||
1295 | module_put(client_demod->dev.driver->owner); | ||
1296 | i2c_unregister_device(client_demod); | ||
1297 | return -ENODEV; | ||
1298 | } | ||
1299 | if (!try_module_get(client_tuner->dev.driver->owner)) { | ||
1300 | i2c_unregister_device(client_tuner); | ||
1301 | module_put(client_demod->dev.driver->owner); | ||
1302 | i2c_unregister_device(client_demod); | ||
1303 | return -ENODEV; | ||
1304 | } | ||
1305 | |||
1306 | st->i2c_client_demod = client_demod; | ||
1307 | st->i2c_client_tuner = client_tuner; | ||
1308 | |||
1309 | /* hook fe: need to resync the slave fifo when signal locks. */ | ||
1310 | mutex_init(&st->stream_mutex); | ||
1311 | st->last_lock = 0; | ||
1312 | st->fe_read_status = adap->fe_adap[0].fe->ops.read_status; | ||
1313 | adap->fe_adap[0].fe->ops.read_status = cxusb_read_status; | ||
1314 | |||
1315 | return 0; | ||
1316 | } | ||
1317 | |||
1242 | /* | 1318 | /* |
1243 | * DViCO has shipped two devices with the same USB ID, but only one of them | 1319 | * DViCO has shipped two devices with the same USB ID, but only one of them |
1244 | * needs a firmware download. Check the device class details to see if they | 1320 | * needs a firmware download. Check the device class details to see if they |
@@ -1321,6 +1397,7 @@ static struct dvb_usb_device_properties cxusb_aver_a868r_properties; | |||
1321 | static struct dvb_usb_device_properties cxusb_d680_dmb_properties; | 1397 | static struct dvb_usb_device_properties cxusb_d680_dmb_properties; |
1322 | static struct dvb_usb_device_properties cxusb_mygica_d689_properties; | 1398 | static struct dvb_usb_device_properties cxusb_mygica_d689_properties; |
1323 | static struct dvb_usb_device_properties cxusb_mygica_t230_properties; | 1399 | static struct dvb_usb_device_properties cxusb_mygica_t230_properties; |
1400 | static struct dvb_usb_device_properties cxusb_mygica_t230c_properties; | ||
1324 | 1401 | ||
1325 | static int cxusb_probe(struct usb_interface *intf, | 1402 | static int cxusb_probe(struct usb_interface *intf, |
1326 | const struct usb_device_id *id) | 1403 | const struct usb_device_id *id) |
@@ -1353,6 +1430,8 @@ static int cxusb_probe(struct usb_interface *intf, | |||
1353 | THIS_MODULE, NULL, adapter_nr) || | 1430 | THIS_MODULE, NULL, adapter_nr) || |
1354 | 0 == dvb_usb_device_init(intf, &cxusb_mygica_t230_properties, | 1431 | 0 == dvb_usb_device_init(intf, &cxusb_mygica_t230_properties, |
1355 | THIS_MODULE, NULL, adapter_nr) || | 1432 | THIS_MODULE, NULL, adapter_nr) || |
1433 | 0 == dvb_usb_device_init(intf, &cxusb_mygica_t230c_properties, | ||
1434 | THIS_MODULE, NULL, adapter_nr) || | ||
1356 | 0) | 1435 | 0) |
1357 | return 0; | 1436 | return 0; |
1358 | 1437 | ||
@@ -1404,6 +1483,7 @@ enum cxusb_table_index { | |||
1404 | CONEXANT_D680_DMB, | 1483 | CONEXANT_D680_DMB, |
1405 | MYGICA_D689, | 1484 | MYGICA_D689, |
1406 | MYGICA_T230, | 1485 | MYGICA_T230, |
1486 | MYGICA_T230C, | ||
1407 | NR__cxusb_table_index | 1487 | NR__cxusb_table_index |
1408 | }; | 1488 | }; |
1409 | 1489 | ||
@@ -1471,6 +1551,9 @@ static struct usb_device_id cxusb_table[NR__cxusb_table_index + 1] = { | |||
1471 | [MYGICA_T230] = { | 1551 | [MYGICA_T230] = { |
1472 | USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230) | 1552 | USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230) |
1473 | }, | 1553 | }, |
1554 | [MYGICA_T230C] = { | ||
1555 | USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230+1) | ||
1556 | }, | ||
1474 | {} /* Terminating entry */ | 1557 | {} /* Terminating entry */ |
1475 | }; | 1558 | }; |
1476 | MODULE_DEVICE_TABLE (usb, cxusb_table); | 1559 | MODULE_DEVICE_TABLE (usb, cxusb_table); |
@@ -1563,7 +1646,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = { | |||
1563 | .rc_codes = RC_MAP_DVICO_PORTABLE, | 1646 | .rc_codes = RC_MAP_DVICO_PORTABLE, |
1564 | .module_name = KBUILD_MODNAME, | 1647 | .module_name = KBUILD_MODNAME, |
1565 | .rc_query = cxusb_rc_query, | 1648 | .rc_query = cxusb_rc_query, |
1566 | .allowed_protos = RC_BIT_UNKNOWN, | 1649 | .allowed_protos = RC_BIT_NEC, |
1567 | }, | 1650 | }, |
1568 | 1651 | ||
1569 | .generic_bulk_ctrl_endpoint = 0x01, | 1652 | .generic_bulk_ctrl_endpoint = 0x01, |
@@ -1620,7 +1703,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = { | |||
1620 | .rc_codes = RC_MAP_DVICO_MCE, | 1703 | .rc_codes = RC_MAP_DVICO_MCE, |
1621 | .module_name = KBUILD_MODNAME, | 1704 | .module_name = KBUILD_MODNAME, |
1622 | .rc_query = cxusb_rc_query, | 1705 | .rc_query = cxusb_rc_query, |
1623 | .allowed_protos = RC_BIT_UNKNOWN, | 1706 | .allowed_protos = RC_BIT_NEC, |
1624 | }, | 1707 | }, |
1625 | 1708 | ||
1626 | .generic_bulk_ctrl_endpoint = 0x01, | 1709 | .generic_bulk_ctrl_endpoint = 0x01, |
@@ -1685,7 +1768,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = { | |||
1685 | .rc_codes = RC_MAP_DVICO_PORTABLE, | 1768 | .rc_codes = RC_MAP_DVICO_PORTABLE, |
1686 | .module_name = KBUILD_MODNAME, | 1769 | .module_name = KBUILD_MODNAME, |
1687 | .rc_query = cxusb_rc_query, | 1770 | .rc_query = cxusb_rc_query, |
1688 | .allowed_protos = RC_BIT_UNKNOWN, | 1771 | .allowed_protos = RC_BIT_NEC, |
1689 | }, | 1772 | }, |
1690 | 1773 | ||
1691 | .generic_bulk_ctrl_endpoint = 0x01, | 1774 | .generic_bulk_ctrl_endpoint = 0x01, |
@@ -1741,7 +1824,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = { | |||
1741 | .rc_codes = RC_MAP_DVICO_PORTABLE, | 1824 | .rc_codes = RC_MAP_DVICO_PORTABLE, |
1742 | .module_name = KBUILD_MODNAME, | 1825 | .module_name = KBUILD_MODNAME, |
1743 | .rc_query = cxusb_rc_query, | 1826 | .rc_query = cxusb_rc_query, |
1744 | .allowed_protos = RC_BIT_UNKNOWN, | 1827 | .allowed_protos = RC_BIT_NEC, |
1745 | }, | 1828 | }, |
1746 | 1829 | ||
1747 | .generic_bulk_ctrl_endpoint = 0x01, | 1830 | .generic_bulk_ctrl_endpoint = 0x01, |
@@ -1796,7 +1879,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = { | |||
1796 | .rc_codes = RC_MAP_DVICO_MCE, | 1879 | .rc_codes = RC_MAP_DVICO_MCE, |
1797 | .module_name = KBUILD_MODNAME, | 1880 | .module_name = KBUILD_MODNAME, |
1798 | .rc_query = cxusb_bluebird2_rc_query, | 1881 | .rc_query = cxusb_bluebird2_rc_query, |
1799 | .allowed_protos = RC_BIT_UNKNOWN, | 1882 | .allowed_protos = RC_BIT_NEC, |
1800 | }, | 1883 | }, |
1801 | 1884 | ||
1802 | .num_device_descs = 1, | 1885 | .num_device_descs = 1, |
@@ -1850,7 +1933,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = { | |||
1850 | .rc_codes = RC_MAP_DVICO_PORTABLE, | 1933 | .rc_codes = RC_MAP_DVICO_PORTABLE, |
1851 | .module_name = KBUILD_MODNAME, | 1934 | .module_name = KBUILD_MODNAME, |
1852 | .rc_query = cxusb_bluebird2_rc_query, | 1935 | .rc_query = cxusb_bluebird2_rc_query, |
1853 | .allowed_protos = RC_BIT_UNKNOWN, | 1936 | .allowed_protos = RC_BIT_NEC, |
1854 | }, | 1937 | }, |
1855 | 1938 | ||
1856 | .num_device_descs = 1, | 1939 | .num_device_descs = 1, |
@@ -1906,7 +1989,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_prope | |||
1906 | .rc_codes = RC_MAP_DVICO_PORTABLE, | 1989 | .rc_codes = RC_MAP_DVICO_PORTABLE, |
1907 | .module_name = KBUILD_MODNAME, | 1990 | .module_name = KBUILD_MODNAME, |
1908 | .rc_query = cxusb_rc_query, | 1991 | .rc_query = cxusb_rc_query, |
1909 | .allowed_protos = RC_BIT_UNKNOWN, | 1992 | .allowed_protos = RC_BIT_NEC, |
1910 | }, | 1993 | }, |
1911 | 1994 | ||
1912 | .num_device_descs = 1, | 1995 | .num_device_descs = 1, |
@@ -2005,7 +2088,7 @@ struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = { | |||
2005 | .rc_codes = RC_MAP_DVICO_MCE, | 2088 | .rc_codes = RC_MAP_DVICO_MCE, |
2006 | .module_name = KBUILD_MODNAME, | 2089 | .module_name = KBUILD_MODNAME, |
2007 | .rc_query = cxusb_rc_query, | 2090 | .rc_query = cxusb_rc_query, |
2008 | .allowed_protos = RC_BIT_UNKNOWN, | 2091 | .allowed_protos = RC_BIT_NEC, |
2009 | }, | 2092 | }, |
2010 | 2093 | ||
2011 | .num_device_descs = 1, | 2094 | .num_device_descs = 1, |
@@ -2165,7 +2248,7 @@ static struct dvb_usb_device_properties cxusb_mygica_t230_properties = { | |||
2165 | 2248 | ||
2166 | .rc.core = { | 2249 | .rc.core = { |
2167 | .rc_interval = 100, | 2250 | .rc_interval = 100, |
2168 | .rc_codes = RC_MAP_D680_DMB, | 2251 | .rc_codes = RC_MAP_TOTAL_MEDIA_IN_HAND_02, |
2169 | .module_name = KBUILD_MODNAME, | 2252 | .module_name = KBUILD_MODNAME, |
2170 | .rc_query = cxusb_d680_dmb_rc_query, | 2253 | .rc_query = cxusb_d680_dmb_rc_query, |
2171 | .allowed_protos = RC_BIT_UNKNOWN, | 2254 | .allowed_protos = RC_BIT_UNKNOWN, |
@@ -2181,6 +2264,60 @@ static struct dvb_usb_device_properties cxusb_mygica_t230_properties = { | |||
2181 | } | 2264 | } |
2182 | }; | 2265 | }; |
2183 | 2266 | ||
2267 | static struct dvb_usb_device_properties cxusb_mygica_t230c_properties = { | ||
2268 | .caps = DVB_USB_IS_AN_I2C_ADAPTER, | ||
2269 | |||
2270 | .usb_ctrl = CYPRESS_FX2, | ||
2271 | |||
2272 | .size_of_priv = sizeof(struct cxusb_state), | ||
2273 | |||
2274 | .num_adapters = 1, | ||
2275 | .adapter = { | ||
2276 | { | ||
2277 | .num_frontends = 1, | ||
2278 | .fe = {{ | ||
2279 | .streaming_ctrl = cxusb_streaming_ctrl, | ||
2280 | .frontend_attach = cxusb_mygica_t230c_frontend_attach, | ||
2281 | |||
2282 | /* parameter for the MPEG2-data transfer */ | ||
2283 | .stream = { | ||
2284 | .type = USB_BULK, | ||
2285 | .count = 5, | ||
2286 | .endpoint = 0x02, | ||
2287 | .u = { | ||
2288 | .bulk = { | ||
2289 | .buffersize = 8192, | ||
2290 | } | ||
2291 | } | ||
2292 | }, | ||
2293 | } }, | ||
2294 | }, | ||
2295 | }, | ||
2296 | |||
2297 | .power_ctrl = cxusb_d680_dmb_power_ctrl, | ||
2298 | |||
2299 | .i2c_algo = &cxusb_i2c_algo, | ||
2300 | |||
2301 | .generic_bulk_ctrl_endpoint = 0x01, | ||
2302 | |||
2303 | .rc.core = { | ||
2304 | .rc_interval = 100, | ||
2305 | .rc_codes = RC_MAP_TOTAL_MEDIA_IN_HAND_02, | ||
2306 | .module_name = KBUILD_MODNAME, | ||
2307 | .rc_query = cxusb_d680_dmb_rc_query, | ||
2308 | .allowed_protos = RC_BIT_UNKNOWN, | ||
2309 | }, | ||
2310 | |||
2311 | .num_device_descs = 1, | ||
2312 | .devices = { | ||
2313 | { | ||
2314 | "Mygica T230C DVB-T/T2/C", | ||
2315 | { NULL }, | ||
2316 | { &cxusb_table[MYGICA_T230C], NULL }, | ||
2317 | }, | ||
2318 | } | ||
2319 | }; | ||
2320 | |||
2184 | static struct usb_driver cxusb_driver = { | 2321 | static struct usb_driver cxusb_driver = { |
2185 | .name = "dvb_usb_cxusb", | 2322 | .name = "dvb_usb_cxusb", |
2186 | .probe = cxusb_probe, | 2323 | .probe = cxusb_probe, |
diff --git a/drivers/media/usb/dvb-usb/dib0700_core.c b/drivers/media/usb/dvb-usb/dib0700_core.c index dd5edd3a17ee..08acdd32e412 100644 --- a/drivers/media/usb/dvb-usb/dib0700_core.c +++ b/drivers/media/usb/dvb-usb/dib0700_core.c | |||
@@ -809,6 +809,9 @@ int dib0700_rc_setup(struct dvb_usb_device *d, struct usb_interface *intf) | |||
809 | 809 | ||
810 | /* Starting in firmware 1.20, the RC info is provided on a bulk pipe */ | 810 | /* Starting in firmware 1.20, the RC info is provided on a bulk pipe */ |
811 | 811 | ||
812 | if (intf->altsetting[0].desc.bNumEndpoints < rc_ep + 1) | ||
813 | return -ENODEV; | ||
814 | |||
812 | purb = usb_alloc_urb(0, GFP_KERNEL); | 815 | purb = usb_alloc_urb(0, GFP_KERNEL); |
813 | if (purb == NULL) | 816 | if (purb == NULL) |
814 | return -ENOMEM; | 817 | return -ENOMEM; |
diff --git a/drivers/media/usb/dvb-usb/dibusb-mc-common.c b/drivers/media/usb/dvb-usb/dibusb-mc-common.c index c989cac9343d..0c2bc97436d5 100644 --- a/drivers/media/usb/dvb-usb/dibusb-mc-common.c +++ b/drivers/media/usb/dvb-usb/dibusb-mc-common.c | |||
@@ -11,6 +11,8 @@ | |||
11 | 11 | ||
12 | #include "dibusb.h" | 12 | #include "dibusb.h" |
13 | 13 | ||
14 | MODULE_LICENSE("GPL"); | ||
15 | |||
14 | /* 3000MC/P stuff */ | 16 | /* 3000MC/P stuff */ |
15 | // Config Adjacent channels Perf -cal22 | 17 | // Config Adjacent channels Perf -cal22 |
16 | static struct dibx000_agc_config dib3000p_mt2060_agc_config = { | 18 | static struct dibx000_agc_config dib3000p_mt2060_agc_config = { |
diff --git a/drivers/media/usb/dvb-usb/digitv.c b/drivers/media/usb/dvb-usb/digitv.c index 4284f6984dc1..475a3c0cdee7 100644 --- a/drivers/media/usb/dvb-usb/digitv.c +++ b/drivers/media/usb/dvb-usb/digitv.c | |||
@@ -33,6 +33,9 @@ static int digitv_ctrl_msg(struct dvb_usb_device *d, | |||
33 | 33 | ||
34 | wo = (rbuf == NULL || rlen == 0); /* write-only */ | 34 | wo = (rbuf == NULL || rlen == 0); /* write-only */ |
35 | 35 | ||
36 | if (wlen > 4 || rlen > 4) | ||
37 | return -EIO; | ||
38 | |||
36 | memset(st->sndbuf, 0, 7); | 39 | memset(st->sndbuf, 0, 7); |
37 | memset(st->rcvbuf, 0, 7); | 40 | memset(st->rcvbuf, 0, 7); |
38 | 41 | ||
diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c index 4f42d57f81d9..6e654e5026dd 100644 --- a/drivers/media/usb/dvb-usb/dw2102.c +++ b/drivers/media/usb/dvb-usb/dw2102.c | |||
@@ -204,6 +204,20 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap, | |||
204 | 204 | ||
205 | switch (num) { | 205 | switch (num) { |
206 | case 2: | 206 | case 2: |
207 | if (msg[0].len != 1) { | ||
208 | warn("i2c rd: len=%d is not 1!\n", | ||
209 | msg[0].len); | ||
210 | num = -EOPNOTSUPP; | ||
211 | break; | ||
212 | } | ||
213 | |||
214 | if (2 + msg[1].len > sizeof(buf6)) { | ||
215 | warn("i2c rd: len=%d is too big!\n", | ||
216 | msg[1].len); | ||
217 | num = -EOPNOTSUPP; | ||
218 | break; | ||
219 | } | ||
220 | |||
207 | /* read si2109 register by number */ | 221 | /* read si2109 register by number */ |
208 | buf6[0] = msg[0].addr << 1; | 222 | buf6[0] = msg[0].addr << 1; |
209 | buf6[1] = msg[0].len; | 223 | buf6[1] = msg[0].len; |
@@ -219,6 +233,13 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap, | |||
219 | case 1: | 233 | case 1: |
220 | switch (msg[0].addr) { | 234 | switch (msg[0].addr) { |
221 | case 0x68: | 235 | case 0x68: |
236 | if (2 + msg[0].len > sizeof(buf6)) { | ||
237 | warn("i2c wr: len=%d is too big!\n", | ||
238 | msg[0].len); | ||
239 | num = -EOPNOTSUPP; | ||
240 | break; | ||
241 | } | ||
242 | |||
222 | /* write to si2109 register */ | 243 | /* write to si2109 register */ |
223 | buf6[0] = msg[0].addr << 1; | 244 | buf6[0] = msg[0].addr << 1; |
224 | buf6[1] = msg[0].len; | 245 | buf6[1] = msg[0].len; |
@@ -262,6 +283,13 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms | |||
262 | /* first write first register number */ | 283 | /* first write first register number */ |
263 | u8 ibuf[MAX_XFER_SIZE], obuf[3]; | 284 | u8 ibuf[MAX_XFER_SIZE], obuf[3]; |
264 | 285 | ||
286 | if (2 + msg[0].len != sizeof(obuf)) { | ||
287 | warn("i2c rd: len=%d is not 1!\n", | ||
288 | msg[0].len); | ||
289 | ret = -EOPNOTSUPP; | ||
290 | goto unlock; | ||
291 | } | ||
292 | |||
265 | if (2 + msg[1].len > sizeof(ibuf)) { | 293 | if (2 + msg[1].len > sizeof(ibuf)) { |
266 | warn("i2c rd: len=%d is too big!\n", | 294 | warn("i2c rd: len=%d is too big!\n", |
267 | msg[1].len); | 295 | msg[1].len); |
@@ -462,6 +490,12 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], | |||
462 | /* first write first register number */ | 490 | /* first write first register number */ |
463 | u8 ibuf[MAX_XFER_SIZE], obuf[3]; | 491 | u8 ibuf[MAX_XFER_SIZE], obuf[3]; |
464 | 492 | ||
493 | if (2 + msg[0].len != sizeof(obuf)) { | ||
494 | warn("i2c rd: len=%d is not 1!\n", | ||
495 | msg[0].len); | ||
496 | ret = -EOPNOTSUPP; | ||
497 | goto unlock; | ||
498 | } | ||
465 | if (2 + msg[1].len > sizeof(ibuf)) { | 499 | if (2 + msg[1].len > sizeof(ibuf)) { |
466 | warn("i2c rd: len=%d is too big!\n", | 500 | warn("i2c rd: len=%d is too big!\n", |
467 | msg[1].len); | 501 | msg[1].len); |
@@ -696,6 +730,13 @@ static int su3000_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], | |||
696 | msg[0].buf[0] = state->data[1]; | 730 | msg[0].buf[0] = state->data[1]; |
697 | break; | 731 | break; |
698 | default: | 732 | default: |
733 | if (3 + msg[0].len > sizeof(state->data)) { | ||
734 | warn("i2c wr: len=%d is too big!\n", | ||
735 | msg[0].len); | ||
736 | num = -EOPNOTSUPP; | ||
737 | break; | ||
738 | } | ||
739 | |||
699 | /* always i2c write*/ | 740 | /* always i2c write*/ |
700 | state->data[0] = 0x08; | 741 | state->data[0] = 0x08; |
701 | state->data[1] = msg[0].addr; | 742 | state->data[1] = msg[0].addr; |
@@ -711,6 +752,19 @@ static int su3000_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], | |||
711 | break; | 752 | break; |
712 | case 2: | 753 | case 2: |
713 | /* always i2c read */ | 754 | /* always i2c read */ |
755 | if (4 + msg[0].len > sizeof(state->data)) { | ||
756 | warn("i2c rd: len=%d is too big!\n", | ||
757 | msg[0].len); | ||
758 | num = -EOPNOTSUPP; | ||
759 | break; | ||
760 | } | ||
761 | if (1 + msg[1].len > sizeof(state->data)) { | ||
762 | warn("i2c rd: len=%d is too big!\n", | ||
763 | msg[1].len); | ||
764 | num = -EOPNOTSUPP; | ||
765 | break; | ||
766 | } | ||
767 | |||
714 | state->data[0] = 0x09; | 768 | state->data[0] = 0x09; |
715 | state->data[1] = msg[0].len; | 769 | state->data[1] = msg[0].len; |
716 | state->data[2] = msg[1].len; | 770 | state->data[2] = msg[1].len; |
diff --git a/drivers/media/usb/dvb-usb/ttusb2.c b/drivers/media/usb/dvb-usb/ttusb2.c index ecc207fbaf3c..9e0d6a4166d2 100644 --- a/drivers/media/usb/dvb-usb/ttusb2.c +++ b/drivers/media/usb/dvb-usb/ttusb2.c | |||
@@ -78,6 +78,9 @@ static int ttusb2_msg(struct dvb_usb_device *d, u8 cmd, | |||
78 | u8 *s, *r = NULL; | 78 | u8 *s, *r = NULL; |
79 | int ret = 0; | 79 | int ret = 0; |
80 | 80 | ||
81 | if (4 + rlen > 64) | ||
82 | return -EIO; | ||
83 | |||
81 | s = kzalloc(wlen+4, GFP_KERNEL); | 84 | s = kzalloc(wlen+4, GFP_KERNEL); |
82 | if (!s) | 85 | if (!s) |
83 | return -ENOMEM; | 86 | return -ENOMEM; |
@@ -381,6 +384,22 @@ static int ttusb2_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num | |||
381 | write_read = i+1 < num && (msg[i+1].flags & I2C_M_RD); | 384 | write_read = i+1 < num && (msg[i+1].flags & I2C_M_RD); |
382 | read = msg[i].flags & I2C_M_RD; | 385 | read = msg[i].flags & I2C_M_RD; |
383 | 386 | ||
387 | if (3 + msg[i].len > sizeof(obuf)) { | ||
388 | err("i2c wr len=%d too high", msg[i].len); | ||
389 | break; | ||
390 | } | ||
391 | if (write_read) { | ||
392 | if (3 + msg[i+1].len > sizeof(ibuf)) { | ||
393 | err("i2c rd len=%d too high", msg[i+1].len); | ||
394 | break; | ||
395 | } | ||
396 | } else if (read) { | ||
397 | if (3 + msg[i].len > sizeof(ibuf)) { | ||
398 | err("i2c rd len=%d too high", msg[i].len); | ||
399 | break; | ||
400 | } | ||
401 | } | ||
402 | |||
384 | obuf[0] = (msg[i].addr << 1) | (write_read | read); | 403 | obuf[0] = (msg[i].addr << 1) | (write_read | read); |
385 | if (read) | 404 | if (read) |
386 | obuf[1] = 0; | 405 | obuf[1] = 0; |
diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig index aa131cf9989b..4cc029f18aa8 100644 --- a/drivers/media/usb/em28xx/Kconfig +++ b/drivers/media/usb/em28xx/Kconfig | |||
@@ -12,7 +12,7 @@ config VIDEO_EM28XX_V4L2 | |||
12 | select VIDEO_TVP5150 if MEDIA_SUBDRV_AUTOSELECT | 12 | select VIDEO_TVP5150 if MEDIA_SUBDRV_AUTOSELECT |
13 | select VIDEO_MSP3400 if MEDIA_SUBDRV_AUTOSELECT | 13 | select VIDEO_MSP3400 if MEDIA_SUBDRV_AUTOSELECT |
14 | select VIDEO_MT9V011 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_CAMERA_SUPPORT | 14 | select VIDEO_MT9V011 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_CAMERA_SUPPORT |
15 | 15 | select VIDEO_OV2640 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_CAMERA_SUPPORT | |
16 | ---help--- | 16 | ---help--- |
17 | This is a video4linux driver for Empia 28xx based TV cards. | 17 | This is a video4linux driver for Empia 28xx based TV cards. |
18 | 18 | ||
@@ -39,6 +39,7 @@ config VIDEO_EM28XX_DVB | |||
39 | depends on VIDEO_EM28XX && DVB_CORE | 39 | depends on VIDEO_EM28XX && DVB_CORE |
40 | select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT | 40 | select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT |
41 | select DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT | 41 | select DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT |
42 | select DVB_LGDT3306A if MEDIA_SUBDRV_AUTOSELECT | ||
42 | select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT | 43 | select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT |
43 | select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT | 44 | select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT |
44 | select DVB_S921 if MEDIA_SUBDRV_AUTOSELECT | 45 | select DVB_S921 if MEDIA_SUBDRV_AUTOSELECT |
@@ -61,6 +62,10 @@ config VIDEO_EM28XX_DVB | |||
61 | select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT | 62 | select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT |
62 | select DVB_TC90522 if MEDIA_SUBDRV_AUTOSELECT | 63 | select DVB_TC90522 if MEDIA_SUBDRV_AUTOSELECT |
63 | select MEDIA_TUNER_QM1D1C0042 if MEDIA_SUBDRV_AUTOSELECT | 64 | select MEDIA_TUNER_QM1D1C0042 if MEDIA_SUBDRV_AUTOSELECT |
65 | select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT | ||
66 | select MEDIA_TUNER_XC2028 if MEDIA_SUBDRV_AUTOSELECT | ||
67 | select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT | ||
68 | select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT | ||
64 | ---help--- | 69 | ---help--- |
65 | This adds support for DVB cards based on the | 70 | This adds support for DVB cards based on the |
66 | Empiatech em28xx chips. | 71 | Empiatech em28xx chips. |
diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index 89c890ba7dd6..ae87dd3e671f 100644 --- a/drivers/media/usb/em28xx/em28xx-camera.c +++ b/drivers/media/usb/em28xx/em28xx-camera.c | |||
@@ -23,9 +23,7 @@ | |||
23 | 23 | ||
24 | #include <linux/i2c.h> | 24 | #include <linux/i2c.h> |
25 | #include <linux/usb.h> | 25 | #include <linux/usb.h> |
26 | #include <media/soc_camera.h> | ||
27 | #include <media/i2c/mt9v011.h> | 26 | #include <media/i2c/mt9v011.h> |
28 | #include <media/v4l2-clk.h> | ||
29 | #include <media/v4l2-common.h> | 27 | #include <media/v4l2-common.h> |
30 | 28 | ||
31 | /* Possible i2c addresses of Micron sensors */ | 29 | /* Possible i2c addresses of Micron sensors */ |
@@ -43,13 +41,6 @@ static unsigned short omnivision_sensor_addrs[] = { | |||
43 | I2C_CLIENT_END | 41 | I2C_CLIENT_END |
44 | }; | 42 | }; |
45 | 43 | ||
46 | static struct soc_camera_link camlink = { | ||
47 | .bus_id = 0, | ||
48 | .flags = 0, | ||
49 | .module_name = "em28xx", | ||
50 | .unbalanced_power = true, | ||
51 | }; | ||
52 | |||
53 | /* FIXME: Should be replaced by a proper mt9m111 driver */ | 44 | /* FIXME: Should be replaced by a proper mt9m111 driver */ |
54 | static int em28xx_initialize_mt9m111(struct em28xx *dev) | 45 | static int em28xx_initialize_mt9m111(struct em28xx *dev) |
55 | { | 46 | { |
@@ -106,55 +97,35 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev) | |||
106 | { | 97 | { |
107 | int ret, i; | 98 | int ret, i; |
108 | char *name; | 99 | char *name; |
109 | u8 reg; | ||
110 | __be16 id_be; | ||
111 | u16 id; | 100 | u16 id; |
112 | 101 | ||
113 | struct i2c_client client = dev->i2c_client[dev->def_i2c_bus]; | 102 | struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus]; |
114 | 103 | ||
115 | dev->em28xx_sensor = EM28XX_NOSENSOR; | 104 | dev->em28xx_sensor = EM28XX_NOSENSOR; |
116 | for (i = 0; micron_sensor_addrs[i] != I2C_CLIENT_END; i++) { | 105 | for (i = 0; micron_sensor_addrs[i] != I2C_CLIENT_END; i++) { |
117 | client.addr = micron_sensor_addrs[i]; | 106 | client->addr = micron_sensor_addrs[i]; |
118 | /* NOTE: i2c_smbus_read_word_data() doesn't work with BE data */ | ||
119 | /* Read chip ID from register 0x00 */ | 107 | /* Read chip ID from register 0x00 */ |
120 | reg = 0x00; | 108 | ret = i2c_smbus_read_word_data(client, 0x00); /* assumes LE */ |
121 | ret = i2c_master_send(&client, ®, 1); | ||
122 | if (ret < 0) { | 109 | if (ret < 0) { |
123 | if (ret != -ENXIO) | 110 | if (ret != -ENXIO) |
124 | dev_err(&dev->intf->dev, | 111 | dev_err(&dev->intf->dev, |
125 | "couldn't read from i2c device 0x%02x: error %i\n", | 112 | "couldn't read from i2c device 0x%02x: error %i\n", |
126 | client.addr << 1, ret); | 113 | client->addr << 1, ret); |
127 | continue; | ||
128 | } | ||
129 | ret = i2c_master_recv(&client, (u8 *)&id_be, 2); | ||
130 | if (ret < 0) { | ||
131 | dev_err(&dev->intf->dev, | ||
132 | "couldn't read from i2c device 0x%02x: error %i\n", | ||
133 | client.addr << 1, ret); | ||
134 | continue; | 114 | continue; |
135 | } | 115 | } |
136 | id = be16_to_cpu(id_be); | 116 | id = swab16(ret); /* LE -> BE */ |
137 | /* Read chip ID from register 0xff */ | 117 | /* Read chip ID from register 0xff */ |
138 | reg = 0xff; | 118 | ret = i2c_smbus_read_word_data(client, 0xff); |
139 | ret = i2c_master_send(&client, ®, 1); | ||
140 | if (ret < 0) { | 119 | if (ret < 0) { |
141 | dev_err(&dev->intf->dev, | 120 | dev_err(&dev->intf->dev, |
142 | "couldn't read from i2c device 0x%02x: error %i\n", | 121 | "couldn't read from i2c device 0x%02x: error %i\n", |
143 | client.addr << 1, ret); | 122 | client->addr << 1, ret); |
144 | continue; | ||
145 | } | ||
146 | ret = i2c_master_recv(&client, (u8 *)&id_be, 2); | ||
147 | if (ret < 0) { | ||
148 | dev_err(&dev->intf->dev, | ||
149 | "couldn't read from i2c device 0x%02x: error %i\n", | ||
150 | client.addr << 1, ret); | ||
151 | continue; | 123 | continue; |
152 | } | 124 | } |
153 | /* Validate chip ID to be sure we have a Micron device */ | 125 | /* Validate chip ID to be sure we have a Micron device */ |
154 | if (id != be16_to_cpu(id_be)) | 126 | if (id != swab16(ret)) |
155 | continue; | 127 | continue; |
156 | /* Check chip ID */ | 128 | /* Check chip ID */ |
157 | id = be16_to_cpu(id_be); | ||
158 | switch (id) { | 129 | switch (id) { |
159 | case 0x1222: | 130 | case 0x1222: |
160 | name = "MT9V012"; /* MI370 */ /* 640x480 */ | 131 | name = "MT9V012"; /* MI370 */ /* 640x480 */ |
@@ -197,7 +168,6 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev) | |||
197 | dev_info(&dev->intf->dev, | 168 | dev_info(&dev->intf->dev, |
198 | "sensor %s detected\n", name); | 169 | "sensor %s detected\n", name); |
199 | 170 | ||
200 | dev->i2c_client[dev->def_i2c_bus].addr = client.addr; | ||
201 | return 0; | 171 | return 0; |
202 | } | 172 | } |
203 | 173 | ||
@@ -213,30 +183,30 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev) | |||
213 | char *name; | 183 | char *name; |
214 | u8 reg; | 184 | u8 reg; |
215 | u16 id; | 185 | u16 id; |
216 | struct i2c_client client = dev->i2c_client[dev->def_i2c_bus]; | 186 | struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus]; |
217 | 187 | ||
218 | dev->em28xx_sensor = EM28XX_NOSENSOR; | 188 | dev->em28xx_sensor = EM28XX_NOSENSOR; |
219 | /* NOTE: these devices have the register auto incrementation disabled | 189 | /* NOTE: these devices have the register auto incrementation disabled |
220 | * by default, so we have to use single byte reads ! */ | 190 | * by default, so we have to use single byte reads ! */ |
221 | for (i = 0; omnivision_sensor_addrs[i] != I2C_CLIENT_END; i++) { | 191 | for (i = 0; omnivision_sensor_addrs[i] != I2C_CLIENT_END; i++) { |
222 | client.addr = omnivision_sensor_addrs[i]; | 192 | client->addr = omnivision_sensor_addrs[i]; |
223 | /* Read manufacturer ID from registers 0x1c-0x1d (BE) */ | 193 | /* Read manufacturer ID from registers 0x1c-0x1d (BE) */ |
224 | reg = 0x1c; | 194 | reg = 0x1c; |
225 | ret = i2c_smbus_read_byte_data(&client, reg); | 195 | ret = i2c_smbus_read_byte_data(client, reg); |
226 | if (ret < 0) { | 196 | if (ret < 0) { |
227 | if (ret != -ENXIO) | 197 | if (ret != -ENXIO) |
228 | dev_err(&dev->intf->dev, | 198 | dev_err(&dev->intf->dev, |
229 | "couldn't read from i2c device 0x%02x: error %i\n", | 199 | "couldn't read from i2c device 0x%02x: error %i\n", |
230 | client.addr << 1, ret); | 200 | client->addr << 1, ret); |
231 | continue; | 201 | continue; |
232 | } | 202 | } |
233 | id = ret << 8; | 203 | id = ret << 8; |
234 | reg = 0x1d; | 204 | reg = 0x1d; |
235 | ret = i2c_smbus_read_byte_data(&client, reg); | 205 | ret = i2c_smbus_read_byte_data(client, reg); |
236 | if (ret < 0) { | 206 | if (ret < 0) { |
237 | dev_err(&dev->intf->dev, | 207 | dev_err(&dev->intf->dev, |
238 | "couldn't read from i2c device 0x%02x: error %i\n", | 208 | "couldn't read from i2c device 0x%02x: error %i\n", |
239 | client.addr << 1, ret); | 209 | client->addr << 1, ret); |
240 | continue; | 210 | continue; |
241 | } | 211 | } |
242 | id += ret; | 212 | id += ret; |
@@ -245,20 +215,20 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev) | |||
245 | continue; | 215 | continue; |
246 | /* Read product ID from registers 0x0a-0x0b (BE) */ | 216 | /* Read product ID from registers 0x0a-0x0b (BE) */ |
247 | reg = 0x0a; | 217 | reg = 0x0a; |
248 | ret = i2c_smbus_read_byte_data(&client, reg); | 218 | ret = i2c_smbus_read_byte_data(client, reg); |
249 | if (ret < 0) { | 219 | if (ret < 0) { |
250 | dev_err(&dev->intf->dev, | 220 | dev_err(&dev->intf->dev, |
251 | "couldn't read from i2c device 0x%02x: error %i\n", | 221 | "couldn't read from i2c device 0x%02x: error %i\n", |
252 | client.addr << 1, ret); | 222 | client->addr << 1, ret); |
253 | continue; | 223 | continue; |
254 | } | 224 | } |
255 | id = ret << 8; | 225 | id = ret << 8; |
256 | reg = 0x0b; | 226 | reg = 0x0b; |
257 | ret = i2c_smbus_read_byte_data(&client, reg); | 227 | ret = i2c_smbus_read_byte_data(client, reg); |
258 | if (ret < 0) { | 228 | if (ret < 0) { |
259 | dev_err(&dev->intf->dev, | 229 | dev_err(&dev->intf->dev, |
260 | "couldn't read from i2c device 0x%02x: error %i\n", | 230 | "couldn't read from i2c device 0x%02x: error %i\n", |
261 | client.addr << 1, ret); | 231 | client->addr << 1, ret); |
262 | continue; | 232 | continue; |
263 | } | 233 | } |
264 | id += ret; | 234 | id += ret; |
@@ -309,7 +279,6 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev) | |||
309 | dev_info(&dev->intf->dev, | 279 | dev_info(&dev->intf->dev, |
310 | "sensor %s detected\n", name); | 280 | "sensor %s detected\n", name); |
311 | 281 | ||
312 | dev->i2c_client[dev->def_i2c_bus].addr = client.addr; | ||
313 | return 0; | 282 | return 0; |
314 | } | 283 | } |
315 | 284 | ||
@@ -341,17 +310,9 @@ int em28xx_detect_sensor(struct em28xx *dev) | |||
341 | 310 | ||
342 | int em28xx_init_camera(struct em28xx *dev) | 311 | int em28xx_init_camera(struct em28xx *dev) |
343 | { | 312 | { |
344 | char clk_name[V4L2_CLK_NAME_SIZE]; | ||
345 | struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus]; | 313 | struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus]; |
346 | struct i2c_adapter *adap = &dev->i2c_adap[dev->def_i2c_bus]; | 314 | struct i2c_adapter *adap = &dev->i2c_adap[dev->def_i2c_bus]; |
347 | struct em28xx_v4l2 *v4l2 = dev->v4l2; | 315 | struct em28xx_v4l2 *v4l2 = dev->v4l2; |
348 | int ret = 0; | ||
349 | |||
350 | v4l2_clk_name_i2c(clk_name, sizeof(clk_name), | ||
351 | i2c_adapter_id(adap), client->addr); | ||
352 | v4l2->clk = v4l2_clk_register_fixed(clk_name, -EINVAL); | ||
353 | if (IS_ERR(v4l2->clk)) | ||
354 | return PTR_ERR(v4l2->clk); | ||
355 | 316 | ||
356 | switch (dev->em28xx_sensor) { | 317 | switch (dev->em28xx_sensor) { |
357 | case EM28XX_MT9V011: | 318 | case EM28XX_MT9V011: |
@@ -381,12 +342,9 @@ int em28xx_init_camera(struct em28xx *dev) | |||
381 | pdata.xtal = v4l2->sensor_xtal; | 342 | pdata.xtal = v4l2->sensor_xtal; |
382 | if (NULL == | 343 | if (NULL == |
383 | v4l2_i2c_new_subdev_board(&v4l2->v4l2_dev, adap, | 344 | v4l2_i2c_new_subdev_board(&v4l2->v4l2_dev, adap, |
384 | &mt9v011_info, NULL)) { | 345 | &mt9v011_info, NULL)) |
385 | ret = -ENODEV; | 346 | return -ENODEV; |
386 | break; | 347 | v4l2->vinmode = EM28XX_VINMODE_RGB8_GRBG; |
387 | } | ||
388 | /* probably means GRGB 16 bit bayer */ | ||
389 | v4l2->vinmode = 0x0d; | ||
390 | v4l2->vinctl = 0x00; | 348 | v4l2->vinctl = 0x00; |
391 | 349 | ||
392 | break; | 350 | break; |
@@ -397,8 +355,7 @@ int em28xx_init_camera(struct em28xx *dev) | |||
397 | 355 | ||
398 | em28xx_initialize_mt9m001(dev); | 356 | em28xx_initialize_mt9m001(dev); |
399 | 357 | ||
400 | /* probably means BGGR 16 bit bayer */ | 358 | v4l2->vinmode = EM28XX_VINMODE_RGB8_BGGR; |
401 | v4l2->vinmode = 0x0c; | ||
402 | v4l2->vinctl = 0x00; | 359 | v4l2->vinctl = 0x00; |
403 | 360 | ||
404 | break; | 361 | break; |
@@ -410,7 +367,7 @@ int em28xx_init_camera(struct em28xx *dev) | |||
410 | em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk); | 367 | em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk); |
411 | em28xx_initialize_mt9m111(dev); | 368 | em28xx_initialize_mt9m111(dev); |
412 | 369 | ||
413 | v4l2->vinmode = 0x0a; | 370 | v4l2->vinmode = EM28XX_VINMODE_YUV422_UYVY; |
414 | v4l2->vinctl = 0x00; | 371 | v4l2->vinctl = 0x00; |
415 | 372 | ||
416 | break; | 373 | break; |
@@ -421,7 +378,6 @@ int em28xx_init_camera(struct em28xx *dev) | |||
421 | .type = "ov2640", | 378 | .type = "ov2640", |
422 | .flags = I2C_CLIENT_SCCB, | 379 | .flags = I2C_CLIENT_SCCB, |
423 | .addr = client->addr, | 380 | .addr = client->addr, |
424 | .platform_data = &camlink, | ||
425 | }; | 381 | }; |
426 | struct v4l2_subdev_format format = { | 382 | struct v4l2_subdev_format format = { |
427 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | 383 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, |
@@ -441,10 +397,8 @@ int em28xx_init_camera(struct em28xx *dev) | |||
441 | subdev = | 397 | subdev = |
442 | v4l2_i2c_new_subdev_board(&v4l2->v4l2_dev, adap, | 398 | v4l2_i2c_new_subdev_board(&v4l2->v4l2_dev, adap, |
443 | &ov2640_info, NULL); | 399 | &ov2640_info, NULL); |
444 | if (NULL == subdev) { | 400 | if (subdev == NULL) |
445 | ret = -ENODEV; | 401 | return -ENODEV; |
446 | break; | ||
447 | } | ||
448 | 402 | ||
449 | format.format.code = MEDIA_BUS_FMT_YUYV8_2X8; | 403 | format.format.code = MEDIA_BUS_FMT_YUYV8_2X8; |
450 | format.format.width = 640; | 404 | format.format.width = 640; |
@@ -454,21 +408,16 @@ int em28xx_init_camera(struct em28xx *dev) | |||
454 | /* NOTE: for UXGA=1600x1200 switch to 12MHz */ | 408 | /* NOTE: for UXGA=1600x1200 switch to 12MHz */ |
455 | dev->board.xclk = EM28XX_XCLK_FREQUENCY_24MHZ; | 409 | dev->board.xclk = EM28XX_XCLK_FREQUENCY_24MHZ; |
456 | em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk); | 410 | em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk); |
457 | v4l2->vinmode = 0x08; | 411 | v4l2->vinmode = EM28XX_VINMODE_YUV422_YUYV; |
458 | v4l2->vinctl = 0x00; | 412 | v4l2->vinctl = 0x00; |
459 | 413 | ||
460 | break; | 414 | break; |
461 | } | 415 | } |
462 | case EM28XX_NOSENSOR: | 416 | case EM28XX_NOSENSOR: |
463 | default: | 417 | default: |
464 | ret = -EINVAL; | 418 | return -EINVAL; |
465 | } | 419 | } |
466 | 420 | ||
467 | if (ret < 0) { | 421 | return 0; |
468 | v4l2_clk_unregister_fixed(v4l2->clk); | ||
469 | v4l2->clk = NULL; | ||
470 | } | ||
471 | |||
472 | return ret; | ||
473 | } | 422 | } |
474 | EXPORT_SYMBOL_GPL(em28xx_init_camera); | 423 | EXPORT_SYMBOL_GPL(em28xx_init_camera); |
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 5f90d0899a45..a12b599a1fa2 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c | |||
@@ -2600,6 +2600,8 @@ struct usb_device_id em28xx_id_table[] = { | |||
2600 | .driver_info = EM28178_BOARD_TERRATEC_T2_STICK_HD }, | 2600 | .driver_info = EM28178_BOARD_TERRATEC_T2_STICK_HD }, |
2601 | { USB_DEVICE(0x3275, 0x0085), | 2601 | { USB_DEVICE(0x3275, 0x0085), |
2602 | .driver_info = EM28178_BOARD_PLEX_PX_BCUD }, | 2602 | .driver_info = EM28178_BOARD_PLEX_PX_BCUD }, |
2603 | { USB_DEVICE(0xeb1a, 0x5051), /* Ion Video 2 PC MKII / Startech svid2usb23 / Raygo R12-41373 */ | ||
2604 | .driver_info = EM2860_BOARD_TVP5150_REFERENCE_DESIGN }, | ||
2603 | { }, | 2605 | { }, |
2604 | }; | 2606 | }; |
2605 | MODULE_DEVICE_TABLE(usb, em28xx_id_table); | 2607 | MODULE_DEVICE_TABLE(usb, em28xx_id_table); |
@@ -2917,7 +2919,9 @@ static void em28xx_card_setup(struct em28xx *dev) | |||
2917 | * If sensor is not found, then it isn't a webcam. | 2919 | * If sensor is not found, then it isn't a webcam. |
2918 | */ | 2920 | */ |
2919 | if (dev->board.is_webcam) { | 2921 | if (dev->board.is_webcam) { |
2920 | if (em28xx_detect_sensor(dev) < 0) | 2922 | em28xx_detect_sensor(dev); |
2923 | if (dev->em28xx_sensor == EM28XX_NOSENSOR) | ||
2924 | /* NOTE: error/unknown sensor/no sensor */ | ||
2921 | dev->board.is_webcam = 0; | 2925 | dev->board.is_webcam = 0; |
2922 | } | 2926 | } |
2923 | 2927 | ||
@@ -2974,8 +2978,7 @@ static void em28xx_card_setup(struct em28xx *dev) | |||
2974 | #endif | 2978 | #endif |
2975 | /* Call first TVeeprom */ | 2979 | /* Call first TVeeprom */ |
2976 | 2980 | ||
2977 | dev->i2c_client[dev->def_i2c_bus].addr = 0xa0 >> 1; | 2981 | tveeprom_hauppauge_analog(&tv, dev->eedata); |
2978 | tveeprom_hauppauge_analog(&dev->i2c_client[dev->def_i2c_bus], &tv, dev->eedata); | ||
2979 | 2982 | ||
2980 | dev->tuner_type = tv.tuner_type; | 2983 | dev->tuner_type = tv.tuner_type; |
2981 | 2984 | ||
@@ -3666,9 +3669,11 @@ static int em28xx_usb_probe(struct usb_interface *interface, | |||
3666 | try_bulk = usb_xfer_mode > 0; | 3669 | try_bulk = usb_xfer_mode > 0; |
3667 | } | 3670 | } |
3668 | 3671 | ||
3669 | /* Disable V4L2 if the device doesn't have a decoder */ | 3672 | /* Disable V4L2 if the device doesn't have a decoder or image sensor */ |
3670 | if (has_video && | 3673 | if (has_video && |
3671 | dev->board.decoder == EM28XX_NODECODER && !dev->board.is_webcam) { | 3674 | dev->board.decoder == EM28XX_NODECODER && |
3675 | dev->em28xx_sensor == EM28XX_NOSENSOR) { | ||
3676 | |||
3672 | dev_err(&interface->dev, | 3677 | dev_err(&interface->dev, |
3673 | "Currently, V4L2 is not supported on this model\n"); | 3678 | "Currently, V4L2 is not supported on this model\n"); |
3674 | has_video = false; | 3679 | has_video = false; |
diff --git a/drivers/media/usb/em28xx/em28xx-reg.h b/drivers/media/usb/em28xx/em28xx-reg.h index afe7a66d7dc8..747525ca7ed5 100644 --- a/drivers/media/usb/em28xx/em28xx-reg.h +++ b/drivers/media/usb/em28xx/em28xx-reg.h | |||
@@ -93,6 +93,24 @@ | |||
93 | #define EM28XX_XCLK_FREQUENCY_24MHZ 0x0b | 93 | #define EM28XX_XCLK_FREQUENCY_24MHZ 0x0b |
94 | 94 | ||
95 | #define EM28XX_R10_VINMODE 0x10 | 95 | #define EM28XX_R10_VINMODE 0x10 |
96 | /* used by all non-camera devices: */ | ||
97 | #define EM28XX_VINMODE_YUV422_CbYCrY 0x10 | ||
98 | /* used by camera devices: */ | ||
99 | #define EM28XX_VINMODE_YUV422_YUYV 0x08 | ||
100 | #define EM28XX_VINMODE_YUV422_YVYU 0x09 | ||
101 | #define EM28XX_VINMODE_YUV422_UYVY 0x0a | ||
102 | #define EM28XX_VINMODE_YUV422_VYUY 0x0b | ||
103 | #define EM28XX_VINMODE_RGB8_BGGR 0x0c | ||
104 | #define EM28XX_VINMODE_RGB8_GRBG 0x0d | ||
105 | #define EM28XX_VINMODE_RGB8_GBRG 0x0e | ||
106 | #define EM28XX_VINMODE_RGB8_RGGB 0x0f | ||
107 | /* | ||
108 | * apparently: | ||
109 | * bit 0: swap component 1+2 with 3+4 | ||
110 | * => e.g.: YUYV => YVYU, BGGR => GRBG | ||
111 | * bit 1: swap component 1 with 2 and 3 with 4 | ||
112 | * => e.g.: YUYV => UYVY, BGGR => GBRG | ||
113 | */ | ||
96 | 114 | ||
97 | #define EM28XX_R11_VINCTRL 0x11 | 115 | #define EM28XX_R11_VINCTRL 0x11 |
98 | 116 | ||
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 8d93100334ea..8d253a5df0a9 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c | |||
@@ -43,7 +43,6 @@ | |||
43 | #include <media/v4l2-common.h> | 43 | #include <media/v4l2-common.h> |
44 | #include <media/v4l2-ioctl.h> | 44 | #include <media/v4l2-ioctl.h> |
45 | #include <media/v4l2-event.h> | 45 | #include <media/v4l2-event.h> |
46 | #include <media/v4l2-clk.h> | ||
47 | #include <media/drv-intf/msp3400.h> | 46 | #include <media/drv-intf/msp3400.h> |
48 | #include <media/tuner.h> | 47 | #include <media/tuner.h> |
49 | 48 | ||
@@ -117,6 +116,11 @@ static struct em28xx_fmt format[] = { | |||
117 | .depth = 16, | 116 | .depth = 16, |
118 | .reg = EM28XX_OUTFMT_RGB_16_656, | 117 | .reg = EM28XX_OUTFMT_RGB_16_656, |
119 | }, { | 118 | }, { |
119 | .name = "8 bpp Bayer RGRG..GBGB", | ||
120 | .fourcc = V4L2_PIX_FMT_SRGGB8, | ||
121 | .depth = 8, | ||
122 | .reg = EM28XX_OUTFMT_RGB_8_RGRG, | ||
123 | }, { | ||
120 | .name = "8 bpp Bayer BGBG..GRGR", | 124 | .name = "8 bpp Bayer BGBG..GRGR", |
121 | .fourcc = V4L2_PIX_FMT_SBGGR8, | 125 | .fourcc = V4L2_PIX_FMT_SBGGR8, |
122 | .depth = 8, | 126 | .depth = 8, |
@@ -2140,11 +2144,6 @@ static int em28xx_v4l2_fini(struct em28xx *dev) | |||
2140 | v4l2_ctrl_handler_free(&v4l2->ctrl_handler); | 2144 | v4l2_ctrl_handler_free(&v4l2->ctrl_handler); |
2141 | v4l2_device_unregister(&v4l2->v4l2_dev); | 2145 | v4l2_device_unregister(&v4l2->v4l2_dev); |
2142 | 2146 | ||
2143 | if (v4l2->clk) { | ||
2144 | v4l2_clk_unregister_fixed(v4l2->clk); | ||
2145 | v4l2->clk = NULL; | ||
2146 | } | ||
2147 | |||
2148 | kref_put(&v4l2->ref, em28xx_free_v4l2); | 2147 | kref_put(&v4l2->ref, em28xx_free_v4l2); |
2149 | 2148 | ||
2150 | mutex_unlock(&dev->lock); | 2149 | mutex_unlock(&dev->lock); |
@@ -2465,7 +2464,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) | |||
2465 | /* | 2464 | /* |
2466 | * Default format, used for tvp5150 or saa711x output formats | 2465 | * Default format, used for tvp5150 or saa711x output formats |
2467 | */ | 2466 | */ |
2468 | v4l2->vinmode = 0x10; | 2467 | v4l2->vinmode = EM28XX_VINMODE_YUV422_CbYCrY; |
2469 | v4l2->vinctl = EM28XX_VINCTRL_INTERLACED | | 2468 | v4l2->vinctl = EM28XX_VINCTRL_INTERLACED | |
2470 | EM28XX_VINCTRL_CCIR656_ENABLE; | 2469 | EM28XX_VINCTRL_CCIR656_ENABLE; |
2471 | 2470 | ||
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index e9f379959fa5..e8d97d5ec161 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h | |||
@@ -510,7 +510,6 @@ struct em28xx_v4l2 { | |||
510 | 510 | ||
511 | struct v4l2_device v4l2_dev; | 511 | struct v4l2_device v4l2_dev; |
512 | struct v4l2_ctrl_handler ctrl_handler; | 512 | struct v4l2_ctrl_handler ctrl_handler; |
513 | struct v4l2_clk *clk; | ||
514 | 513 | ||
515 | struct video_device vdev; | 514 | struct video_device vdev; |
516 | struct video_device vbi_dev; | 515 | struct video_device vbi_dev; |
diff --git a/drivers/media/usb/go7007/go7007-v4l2.c b/drivers/media/usb/go7007/go7007-v4l2.c index 4eaba0c24629..ed5ec9773969 100644 --- a/drivers/media/usb/go7007/go7007-v4l2.c +++ b/drivers/media/usb/go7007/go7007-v4l2.c | |||
@@ -792,14 +792,13 @@ static int vidioc_subscribe_event(struct v4l2_fh *fh, | |||
792 | { | 792 | { |
793 | 793 | ||
794 | switch (sub->type) { | 794 | switch (sub->type) { |
795 | case V4L2_EVENT_CTRL: | ||
796 | return v4l2_ctrl_subscribe_event(fh, sub); | ||
797 | case V4L2_EVENT_MOTION_DET: | 795 | case V4L2_EVENT_MOTION_DET: |
798 | /* Allow for up to 30 events (1 second for NTSC) to be | 796 | /* Allow for up to 30 events (1 second for NTSC) to be |
799 | * stored. */ | 797 | * stored. */ |
800 | return v4l2_event_subscribe(fh, sub, 30, NULL); | 798 | return v4l2_event_subscribe(fh, sub, 30, NULL); |
799 | default: | ||
800 | return v4l2_ctrl_subscribe_event(fh, sub); | ||
801 | } | 801 | } |
802 | return -EINVAL; | ||
803 | } | 802 | } |
804 | 803 | ||
805 | 804 | ||
diff --git a/drivers/media/usb/gspca/konica.c b/drivers/media/usb/gspca/konica.c index 71f273377f83..31b2117e8f1d 100644 --- a/drivers/media/usb/gspca/konica.c +++ b/drivers/media/usb/gspca/konica.c | |||
@@ -184,6 +184,9 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
184 | return -EIO; | 184 | return -EIO; |
185 | } | 185 | } |
186 | 186 | ||
187 | if (alt->desc.bNumEndpoints < 2) | ||
188 | return -ENODEV; | ||
189 | |||
187 | packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); | 190 | packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); |
188 | 191 | ||
189 | n = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; | 192 | n = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; |
diff --git a/drivers/media/usb/pulse8-cec/Kconfig b/drivers/media/usb/pulse8-cec/Kconfig index 6ffc407de62f..8937f3986a01 100644 --- a/drivers/media/usb/pulse8-cec/Kconfig +++ b/drivers/media/usb/pulse8-cec/Kconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | config USB_PULSE8_CEC | 1 | config USB_PULSE8_CEC |
2 | tristate "Pulse Eight HDMI CEC" | 2 | tristate "Pulse Eight HDMI CEC" |
3 | depends on USB_ACM && MEDIA_CEC_SUPPORT | 3 | depends on USB_ACM && CEC_CORE |
4 | select SERIO | 4 | select SERIO |
5 | select SERIO_SERPORT | 5 | select SERIO_SERPORT |
6 | ---help--- | 6 | ---help--- |
diff --git a/drivers/media/usb/pulse8-cec/pulse8-cec.c b/drivers/media/usb/pulse8-cec/pulse8-cec.c index 7c18daeb0ade..1dfc2de1fe77 100644 --- a/drivers/media/usb/pulse8-cec/pulse8-cec.c +++ b/drivers/media/usb/pulse8-cec/pulse8-cec.c | |||
@@ -461,7 +461,7 @@ static int pulse8_apply_persistent_config(struct pulse8 *pulse8, | |||
461 | 461 | ||
462 | static int pulse8_cec_adap_enable(struct cec_adapter *adap, bool enable) | 462 | static int pulse8_cec_adap_enable(struct cec_adapter *adap, bool enable) |
463 | { | 463 | { |
464 | struct pulse8 *pulse8 = adap->priv; | 464 | struct pulse8 *pulse8 = cec_get_drvdata(adap); |
465 | u8 cmd[16]; | 465 | u8 cmd[16]; |
466 | int err; | 466 | int err; |
467 | 467 | ||
@@ -474,7 +474,7 @@ static int pulse8_cec_adap_enable(struct cec_adapter *adap, bool enable) | |||
474 | 474 | ||
475 | static int pulse8_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr) | 475 | static int pulse8_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr) |
476 | { | 476 | { |
477 | struct pulse8 *pulse8 = adap->priv; | 477 | struct pulse8 *pulse8 = cec_get_drvdata(adap); |
478 | u16 mask = 0; | 478 | u16 mask = 0; |
479 | u16 pa = adap->phys_addr; | 479 | u16 pa = adap->phys_addr; |
480 | u8 cmd[16]; | 480 | u8 cmd[16]; |
@@ -594,7 +594,7 @@ unlock: | |||
594 | static int pulse8_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, | 594 | static int pulse8_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, |
595 | u32 signal_free_time, struct cec_msg *msg) | 595 | u32 signal_free_time, struct cec_msg *msg) |
596 | { | 596 | { |
597 | struct pulse8 *pulse8 = adap->priv; | 597 | struct pulse8 *pulse8 = cec_get_drvdata(adap); |
598 | u8 cmd[2]; | 598 | u8 cmd[2]; |
599 | unsigned int i; | 599 | unsigned int i; |
600 | int err; | 600 | int err; |
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c index 4af2fb5c85d5..8b643d511a0b 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c | |||
@@ -118,15 +118,10 @@ int pvr2_eeprom_analyze(struct pvr2_hdw *hdw) | |||
118 | memset(&tvdata,0,sizeof(tvdata)); | 118 | memset(&tvdata,0,sizeof(tvdata)); |
119 | 119 | ||
120 | eeprom = pvr2_eeprom_fetch(hdw); | 120 | eeprom = pvr2_eeprom_fetch(hdw); |
121 | if (!eeprom) return -EINVAL; | 121 | if (!eeprom) |
122 | 122 | return -EINVAL; | |
123 | { | 123 | |
124 | struct i2c_client fake_client; | 124 | tveeprom_hauppauge_analog(&tvdata, eeprom); |
125 | /* Newer version expects a useless client interface */ | ||
126 | fake_client.addr = hdw->eeprom_addr; | ||
127 | fake_client.adapter = &hdw->i2c_adap; | ||
128 | tveeprom_hauppauge_analog(&fake_client,&tvdata,eeprom); | ||
129 | } | ||
130 | 125 | ||
131 | trace_eeprom("eeprom assumed v4l tveeprom module"); | 126 | trace_eeprom("eeprom assumed v4l tveeprom module"); |
132 | trace_eeprom("eeprom direct call results:"); | 127 | trace_eeprom("eeprom direct call results:"); |
diff --git a/drivers/media/usb/rainshadow-cec/Kconfig b/drivers/media/usb/rainshadow-cec/Kconfig new file mode 100644 index 000000000000..3eb86607efb8 --- /dev/null +++ b/drivers/media/usb/rainshadow-cec/Kconfig | |||
@@ -0,0 +1,10 @@ | |||
1 | config USB_RAINSHADOW_CEC | ||
2 | tristate "RainShadow Tech HDMI CEC" | ||
3 | depends on USB_ACM && CEC_CORE | ||
4 | select SERIO | ||
5 | select SERIO_SERPORT | ||
6 | ---help--- | ||
7 | This is a cec driver for the RainShadow Tech HDMI CEC device. | ||
8 | |||
9 | To compile this driver as a module, choose M here: the | ||
10 | module will be called rainshadow-cec. | ||
diff --git a/drivers/media/usb/rainshadow-cec/Makefile b/drivers/media/usb/rainshadow-cec/Makefile new file mode 100644 index 000000000000..a79fbc77e1f7 --- /dev/null +++ b/drivers/media/usb/rainshadow-cec/Makefile | |||
@@ -0,0 +1 @@ | |||
obj-$(CONFIG_USB_RAINSHADOW_CEC) += rainshadow-cec.o | |||
diff --git a/drivers/media/usb/rainshadow-cec/rainshadow-cec.c b/drivers/media/usb/rainshadow-cec/rainshadow-cec.c new file mode 100644 index 000000000000..541ca543f71f --- /dev/null +++ b/drivers/media/usb/rainshadow-cec/rainshadow-cec.c | |||
@@ -0,0 +1,388 @@ | |||
1 | /* | ||
2 | * RainShadow Tech HDMI CEC driver | ||
3 | * | ||
4 | * Copyright 2016 Hans Verkuil <hverkuil@xs4all.nl | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version of 2 of the License, or (at your | ||
9 | * option) any later version. See the file COPYING in the main directory of | ||
10 | * this archive for more details. | ||
11 | */ | ||
12 | |||
13 | /* | ||
14 | * Notes: | ||
15 | * | ||
16 | * The higher level protocols are currently disabled. This can be added | ||
17 | * later, similar to how this is done for the Pulse Eight CEC driver. | ||
18 | * | ||
19 | * Documentation of the protocol is available here: | ||
20 | * | ||
21 | * http://rainshadowtech.com/doc/HDMICECtoUSBandRS232v2.0.pdf | ||
22 | */ | ||
23 | |||
24 | #include <linux/completion.h> | ||
25 | #include <linux/ctype.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <linux/interrupt.h> | ||
29 | #include <linux/kernel.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/serio.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include <linux/spinlock.h> | ||
34 | #include <linux/time.h> | ||
35 | #include <linux/workqueue.h> | ||
36 | |||
37 | #include <media/cec.h> | ||
38 | |||
39 | MODULE_AUTHOR("Hans Verkuil <hverkuil@xs4all.nl>"); | ||
40 | MODULE_DESCRIPTION("RainShadow Tech HDMI CEC driver"); | ||
41 | MODULE_LICENSE("GPL"); | ||
42 | |||
43 | #define DATA_SIZE 256 | ||
44 | |||
45 | struct rain { | ||
46 | struct device *dev; | ||
47 | struct serio *serio; | ||
48 | struct cec_adapter *adap; | ||
49 | struct completion cmd_done; | ||
50 | struct work_struct work; | ||
51 | |||
52 | /* Low-level ringbuffer, collecting incoming characters */ | ||
53 | char buf[DATA_SIZE]; | ||
54 | unsigned int buf_rd_idx; | ||
55 | unsigned int buf_wr_idx; | ||
56 | unsigned int buf_len; | ||
57 | spinlock_t buf_lock; | ||
58 | |||
59 | /* command buffer */ | ||
60 | char cmd[DATA_SIZE]; | ||
61 | unsigned int cmd_idx; | ||
62 | bool cmd_started; | ||
63 | |||
64 | /* reply to a command, only used to store the firmware version */ | ||
65 | char cmd_reply[DATA_SIZE]; | ||
66 | |||
67 | struct mutex write_lock; | ||
68 | }; | ||
69 | |||
70 | static void rain_process_msg(struct rain *rain) | ||
71 | { | ||
72 | struct cec_msg msg = {}; | ||
73 | const char *cmd = rain->cmd + 3; | ||
74 | int stat = -1; | ||
75 | |||
76 | for (; *cmd; cmd++) { | ||
77 | if (!isxdigit(*cmd)) | ||
78 | continue; | ||
79 | if (isxdigit(cmd[0]) && isxdigit(cmd[1])) { | ||
80 | if (msg.len == CEC_MAX_MSG_SIZE) | ||
81 | break; | ||
82 | if (hex2bin(msg.msg + msg.len, cmd, 1)) | ||
83 | continue; | ||
84 | msg.len++; | ||
85 | cmd++; | ||
86 | continue; | ||
87 | } | ||
88 | if (!cmd[1]) | ||
89 | stat = hex_to_bin(cmd[0]); | ||
90 | break; | ||
91 | } | ||
92 | |||
93 | if (rain->cmd[0] == 'R') { | ||
94 | if (stat == 1 || stat == 2) | ||
95 | cec_received_msg(rain->adap, &msg); | ||
96 | return; | ||
97 | } | ||
98 | |||
99 | switch (stat) { | ||
100 | case 1: | ||
101 | cec_transmit_done(rain->adap, CEC_TX_STATUS_OK, | ||
102 | 0, 0, 0, 0); | ||
103 | break; | ||
104 | case 2: | ||
105 | cec_transmit_done(rain->adap, CEC_TX_STATUS_NACK, | ||
106 | 0, 1, 0, 0); | ||
107 | break; | ||
108 | default: | ||
109 | cec_transmit_done(rain->adap, CEC_TX_STATUS_LOW_DRIVE, | ||
110 | 0, 0, 0, 1); | ||
111 | break; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | static void rain_irq_work_handler(struct work_struct *work) | ||
116 | { | ||
117 | struct rain *rain = | ||
118 | container_of(work, struct rain, work); | ||
119 | |||
120 | while (true) { | ||
121 | unsigned long flags; | ||
122 | bool exit_loop; | ||
123 | char data; | ||
124 | |||
125 | spin_lock_irqsave(&rain->buf_lock, flags); | ||
126 | exit_loop = rain->buf_len == 0; | ||
127 | if (rain->buf_len) { | ||
128 | data = rain->buf[rain->buf_rd_idx]; | ||
129 | rain->buf_len--; | ||
130 | rain->buf_rd_idx = (rain->buf_rd_idx + 1) & 0xff; | ||
131 | } | ||
132 | spin_unlock_irqrestore(&rain->buf_lock, flags); | ||
133 | |||
134 | if (exit_loop) | ||
135 | break; | ||
136 | |||
137 | if (!rain->cmd_started && data != '?') | ||
138 | continue; | ||
139 | |||
140 | switch (data) { | ||
141 | case '\r': | ||
142 | rain->cmd[rain->cmd_idx] = '\0'; | ||
143 | dev_dbg(rain->dev, "received: %s\n", rain->cmd); | ||
144 | if (!memcmp(rain->cmd, "REC", 3) || | ||
145 | !memcmp(rain->cmd, "STA", 3)) { | ||
146 | rain_process_msg(rain); | ||
147 | } else { | ||
148 | strcpy(rain->cmd_reply, rain->cmd); | ||
149 | complete(&rain->cmd_done); | ||
150 | } | ||
151 | rain->cmd_idx = 0; | ||
152 | rain->cmd_started = false; | ||
153 | break; | ||
154 | |||
155 | case '\n': | ||
156 | rain->cmd_idx = 0; | ||
157 | rain->cmd_started = false; | ||
158 | break; | ||
159 | |||
160 | case '?': | ||
161 | rain->cmd_idx = 0; | ||
162 | rain->cmd_started = true; | ||
163 | break; | ||
164 | |||
165 | default: | ||
166 | if (rain->cmd_idx >= DATA_SIZE - 1) { | ||
167 | dev_dbg(rain->dev, | ||
168 | "throwing away %d bytes of garbage\n", rain->cmd_idx); | ||
169 | rain->cmd_idx = 0; | ||
170 | } | ||
171 | rain->cmd[rain->cmd_idx++] = data; | ||
172 | break; | ||
173 | } | ||
174 | } | ||
175 | } | ||
176 | |||
177 | static irqreturn_t rain_interrupt(struct serio *serio, unsigned char data, | ||
178 | unsigned int flags) | ||
179 | { | ||
180 | struct rain *rain = serio_get_drvdata(serio); | ||
181 | |||
182 | if (rain->buf_len == DATA_SIZE) { | ||
183 | dev_warn_once(rain->dev, "buffer overflow\n"); | ||
184 | return IRQ_HANDLED; | ||
185 | } | ||
186 | spin_lock(&rain->buf_lock); | ||
187 | rain->buf_len++; | ||
188 | rain->buf[rain->buf_wr_idx] = data; | ||
189 | rain->buf_wr_idx = (rain->buf_wr_idx + 1) & 0xff; | ||
190 | spin_unlock(&rain->buf_lock); | ||
191 | schedule_work(&rain->work); | ||
192 | return IRQ_HANDLED; | ||
193 | } | ||
194 | |||
195 | static void rain_disconnect(struct serio *serio) | ||
196 | { | ||
197 | struct rain *rain = serio_get_drvdata(serio); | ||
198 | |||
199 | cancel_work_sync(&rain->work); | ||
200 | cec_unregister_adapter(rain->adap); | ||
201 | dev_info(&serio->dev, "disconnected\n"); | ||
202 | serio_close(serio); | ||
203 | serio_set_drvdata(serio, NULL); | ||
204 | kfree(rain); | ||
205 | } | ||
206 | |||
207 | static int rain_send(struct rain *rain, const char *command) | ||
208 | { | ||
209 | int err = serio_write(rain->serio, '!'); | ||
210 | |||
211 | dev_dbg(rain->dev, "send: %s\n", command); | ||
212 | while (!err && *command) | ||
213 | err = serio_write(rain->serio, *command++); | ||
214 | if (!err) | ||
215 | err = serio_write(rain->serio, '~'); | ||
216 | |||
217 | return err; | ||
218 | } | ||
219 | |||
220 | static int rain_send_and_wait(struct rain *rain, | ||
221 | const char *cmd, const char *reply) | ||
222 | { | ||
223 | int err; | ||
224 | |||
225 | init_completion(&rain->cmd_done); | ||
226 | |||
227 | mutex_lock(&rain->write_lock); | ||
228 | err = rain_send(rain, cmd); | ||
229 | if (err) | ||
230 | goto err; | ||
231 | |||
232 | if (!wait_for_completion_timeout(&rain->cmd_done, HZ)) { | ||
233 | err = -ETIMEDOUT; | ||
234 | goto err; | ||
235 | } | ||
236 | if (reply && strncmp(rain->cmd_reply, reply, strlen(reply))) { | ||
237 | dev_dbg(rain->dev, | ||
238 | "transmit of '%s': received '%s' instead of '%s'\n", | ||
239 | cmd, rain->cmd_reply, reply); | ||
240 | err = -EIO; | ||
241 | } | ||
242 | err: | ||
243 | mutex_unlock(&rain->write_lock); | ||
244 | return err; | ||
245 | } | ||
246 | |||
247 | static int rain_setup(struct rain *rain, struct serio *serio, | ||
248 | struct cec_log_addrs *log_addrs, u16 *pa) | ||
249 | { | ||
250 | int err; | ||
251 | |||
252 | err = rain_send_and_wait(rain, "R", "REV"); | ||
253 | if (err) | ||
254 | return err; | ||
255 | dev_info(rain->dev, "Firmware version %s\n", rain->cmd_reply + 4); | ||
256 | |||
257 | err = rain_send_and_wait(rain, "Q 1", "QTY"); | ||
258 | if (err) | ||
259 | return err; | ||
260 | err = rain_send_and_wait(rain, "c0000", "CFG"); | ||
261 | if (err) | ||
262 | return err; | ||
263 | return rain_send_and_wait(rain, "A F 0000", "ADR"); | ||
264 | } | ||
265 | |||
266 | static int rain_cec_adap_enable(struct cec_adapter *adap, bool enable) | ||
267 | { | ||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | static int rain_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr) | ||
272 | { | ||
273 | struct rain *rain = cec_get_drvdata(adap); | ||
274 | u8 cmd[16]; | ||
275 | |||
276 | if (log_addr == CEC_LOG_ADDR_INVALID) | ||
277 | log_addr = CEC_LOG_ADDR_UNREGISTERED; | ||
278 | snprintf(cmd, sizeof(cmd), "A %x", log_addr); | ||
279 | return rain_send_and_wait(rain, cmd, "ADR"); | ||
280 | } | ||
281 | |||
282 | static int rain_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, | ||
283 | u32 signal_free_time, struct cec_msg *msg) | ||
284 | { | ||
285 | struct rain *rain = cec_get_drvdata(adap); | ||
286 | char cmd[2 * CEC_MAX_MSG_SIZE + 16]; | ||
287 | unsigned int i; | ||
288 | int err; | ||
289 | |||
290 | if (msg->len == 1) { | ||
291 | snprintf(cmd, sizeof(cmd), "x%x", cec_msg_destination(msg)); | ||
292 | } else { | ||
293 | char hex[3]; | ||
294 | |||
295 | snprintf(cmd, sizeof(cmd), "x%x %02x ", | ||
296 | cec_msg_destination(msg), msg->msg[1]); | ||
297 | for (i = 2; i < msg->len; i++) { | ||
298 | snprintf(hex, sizeof(hex), "%02x", msg->msg[i]); | ||
299 | strncat(cmd, hex, sizeof(cmd)); | ||
300 | } | ||
301 | } | ||
302 | mutex_lock(&rain->write_lock); | ||
303 | err = rain_send(rain, cmd); | ||
304 | mutex_unlock(&rain->write_lock); | ||
305 | return err; | ||
306 | } | ||
307 | |||
308 | static const struct cec_adap_ops rain_cec_adap_ops = { | ||
309 | .adap_enable = rain_cec_adap_enable, | ||
310 | .adap_log_addr = rain_cec_adap_log_addr, | ||
311 | .adap_transmit = rain_cec_adap_transmit, | ||
312 | }; | ||
313 | |||
314 | static int rain_connect(struct serio *serio, struct serio_driver *drv) | ||
315 | { | ||
316 | u32 caps = CEC_CAP_TRANSMIT | CEC_CAP_LOG_ADDRS | CEC_CAP_PHYS_ADDR | | ||
317 | CEC_CAP_PASSTHROUGH | CEC_CAP_RC | CEC_CAP_MONITOR_ALL; | ||
318 | struct rain *rain; | ||
319 | int err = -ENOMEM; | ||
320 | struct cec_log_addrs log_addrs = {}; | ||
321 | u16 pa = CEC_PHYS_ADDR_INVALID; | ||
322 | |||
323 | rain = kzalloc(sizeof(*rain), GFP_KERNEL); | ||
324 | |||
325 | if (!rain) | ||
326 | return -ENOMEM; | ||
327 | |||
328 | rain->serio = serio; | ||
329 | rain->adap = cec_allocate_adapter(&rain_cec_adap_ops, rain, | ||
330 | "HDMI CEC", caps, 1); | ||
331 | err = PTR_ERR_OR_ZERO(rain->adap); | ||
332 | if (err < 0) | ||
333 | goto free_device; | ||
334 | |||
335 | rain->dev = &serio->dev; | ||
336 | serio_set_drvdata(serio, rain); | ||
337 | INIT_WORK(&rain->work, rain_irq_work_handler); | ||
338 | mutex_init(&rain->write_lock); | ||
339 | |||
340 | err = serio_open(serio, drv); | ||
341 | if (err) | ||
342 | goto delete_adap; | ||
343 | |||
344 | err = rain_setup(rain, serio, &log_addrs, &pa); | ||
345 | if (err) | ||
346 | goto close_serio; | ||
347 | |||
348 | err = cec_register_adapter(rain->adap, &serio->dev); | ||
349 | if (err < 0) | ||
350 | goto close_serio; | ||
351 | |||
352 | rain->dev = &rain->adap->devnode.dev; | ||
353 | return 0; | ||
354 | |||
355 | close_serio: | ||
356 | serio_close(serio); | ||
357 | delete_adap: | ||
358 | cec_delete_adapter(rain->adap); | ||
359 | serio_set_drvdata(serio, NULL); | ||
360 | free_device: | ||
361 | kfree(rain); | ||
362 | return err; | ||
363 | } | ||
364 | |||
365 | static struct serio_device_id rain_serio_ids[] = { | ||
366 | { | ||
367 | .type = SERIO_RS232, | ||
368 | .proto = SERIO_RAINSHADOW_CEC, | ||
369 | .id = SERIO_ANY, | ||
370 | .extra = SERIO_ANY, | ||
371 | }, | ||
372 | { 0 } | ||
373 | }; | ||
374 | |||
375 | MODULE_DEVICE_TABLE(serio, rain_serio_ids); | ||
376 | |||
377 | static struct serio_driver rain_drv = { | ||
378 | .driver = { | ||
379 | .name = "rainshadow-cec", | ||
380 | }, | ||
381 | .description = "RainShadow Tech HDMI CEC driver", | ||
382 | .id_table = rain_serio_ids, | ||
383 | .interrupt = rain_interrupt, | ||
384 | .connect = rain_connect, | ||
385 | .disconnect = rain_disconnect, | ||
386 | }; | ||
387 | |||
388 | module_serio_driver(rain_drv); | ||
diff --git a/drivers/media/usb/stk1160/Kconfig b/drivers/media/usb/stk1160/Kconfig index 22dff4f3b921..425ed00e2599 100644 --- a/drivers/media/usb/stk1160/Kconfig +++ b/drivers/media/usb/stk1160/Kconfig | |||
@@ -6,7 +6,11 @@ config VIDEO_STK1160_COMMON | |||
6 | This is a video4linux driver for STK1160 based video capture devices. | 6 | This is a video4linux driver for STK1160 based video capture devices. |
7 | 7 | ||
8 | To compile this driver as a module, choose M here: the | 8 | To compile this driver as a module, choose M here: the |
9 | module will be called stk1160 | 9 | module will be called stk1160. |
10 | |||
11 | This driver only provides support for video capture. For audio | ||
12 | capture, you need to select the snd-usb-audio driver (i.e. | ||
13 | CONFIG_SND_USB_AUDIO). | ||
10 | 14 | ||
11 | config VIDEO_STK1160 | 15 | config VIDEO_STK1160 |
12 | tristate | 16 | tristate |
diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index c4fdc1fa32ef..7e960d0a5b92 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c | |||
@@ -631,7 +631,7 @@ static int tm6000_prepare_isoc(struct tm6000_core *dev) | |||
631 | urb = usb_alloc_urb(max_packets, GFP_KERNEL); | 631 | urb = usb_alloc_urb(max_packets, GFP_KERNEL); |
632 | if (!urb) { | 632 | if (!urb) { |
633 | tm6000_uninit_isoc(dev); | 633 | tm6000_uninit_isoc(dev); |
634 | usb_free_urb(urb); | 634 | tm6000_free_urb_buffers(dev); |
635 | return -ENOMEM; | 635 | return -ENOMEM; |
636 | } | 636 | } |
637 | dev->isoc_ctl.urb[i] = urb; | 637 | dev->isoc_ctl.urb[i] = urb; |
diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c index f5c635a67d74..f9c3325aa4d4 100644 --- a/drivers/media/usb/usbvision/usbvision-video.c +++ b/drivers/media/usb/usbvision/usbvision-video.c | |||
@@ -1501,7 +1501,14 @@ static int usbvision_probe(struct usb_interface *intf, | |||
1501 | } | 1501 | } |
1502 | 1502 | ||
1503 | for (i = 0; i < usbvision->num_alt; i++) { | 1503 | for (i = 0; i < usbvision->num_alt; i++) { |
1504 | u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[1].desc. | 1504 | u16 tmp; |
1505 | |||
1506 | if (uif->altsetting[i].desc.bNumEndpoints < 2) { | ||
1507 | ret = -ENODEV; | ||
1508 | goto err_pkt; | ||
1509 | } | ||
1510 | |||
1511 | tmp = le16_to_cpu(uif->altsetting[i].endpoint[1].desc. | ||
1505 | wMaxPacketSize); | 1512 | wMaxPacketSize); |
1506 | usbvision->alt_max_pkt_size[i] = | 1513 | usbvision->alt_max_pkt_size[i] = |
1507 | (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); | 1514 | (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); |
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 04bf35063c4c..46d6be0bb316 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c | |||
@@ -188,6 +188,21 @@ static struct uvc_format_desc uvc_fmts[] = { | |||
188 | .guid = UVC_GUID_FORMAT_GR16, | 188 | .guid = UVC_GUID_FORMAT_GR16, |
189 | .fcc = V4L2_PIX_FMT_SGRBG16, | 189 | .fcc = V4L2_PIX_FMT_SGRBG16, |
190 | }, | 190 | }, |
191 | { | ||
192 | .name = "Depth data 16-bit (Z16)", | ||
193 | .guid = UVC_GUID_FORMAT_INVZ, | ||
194 | .fcc = V4L2_PIX_FMT_Z16, | ||
195 | }, | ||
196 | { | ||
197 | .name = "Greyscale 10-bit (Y10 )", | ||
198 | .guid = UVC_GUID_FORMAT_INVI, | ||
199 | .fcc = V4L2_PIX_FMT_Y10, | ||
200 | }, | ||
201 | { | ||
202 | .name = "IR:Depth 26-bit (INZI)", | ||
203 | .guid = UVC_GUID_FORMAT_INZI, | ||
204 | .fcc = V4L2_PIX_FMT_INZI, | ||
205 | }, | ||
191 | }; | 206 | }; |
192 | 207 | ||
193 | /* ------------------------------------------------------------------------ | 208 | /* ------------------------------------------------------------------------ |
diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 07a6c833ef7b..47d93a938dde 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c | |||
@@ -818,7 +818,7 @@ static void uvc_video_stats_decode(struct uvc_streaming *stream, | |||
818 | 818 | ||
819 | /* Update the packets counters. */ | 819 | /* Update the packets counters. */ |
820 | stream->stats.frame.nb_packets++; | 820 | stream->stats.frame.nb_packets++; |
821 | if (len > header_size) | 821 | if (len <= header_size) |
822 | stream->stats.frame.nb_empty++; | 822 | stream->stats.frame.nb_empty++; |
823 | 823 | ||
824 | if (data[1] & UVC_STREAM_ERR) | 824 | if (data[1] & UVC_STREAM_ERR) |
@@ -868,14 +868,8 @@ size_t uvc_video_stats_dump(struct uvc_streaming *stream, char *buf, | |||
868 | struct timespec ts; | 868 | struct timespec ts; |
869 | size_t count = 0; | 869 | size_t count = 0; |
870 | 870 | ||
871 | ts.tv_sec = stream->stats.stream.stop_ts.tv_sec | 871 | ts = timespec_sub(stream->stats.stream.stop_ts, |
872 | - stream->stats.stream.start_ts.tv_sec; | 872 | stream->stats.stream.start_ts); |
873 | ts.tv_nsec = stream->stats.stream.stop_ts.tv_nsec | ||
874 | - stream->stats.stream.start_ts.tv_nsec; | ||
875 | if (ts.tv_nsec < 0) { | ||
876 | ts.tv_sec--; | ||
877 | ts.tv_nsec += 1000000000; | ||
878 | } | ||
879 | 873 | ||
880 | /* Compute the SCR.SOF frequency estimate. At the nominal 1kHz SOF | 874 | /* Compute the SCR.SOF frequency estimate. At the nominal 1kHz SOF |
881 | * frequency this will not overflow before more than 1h. | 875 | * frequency this will not overflow before more than 1h. |
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 4205e7a423f0..15e415e32c7f 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h | |||
@@ -143,6 +143,15 @@ | |||
143 | #define UVC_GUID_FORMAT_RW10 \ | 143 | #define UVC_GUID_FORMAT_RW10 \ |
144 | { 'R', 'W', '1', '0', 0x00, 0x00, 0x10, 0x00, \ | 144 | { 'R', 'W', '1', '0', 0x00, 0x00, 0x10, 0x00, \ |
145 | 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} | 145 | 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} |
146 | #define UVC_GUID_FORMAT_INVZ \ | ||
147 | { 'I', 'N', 'V', 'Z', 0x90, 0x2d, 0x58, 0x4a, \ | ||
148 | 0x92, 0x0b, 0x77, 0x3f, 0x1f, 0x2c, 0x55, 0x6b} | ||
149 | #define UVC_GUID_FORMAT_INZI \ | ||
150 | { 'I', 'N', 'Z', 'I', 0x66, 0x1a, 0x42, 0xa2, \ | ||
151 | 0x90, 0x65, 0xd0, 0x18, 0x14, 0xa8, 0xef, 0x8a} | ||
152 | #define UVC_GUID_FORMAT_INVI \ | ||
153 | { 'I', 'N', 'V', 'I', 0xdb, 0x57, 0x49, 0x5e, \ | ||
154 | 0x8e, 0x3f, 0xf4, 0x79, 0x53, 0x2b, 0x94, 0x6f} | ||
146 | 155 | ||
147 | /* ------------------------------------------------------------------------ | 156 | /* ------------------------------------------------------------------------ |
148 | * Driver specific constants. | 157 | * Driver specific constants. |
diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c index f2d6fc03dda0..efdcd5bd6a4c 100644 --- a/drivers/media/usb/zr364xx/zr364xx.c +++ b/drivers/media/usb/zr364xx/zr364xx.c | |||
@@ -600,6 +600,14 @@ static int zr364xx_read_video_callback(struct zr364xx_camera *cam, | |||
600 | ptr = pdest = frm->lpvbits; | 600 | ptr = pdest = frm->lpvbits; |
601 | 601 | ||
602 | if (frm->ulState == ZR364XX_READ_IDLE) { | 602 | if (frm->ulState == ZR364XX_READ_IDLE) { |
603 | if (purb->actual_length < 128) { | ||
604 | /* header incomplete */ | ||
605 | dev_info(&cam->udev->dev, | ||
606 | "%s: buffer (%d bytes) too small to hold jpeg header. Discarding.\n", | ||
607 | __func__, purb->actual_length); | ||
608 | return -EINVAL; | ||
609 | } | ||
610 | |||
603 | frm->ulState = ZR364XX_READ_FRAME; | 611 | frm->ulState = ZR364XX_READ_FRAME; |
604 | frm->cur_size = 0; | 612 | frm->cur_size = 0; |
605 | 613 | ||
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index eac9565dc3d8..6f52970f8b54 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c | |||
@@ -161,6 +161,20 @@ static inline int put_v4l2_sdr_format(struct v4l2_sdr_format *kp, struct v4l2_sd | |||
161 | return 0; | 161 | return 0; |
162 | } | 162 | } |
163 | 163 | ||
164 | static inline int get_v4l2_meta_format(struct v4l2_meta_format *kp, struct v4l2_meta_format __user *up) | ||
165 | { | ||
166 | if (copy_from_user(kp, up, sizeof(struct v4l2_meta_format))) | ||
167 | return -EFAULT; | ||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | static inline int put_v4l2_meta_format(struct v4l2_meta_format *kp, struct v4l2_meta_format __user *up) | ||
172 | { | ||
173 | if (copy_to_user(up, kp, sizeof(struct v4l2_meta_format))) | ||
174 | return -EFAULT; | ||
175 | return 0; | ||
176 | } | ||
177 | |||
164 | struct v4l2_format32 { | 178 | struct v4l2_format32 { |
165 | __u32 type; /* enum v4l2_buf_type */ | 179 | __u32 type; /* enum v4l2_buf_type */ |
166 | union { | 180 | union { |
@@ -170,6 +184,7 @@ struct v4l2_format32 { | |||
170 | struct v4l2_vbi_format vbi; | 184 | struct v4l2_vbi_format vbi; |
171 | struct v4l2_sliced_vbi_format sliced; | 185 | struct v4l2_sliced_vbi_format sliced; |
172 | struct v4l2_sdr_format sdr; | 186 | struct v4l2_sdr_format sdr; |
187 | struct v4l2_meta_format meta; | ||
173 | __u8 raw_data[200]; /* user-defined */ | 188 | __u8 raw_data[200]; /* user-defined */ |
174 | } fmt; | 189 | } fmt; |
175 | }; | 190 | }; |
@@ -216,6 +231,8 @@ static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us | |||
216 | case V4L2_BUF_TYPE_SDR_CAPTURE: | 231 | case V4L2_BUF_TYPE_SDR_CAPTURE: |
217 | case V4L2_BUF_TYPE_SDR_OUTPUT: | 232 | case V4L2_BUF_TYPE_SDR_OUTPUT: |
218 | return get_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr); | 233 | return get_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr); |
234 | case V4L2_BUF_TYPE_META_CAPTURE: | ||
235 | return get_v4l2_meta_format(&kp->fmt.meta, &up->fmt.meta); | ||
219 | default: | 236 | default: |
220 | pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", | 237 | pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", |
221 | kp->type); | 238 | kp->type); |
@@ -263,6 +280,8 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us | |||
263 | case V4L2_BUF_TYPE_SDR_CAPTURE: | 280 | case V4L2_BUF_TYPE_SDR_CAPTURE: |
264 | case V4L2_BUF_TYPE_SDR_OUTPUT: | 281 | case V4L2_BUF_TYPE_SDR_OUTPUT: |
265 | return put_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr); | 282 | return put_v4l2_sdr_format(&kp->fmt.sdr, &up->fmt.sdr); |
283 | case V4L2_BUF_TYPE_META_CAPTURE: | ||
284 | return put_v4l2_meta_format(&kp->fmt.meta, &up->fmt.meta); | ||
266 | default: | 285 | default: |
267 | pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", | 286 | pr_info("compat_ioctl32: unexpected VIDIOC_FMT type %d\n", |
268 | kp->type); | 287 | kp->type); |
@@ -990,6 +1009,10 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar | |||
990 | if (put_v4l2_ext_controls32(&karg.v2ecs, up)) | 1009 | if (put_v4l2_ext_controls32(&karg.v2ecs, up)) |
991 | err = -EFAULT; | 1010 | err = -EFAULT; |
992 | break; | 1011 | break; |
1012 | case VIDIOC_S_EDID: | ||
1013 | if (put_v4l2_edid32(&karg.v2edid, up)) | ||
1014 | err = -EFAULT; | ||
1015 | break; | ||
993 | } | 1016 | } |
994 | if (err) | 1017 | if (err) |
995 | return err; | 1018 | return err; |
@@ -1011,7 +1034,6 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar | |||
1011 | break; | 1034 | break; |
1012 | 1035 | ||
1013 | case VIDIOC_G_EDID: | 1036 | case VIDIOC_G_EDID: |
1014 | case VIDIOC_S_EDID: | ||
1015 | err = put_v4l2_edid32(&karg.v2edid, up); | 1037 | err = put_v4l2_edid32(&karg.v2edid, up); |
1016 | break; | 1038 | break; |
1017 | 1039 | ||
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index b9e08e3d6e0e..ec42872d11cf 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c | |||
@@ -459,8 +459,8 @@ const char * const *v4l2_ctrl_get_menu(u32 id) | |||
459 | }; | 459 | }; |
460 | static const char * const dv_rgb_range[] = { | 460 | static const char * const dv_rgb_range[] = { |
461 | "Automatic", | 461 | "Automatic", |
462 | "RGB limited range (16-235)", | 462 | "RGB Limited Range (16-235)", |
463 | "RGB full range (0-255)", | 463 | "RGB Full Range (0-255)", |
464 | NULL, | 464 | NULL, |
465 | }; | 465 | }; |
466 | static const char * const dv_it_content_type[] = { | 466 | static const char * const dv_it_content_type[] = { |
@@ -997,6 +997,10 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, | |||
997 | *min = 0; | 997 | *min = 0; |
998 | *max = *step = 1; | 998 | *max = *step = 1; |
999 | break; | 999 | break; |
1000 | case V4L2_CID_ROTATE: | ||
1001 | *type = V4L2_CTRL_TYPE_INTEGER; | ||
1002 | *flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; | ||
1003 | break; | ||
1000 | case V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE: | 1004 | case V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE: |
1001 | case V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE: | 1005 | case V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE: |
1002 | *type = V4L2_CTRL_TYPE_INTEGER; | 1006 | *type = V4L2_CTRL_TYPE_INTEGER; |
diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index fa2124cb31bd..c647ba648805 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c | |||
@@ -575,30 +575,34 @@ static void determine_valid_ioctls(struct video_device *vdev) | |||
575 | set_bit(_IOC_NR(VIDIOC_ENUM_FREQ_BANDS), valid_ioctls); | 575 | set_bit(_IOC_NR(VIDIOC_ENUM_FREQ_BANDS), valid_ioctls); |
576 | 576 | ||
577 | if (is_vid || is_tch) { | 577 | if (is_vid || is_tch) { |
578 | /* video specific ioctls */ | 578 | /* video and metadata specific ioctls */ |
579 | if ((is_rx && (ops->vidioc_enum_fmt_vid_cap || | 579 | if ((is_rx && (ops->vidioc_enum_fmt_vid_cap || |
580 | ops->vidioc_enum_fmt_vid_cap_mplane || | 580 | ops->vidioc_enum_fmt_vid_cap_mplane || |
581 | ops->vidioc_enum_fmt_vid_overlay)) || | 581 | ops->vidioc_enum_fmt_vid_overlay || |
582 | ops->vidioc_enum_fmt_meta_cap)) || | ||
582 | (is_tx && (ops->vidioc_enum_fmt_vid_out || | 583 | (is_tx && (ops->vidioc_enum_fmt_vid_out || |
583 | ops->vidioc_enum_fmt_vid_out_mplane))) | 584 | ops->vidioc_enum_fmt_vid_out_mplane))) |
584 | set_bit(_IOC_NR(VIDIOC_ENUM_FMT), valid_ioctls); | 585 | set_bit(_IOC_NR(VIDIOC_ENUM_FMT), valid_ioctls); |
585 | if ((is_rx && (ops->vidioc_g_fmt_vid_cap || | 586 | if ((is_rx && (ops->vidioc_g_fmt_vid_cap || |
586 | ops->vidioc_g_fmt_vid_cap_mplane || | 587 | ops->vidioc_g_fmt_vid_cap_mplane || |
587 | ops->vidioc_g_fmt_vid_overlay)) || | 588 | ops->vidioc_g_fmt_vid_overlay || |
589 | ops->vidioc_g_fmt_meta_cap)) || | ||
588 | (is_tx && (ops->vidioc_g_fmt_vid_out || | 590 | (is_tx && (ops->vidioc_g_fmt_vid_out || |
589 | ops->vidioc_g_fmt_vid_out_mplane || | 591 | ops->vidioc_g_fmt_vid_out_mplane || |
590 | ops->vidioc_g_fmt_vid_out_overlay))) | 592 | ops->vidioc_g_fmt_vid_out_overlay))) |
591 | set_bit(_IOC_NR(VIDIOC_G_FMT), valid_ioctls); | 593 | set_bit(_IOC_NR(VIDIOC_G_FMT), valid_ioctls); |
592 | if ((is_rx && (ops->vidioc_s_fmt_vid_cap || | 594 | if ((is_rx && (ops->vidioc_s_fmt_vid_cap || |
593 | ops->vidioc_s_fmt_vid_cap_mplane || | 595 | ops->vidioc_s_fmt_vid_cap_mplane || |
594 | ops->vidioc_s_fmt_vid_overlay)) || | 596 | ops->vidioc_s_fmt_vid_overlay || |
597 | ops->vidioc_s_fmt_meta_cap)) || | ||
595 | (is_tx && (ops->vidioc_s_fmt_vid_out || | 598 | (is_tx && (ops->vidioc_s_fmt_vid_out || |
596 | ops->vidioc_s_fmt_vid_out_mplane || | 599 | ops->vidioc_s_fmt_vid_out_mplane || |
597 | ops->vidioc_s_fmt_vid_out_overlay))) | 600 | ops->vidioc_s_fmt_vid_out_overlay))) |
598 | set_bit(_IOC_NR(VIDIOC_S_FMT), valid_ioctls); | 601 | set_bit(_IOC_NR(VIDIOC_S_FMT), valid_ioctls); |
599 | if ((is_rx && (ops->vidioc_try_fmt_vid_cap || | 602 | if ((is_rx && (ops->vidioc_try_fmt_vid_cap || |
600 | ops->vidioc_try_fmt_vid_cap_mplane || | 603 | ops->vidioc_try_fmt_vid_cap_mplane || |
601 | ops->vidioc_try_fmt_vid_overlay)) || | 604 | ops->vidioc_try_fmt_vid_overlay || |
605 | ops->vidioc_try_fmt_meta_cap)) || | ||
602 | (is_tx && (ops->vidioc_try_fmt_vid_out || | 606 | (is_tx && (ops->vidioc_try_fmt_vid_out || |
603 | ops->vidioc_try_fmt_vid_out_mplane || | 607 | ops->vidioc_try_fmt_vid_out_mplane || |
604 | ops->vidioc_try_fmt_vid_out_overlay))) | 608 | ops->vidioc_try_fmt_vid_out_overlay))) |
@@ -664,7 +668,7 @@ static void determine_valid_ioctls(struct video_device *vdev) | |||
664 | } | 668 | } |
665 | 669 | ||
666 | if (is_vid || is_vbi || is_sdr || is_tch) { | 670 | if (is_vid || is_vbi || is_sdr || is_tch) { |
667 | /* ioctls valid for video, vbi or sdr */ | 671 | /* ioctls valid for video, metadata, vbi or sdr */ |
668 | SET_VALID_IOCTL(ops, VIDIOC_REQBUFS, vidioc_reqbufs); | 672 | SET_VALID_IOCTL(ops, VIDIOC_REQBUFS, vidioc_reqbufs); |
669 | SET_VALID_IOCTL(ops, VIDIOC_QUERYBUF, vidioc_querybuf); | 673 | SET_VALID_IOCTL(ops, VIDIOC_QUERYBUF, vidioc_querybuf); |
670 | SET_VALID_IOCTL(ops, VIDIOC_QBUF, vidioc_qbuf); | 674 | SET_VALID_IOCTL(ops, VIDIOC_QBUF, vidioc_qbuf); |
diff --git a/drivers/media/v4l2-core/v4l2-device.c b/drivers/media/v4l2-core/v4l2-device.c index f364cc1b521d..937c6de85606 100644 --- a/drivers/media/v4l2-core/v4l2-device.c +++ b/drivers/media/v4l2-core/v4l2-device.c | |||
@@ -235,6 +235,9 @@ int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev) | |||
235 | if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)) | 235 | if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)) |
236 | continue; | 236 | continue; |
237 | 237 | ||
238 | if (sd->devnode) | ||
239 | continue; | ||
240 | |||
238 | vdev = kzalloc(sizeof(*vdev), GFP_KERNEL); | 241 | vdev = kzalloc(sizeof(*vdev), GFP_KERNEL); |
239 | if (!vdev) { | 242 | if (!vdev) { |
240 | err = -ENOMEM; | 243 | err = -ENOMEM; |
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 0c3f238a2e76..e5a2187381db 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c | |||
@@ -155,6 +155,7 @@ const char *v4l2_type_names[] = { | |||
155 | [V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE] = "vid-out-mplane", | 155 | [V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE] = "vid-out-mplane", |
156 | [V4L2_BUF_TYPE_SDR_CAPTURE] = "sdr-cap", | 156 | [V4L2_BUF_TYPE_SDR_CAPTURE] = "sdr-cap", |
157 | [V4L2_BUF_TYPE_SDR_OUTPUT] = "sdr-out", | 157 | [V4L2_BUF_TYPE_SDR_OUTPUT] = "sdr-out", |
158 | [V4L2_BUF_TYPE_META_CAPTURE] = "meta-cap", | ||
158 | }; | 159 | }; |
159 | EXPORT_SYMBOL(v4l2_type_names); | 160 | EXPORT_SYMBOL(v4l2_type_names); |
160 | 161 | ||
@@ -246,6 +247,7 @@ static void v4l_print_format(const void *arg, bool write_only) | |||
246 | const struct v4l2_sliced_vbi_format *sliced; | 247 | const struct v4l2_sliced_vbi_format *sliced; |
247 | const struct v4l2_window *win; | 248 | const struct v4l2_window *win; |
248 | const struct v4l2_sdr_format *sdr; | 249 | const struct v4l2_sdr_format *sdr; |
250 | const struct v4l2_meta_format *meta; | ||
249 | unsigned i; | 251 | unsigned i; |
250 | 252 | ||
251 | pr_cont("type=%s", prt_names(p->type, v4l2_type_names)); | 253 | pr_cont("type=%s", prt_names(p->type, v4l2_type_names)); |
@@ -325,6 +327,15 @@ static void v4l_print_format(const void *arg, bool write_only) | |||
325 | (sdr->pixelformat >> 16) & 0xff, | 327 | (sdr->pixelformat >> 16) & 0xff, |
326 | (sdr->pixelformat >> 24) & 0xff); | 328 | (sdr->pixelformat >> 24) & 0xff); |
327 | break; | 329 | break; |
330 | case V4L2_BUF_TYPE_META_CAPTURE: | ||
331 | meta = &p->fmt.meta; | ||
332 | pr_cont(", dataformat=%c%c%c%c, buffersize=%u\n", | ||
333 | (meta->dataformat >> 0) & 0xff, | ||
334 | (meta->dataformat >> 8) & 0xff, | ||
335 | (meta->dataformat >> 16) & 0xff, | ||
336 | (meta->dataformat >> 24) & 0xff, | ||
337 | meta->buffersize); | ||
338 | break; | ||
328 | } | 339 | } |
329 | } | 340 | } |
330 | 341 | ||
@@ -943,6 +954,10 @@ static int check_fmt(struct file *file, enum v4l2_buf_type type) | |||
943 | if (is_sdr && is_tx && ops->vidioc_g_fmt_sdr_out) | 954 | if (is_sdr && is_tx && ops->vidioc_g_fmt_sdr_out) |
944 | return 0; | 955 | return 0; |
945 | break; | 956 | break; |
957 | case V4L2_BUF_TYPE_META_CAPTURE: | ||
958 | if (is_vid && is_rx && ops->vidioc_g_fmt_meta_cap) | ||
959 | return 0; | ||
960 | break; | ||
946 | default: | 961 | default: |
947 | break; | 962 | break; |
948 | } | 963 | } |
@@ -1131,6 +1146,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) | |||
1131 | case V4L2_PIX_FMT_Y8I: descr = "Interleaved 8-bit Greyscale"; break; | 1146 | case V4L2_PIX_FMT_Y8I: descr = "Interleaved 8-bit Greyscale"; break; |
1132 | case V4L2_PIX_FMT_Y12I: descr = "Interleaved 12-bit Greyscale"; break; | 1147 | case V4L2_PIX_FMT_Y12I: descr = "Interleaved 12-bit Greyscale"; break; |
1133 | case V4L2_PIX_FMT_Z16: descr = "16-bit Depth"; break; | 1148 | case V4L2_PIX_FMT_Z16: descr = "16-bit Depth"; break; |
1149 | case V4L2_PIX_FMT_INZI: descr = "Planar 10:16 Greyscale Depth"; break; | ||
1134 | case V4L2_PIX_FMT_PAL8: descr = "8-bit Palette"; break; | 1150 | case V4L2_PIX_FMT_PAL8: descr = "8-bit Palette"; break; |
1135 | case V4L2_PIX_FMT_UV8: descr = "8-bit Chrominance UV 4-4"; break; | 1151 | case V4L2_PIX_FMT_UV8: descr = "8-bit Chrominance UV 4-4"; break; |
1136 | case V4L2_PIX_FMT_YVU410: descr = "Planar YVU 4:1:0"; break; | 1152 | case V4L2_PIX_FMT_YVU410: descr = "Planar YVU 4:1:0"; break; |
@@ -1217,6 +1233,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) | |||
1217 | case V4L2_TCH_FMT_DELTA_TD08: descr = "8-bit signed deltas"; break; | 1233 | case V4L2_TCH_FMT_DELTA_TD08: descr = "8-bit signed deltas"; break; |
1218 | case V4L2_TCH_FMT_TU16: descr = "16-bit unsigned touch data"; break; | 1234 | case V4L2_TCH_FMT_TU16: descr = "16-bit unsigned touch data"; break; |
1219 | case V4L2_TCH_FMT_TU08: descr = "8-bit unsigned touch data"; break; | 1235 | case V4L2_TCH_FMT_TU08: descr = "8-bit unsigned touch data"; break; |
1236 | case V4L2_META_FMT_VSP1_HGO: descr = "R-Car VSP1 1-D Histogram"; break; | ||
1237 | case V4L2_META_FMT_VSP1_HGT: descr = "R-Car VSP1 2-D Histogram"; break; | ||
1220 | 1238 | ||
1221 | default: | 1239 | default: |
1222 | /* Compressed formats */ | 1240 | /* Compressed formats */ |
@@ -1326,6 +1344,11 @@ static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops, | |||
1326 | break; | 1344 | break; |
1327 | ret = ops->vidioc_enum_fmt_sdr_out(file, fh, arg); | 1345 | ret = ops->vidioc_enum_fmt_sdr_out(file, fh, arg); |
1328 | break; | 1346 | break; |
1347 | case V4L2_BUF_TYPE_META_CAPTURE: | ||
1348 | if (unlikely(!is_rx || !is_vid || !ops->vidioc_enum_fmt_meta_cap)) | ||
1349 | break; | ||
1350 | ret = ops->vidioc_enum_fmt_meta_cap(file, fh, arg); | ||
1351 | break; | ||
1329 | } | 1352 | } |
1330 | if (ret == 0) | 1353 | if (ret == 0) |
1331 | v4l_fill_fmtdesc(p); | 1354 | v4l_fill_fmtdesc(p); |
@@ -1425,6 +1448,10 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops, | |||
1425 | if (unlikely(!is_tx || !is_sdr || !ops->vidioc_g_fmt_sdr_out)) | 1448 | if (unlikely(!is_tx || !is_sdr || !ops->vidioc_g_fmt_sdr_out)) |
1426 | break; | 1449 | break; |
1427 | return ops->vidioc_g_fmt_sdr_out(file, fh, arg); | 1450 | return ops->vidioc_g_fmt_sdr_out(file, fh, arg); |
1451 | case V4L2_BUF_TYPE_META_CAPTURE: | ||
1452 | if (unlikely(!is_rx || !is_vid || !ops->vidioc_g_fmt_meta_cap)) | ||
1453 | break; | ||
1454 | return ops->vidioc_g_fmt_meta_cap(file, fh, arg); | ||
1428 | } | 1455 | } |
1429 | return -EINVAL; | 1456 | return -EINVAL; |
1430 | } | 1457 | } |
@@ -1530,6 +1557,11 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, | |||
1530 | break; | 1557 | break; |
1531 | CLEAR_AFTER_FIELD(p, fmt.sdr); | 1558 | CLEAR_AFTER_FIELD(p, fmt.sdr); |
1532 | return ops->vidioc_s_fmt_sdr_out(file, fh, arg); | 1559 | return ops->vidioc_s_fmt_sdr_out(file, fh, arg); |
1560 | case V4L2_BUF_TYPE_META_CAPTURE: | ||
1561 | if (unlikely(!is_rx || !is_vid || !ops->vidioc_s_fmt_meta_cap)) | ||
1562 | break; | ||
1563 | CLEAR_AFTER_FIELD(p, fmt.meta); | ||
1564 | return ops->vidioc_s_fmt_meta_cap(file, fh, arg); | ||
1533 | } | 1565 | } |
1534 | return -EINVAL; | 1566 | return -EINVAL; |
1535 | } | 1567 | } |
@@ -1615,6 +1647,11 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, | |||
1615 | break; | 1647 | break; |
1616 | CLEAR_AFTER_FIELD(p, fmt.sdr); | 1648 | CLEAR_AFTER_FIELD(p, fmt.sdr); |
1617 | return ops->vidioc_try_fmt_sdr_out(file, fh, arg); | 1649 | return ops->vidioc_try_fmt_sdr_out(file, fh, arg); |
1650 | case V4L2_BUF_TYPE_META_CAPTURE: | ||
1651 | if (unlikely(!is_rx || !is_vid || !ops->vidioc_try_fmt_meta_cap)) | ||
1652 | break; | ||
1653 | CLEAR_AFTER_FIELD(p, fmt.meta); | ||
1654 | return ops->vidioc_try_fmt_meta_cap(file, fh, arg); | ||
1618 | } | 1655 | } |
1619 | return -EINVAL; | 1656 | return -EINVAL; |
1620 | } | 1657 | } |
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 7c1d390ea438..94afbbf92807 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c | |||
@@ -984,11 +984,12 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const void *pb) | |||
984 | 984 | ||
985 | memset(planes, 0, sizeof(planes[0]) * vb->num_planes); | 985 | memset(planes, 0, sizeof(planes[0]) * vb->num_planes); |
986 | /* Copy relevant information provided by the userspace */ | 986 | /* Copy relevant information provided by the userspace */ |
987 | if (pb) | 987 | if (pb) { |
988 | ret = call_bufop(vb->vb2_queue, fill_vb2_buffer, | 988 | ret = call_bufop(vb->vb2_queue, fill_vb2_buffer, |
989 | vb, pb, planes); | 989 | vb, pb, planes); |
990 | if (ret) | 990 | if (ret) |
991 | return ret; | 991 | return ret; |
992 | } | ||
992 | 993 | ||
993 | for (plane = 0; plane < vb->num_planes; ++plane) { | 994 | for (plane = 0; plane < vb->num_planes; ++plane) { |
994 | /* Skip the plane if already verified */ | 995 | /* Skip the plane if already verified */ |
@@ -1101,11 +1102,12 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const void *pb) | |||
1101 | 1102 | ||
1102 | memset(planes, 0, sizeof(planes[0]) * vb->num_planes); | 1103 | memset(planes, 0, sizeof(planes[0]) * vb->num_planes); |
1103 | /* Copy relevant information provided by the userspace */ | 1104 | /* Copy relevant information provided by the userspace */ |
1104 | if (pb) | 1105 | if (pb) { |
1105 | ret = call_bufop(vb->vb2_queue, fill_vb2_buffer, | 1106 | ret = call_bufop(vb->vb2_queue, fill_vb2_buffer, |
1106 | vb, pb, planes); | 1107 | vb, pb, planes); |
1107 | if (ret) | 1108 | if (ret) |
1108 | return ret; | 1109 | return ret; |
1110 | } | ||
1109 | 1111 | ||
1110 | for (plane = 0; plane < vb->num_planes; ++plane) { | 1112 | for (plane = 0; plane < vb->num_planes; ++plane) { |
1111 | struct dma_buf *dbuf = dma_buf_get(planes[plane].m.fd); | 1113 | struct dma_buf *dbuf = dma_buf_get(planes[plane].m.fd); |
diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c index 2db0413f5d57..4f246d166111 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c | |||
@@ -12,6 +12,7 @@ | |||
12 | 12 | ||
13 | #include <linux/dma-buf.h> | 13 | #include <linux/dma-buf.h> |
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/refcount.h> | ||
15 | #include <linux/scatterlist.h> | 16 | #include <linux/scatterlist.h> |
16 | #include <linux/sched.h> | 17 | #include <linux/sched.h> |
17 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
@@ -34,7 +35,7 @@ struct vb2_dc_buf { | |||
34 | 35 | ||
35 | /* MMAP related */ | 36 | /* MMAP related */ |
36 | struct vb2_vmarea_handler handler; | 37 | struct vb2_vmarea_handler handler; |
37 | atomic_t refcount; | 38 | refcount_t refcount; |
38 | struct sg_table *sgt_base; | 39 | struct sg_table *sgt_base; |
39 | 40 | ||
40 | /* DMABUF related */ | 41 | /* DMABUF related */ |
@@ -86,7 +87,7 @@ static unsigned int vb2_dc_num_users(void *buf_priv) | |||
86 | { | 87 | { |
87 | struct vb2_dc_buf *buf = buf_priv; | 88 | struct vb2_dc_buf *buf = buf_priv; |
88 | 89 | ||
89 | return atomic_read(&buf->refcount); | 90 | return refcount_read(&buf->refcount); |
90 | } | 91 | } |
91 | 92 | ||
92 | static void vb2_dc_prepare(void *buf_priv) | 93 | static void vb2_dc_prepare(void *buf_priv) |
@@ -122,7 +123,7 @@ static void vb2_dc_put(void *buf_priv) | |||
122 | { | 123 | { |
123 | struct vb2_dc_buf *buf = buf_priv; | 124 | struct vb2_dc_buf *buf = buf_priv; |
124 | 125 | ||
125 | if (!atomic_dec_and_test(&buf->refcount)) | 126 | if (!refcount_dec_and_test(&buf->refcount)) |
126 | return; | 127 | return; |
127 | 128 | ||
128 | if (buf->sgt_base) { | 129 | if (buf->sgt_base) { |
@@ -170,7 +171,7 @@ static void *vb2_dc_alloc(struct device *dev, unsigned long attrs, | |||
170 | buf->handler.put = vb2_dc_put; | 171 | buf->handler.put = vb2_dc_put; |
171 | buf->handler.arg = buf; | 172 | buf->handler.arg = buf; |
172 | 173 | ||
173 | atomic_inc(&buf->refcount); | 174 | refcount_set(&buf->refcount, 1); |
174 | 175 | ||
175 | return buf; | 176 | return buf; |
176 | } | 177 | } |
@@ -407,7 +408,7 @@ static struct dma_buf *vb2_dc_get_dmabuf(void *buf_priv, unsigned long flags) | |||
407 | return NULL; | 408 | return NULL; |
408 | 409 | ||
409 | /* dmabuf keeps reference to vb2 buffer */ | 410 | /* dmabuf keeps reference to vb2 buffer */ |
410 | atomic_inc(&buf->refcount); | 411 | refcount_inc(&buf->refcount); |
411 | 412 | ||
412 | return dbuf; | 413 | return dbuf; |
413 | } | 414 | } |
diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c b/drivers/media/v4l2-core/videobuf2-dma-sg.c index 6fd1343b7c13..8e8798a74760 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-sg.c +++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c | |||
@@ -12,6 +12,7 @@ | |||
12 | 12 | ||
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/mm.h> | 14 | #include <linux/mm.h> |
15 | #include <linux/refcount.h> | ||
15 | #include <linux/scatterlist.h> | 16 | #include <linux/scatterlist.h> |
16 | #include <linux/sched.h> | 17 | #include <linux/sched.h> |
17 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
@@ -46,7 +47,7 @@ struct vb2_dma_sg_buf { | |||
46 | struct sg_table *dma_sgt; | 47 | struct sg_table *dma_sgt; |
47 | size_t size; | 48 | size_t size; |
48 | unsigned int num_pages; | 49 | unsigned int num_pages; |
49 | atomic_t refcount; | 50 | refcount_t refcount; |
50 | struct vb2_vmarea_handler handler; | 51 | struct vb2_vmarea_handler handler; |
51 | 52 | ||
52 | struct dma_buf_attachment *db_attach; | 53 | struct dma_buf_attachment *db_attach; |
@@ -150,7 +151,7 @@ static void *vb2_dma_sg_alloc(struct device *dev, unsigned long dma_attrs, | |||
150 | buf->handler.put = vb2_dma_sg_put; | 151 | buf->handler.put = vb2_dma_sg_put; |
151 | buf->handler.arg = buf; | 152 | buf->handler.arg = buf; |
152 | 153 | ||
153 | atomic_inc(&buf->refcount); | 154 | refcount_set(&buf->refcount, 1); |
154 | 155 | ||
155 | dprintk(1, "%s: Allocated buffer of %d pages\n", | 156 | dprintk(1, "%s: Allocated buffer of %d pages\n", |
156 | __func__, buf->num_pages); | 157 | __func__, buf->num_pages); |
@@ -176,7 +177,7 @@ static void vb2_dma_sg_put(void *buf_priv) | |||
176 | struct sg_table *sgt = &buf->sg_table; | 177 | struct sg_table *sgt = &buf->sg_table; |
177 | int i = buf->num_pages; | 178 | int i = buf->num_pages; |
178 | 179 | ||
179 | if (atomic_dec_and_test(&buf->refcount)) { | 180 | if (refcount_dec_and_test(&buf->refcount)) { |
180 | dprintk(1, "%s: Freeing buffer of %d pages\n", __func__, | 181 | dprintk(1, "%s: Freeing buffer of %d pages\n", __func__, |
181 | buf->num_pages); | 182 | buf->num_pages); |
182 | dma_unmap_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents, | 183 | dma_unmap_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents, |
@@ -320,7 +321,7 @@ static unsigned int vb2_dma_sg_num_users(void *buf_priv) | |||
320 | { | 321 | { |
321 | struct vb2_dma_sg_buf *buf = buf_priv; | 322 | struct vb2_dma_sg_buf *buf = buf_priv; |
322 | 323 | ||
323 | return atomic_read(&buf->refcount); | 324 | return refcount_read(&buf->refcount); |
324 | } | 325 | } |
325 | 326 | ||
326 | static int vb2_dma_sg_mmap(void *buf_priv, struct vm_area_struct *vma) | 327 | static int vb2_dma_sg_mmap(void *buf_priv, struct vm_area_struct *vma) |
@@ -530,7 +531,7 @@ static struct dma_buf *vb2_dma_sg_get_dmabuf(void *buf_priv, unsigned long flags | |||
530 | return NULL; | 531 | return NULL; |
531 | 532 | ||
532 | /* dmabuf keeps reference to vb2 buffer */ | 533 | /* dmabuf keeps reference to vb2 buffer */ |
533 | atomic_inc(&buf->refcount); | 534 | refcount_inc(&buf->refcount); |
534 | 535 | ||
535 | return dbuf; | 536 | return dbuf; |
536 | } | 537 | } |
diff --git a/drivers/media/v4l2-core/videobuf2-memops.c b/drivers/media/v4l2-core/videobuf2-memops.c index 1cd322e939c7..4bb8424114ce 100644 --- a/drivers/media/v4l2-core/videobuf2-memops.c +++ b/drivers/media/v4l2-core/videobuf2-memops.c | |||
@@ -96,10 +96,10 @@ static void vb2_common_vm_open(struct vm_area_struct *vma) | |||
96 | struct vb2_vmarea_handler *h = vma->vm_private_data; | 96 | struct vb2_vmarea_handler *h = vma->vm_private_data; |
97 | 97 | ||
98 | pr_debug("%s: %p, refcount: %d, vma: %08lx-%08lx\n", | 98 | pr_debug("%s: %p, refcount: %d, vma: %08lx-%08lx\n", |
99 | __func__, h, atomic_read(h->refcount), vma->vm_start, | 99 | __func__, h, refcount_read(h->refcount), vma->vm_start, |
100 | vma->vm_end); | 100 | vma->vm_end); |
101 | 101 | ||
102 | atomic_inc(h->refcount); | 102 | refcount_inc(h->refcount); |
103 | } | 103 | } |
104 | 104 | ||
105 | /** | 105 | /** |
@@ -114,7 +114,7 @@ static void vb2_common_vm_close(struct vm_area_struct *vma) | |||
114 | struct vb2_vmarea_handler *h = vma->vm_private_data; | 114 | struct vb2_vmarea_handler *h = vma->vm_private_data; |
115 | 115 | ||
116 | pr_debug("%s: %p, refcount: %d, vma: %08lx-%08lx\n", | 116 | pr_debug("%s: %p, refcount: %d, vma: %08lx-%08lx\n", |
117 | __func__, h, atomic_read(h->refcount), vma->vm_start, | 117 | __func__, h, refcount_read(h->refcount), vma->vm_start, |
118 | vma->vm_end); | 118 | vma->vm_end); |
119 | 119 | ||
120 | h->put(h->arg); | 120 | h->put(h->arg); |
diff --git a/drivers/media/v4l2-core/videobuf2-v4l2.c b/drivers/media/v4l2-core/videobuf2-v4l2.c index 3529849d2218..0c0669976bdc 100644 --- a/drivers/media/v4l2-core/videobuf2-v4l2.c +++ b/drivers/media/v4l2-core/videobuf2-v4l2.c | |||
@@ -544,6 +544,9 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create) | |||
544 | case V4L2_BUF_TYPE_SDR_OUTPUT: | 544 | case V4L2_BUF_TYPE_SDR_OUTPUT: |
545 | requested_sizes[0] = f->fmt.sdr.buffersize; | 545 | requested_sizes[0] = f->fmt.sdr.buffersize; |
546 | break; | 546 | break; |
547 | case V4L2_BUF_TYPE_META_CAPTURE: | ||
548 | requested_sizes[0] = f->fmt.meta.buffersize; | ||
549 | break; | ||
547 | default: | 550 | default: |
548 | return -EINVAL; | 551 | return -EINVAL; |
549 | } | 552 | } |
diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c b/drivers/media/v4l2-core/videobuf2-vmalloc.c index 27d1db3bb8cf..b337d780844c 100644 --- a/drivers/media/v4l2-core/videobuf2-vmalloc.c +++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/io.h> | 13 | #include <linux/io.h> |
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/mm.h> | 15 | #include <linux/mm.h> |
16 | #include <linux/refcount.h> | ||
16 | #include <linux/sched.h> | 17 | #include <linux/sched.h> |
17 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
18 | #include <linux/vmalloc.h> | 19 | #include <linux/vmalloc.h> |
@@ -26,7 +27,7 @@ struct vb2_vmalloc_buf { | |||
26 | struct frame_vector *vec; | 27 | struct frame_vector *vec; |
27 | enum dma_data_direction dma_dir; | 28 | enum dma_data_direction dma_dir; |
28 | unsigned long size; | 29 | unsigned long size; |
29 | atomic_t refcount; | 30 | refcount_t refcount; |
30 | struct vb2_vmarea_handler handler; | 31 | struct vb2_vmarea_handler handler; |
31 | struct dma_buf *dbuf; | 32 | struct dma_buf *dbuf; |
32 | }; | 33 | }; |
@@ -56,7 +57,7 @@ static void *vb2_vmalloc_alloc(struct device *dev, unsigned long attrs, | |||
56 | return ERR_PTR(-ENOMEM); | 57 | return ERR_PTR(-ENOMEM); |
57 | } | 58 | } |
58 | 59 | ||
59 | atomic_inc(&buf->refcount); | 60 | refcount_set(&buf->refcount, 1); |
60 | return buf; | 61 | return buf; |
61 | } | 62 | } |
62 | 63 | ||
@@ -64,7 +65,7 @@ static void vb2_vmalloc_put(void *buf_priv) | |||
64 | { | 65 | { |
65 | struct vb2_vmalloc_buf *buf = buf_priv; | 66 | struct vb2_vmalloc_buf *buf = buf_priv; |
66 | 67 | ||
67 | if (atomic_dec_and_test(&buf->refcount)) { | 68 | if (refcount_dec_and_test(&buf->refcount)) { |
68 | vfree(buf->vaddr); | 69 | vfree(buf->vaddr); |
69 | kfree(buf); | 70 | kfree(buf); |
70 | } | 71 | } |
@@ -161,7 +162,7 @@ static void *vb2_vmalloc_vaddr(void *buf_priv) | |||
161 | static unsigned int vb2_vmalloc_num_users(void *buf_priv) | 162 | static unsigned int vb2_vmalloc_num_users(void *buf_priv) |
162 | { | 163 | { |
163 | struct vb2_vmalloc_buf *buf = buf_priv; | 164 | struct vb2_vmalloc_buf *buf = buf_priv; |
164 | return atomic_read(&buf->refcount); | 165 | return refcount_read(&buf->refcount); |
165 | } | 166 | } |
166 | 167 | ||
167 | static int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma) | 168 | static int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma) |
@@ -368,7 +369,7 @@ static struct dma_buf *vb2_vmalloc_get_dmabuf(void *buf_priv, unsigned long flag | |||
368 | return NULL; | 369 | return NULL; |
369 | 370 | ||
370 | /* dmabuf keeps reference to vb2 buffer */ | 371 | /* dmabuf keeps reference to vb2 buffer */ |
371 | atomic_inc(&buf->refcount); | 372 | refcount_inc(&buf->refcount); |
372 | 373 | ||
373 | return dbuf; | 374 | return dbuf; |
374 | } | 375 | } |