diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2022-02-05 08:58:25 +0300 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2022-02-05 08:58:25 +0300 |
commit | 7e6a6b400db8048bd1c06e497e338388413cf5bc (patch) | |
tree | 794f9fcdc7a1bfb9a2812e90fc76809d810203b2 /drivers/media | |
parent | 6e37ec8825a113bc2dd1b280be10e5ac6eb4f6b1 (diff) | |
parent | 1dd498e5e26ad71e3e9130daf72cfb6a693fee03 (diff) | |
download | linux-7e6a6b400db8048bd1c06e497e338388413cf5bc.tar.xz |
Merge tag 'kvmarm-fixes-5.17-2' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm into HEAD
KVM/arm64 fixes for 5.17, take #2
- A couple of fixes when handling an exception while a SError has been
delivered
- Workaround for Cortex-A510's single-step[ erratum
Diffstat (limited to 'drivers/media')
173 files changed, 6860 insertions, 1625 deletions
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index b07812657cee..f3f24c63536b 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -141,10 +141,10 @@ config MEDIA_TEST_SUPPORT prompt "Test drivers" if MEDIA_SUPPORT_FILTER default y if !MEDIA_SUPPORT_FILTER help - Those drivers should not be used on production Kernels, but - can be useful on debug ones. It enables several dummy drivers - that simulate a real hardware. Very useful to test userspace - applications and to validate if the subsystem core is doesn't + These drivers should not be used on production kernels, but + can be useful on debug ones. This option enables several dummy drivers + that simulate real hardware. Very useful to test userspace + applications and to validate if the subsystem core doesn't have regressions. Say Y if you want to use some virtual test driver. diff --git a/drivers/media/cec/core/cec-adap.c b/drivers/media/cec/core/cec-adap.c index cd9cb354dc2c..2e12331c12a9 100644 --- a/drivers/media/cec/core/cec-adap.c +++ b/drivers/media/cec/core/cec-adap.c @@ -161,10 +161,10 @@ static void cec_queue_event(struct cec_adapter *adap, u64 ts = ktime_get_ns(); struct cec_fh *fh; - mutex_lock(&adap->devnode.lock); + mutex_lock(&adap->devnode.lock_fhs); list_for_each_entry(fh, &adap->devnode.fhs, list) cec_queue_event_fh(fh, ev, ts); - mutex_unlock(&adap->devnode.lock); + mutex_unlock(&adap->devnode.lock_fhs); } /* Notify userspace that the CEC pin changed state at the given time. */ @@ -178,11 +178,12 @@ void cec_queue_pin_cec_event(struct cec_adapter *adap, bool is_high, }; struct cec_fh *fh; - mutex_lock(&adap->devnode.lock); - list_for_each_entry(fh, &adap->devnode.fhs, list) + mutex_lock(&adap->devnode.lock_fhs); + list_for_each_entry(fh, &adap->devnode.fhs, list) { if (fh->mode_follower == CEC_MODE_MONITOR_PIN) cec_queue_event_fh(fh, &ev, ktime_to_ns(ts)); - mutex_unlock(&adap->devnode.lock); + } + mutex_unlock(&adap->devnode.lock_fhs); } EXPORT_SYMBOL_GPL(cec_queue_pin_cec_event); @@ -195,10 +196,10 @@ void cec_queue_pin_hpd_event(struct cec_adapter *adap, bool is_high, ktime_t ts) }; struct cec_fh *fh; - mutex_lock(&adap->devnode.lock); + mutex_lock(&adap->devnode.lock_fhs); list_for_each_entry(fh, &adap->devnode.fhs, list) cec_queue_event_fh(fh, &ev, ktime_to_ns(ts)); - mutex_unlock(&adap->devnode.lock); + mutex_unlock(&adap->devnode.lock_fhs); } EXPORT_SYMBOL_GPL(cec_queue_pin_hpd_event); @@ -211,10 +212,10 @@ void cec_queue_pin_5v_event(struct cec_adapter *adap, bool is_high, ktime_t ts) }; struct cec_fh *fh; - mutex_lock(&adap->devnode.lock); + mutex_lock(&adap->devnode.lock_fhs); list_for_each_entry(fh, &adap->devnode.fhs, list) cec_queue_event_fh(fh, &ev, ktime_to_ns(ts)); - mutex_unlock(&adap->devnode.lock); + mutex_unlock(&adap->devnode.lock_fhs); } EXPORT_SYMBOL_GPL(cec_queue_pin_5v_event); @@ -286,12 +287,12 @@ static void cec_queue_msg_monitor(struct cec_adapter *adap, u32 monitor_mode = valid_la ? CEC_MODE_MONITOR : CEC_MODE_MONITOR_ALL; - mutex_lock(&adap->devnode.lock); + mutex_lock(&adap->devnode.lock_fhs); list_for_each_entry(fh, &adap->devnode.fhs, list) { if (fh->mode_follower >= monitor_mode) cec_queue_msg_fh(fh, msg); } - mutex_unlock(&adap->devnode.lock); + mutex_unlock(&adap->devnode.lock_fhs); } /* @@ -302,12 +303,12 @@ static void cec_queue_msg_followers(struct cec_adapter *adap, { struct cec_fh *fh; - mutex_lock(&adap->devnode.lock); + mutex_lock(&adap->devnode.lock_fhs); list_for_each_entry(fh, &adap->devnode.fhs, list) { if (fh->mode_follower == CEC_MODE_FOLLOWER) cec_queue_msg_fh(fh, msg); } - mutex_unlock(&adap->devnode.lock); + mutex_unlock(&adap->devnode.lock_fhs); } /* Notify userspace of an adapter state change. */ @@ -342,7 +343,7 @@ static void cec_data_completed(struct cec_data *data) * Without that we would be referring to a closed filehandle. */ if (data->fh) - list_del(&data->xfer_list); + list_del_init(&data->xfer_list); if (data->blocking) { /* @@ -898,6 +899,8 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, if (fh) list_add_tail(&data->xfer_list, &fh->xfer_list); + else + INIT_LIST_HEAD(&data->xfer_list); list_add_tail(&data->list, &adap->transmit_queue); adap->transmit_queue_sz++; @@ -923,6 +926,10 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, /* The transmit completed (possibly with an error) */ *msg = data->msg; + if (WARN_ON(!list_empty(&data->list))) + list_del(&data->list); + if (WARN_ON(!list_empty(&data->xfer_list))) + list_del(&data->xfer_list); kfree(data); return 0; } @@ -1573,6 +1580,7 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block) /* Disabling monitor all mode should always succeed */ if (adap->monitor_all_cnt) WARN_ON(call_op(adap, adap_monitor_all_enable, false)); + /* serialize adap_enable */ mutex_lock(&adap->devnode.lock); if (adap->needs_hpd || list_empty(&adap->devnode.fhs)) { WARN_ON(adap->ops->adap_enable(adap, false)); @@ -1584,14 +1592,16 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block) return; } + /* serialize adap_enable */ mutex_lock(&adap->devnode.lock); adap->last_initiator = 0xff; adap->transmit_in_progress = false; - if ((adap->needs_hpd || list_empty(&adap->devnode.fhs)) && - adap->ops->adap_enable(adap, true)) { - mutex_unlock(&adap->devnode.lock); - return; + if (adap->needs_hpd || list_empty(&adap->devnode.fhs)) { + if (adap->ops->adap_enable(adap, true)) { + mutex_unlock(&adap->devnode.lock); + return; + } } if (adap->monitor_all_cnt && diff --git a/drivers/media/cec/core/cec-api.c b/drivers/media/cec/core/cec-api.c index 769e6b4cddce..d72ad48c9898 100644 --- a/drivers/media/cec/core/cec-api.c +++ b/drivers/media/cec/core/cec-api.c @@ -586,6 +586,7 @@ static int cec_open(struct inode *inode, struct file *filp) return err; } + /* serialize adap_enable */ mutex_lock(&devnode->lock); if (list_empty(&devnode->fhs) && !adap->needs_hpd && @@ -624,7 +625,9 @@ static int cec_open(struct inode *inode, struct file *filp) } #endif + mutex_lock(&devnode->lock_fhs); list_add(&fh->list, &devnode->fhs); + mutex_unlock(&devnode->lock_fhs); mutex_unlock(&devnode->lock); return 0; @@ -653,8 +656,11 @@ static int cec_release(struct inode *inode, struct file *filp) cec_monitor_all_cnt_dec(adap); mutex_unlock(&adap->lock); + /* serialize adap_enable */ mutex_lock(&devnode->lock); + mutex_lock(&devnode->lock_fhs); list_del(&fh->list); + mutex_unlock(&devnode->lock_fhs); if (cec_is_registered(adap) && list_empty(&devnode->fhs) && !adap->needs_hpd && adap->phys_addr == CEC_PHYS_ADDR_INVALID) { WARN_ON(adap->ops->adap_enable(adap, false)); @@ -669,7 +675,7 @@ static int cec_release(struct inode *inode, struct file *filp) data->blocking = false; data->fh = NULL; - list_del(&data->xfer_list); + list_del_init(&data->xfer_list); } mutex_unlock(&adap->lock); while (!list_empty(&fh->msgs)) { diff --git a/drivers/media/cec/core/cec-core.c b/drivers/media/cec/core/cec-core.c index 551689d371a7..a3ab6a43fb14 100644 --- a/drivers/media/cec/core/cec-core.c +++ b/drivers/media/cec/core/cec-core.c @@ -106,7 +106,7 @@ static int __must_check cec_devnode_register(struct cec_devnode *devnode, /* Part 1: Find a free minor number */ mutex_lock(&cec_devnode_lock); - minor = find_next_zero_bit(cec_devnode_nums, CEC_NUM_DEVICES, 0); + minor = find_first_zero_bit(cec_devnode_nums, CEC_NUM_DEVICES); if (minor == CEC_NUM_DEVICES) { mutex_unlock(&cec_devnode_lock); pr_err("could not get a free minor\n"); @@ -169,8 +169,10 @@ static void cec_devnode_unregister(struct cec_adapter *adap) devnode->registered = false; devnode->unregistered = true; + mutex_lock(&devnode->lock_fhs); list_for_each_entry(fh, &devnode->fhs, list) wake_up_interruptible(&fh->wait); + mutex_unlock(&devnode->lock_fhs); mutex_unlock(&devnode->lock); @@ -272,6 +274,7 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, /* adap->devnode initialization */ INIT_LIST_HEAD(&adap->devnode.fhs); + mutex_init(&adap->devnode.lock_fhs); mutex_init(&adap->devnode.lock); adap->kthread = kthread_run(cec_thread_func, adap, "cec-%s", name); diff --git a/drivers/media/cec/core/cec-pin-priv.h b/drivers/media/cec/core/cec-pin-priv.h index fb101f15865c..7bad5a0b7cb7 100644 --- a/drivers/media/cec/core/cec-pin-priv.h +++ b/drivers/media/cec/core/cec-pin-priv.h @@ -170,7 +170,6 @@ struct cec_pin { ktime_t ts; unsigned int wait_usecs; u16 la_mask; - bool enabled; bool monitor_all; bool rx_eom; bool enable_irq_failed; diff --git a/drivers/media/cec/core/cec-pin.c b/drivers/media/cec/core/cec-pin.c index a60b6f03a6a1..21f0f749713e 100644 --- a/drivers/media/cec/core/cec-pin.c +++ b/drivers/media/cec/core/cec-pin.c @@ -1033,6 +1033,7 @@ static int cec_pin_thread_func(void *_adap) { struct cec_adapter *adap = _adap; struct cec_pin *pin = adap->pin; + bool irq_enabled = false; for (;;) { wait_event_interruptible(pin->kthread_waitq, @@ -1060,6 +1061,7 @@ static int cec_pin_thread_func(void *_adap) ns_to_ktime(pin->work_rx_msg.rx_ts)); msg->len = 0; } + if (pin->work_tx_status) { unsigned int tx_status = pin->work_tx_status; @@ -1083,27 +1085,39 @@ static int cec_pin_thread_func(void *_adap) switch (atomic_xchg(&pin->work_irq_change, CEC_PIN_IRQ_UNCHANGED)) { case CEC_PIN_IRQ_DISABLE: - pin->ops->disable_irq(adap); + if (irq_enabled) { + pin->ops->disable_irq(adap); + irq_enabled = false; + } cec_pin_high(pin); cec_pin_to_idle(pin); hrtimer_start(&pin->timer, ns_to_ktime(0), HRTIMER_MODE_REL); break; case CEC_PIN_IRQ_ENABLE: + if (irq_enabled) + break; pin->enable_irq_failed = !pin->ops->enable_irq(adap); if (pin->enable_irq_failed) { cec_pin_to_idle(pin); hrtimer_start(&pin->timer, ns_to_ktime(0), HRTIMER_MODE_REL); + } else { + irq_enabled = true; } break; default: break; } - if (kthread_should_stop()) break; } + if (pin->ops->disable_irq && irq_enabled) + pin->ops->disable_irq(adap); + hrtimer_cancel(&pin->timer); + cec_pin_read(pin); + cec_pin_to_idle(pin); + pin->state = CEC_ST_OFF; return 0; } @@ -1111,7 +1125,6 @@ static int cec_pin_adap_enable(struct cec_adapter *adap, bool enable) { struct cec_pin *pin = adap->pin; - pin->enabled = enable; if (enable) { atomic_set(&pin->work_pin_num_events, 0); pin->work_pin_events_rd = pin->work_pin_events_wr = 0; @@ -1130,13 +1143,7 @@ static int cec_pin_adap_enable(struct cec_adapter *adap, bool enable) hrtimer_start(&pin->timer, ns_to_ktime(0), HRTIMER_MODE_REL); } else { - if (pin->ops->disable_irq) - pin->ops->disable_irq(adap); - hrtimer_cancel(&pin->timer); kthread_stop(pin->kthread); - cec_pin_read(pin); - cec_pin_to_idle(pin); - pin->state = CEC_ST_OFF; } return 0; } @@ -1157,11 +1164,8 @@ void cec_pin_start_timer(struct cec_pin *pin) if (pin->state != CEC_ST_RX_IRQ) return; - atomic_set(&pin->work_irq_change, CEC_PIN_IRQ_UNCHANGED); - pin->ops->disable_irq(pin->adap); - cec_pin_high(pin); - cec_pin_to_idle(pin); - hrtimer_start(&pin->timer, ns_to_ktime(0), HRTIMER_MODE_REL); + atomic_set(&pin->work_irq_change, CEC_PIN_IRQ_DISABLE); + wake_up_interruptible(&pin->kthread_waitq); } static int cec_pin_adap_transmit(struct cec_adapter *adap, u8 attempts, diff --git a/drivers/media/common/b2c2/flexcop.c b/drivers/media/common/b2c2/flexcop.c index cbaa61f10d5f..e7a88a2d248c 100644 --- a/drivers/media/common/b2c2/flexcop.c +++ b/drivers/media/common/b2c2/flexcop.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later /* * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III * flexcop.c - main module part @@ -15,16 +16,6 @@ * Uwe Bugla, uwe.bugla at gmx.de (doing tests, restyling code, writing docu) * Niklas Peinecke, peinecke at gdv.uni-hannover.de (hardware pid/mac * filtering) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include "flexcop.h" diff --git a/drivers/media/common/saa7146/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c index baf5772c52a9..e9a15de6126e 100644 --- a/drivers/media/common/saa7146/saa7146_fops.c +++ b/drivers/media/common/saa7146/saa7146_fops.c @@ -487,6 +487,7 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv) if (hdl->error) { err = hdl->error; v4l2_ctrl_handler_free(hdl); + v4l2_device_unregister(&dev->v4l2_dev); return err; } dev->v4l2_dev.ctrl_handler = hdl; @@ -495,6 +496,7 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv) if (vv == NULL) { ERR("out of memory. aborting.\n"); v4l2_ctrl_handler_free(hdl); + v4l2_device_unregister(&dev->v4l2_dev); return -ENOMEM; } ext_vv->vid_ops = saa7146_video_ioctl_ops; @@ -521,7 +523,8 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv) ERR("out of memory. aborting.\n"); kfree(vv); v4l2_ctrl_handler_free(hdl); - return -1; + v4l2_device_unregister(&dev->v4l2_dev); + return -ENOMEM; } saa7146_video_uops.init(dev,vv); diff --git a/drivers/media/common/videobuf2/frame_vector.c b/drivers/media/common/videobuf2/frame_vector.c index ce879f6f8f82..542dde9d2609 100644 --- a/drivers/media/common/videobuf2/frame_vector.c +++ b/drivers/media/common/videobuf2/frame_vector.c @@ -37,6 +37,7 @@ int get_vaddr_frames(unsigned long start, unsigned int nr_frames, { struct mm_struct *mm = current->mm; struct vm_area_struct *vma; + int ret_pin_user_pages_fast = 0; int ret = 0; int err; @@ -56,6 +57,7 @@ int get_vaddr_frames(unsigned long start, unsigned int nr_frames, vec->is_pfns = false; goto out_unlocked; } + ret_pin_user_pages_fast = ret; mmap_read_lock(mm); vec->got_ref = false; @@ -71,7 +73,18 @@ int get_vaddr_frames(unsigned long start, unsigned int nr_frames, while (ret < nr_frames && start + PAGE_SIZE <= vma->vm_end) { err = follow_pfn(vma, start, &nums[ret]); if (err) { - if (ret == 0) + if (ret) + goto out; + // If follow_pfn() returns -EINVAL, then this + // is not an IO mapping or a raw PFN mapping. + // In that case, return the original error from + // pin_user_pages_fast(). Otherwise this + // function would return -EINVAL when + // pin_user_pages_fast() returned -ENOMEM, + // which makes debugging hard. + if (err == -EINVAL && ret_pin_user_pages_fast) + ret = ret_pin_user_pages_fast; + else ret = err; goto out; } diff --git a/drivers/media/common/videobuf2/videobuf2-dma-contig.c b/drivers/media/common/videobuf2/videobuf2-dma-contig.c index 556e42ba66e5..7c4096e62173 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-contig.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-contig.c @@ -257,7 +257,7 @@ static void *vb2_dc_alloc(struct vb2_buffer *vb, ret = vb2_dc_alloc_coherent(buf); if (ret) { - dev_err(dev, "dma alloc of size %ld failed\n", size); + dev_err(dev, "dma alloc of size %lu failed\n", size); kfree(buf); return ERR_PTR(-ENOMEM); } @@ -298,9 +298,9 @@ static int vb2_dc_mmap(void *buf_priv, struct vm_area_struct *vma) vma->vm_ops->open(vma); - pr_debug("%s: mapped dma addr 0x%08lx at 0x%08lx, size %ld\n", - __func__, (unsigned long)buf->dma_addr, vma->vm_start, - buf->size); + pr_debug("%s: mapped dma addr 0x%08lx at 0x%08lx, size %lu\n", + __func__, (unsigned long)buf->dma_addr, vma->vm_start, + buf->size); return 0; } diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index 5d5a48475a54..f6ee678107d3 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -1,19 +1,9 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later /* * dmxdev.c - DVB demultiplexer device * * Copyright (C) 2000 Ralph Metzler & Marcus Metzler * for convergence integrated media GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #define pr_fmt(fmt) "dmxdev: " fmt @@ -1413,7 +1403,7 @@ static const struct dvb_device dvbdev_dvr = { }; int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter) { - int i; + int i, ret; if (dmxdev->demux->open(dmxdev->demux) < 0) return -EUSERS; @@ -1432,14 +1422,26 @@ int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter) DMXDEV_STATE_FREE); } - dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev, + ret = dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev, DVB_DEVICE_DEMUX, dmxdev->filternum); - dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr, + if (ret < 0) + goto err_register_dvbdev; + + ret = dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr, dmxdev, DVB_DEVICE_DVR, dmxdev->filternum); + if (ret < 0) + goto err_register_dvr_dvbdev; dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192); return 0; + +err_register_dvr_dvbdev: + dvb_unregister_device(dmxdev->dvbdev); +err_register_dvbdev: + vfree(dmxdev->filter); + dmxdev->filter = NULL; + return ret; } EXPORT_SYMBOL(dvb_dmxdev_init); diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c index 5fde1d38b3e3..83cc32ad7e12 100644 --- a/drivers/media/dvb-core/dvb_demux.c +++ b/drivers/media/dvb-core/dvb_demux.c @@ -1,20 +1,10 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later /* * dvb_demux.c - DVB kernel demux API * * Copyright (C) 2000-2001 Ralph Metzler <ralph@convergence.de> * & Marcus Metzler <marcus@convergence.de> * for convergence integrated media GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #define pr_fmt(fmt) "dvb_demux: " fmt diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 258637d762d6..48e735cdbe6b 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -2554,8 +2554,7 @@ static int dvb_frontend_handle_ioctl(struct file *file, case FE_DISEQC_SEND_BURST: if (fe->ops.diseqc_send_burst) { - err = fe->ops.diseqc_send_burst(fe, - (enum fe_sec_mini_cmd)parg); + err = fe->ops.diseqc_send_burst(fe, (long)parg); fepriv->state = FESTATE_DISEQC; fepriv->status = 0; } @@ -2563,9 +2562,8 @@ static int dvb_frontend_handle_ioctl(struct file *file, case FE_SET_TONE: if (fe->ops.set_tone) { - err = fe->ops.set_tone(fe, - (enum fe_sec_tone_mode)parg); - fepriv->tone = (enum fe_sec_tone_mode)parg; + fepriv->tone = (long)parg; + err = fe->ops.set_tone(fe, fepriv->tone); fepriv->state = FESTATE_DISEQC; fepriv->status = 0; } @@ -2573,9 +2571,8 @@ static int dvb_frontend_handle_ioctl(struct file *file, case FE_SET_VOLTAGE: if (fe->ops.set_voltage) { - err = fe->ops.set_voltage(fe, - (enum fe_sec_voltage)parg); - fepriv->voltage = (enum fe_sec_voltage)parg; + fepriv->voltage = (long)parg; + err = fe->ops.set_voltage(fe, fepriv->voltage); fepriv->state = FESTATE_DISEQC; fepriv->status = 0; } @@ -2935,7 +2932,9 @@ int dvb_frontend_suspend(struct dvb_frontend *fe) else if (fe->ops.tuner_ops.sleep) ret = fe->ops.tuner_ops.sleep(fe); - if (fe->ops.sleep) + if (fe->ops.suspend) + ret = fe->ops.suspend(fe); + else if (fe->ops.sleep) ret = fe->ops.sleep(fe); return ret; @@ -2951,7 +2950,9 @@ int dvb_frontend_resume(struct dvb_frontend *fe) fe->id); fe->exit = DVB_FE_DEVICE_RESUME; - if (fe->ops.init) + if (fe->ops.resume) + ret = fe->ops.resume(fe); + else if (fe->ops.init) ret = fe->ops.init(fe); if (fe->ops.tuner_ops.resume) diff --git a/drivers/media/dvb-core/dvb_vb2.c b/drivers/media/dvb-core/dvb_vb2.c index 959d110407a4..a1bd6d9c9223 100644 --- a/drivers/media/dvb-core/dvb_vb2.c +++ b/drivers/media/dvb-core/dvb_vb2.c @@ -5,10 +5,6 @@ * Copyright (C) 2015 Samsung Electronics * * Author: jh1009.sung@samsung.com - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation. */ #include <linux/err.h> diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c index 795d9bfaba5c..675d877a67b2 100644 --- a/drivers/media/dvb-core/dvbdev.c +++ b/drivers/media/dvb-core/dvbdev.c @@ -1,20 +1,10 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later /* * dvbdev.c * * Copyright (C) 2000 Ralph Metzler <ralph@convergence.de> * & Marcus Metzler <marcus@convergence.de> * for convergence integrated media GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #define pr_fmt(fmt) "dvbdev: " fmt diff --git a/drivers/media/dvb-frontends/cx24113.c b/drivers/media/dvb-frontends/cx24113.c index 60a9f70275f7..dd55d314bf9a 100644 --- a/drivers/media/dvb-frontends/cx24113.c +++ b/drivers/media/dvb-frontends/cx24113.c @@ -378,7 +378,7 @@ static void cx24113_set_nfr(struct cx24113_state *state, u16 n, s32 f, u8 r) static int cx24113_set_frequency(struct cx24113_state *state, u32 frequency) { - u8 r = 1; /* or 2 */ + u8 r; u16 n = 6; s32 f = 0; diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c index bb02354a48b8..d67f2dd997d0 100644 --- a/drivers/media/dvb-frontends/dib8000.c +++ b/drivers/media/dvb-frontends/dib8000.c @@ -4473,8 +4473,10 @@ static struct dvb_frontend *dib8000_init(struct i2c_adapter *i2c_adap, u8 i2c_ad state->timf_default = cfg->pll->timf; - if (dib8000_identify(&state->i2c) == 0) + if (dib8000_identify(&state->i2c) == 0) { + kfree(fe); goto error; + } dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr); diff --git a/drivers/media/dvb-frontends/dib9000.c b/drivers/media/dvb-frontends/dib9000.c index 04d92d614279..914ca820c174 100644 --- a/drivers/media/dvb-frontends/dib9000.c +++ b/drivers/media/dvb-frontends/dib9000.c @@ -258,7 +258,7 @@ static int dib9000_read16_attr(struct dib9000_state *state, u16 reg, u8 *b, u32 state->i2c_write_buffer[0] |= (1 << 4); do { - l = len < chunk_size ? len : chunk_size; + l = min(len, chunk_size); state->msg[1].len = l; state->msg[1].buf = b; ret = i2c_transfer(state->i2c.i2c_adap, state->msg, 2) != 2 ? -EREMOTEIO : 0; @@ -342,7 +342,7 @@ static int dib9000_write16_attr(struct dib9000_state *state, u16 reg, const u8 * state->i2c_write_buffer[0] |= (1 << 4); do { - l = len < chunk_size ? len : chunk_size; + l = min(len, chunk_size); state->msg[0].len = l + 2; memcpy(&state->i2c_write_buffer[2], buf, l); diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c index a7eb81df88c2..9860cae65f1c 100644 --- a/drivers/media/dvb-frontends/drxd_hard.c +++ b/drivers/media/dvb-frontends/drxd_hard.c @@ -914,44 +914,36 @@ static int DownloadMicrocode(struct drxd_state *state, u32 Address; u16 nBlocks; u16 BlockSize; - u32 offset = 0; int i, status = 0; pSrc = (u8 *) pMCImage; /* We're not using Flags */ /* Flags = (pSrc[0] << 8) | pSrc[1]; */ pSrc += sizeof(u16); - offset += sizeof(u16); nBlocks = (pSrc[0] << 8) | pSrc[1]; pSrc += sizeof(u16); - offset += sizeof(u16); for (i = 0; i < nBlocks; i++) { Address = (pSrc[0] << 24) | (pSrc[1] << 16) | (pSrc[2] << 8) | pSrc[3]; pSrc += sizeof(u32); - offset += sizeof(u32); BlockSize = ((pSrc[0] << 8) | pSrc[1]) * sizeof(u16); pSrc += sizeof(u16); - offset += sizeof(u16); /* We're not using Flags */ /* u16 Flags = (pSrc[0] << 8) | pSrc[1]; */ pSrc += sizeof(u16); - offset += sizeof(u16); /* We're not using BlockCRC */ /* u16 BlockCRC = (pSrc[0] << 8) | pSrc[1]; */ pSrc += sizeof(u16); - offset += sizeof(u16); status = WriteBlock(state, Address, BlockSize, pSrc, DRX_I2C_CLEARCRC); if (status < 0) break; pSrc += BlockSize; - offset += BlockSize; } return status; diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c index d7fc2595f15b..9430295a8175 100644 --- a/drivers/media/dvb-frontends/drxk_hard.c +++ b/drivers/media/dvb-frontends/drxk_hard.c @@ -3720,7 +3720,6 @@ static int set_dvbt(struct drxk_state *state, u16 intermediate_freqk_hz, { u16 cmd_result = 0; u16 transmission_params = 0; - u16 operation_mode = 0; u32 iqm_rc_rate_ofs = 0; u32 bandwidth = 0; u16 param1; @@ -3759,10 +3758,8 @@ static int set_dvbt(struct drxk_state *state, u16 intermediate_freqk_hz, /* mode */ switch (state->props.transmission_mode) { case TRANSMISSION_MODE_AUTO: - default: - operation_mode |= OFDM_SC_RA_RAM_OP_AUTO_MODE__M; - fallthrough; /* try first guess DRX_FFTMODE_8K */ case TRANSMISSION_MODE_8K: + default: transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_MODE_8K; break; case TRANSMISSION_MODE_2K: @@ -3773,9 +3770,7 @@ static int set_dvbt(struct drxk_state *state, u16 intermediate_freqk_hz, /* guard */ switch (state->props.guard_interval) { default: - case GUARD_INTERVAL_AUTO: - operation_mode |= OFDM_SC_RA_RAM_OP_AUTO_GUARD__M; - fallthrough; /* try first guess DRX_GUARD_1DIV4 */ + case GUARD_INTERVAL_AUTO: /* try first guess DRX_GUARD_1DIV4 */ case GUARD_INTERVAL_1_4: transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_4; break; @@ -3794,11 +3789,7 @@ static int set_dvbt(struct drxk_state *state, u16 intermediate_freqk_hz, switch (state->props.hierarchy) { case HIERARCHY_AUTO: case HIERARCHY_NONE: - default: - operation_mode |= OFDM_SC_RA_RAM_OP_AUTO_HIER__M; - /* try first guess SC_RA_RAM_OP_PARAM_HIER_NO */ - /* transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_HIER_NO; */ - fallthrough; + default: /* try first guess SC_RA_RAM_OP_PARAM_HIER_NO */ case HIERARCHY_1: transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A1; break; @@ -3814,9 +3805,7 @@ static int set_dvbt(struct drxk_state *state, u16 intermediate_freqk_hz, /* modulation */ switch (state->props.modulation) { case QAM_AUTO: - default: - operation_mode |= OFDM_SC_RA_RAM_OP_AUTO_CONST__M; - fallthrough; /* try first guess DRX_CONSTELLATION_QAM64 */ + default: /* try first guess DRX_CONSTELLATION_QAM64 */ case QAM_64: transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM64; break; @@ -3857,9 +3846,7 @@ static int set_dvbt(struct drxk_state *state, u16 intermediate_freqk_hz, /* coderate */ switch (state->props.code_rate_HP) { case FEC_AUTO: - default: - operation_mode |= OFDM_SC_RA_RAM_OP_AUTO_RATE__M; - fallthrough; /* try first guess DRX_CODERATE_2DIV3 */ + default: /* try first guess DRX_CODERATE_2DIV3 */ case FEC_2_3: transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_RATE_2_3; break; diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c index 02e8aa11e36e..bce0f42f3d19 100644 --- a/drivers/media/dvb-frontends/m88ds3103.c +++ b/drivers/media/dvb-frontends/m88ds3103.c @@ -451,7 +451,7 @@ static int m88ds3103b_select_mclk(struct m88ds3103_dev *dev) static int m88ds3103b_set_mclk(struct m88ds3103_dev *dev, u32 mclk_khz) { - u8 reg11 = 0x0A, reg15, reg16, reg1D, reg1E, reg1F, tmp; + u8 reg15, reg16, reg1D, reg1E, reg1F, tmp; u8 sm, f0 = 0, f1 = 0, f2 = 0, f3 = 0; u16 pll_div_fb, N; u32 div; @@ -480,8 +480,6 @@ static int m88ds3103b_set_mclk(struct m88ds3103_dev *dev, u32 mclk_khz) div /= mclk_khz; if (dev->cfg->ts_mode == M88DS3103_TS_SERIAL) { - reg11 |= 0x02; - if (div <= 32) { N = 2; @@ -532,8 +530,6 @@ static int m88ds3103b_set_mclk(struct m88ds3103_dev *dev, u32 mclk_khz) else if ((f3 < 8) && (f3 != 0)) f3 = 8; } else { - reg11 &= ~0x02; - if (div <= 32) { N = 2; diff --git a/drivers/media/dvb-frontends/s5h1411.c b/drivers/media/dvb-frontends/s5h1411.c index c1334d7eb442..2563a72e98b7 100644 --- a/drivers/media/dvb-frontends/s5h1411.c +++ b/drivers/media/dvb-frontends/s5h1411.c @@ -150,7 +150,7 @@ static struct vsb_snr_tab { { 0x35b, 235, }, { 0x353, 230, }, { 0x349, 225, }, - { 0x340, 320, }, + { 0x340, 220, }, { 0x337, 215, }, { 0x327, 210, }, { 0x31b, 205, }, diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index 14b93a7d3358..196e028a6617 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -448,23 +448,10 @@ static int si2168_init(struct dvb_frontend *fe) /* request the firmware, this will block and timeout */ ret = request_firmware(&fw, dev->firmware_name, &client->dev); if (ret) { - /* fallback mechanism to handle old name for Si2168 B40 fw */ - if (dev->chip_id == SI2168_CHIP_ID_B40) { - dev->firmware_name = SI2168_B40_FIRMWARE_FALLBACK; - ret = request_firmware(&fw, dev->firmware_name, - &client->dev); - } - - if (ret == 0) { - dev_notice(&client->dev, - "please install firmware file '%s'\n", - SI2168_B40_FIRMWARE); - } else { - dev_err(&client->dev, - "firmware file '%s' not found\n", - dev->firmware_name); - goto err_release_firmware; - } + dev_err(&client->dev, + "firmware file '%s' not found\n", + dev->firmware_name); + goto err_release_firmware; } dev_info(&client->dev, "downloading firmware from file '%s'\n", @@ -527,6 +514,7 @@ static int si2168_init(struct dvb_frontend *fe) goto err; dev->warm = true; + dev->initialized = true; warm: /* Init stats here to indicate which stats are supported */ c->cnr.len = 1; @@ -548,6 +536,26 @@ err: return ret; } +static int si2168_resume(struct dvb_frontend *fe) +{ + struct i2c_client *client = fe->demodulator_priv; + struct si2168_dev *dev = i2c_get_clientdata(client); + + /* + * check whether si2168_init() has been called successfully + * outside of a resume cycle. Only call it (and load firmware) + * in this case. si2168_init() is only called during resume + * once the device has actually been used. Otherwise, leave the + * device untouched. + */ + if (dev->initialized) { + dev_dbg(&client->dev, "previously initialized, call si2168_init()\n"); + return si2168_init(fe); + } + dev_dbg(&client->dev, "not initialized yet, skipping init on resume\n"); + return 0; +} + static int si2168_sleep(struct dvb_frontend *fe) { struct i2c_client *client = fe->demodulator_priv; @@ -657,6 +665,7 @@ static const struct dvb_frontend_ops si2168_ops = { .init = si2168_init, .sleep = si2168_sleep, + .resume = si2168_resume, .set_frontend = si2168_set_frontend, diff --git a/drivers/media/dvb-frontends/si2168_priv.h b/drivers/media/dvb-frontends/si2168_priv.h index 18bea5222082..3a8976229a4a 100644 --- a/drivers/media/dvb-frontends/si2168_priv.h +++ b/drivers/media/dvb-frontends/si2168_priv.h @@ -18,7 +18,6 @@ #define SI2168_A30_FIRMWARE "dvb-demod-si2168-a30-01.fw" #define SI2168_B40_FIRMWARE "dvb-demod-si2168-b40-01.fw" #define SI2168_D60_FIRMWARE "dvb-demod-si2168-d60-01.fw" -#define SI2168_B40_FIRMWARE_FALLBACK "dvb-demod-si2168-02.fw" /* state struct */ struct si2168_dev { @@ -37,6 +36,7 @@ struct si2168_dev { u8 ts_mode; unsigned int active:1; unsigned int warm:1; + unsigned int initialized:1; unsigned int ts_clock_inv:1; unsigned int ts_clock_gapped:1; unsigned int spectral_inversion:1; diff --git a/drivers/media/dvb-frontends/si21xx.c b/drivers/media/dvb-frontends/si21xx.c index e31eb2c5cc4c..001b23588389 100644 --- a/drivers/media/dvb-frontends/si21xx.c +++ b/drivers/media/dvb-frontends/si21xx.c @@ -711,7 +711,7 @@ static int si21xx_set_frontend(struct dvb_frontend *fe) int i; bool inband_interferer_div2[ALLOWABLE_FS_COUNT]; bool inband_interferer_div4[ALLOWABLE_FS_COUNT]; - int status; + int status = 0; /* allowable sample rates for ADC in MHz */ int afs[ALLOWABLE_FS_COUNT] = { 200, 192, 193, 194, 195, @@ -747,8 +747,6 @@ static int si21xx_set_frontend(struct dvb_frontend *fe) rf_freq = 10 * c->frequency ; data_rate = c->symbol_rate / 100; - status = PASS; - band_low = (rf_freq - lnb_lo) - ((lnb_uncertanity * 200) + (data_rate * 135)) / 200; @@ -832,6 +830,9 @@ static int si21xx_set_frontend(struct dvb_frontend *fe) state->fs = sample_rate;/*ADC MHz*/ si21xx_setacquire(fe, c->symbol_rate, c->fec_inner); + if (status) + return -EREMOTEIO; + return 0; } diff --git a/drivers/media/dvb-frontends/sp887x.c b/drivers/media/dvb-frontends/sp887x.c index c89a91a3daf4..146e7f2dd3c5 100644 --- a/drivers/media/dvb-frontends/sp887x.c +++ b/drivers/media/dvb-frontends/sp887x.c @@ -140,7 +140,7 @@ static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware u8 buf [BLOCKSIZE + 2]; int i; int fw_size = fw->size; - const unsigned char *mem = fw->data; + const unsigned char *mem = fw->data + 10; dprintk("%s\n", __func__); @@ -148,8 +148,6 @@ static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware if (fw_size < FW_SIZE + 10) return -ENODEV; - mem = fw->data + 10; - /* soft reset */ sp887x_writereg(state, 0xf1a, 0x000); diff --git a/drivers/media/dvb-frontends/stb6100.c b/drivers/media/dvb-frontends/stb6100.c index d541d6613610..698866c4f15a 100644 --- a/drivers/media/dvb-frontends/stb6100.c +++ b/drivers/media/dvb-frontends/stb6100.c @@ -110,7 +110,7 @@ static const struct stb6100_regmask stb6100_template[] = { /* * Currently unused. Some boards might need it in the future */ -static inline void stb6100_normalise_regs(u8 regs[]) +static __always_unused inline void stb6100_normalise_regs(u8 regs[]) { int i; diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c index 6c2b05fae1c5..95e376f23506 100644 --- a/drivers/media/dvb-frontends/stv0367.c +++ b/drivers/media/dvb-frontends/stv0367.c @@ -1797,11 +1797,7 @@ static u32 stv0367cab_get_mclk(struct dvb_frontend *fe, u32 ExtClk_Hz) static u32 stv0367cab_get_adc_freq(struct dvb_frontend *fe, u32 ExtClk_Hz) { - u32 ADCClk_Hz = ExtClk_Hz; - - ADCClk_Hz = stv0367cab_get_mclk(fe, ExtClk_Hz); - - return ADCClk_Hz; + return stv0367cab_get_mclk(fe, ExtClk_Hz); } static enum stv0367cab_mod stv0367cab_SetQamSize(struct stv0367_state *state, diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index d6a5d4ca439a..69c56e24a612 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -469,6 +469,7 @@ config VIDEO_VPX3220 config VIDEO_MAX9286 tristate "Maxim MAX9286 GMSL deserializer support" depends on I2C && I2C_MUX + depends on VIDEO_V4L2 depends on OF_GPIO select V4L2_FWNODE select VIDEO_V4L2_SUBDEV_API @@ -1058,6 +1059,17 @@ config VIDEO_OV5675 To compile this driver as a module, choose M here: the module will be called ov5675. +config VIDEO_OV5693 + tristate "OmniVision OV5693 sensor support" + depends on I2C && VIDEO_V4L2 + select V4L2_FWNODE + help + This is a Video4Linux2 sensor driver for the OmniVision + OV5693 camera. + + To compile this driver as a module, choose M here: the + module will be called ov5693. + config VIDEO_OV5695 tristate "OmniVision OV5695 sensor support" depends on I2C && VIDEO_V4L2 diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 4d4fe08d7a6a..b01f6cd05ee8 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -75,6 +75,7 @@ obj-$(CONFIG_VIDEO_OV5647) += ov5647.o obj-$(CONFIG_VIDEO_OV5648) += ov5648.o obj-$(CONFIG_VIDEO_OV5670) += ov5670.o obj-$(CONFIG_VIDEO_OV5675) += ov5675.o +obj-$(CONFIG_VIDEO_OV5693) += ov5693.o obj-$(CONFIG_VIDEO_OV5695) += ov5695.o obj-$(CONFIG_VIDEO_OV6650) += ov6650.o obj-$(CONFIG_VIDEO_OV7251) += ov7251.o diff --git a/drivers/media/i2c/adv7511-v4l2.c b/drivers/media/i2c/adv7511-v4l2.c index 41f4e749a859..8e13cae40ec5 100644 --- a/drivers/media/i2c/adv7511-v4l2.c +++ b/drivers/media/i2c/adv7511-v4l2.c @@ -270,28 +270,6 @@ static int adv7511_pktmem_rd(struct v4l2_subdev *sd, u8 reg) return adv_smbus_read_byte_data(state->i2c_pktmem, reg); } -static int adv7511_pktmem_wr(struct v4l2_subdev *sd, u8 reg, u8 val) -{ - struct adv7511_state *state = get_adv7511_state(sd); - int ret; - int i; - - for (i = 0; i < 3; i++) { - ret = i2c_smbus_write_byte_data(state->i2c_pktmem, reg, val); - if (ret == 0) - return 0; - } - v4l2_err(sd, "%s: i2c write error\n", __func__); - return ret; -} - -/* To set specific bits in the register, a clear-mask is given (to be AND-ed), - and then the value-mask (to be OR-ed). */ -static inline void adv7511_pktmem_wr_and_or(struct v4l2_subdev *sd, u8 reg, u8 clr_mask, u8 val_mask) -{ - adv7511_pktmem_wr(sd, reg, (adv7511_pktmem_rd(sd, reg) & clr_mask) | val_mask); -} - static inline bool adv7511_have_hotplug(struct v4l2_subdev *sd) { return adv7511_rd(sd, 0x42) & MASK_ADV7511_HPD_DETECT; diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 44768b59a6ff..a2fa408d2d9f 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -398,14 +398,14 @@ static inline int io_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, return io_write(sd, reg, (io_read(sd, reg) & ~mask) | val); } -static inline int avlink_read(struct v4l2_subdev *sd, u8 reg) +static inline int __always_unused avlink_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); return adv76xx_read_check(state, ADV7604_PAGE_AVLINK, reg); } -static inline int avlink_write(struct v4l2_subdev *sd, u8 reg, u8 val) +static inline int __always_unused avlink_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); @@ -439,14 +439,14 @@ static inline int infoframe_read(struct v4l2_subdev *sd, u8 reg) return adv76xx_read_check(state, ADV76XX_PAGE_INFOFRAME, reg); } -static inline int infoframe_write(struct v4l2_subdev *sd, u8 reg, u8 val) +static inline int __always_unused infoframe_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); return regmap_write(state->regmap[ADV76XX_PAGE_INFOFRAME], reg, val); } -static inline int afe_read(struct v4l2_subdev *sd, u8 reg) +static inline int __always_unused afe_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); @@ -479,14 +479,14 @@ static inline int rep_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 return rep_write(sd, reg, (rep_read(sd, reg) & ~mask) | val); } -static inline int edid_read(struct v4l2_subdev *sd, u8 reg) +static inline int __always_unused edid_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); return adv76xx_read_check(state, ADV76XX_PAGE_EDID, reg); } -static inline int edid_write(struct v4l2_subdev *sd, u8 reg, u8 val) +static inline int __always_unused edid_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); @@ -570,7 +570,7 @@ static inline int hdmi_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 return hdmi_write(sd, reg, (hdmi_read(sd, reg) & ~mask) | val); } -static inline int test_write(struct v4l2_subdev *sd, u8 reg, u8 val) +static inline int __always_unused test_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); @@ -601,14 +601,14 @@ static inline int cp_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 v return cp_write(sd, reg, (cp_read(sd, reg) & ~mask) | val); } -static inline int vdp_read(struct v4l2_subdev *sd, u8 reg) +static inline int __always_unused vdp_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); return adv76xx_read_check(state, ADV7604_PAGE_VDP, reg); } -static inline int vdp_write(struct v4l2_subdev *sd, u8 reg, u8 val) +static inline int __always_unused vdp_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 7f8acbdf0db4..9d6eed0f8281 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -256,21 +256,11 @@ static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) return &container_of(ctrl->handler, struct adv7842_state, hdl)->sd; } -static inline unsigned hblanking(const struct v4l2_bt_timings *t) -{ - return V4L2_DV_BT_BLANKING_WIDTH(t); -} - static inline unsigned htotal(const struct v4l2_bt_timings *t) { return V4L2_DV_BT_FRAME_WIDTH(t); } -static inline unsigned vblanking(const struct v4l2_bt_timings *t) -{ - return V4L2_DV_BT_BLANKING_HEIGHT(t); -} - static inline unsigned vtotal(const struct v4l2_bt_timings *t) { return V4L2_DV_BT_FRAME_HEIGHT(t); diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 5363f3bcafe3..9158d3ce45c0 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -2758,13 +2758,13 @@ ident_show(struct device *dev, struct device_attribute *attr, char *buf) struct ccs_module_info *minfo = &sensor->minfo; if (minfo->mipi_manufacturer_id) - return snprintf(buf, PAGE_SIZE, "%4.4x%4.4x%2.2x\n", - minfo->mipi_manufacturer_id, minfo->model_id, - minfo->revision_number) + 1; + return sysfs_emit(buf, "%4.4x%4.4x%2.2x\n", + minfo->mipi_manufacturer_id, minfo->model_id, + minfo->revision_number) + 1; else - return snprintf(buf, PAGE_SIZE, "%2.2x%4.4x%2.2x\n", - minfo->smia_manufacturer_id, minfo->model_id, - minfo->revision_number) + 1; + return sysfs_emit(buf, "%2.2x%4.4x%2.2x\n", + minfo->smia_manufacturer_id, minfo->model_id, + minfo->revision_number) + 1; } static DEVICE_ATTR_RO(ident); diff --git a/drivers/media/i2c/cx25840/cx25840-ir.c b/drivers/media/i2c/cx25840/cx25840-ir.c index 2cf3e6a1f9e1..9d7d1d149f1a 100644 --- a/drivers/media/i2c/cx25840/cx25840-ir.c +++ b/drivers/media/i2c/cx25840/cx25840-ir.c @@ -136,19 +136,6 @@ static inline u16 count_to_clock_divider(unsigned int d) return (u16) d; } -static inline u16 ns_to_clock_divider(unsigned int ns) -{ - return count_to_clock_divider( - DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ / 1000000 * ns, 1000)); -} - -static inline unsigned int clock_divider_to_ns(unsigned int divider) -{ - /* Period of the Rx or Tx clock in ns */ - return DIV_ROUND_CLOSEST((divider + 1) * 1000, - CX25840_IR_REFCLK_FREQ / 1000000); -} - static inline u16 carrier_freq_to_clock_divider(unsigned int freq) { return count_to_clock_divider( @@ -160,13 +147,6 @@ static inline unsigned int clock_divider_to_carrier_freq(unsigned int divider) return DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ, (divider + 1) * 16); } -static inline u16 freq_to_clock_divider(unsigned int freq, - unsigned int rollovers) -{ - return count_to_clock_divider( - DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ, freq * rollovers)); -} - static inline unsigned int clock_divider_to_freq(unsigned int divider, unsigned int rollovers) { diff --git a/drivers/media/i2c/dw9768.c b/drivers/media/i2c/dw9768.c index c086580efac7..65c6acf3ced9 100644 --- a/drivers/media/i2c/dw9768.c +++ b/drivers/media/i2c/dw9768.c @@ -469,6 +469,11 @@ static int dw9768_probe(struct i2c_client *client) dw9768->sd.entity.function = MEDIA_ENT_F_LENS; + /* + * Device is already turned on by i2c-core with ACPI domain PM. + * Attempt to turn off the device to satisfy the privacy LED concerns. + */ + pm_runtime_set_active(dev); pm_runtime_enable(dev); if (!pm_runtime_enabled(dev)) { ret = dw9768_runtime_resume(dev); @@ -483,6 +488,7 @@ static int dw9768_probe(struct i2c_client *client) dev_err(dev, "failed to register V4L2 subdev: %d", ret); goto err_power_off; } + pm_runtime_idle(dev); return 0; diff --git a/drivers/media/i2c/hi556.c b/drivers/media/i2c/hi556.c index 8db1cbedc1fd..055d1aa8410e 100644 --- a/drivers/media/i2c/hi556.c +++ b/drivers/media/i2c/hi556.c @@ -495,6 +495,9 @@ struct hi556 { /* Streaming on/off */ bool streaming; + + /* True if the device has been identified */ + bool identified; }; static u64 to_pixel_rate(u32 f_index) @@ -757,12 +760,41 @@ static void hi556_assign_pad_format(const struct hi556_mode *mode, fmt->field = V4L2_FIELD_NONE; } +static int hi556_identify_module(struct hi556 *hi556) +{ + struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd); + int ret; + u32 val; + + if (hi556->identified) + return 0; + + ret = hi556_read_reg(hi556, HI556_REG_CHIP_ID, + HI556_REG_VALUE_16BIT, &val); + if (ret) + return ret; + + if (val != HI556_CHIP_ID) { + dev_err(&client->dev, "chip id mismatch: %x!=%x", + HI556_CHIP_ID, val); + return -ENXIO; + } + + hi556->identified = true; + + return 0; +} + static int hi556_start_streaming(struct hi556 *hi556) { struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd); const struct hi556_reg_list *reg_list; int link_freq_index, ret; + ret = hi556_identify_module(hi556); + if (ret) + return ret; + link_freq_index = hi556->cur_mode->link_freq_index; reg_list = &link_freq_configs[link_freq_index].reg_list; ret = hi556_write_reg_list(hi556, reg_list); @@ -1001,26 +1033,6 @@ static const struct v4l2_subdev_internal_ops hi556_internal_ops = { .open = hi556_open, }; -static int hi556_identify_module(struct hi556 *hi556) -{ - struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd); - int ret; - u32 val; - - ret = hi556_read_reg(hi556, HI556_REG_CHIP_ID, - HI556_REG_VALUE_16BIT, &val); - if (ret) - return ret; - - if (val != HI556_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x", - HI556_CHIP_ID, val); - return -ENXIO; - } - - return 0; -} - static int hi556_check_hwcfg(struct device *dev) { struct fwnode_handle *ep; @@ -1106,6 +1118,7 @@ static int hi556_remove(struct i2c_client *client) static int hi556_probe(struct i2c_client *client) { struct hi556 *hi556; + bool full_power; int ret; ret = hi556_check_hwcfg(&client->dev); @@ -1120,10 +1133,14 @@ static int hi556_probe(struct i2c_client *client) return -ENOMEM; v4l2_i2c_subdev_init(&hi556->sd, client, &hi556_subdev_ops); - ret = hi556_identify_module(hi556); - if (ret) { - dev_err(&client->dev, "failed to find sensor: %d", ret); - return ret; + + full_power = acpi_dev_state_d0(&client->dev); + if (full_power) { + ret = hi556_identify_module(hi556); + if (ret) { + dev_err(&client->dev, "failed to find sensor: %d", ret); + return ret; + } } mutex_init(&hi556->mutex); @@ -1152,7 +1169,9 @@ static int hi556_probe(struct i2c_client *client) goto probe_error_media_entity_cleanup; } - pm_runtime_set_active(&client->dev); + /* Set the device's state to active if it's in D0 state. */ + if (full_power) + pm_runtime_set_active(&client->dev); pm_runtime_enable(&client->dev); pm_runtime_idle(&client->dev); @@ -1189,6 +1208,7 @@ static struct i2c_driver hi556_i2c_driver = { }, .probe_new = hi556_probe, .remove = hi556_remove, + .flags = I2C_DRV_ACPI_WAIVE_D0_PROBE, }; module_i2c_driver(hi556_i2c_driver); diff --git a/drivers/media/i2c/hi846.c b/drivers/media/i2c/hi846.c index 48909faeced4..ad35c3ff3611 100644 --- a/drivers/media/i2c/hi846.c +++ b/drivers/media/i2c/hi846.c @@ -1656,7 +1656,7 @@ err_reg: return ret; } -static void hi846_power_off(struct hi846 *hi846) +static int hi846_power_off(struct hi846 *hi846) { if (hi846->rst_gpio) gpiod_set_value_cansleep(hi846->rst_gpio, 1); @@ -1665,7 +1665,7 @@ static void hi846_power_off(struct hi846 *hi846) gpiod_set_value_cansleep(hi846->shutdown_gpio, 1); clk_disable_unprepare(hi846->clock); - regulator_bulk_disable(HI846_NUM_SUPPLIES, hi846->supplies); + return regulator_bulk_disable(HI846_NUM_SUPPLIES, hi846->supplies); } static int __maybe_unused hi846_suspend(struct device *dev) @@ -1677,9 +1677,7 @@ static int __maybe_unused hi846_suspend(struct device *dev) if (hi846->streaming) hi846_stop_streaming(hi846); - hi846_power_off(hi846); - - return 0; + return hi846_power_off(hi846); } static int __maybe_unused hi846_resume(struct device *dev) @@ -2164,7 +2162,11 @@ static int hi846_remove(struct i2c_client *client) return 0; } -static UNIVERSAL_DEV_PM_OPS(hi846_pm_ops, hi846_suspend, hi846_resume, NULL); +static const struct dev_pm_ops hi846_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(hi846_suspend, hi846_resume, NULL) +}; static const struct of_device_id hi846_of_match[] = { { .compatible = "hynix,hi846", }, diff --git a/drivers/media/i2c/imx208.c b/drivers/media/i2c/imx208.c index 6f3d9c1b5879..b9516b2f1c15 100644 --- a/drivers/media/i2c/imx208.c +++ b/drivers/media/i2c/imx208.c @@ -296,6 +296,9 @@ struct imx208 { /* OTP data */ bool otp_read; char otp_data[IMX208_OTP_SIZE]; + + /* True if the device has been identified */ + bool identified; }; static inline struct imx208 *to_imx208(struct v4l2_subdev *_sd) @@ -619,6 +622,34 @@ static int imx208_set_pad_format(struct v4l2_subdev *sd, return 0; } +static int imx208_identify_module(struct imx208 *imx208) +{ + struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd); + int ret; + u32 val; + + if (imx208->identified) + return 0; + + ret = imx208_read_reg(imx208, IMX208_REG_CHIP_ID, + 2, &val); + if (ret) { + dev_err(&client->dev, "failed to read chip id %x\n", + IMX208_CHIP_ID); + return ret; + } + + if (val != IMX208_CHIP_ID) { + dev_err(&client->dev, "chip id mismatch: %x!=%x\n", + IMX208_CHIP_ID, val); + return -EIO; + } + + imx208->identified = true; + + return 0; +} + /* Start streaming */ static int imx208_start_streaming(struct imx208 *imx208) { @@ -626,6 +657,10 @@ static int imx208_start_streaming(struct imx208 *imx208) const struct imx208_reg_list *reg_list; int ret, link_freq_index; + ret = imx208_identify_module(imx208); + if (ret) + return ret; + /* Setup PLL */ link_freq_index = imx208->cur_mode->link_freq_index; reg_list = &link_freq_configs[link_freq_index].reg_list; @@ -752,29 +787,6 @@ error: } /* Verify chip ID */ -static int imx208_identify_module(struct imx208 *imx208) -{ - struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd); - int ret; - u32 val; - - ret = imx208_read_reg(imx208, IMX208_REG_CHIP_ID, - 2, &val); - if (ret) { - dev_err(&client->dev, "failed to read chip id %x\n", - IMX208_CHIP_ID); - return ret; - } - - if (val != IMX208_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x\n", - IMX208_CHIP_ID, val); - return -EIO; - } - - return 0; -} - static const struct v4l2_subdev_video_ops imx208_video_ops = { .s_stream = imx208_set_stream, }; @@ -813,6 +825,10 @@ static int imx208_read_otp(struct imx208 *imx208) goto out_unlock; } + ret = imx208_identify_module(imx208); + if (ret) + goto out_pm_put; + /* Write register address */ msgs[0].addr = client->addr; msgs[0].flags = 0; @@ -831,6 +847,7 @@ static int imx208_read_otp(struct imx208 *imx208) ret = 0; } +out_pm_put: pm_runtime_put(&client->dev); out_unlock: @@ -961,6 +978,7 @@ static int imx208_probe(struct i2c_client *client) { struct imx208 *imx208; int ret; + bool full_power; u32 val = 0; device_property_read_u32(&client->dev, "clock-frequency", &val); @@ -978,11 +996,14 @@ static int imx208_probe(struct i2c_client *client) /* Initialize subdev */ v4l2_i2c_subdev_init(&imx208->sd, client, &imx208_subdev_ops); - /* Check module identity */ - ret = imx208_identify_module(imx208); - if (ret) { - dev_err(&client->dev, "failed to find sensor: %d", ret); - goto error_probe; + full_power = acpi_dev_state_d0(&client->dev); + if (full_power) { + /* Check module identity */ + ret = imx208_identify_module(imx208); + if (ret) { + dev_err(&client->dev, "failed to find sensor: %d", ret); + goto error_probe; + } } /* Set default mode to max resolution */ @@ -1017,7 +1038,9 @@ static int imx208_probe(struct i2c_client *client) goto error_async_subdev; } - pm_runtime_set_active(&client->dev); + /* Set the device's state to active if it's in D0 state. */ + if (full_power) + pm_runtime_set_active(&client->dev); pm_runtime_enable(&client->dev); pm_runtime_idle(&client->dev); @@ -1077,6 +1100,7 @@ static struct i2c_driver imx208_i2c_driver = { }, .probe_new = imx208_probe, .remove = imx208_remove, + .flags = I2C_DRV_ACPI_WAIVE_D0_PROBE, }; module_i2c_driver(imx208_i2c_driver); diff --git a/drivers/media/i2c/imx274.c b/drivers/media/i2c/imx274.c index 0dce92872176..2aa15b9c23cc 100644 --- a/drivers/media/i2c/imx274.c +++ b/drivers/media/i2c/imx274.c @@ -27,6 +27,7 @@ #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> #include <media/v4l2-subdev.h> /* @@ -1367,6 +1368,10 @@ static int imx274_s_frame_interval(struct v4l2_subdev *sd, int min, max, def; int ret; + ret = pm_runtime_resume_and_get(&imx274->client->dev); + if (ret < 0) + return ret; + mutex_lock(&imx274->lock); ret = imx274_set_frame_interval(imx274, fi->interval); @@ -1398,6 +1403,7 @@ static int imx274_s_frame_interval(struct v4l2_subdev *sd, unlock: mutex_unlock(&imx274->lock); + pm_runtime_put(&imx274->client->dev); return ret; } @@ -1457,7 +1463,7 @@ static int imx274_s_stream(struct v4l2_subdev *sd, int on) goto fail; /* - * update frame rate & expsoure. if the last mode is different, + * update frame rate & exposure. if the last mode is different, * HMAX could be changed. As the result, frame rate & exposure * are changed. * gain is not affected. @@ -1494,7 +1500,7 @@ fail: /* * imx274_get_frame_length - Function for obtaining current frame length * @priv: Pointer to device structure - * @val: Pointer to obainted value + * @val: Pointer to obtained value * * frame_length = vmax x (svr + 1), in unit of hmax. * @@ -1904,7 +1910,21 @@ fail: return err; } +static int imx274_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index > 0) + return -EINVAL; + + /* only supported format in the driver is Raw 10 bits SRGGB */ + code->code = MEDIA_BUS_FMT_SRGGB10_1X10; + + return 0; +} + static const struct v4l2_subdev_pad_ops imx274_pad_ops = { + .enum_mbus_code = imx274_enum_mbus_code, .get_fmt = imx274_get_fmt, .set_fmt = imx274_set_fmt, .get_selection = imx274_get_selection, @@ -1938,27 +1958,66 @@ static const struct i2c_device_id imx274_id[] = { }; MODULE_DEVICE_TABLE(i2c, imx274_id); +static int imx274_fwnode_parse(struct device *dev) +{ + struct fwnode_handle *endpoint; + /* Only CSI2 is supported */ + struct v4l2_fwnode_endpoint ep = { + .bus_type = V4L2_MBUS_CSI2_DPHY + }; + int ret; + + endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); + if (!endpoint) { + dev_err(dev, "Endpoint node not found\n"); + return -EINVAL; + } + + ret = v4l2_fwnode_endpoint_parse(endpoint, &ep); + fwnode_handle_put(endpoint); + if (ret == -ENXIO) { + dev_err(dev, "Unsupported bus type, should be CSI2\n"); + return ret; + } else if (ret) { + dev_err(dev, "Parsing endpoint node failed %d\n", ret); + return ret; + } + + /* Check number of data lanes, only 4 lanes supported */ + if (ep.bus.mipi_csi2.num_data_lanes != 4) { + dev_err(dev, "Invalid data lanes: %d\n", + ep.bus.mipi_csi2.num_data_lanes); + return -EINVAL; + } + + return 0; +} + static int imx274_probe(struct i2c_client *client) { struct v4l2_subdev *sd; struct stimx274 *imx274; + struct device *dev = &client->dev; int ret; /* initialize imx274 */ - imx274 = devm_kzalloc(&client->dev, sizeof(*imx274), GFP_KERNEL); + imx274 = devm_kzalloc(dev, sizeof(*imx274), GFP_KERNEL); if (!imx274) return -ENOMEM; mutex_init(&imx274->lock); - imx274->inck = devm_clk_get_optional(&client->dev, "inck"); + ret = imx274_fwnode_parse(dev); + if (ret) + return ret; + + imx274->inck = devm_clk_get_optional(dev, "inck"); if (IS_ERR(imx274->inck)) return PTR_ERR(imx274->inck); - ret = imx274_regulators_get(&client->dev, imx274); + ret = imx274_regulators_get(dev, imx274); if (ret) { - dev_err(&client->dev, - "Failed to get power regulators, err: %d\n", ret); + dev_err(dev, "Failed to get power regulators, err: %d\n", ret); return ret; } @@ -1977,7 +2036,7 @@ static int imx274_probe(struct i2c_client *client) /* initialize regmap */ imx274->regmap = devm_regmap_init_i2c(client, &imx274_regmap_config); if (IS_ERR(imx274->regmap)) { - dev_err(&client->dev, + dev_err(dev, "regmap init failed: %ld\n", PTR_ERR(imx274->regmap)); ret = -ENODEV; goto err_regmap; @@ -1994,34 +2053,32 @@ static int imx274_probe(struct i2c_client *client) sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&sd->entity, 1, &imx274->pad); if (ret < 0) { - dev_err(&client->dev, + dev_err(dev, "%s : media entity init Failed %d\n", __func__, ret); goto err_regmap; } /* initialize sensor reset gpio */ - imx274->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", + imx274->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(imx274->reset_gpio)) { if (PTR_ERR(imx274->reset_gpio) != -EPROBE_DEFER) - dev_err(&client->dev, "Reset GPIO not setup in DT"); + dev_err(dev, "Reset GPIO not setup in DT"); ret = PTR_ERR(imx274->reset_gpio); goto err_me; } /* power on the sensor */ - ret = imx274_power_on(&client->dev); + ret = imx274_power_on(dev); if (ret < 0) { - dev_err(&client->dev, - "%s : imx274 power on failed\n", __func__); + dev_err(dev, "%s : imx274 power on failed\n", __func__); goto err_me; } /* initialize controls */ ret = v4l2_ctrl_handler_init(&imx274->ctrls.handler, 4); if (ret < 0) { - dev_err(&client->dev, - "%s : ctrl handler init Failed\n", __func__); + dev_err(dev, "%s : ctrl handler init Failed\n", __func__); goto err_power_off; } @@ -2064,23 +2121,22 @@ static int imx274_probe(struct i2c_client *client) /* register subdevice */ ret = v4l2_async_register_subdev(sd); if (ret < 0) { - dev_err(&client->dev, - "%s : v4l2_async_register_subdev failed %d\n", + dev_err(dev, "%s : v4l2_async_register_subdev failed %d\n", __func__, ret); goto err_ctrls; } - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_runtime_idle(dev); - dev_info(&client->dev, "imx274 : imx274 probe success !\n"); + dev_info(dev, "imx274 : imx274 probe success !\n"); return 0; err_ctrls: v4l2_ctrl_handler_free(&imx274->ctrls.handler); err_power_off: - imx274_power_off(&client->dev); + imx274_power_off(dev); err_me: media_entity_cleanup(&sd->entity); err_regmap: diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c index bf7a6c37ca5d..99f2a50d39a4 100644 --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -363,7 +363,7 @@ static inline struct imx290 *to_imx290(struct v4l2_subdev *_sd) return container_of(_sd, struct imx290, sd); } -static inline int imx290_read_reg(struct imx290 *imx290, u16 addr, u8 *value) +static inline int __always_unused imx290_read_reg(struct imx290 *imx290, u16 addr, u8 *value) { unsigned int regval; int ret; diff --git a/drivers/media/i2c/imx319.c b/drivers/media/i2c/imx319.c index daa976858e29..a2b5a34de76b 100644 --- a/drivers/media/i2c/imx319.c +++ b/drivers/media/i2c/imx319.c @@ -2565,6 +2565,6 @@ module_i2c_driver(imx319_i2c_driver); MODULE_AUTHOR("Qiu, Tianshu <tian.shu.qiu@intel.com>"); MODULE_AUTHOR("Rapolu, Chiranjeevi <chiranjeevi.rapolu@intel.com>"); MODULE_AUTHOR("Bingbu Cao <bingbu.cao@intel.com>"); -MODULE_AUTHOR("Yang, Hyungwoo <hyungwoo.yang@intel.com>"); +MODULE_AUTHOR("Yang, Hyungwoo"); MODULE_DESCRIPTION("Sony imx319 sensor driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c index cb51c81786bd..3922b9305978 100644 --- a/drivers/media/i2c/imx355.c +++ b/drivers/media/i2c/imx355.c @@ -1851,6 +1851,6 @@ module_i2c_driver(imx355_i2c_driver); MODULE_AUTHOR("Qiu, Tianshu <tian.shu.qiu@intel.com>"); MODULE_AUTHOR("Rapolu, Chiranjeevi <chiranjeevi.rapolu@intel.com>"); MODULE_AUTHOR("Bingbu Cao <bingbu.cao@intel.com>"); -MODULE_AUTHOR("Yang, Hyungwoo <hyungwoo.yang@intel.com>"); +MODULE_AUTHOR("Yang, Hyungwoo"); MODULE_DESCRIPTION("Sony imx355 sensor driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c index 7c663fd587bb..eb2b8e42335b 100644 --- a/drivers/media/i2c/max9286.c +++ b/drivers/media/i2c/max9286.c @@ -1055,7 +1055,6 @@ static int max9286_register_gpio(struct max9286_priv *priv) gpio->label = dev_name(dev); gpio->parent = dev; gpio->owner = THIS_MODULE; - gpio->of_node = dev->of_node; gpio->ngpio = 2; gpio->base = -1; gpio->set = max9286_gpio_set; @@ -1295,11 +1294,9 @@ static int max9286_probe(struct i2c_client *client) priv->regulator = devm_regulator_get(&client->dev, "poc"); if (IS_ERR(priv->regulator)) { - if (PTR_ERR(priv->regulator) != -EPROBE_DEFER) - dev_err(&client->dev, - "Unable to get PoC regulator (%ld)\n", - PTR_ERR(priv->regulator)); ret = PTR_ERR(priv->regulator); + dev_err_probe(&client->dev, ret, + "Unable to get PoC regulator\n"); goto err_powerdown; } diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c index b4d22f5d9933..d5fe67c763f7 100644 --- a/drivers/media/i2c/ov13858.c +++ b/drivers/media/i2c/ov13858.c @@ -1818,6 +1818,6 @@ module_i2c_driver(ov13858_i2c_driver); MODULE_AUTHOR("Kan, Chris <chris.kan@intel.com>"); MODULE_AUTHOR("Rapolu, Chiranjeevi <chiranjeevi.rapolu@intel.com>"); -MODULE_AUTHOR("Yang, Hyungwoo <hyungwoo.yang@intel.com>"); +MODULE_AUTHOR("Yang, Hyungwoo"); MODULE_DESCRIPTION("Omnivision ov13858 sensor driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c index 934c9d65cb09..bab720c7c1de 100644 --- a/drivers/media/i2c/ov2740.c +++ b/drivers/media/i2c/ov2740.c @@ -345,6 +345,9 @@ struct ov2740 { /* NVM data inforamtion */ struct nvm_data *nvm; + + /* True if the device has been identified */ + bool identified; }; static inline struct ov2740 *to_ov2740(struct v4l2_subdev *subdev) @@ -440,6 +443,30 @@ static int ov2740_write_reg_list(struct ov2740 *ov2740, return 0; } +static int ov2740_identify_module(struct ov2740 *ov2740) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov2740->sd); + int ret; + u32 val; + + if (ov2740->identified) + return 0; + + ret = ov2740_read_reg(ov2740, OV2740_REG_CHIP_ID, 3, &val); + if (ret) + return ret; + + if (val != OV2740_CHIP_ID) { + dev_err(&client->dev, "chip id mismatch: %x!=%x", + OV2740_CHIP_ID, val); + return -ENXIO; + } + + ov2740->identified = true; + + return 0; +} + static int ov2740_update_digital_gain(struct ov2740 *ov2740, u32 d_gain) { int ret = 0; @@ -724,6 +751,10 @@ static int ov2740_start_streaming(struct ov2740 *ov2740) int link_freq_index; int ret = 0; + ret = ov2740_identify_module(ov2740); + if (ret) + return ret; + ov2740_load_otp_data(nvm); link_freq_index = ov2740->cur_mode->link_freq_index; @@ -956,25 +987,6 @@ static const struct v4l2_subdev_internal_ops ov2740_internal_ops = { .open = ov2740_open, }; -static int ov2740_identify_module(struct ov2740 *ov2740) -{ - struct i2c_client *client = v4l2_get_subdevdata(&ov2740->sd); - int ret; - u32 val; - - ret = ov2740_read_reg(ov2740, OV2740_REG_CHIP_ID, 3, &val); - if (ret) - return ret; - - if (val != OV2740_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x", - OV2740_CHIP_ID, val); - return -ENXIO; - } - - return 0; -} - static int ov2740_check_hwcfg(struct device *dev) { struct fwnode_handle *ep; @@ -1137,6 +1149,7 @@ static int ov2740_probe(struct i2c_client *client) { struct ov2740 *ov2740; int ret = 0; + bool full_power; ret = ov2740_check_hwcfg(&client->dev); if (ret) { @@ -1149,6 +1162,15 @@ static int ov2740_probe(struct i2c_client *client) if (!ov2740) return -ENOMEM; + full_power = acpi_dev_state_d0(&client->dev); + if (full_power) { + ret = ov2740_identify_module(ov2740); + if (ret) { + dev_err(&client->dev, "failed to find sensor: %d", ret); + return ret; + } + } + v4l2_i2c_subdev_init(&ov2740->sd, client, &ov2740_subdev_ops); ret = ov2740_identify_module(ov2740); if (ret) { @@ -1186,11 +1208,9 @@ static int ov2740_probe(struct i2c_client *client) if (ret) dev_warn(&client->dev, "register nvmem failed, ret %d\n", ret); - /* - * Device is already turned on by i2c-core with ACPI domain PM. - * Enable runtime PM and turn off the device. - */ - pm_runtime_set_active(&client->dev); + /* Set the device's state to active if it's in D0 state. */ + if (full_power) + pm_runtime_set_active(&client->dev); pm_runtime_enable(&client->dev); pm_runtime_idle(&client->dev); @@ -1225,6 +1245,7 @@ static struct i2c_driver ov2740_i2c_driver = { }, .probe_new = ov2740_probe, .remove = ov2740_remove, + .flags = I2C_DRV_ACPI_WAIVE_D0_PROBE, }; module_i2c_driver(ov2740_i2c_driver); diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c index 251f459ab484..02f75c18e480 100644 --- a/drivers/media/i2c/ov5670.c +++ b/drivers/media/i2c/ov5670.c @@ -1833,6 +1833,8 @@ struct ov5670 { /* Streaming on/off */ bool streaming; + /* True if the device has been identified */ + bool identified; }; #define to_ov5670(_sd) container_of(_sd, struct ov5670, sd) @@ -2273,6 +2275,32 @@ static int ov5670_get_skip_frames(struct v4l2_subdev *sd, u32 *frames) return 0; } +/* Verify chip ID */ +static int ov5670_identify_module(struct ov5670 *ov5670) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); + int ret; + u32 val; + + if (ov5670->identified) + return 0; + + ret = ov5670_read_reg(ov5670, OV5670_REG_CHIP_ID, + OV5670_REG_VALUE_24BIT, &val); + if (ret) + return ret; + + if (val != OV5670_CHIP_ID) { + dev_err(&client->dev, "chip id mismatch: %x!=%x\n", + OV5670_CHIP_ID, val); + return -ENXIO; + } + + ov5670->identified = true; + + return 0; +} + /* Prepare streaming by writing default values and customized values */ static int ov5670_start_streaming(struct ov5670 *ov5670) { @@ -2281,6 +2309,10 @@ static int ov5670_start_streaming(struct ov5670 *ov5670) int link_freq_index; int ret; + ret = ov5670_identify_module(ov5670); + if (ret) + return ret; + /* Get out of from software reset */ ret = ov5670_write_reg(ov5670, OV5670_REG_SOFTWARE_RST, OV5670_REG_VALUE_08BIT, OV5670_SOFTWARE_RST); @@ -2400,27 +2432,6 @@ static int __maybe_unused ov5670_resume(struct device *dev) return 0; } -/* Verify chip ID */ -static int ov5670_identify_module(struct ov5670 *ov5670) -{ - struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); - int ret; - u32 val; - - ret = ov5670_read_reg(ov5670, OV5670_REG_CHIP_ID, - OV5670_REG_VALUE_24BIT, &val); - if (ret) - return ret; - - if (val != OV5670_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x\n", - OV5670_CHIP_ID, val); - return -ENXIO; - } - - return 0; -} - static const struct v4l2_subdev_core_ops ov5670_core_ops = { .log_status = v4l2_ctrl_subdev_log_status, .subscribe_event = v4l2_ctrl_subdev_subscribe_event, @@ -2462,6 +2473,7 @@ static int ov5670_probe(struct i2c_client *client) struct ov5670 *ov5670; const char *err_msg; u32 input_clk = 0; + bool full_power; int ret; device_property_read_u32(&client->dev, "clock-frequency", &input_clk); @@ -2478,11 +2490,14 @@ static int ov5670_probe(struct i2c_client *client) /* Initialize subdev */ v4l2_i2c_subdev_init(&ov5670->sd, client, &ov5670_subdev_ops); - /* Check module identity */ - ret = ov5670_identify_module(ov5670); - if (ret) { - err_msg = "ov5670_identify_module() error"; - goto error_print; + full_power = acpi_dev_state_d0(&client->dev); + if (full_power) { + /* Check module identity */ + ret = ov5670_identify_module(ov5670); + if (ret) { + err_msg = "ov5670_identify_module() error"; + goto error_print; + } } mutex_init(&ov5670->mutex); @@ -2519,11 +2534,9 @@ static int ov5670_probe(struct i2c_client *client) ov5670->streaming = false; - /* - * Device is already turned on by i2c-core with ACPI domain PM. - * Enable runtime PM and turn off the device. - */ - pm_runtime_set_active(&client->dev); + /* Set the device's state to active if it's in D0 state. */ + if (full_power) + pm_runtime_set_active(&client->dev); pm_runtime_enable(&client->dev); pm_runtime_idle(&client->dev); @@ -2565,7 +2578,7 @@ static const struct dev_pm_ops ov5670_pm_ops = { #ifdef CONFIG_ACPI static const struct acpi_device_id ov5670_acpi_ids[] = { - {"INT3479"}, + { "INT3479" }, { /* sentinel */ } }; @@ -2580,11 +2593,12 @@ static struct i2c_driver ov5670_i2c_driver = { }, .probe_new = ov5670_probe, .remove = ov5670_remove, + .flags = I2C_DRV_ACPI_WAIVE_D0_PROBE, }; module_i2c_driver(ov5670_i2c_driver); MODULE_AUTHOR("Rapolu, Chiranjeevi <chiranjeevi.rapolu@intel.com>"); -MODULE_AUTHOR("Yang, Hyungwoo <hyungwoo.yang@intel.com>"); +MODULE_AUTHOR("Yang, Hyungwoo"); MODULE_DESCRIPTION("Omnivision ov5670 sensor driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/ov5675.c b/drivers/media/i2c/ov5675.c index da5850b7ad07..00925850fa7c 100644 --- a/drivers/media/i2c/ov5675.c +++ b/drivers/media/i2c/ov5675.c @@ -493,6 +493,9 @@ struct ov5675 { /* Streaming on/off */ bool streaming; + + /* True if the device has been identified */ + bool identified; }; static u64 to_pixel_rate(u32 f_index) @@ -808,12 +811,41 @@ static void ov5675_update_pad_format(const struct ov5675_mode *mode, fmt->field = V4L2_FIELD_NONE; } +static int ov5675_identify_module(struct ov5675 *ov5675) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd); + int ret; + u32 val; + + if (ov5675->identified) + return 0; + + ret = ov5675_read_reg(ov5675, OV5675_REG_CHIP_ID, + OV5675_REG_VALUE_24BIT, &val); + if (ret) + return ret; + + if (val != OV5675_CHIP_ID) { + dev_err(&client->dev, "chip id mismatch: %x!=%x", + OV5675_CHIP_ID, val); + return -ENXIO; + } + + ov5675->identified = true; + + return 0; +} + static int ov5675_start_streaming(struct ov5675 *ov5675) { struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd); const struct ov5675_reg_list *reg_list; int link_freq_index, ret; + ret = ov5675_identify_module(ov5675); + if (ret) + return ret; + link_freq_index = ov5675->cur_mode->link_freq_index; reg_list = &link_freq_configs[link_freq_index].reg_list; ret = ov5675_write_reg_list(ov5675, reg_list); @@ -1048,26 +1080,6 @@ static const struct v4l2_subdev_internal_ops ov5675_internal_ops = { .open = ov5675_open, }; -static int ov5675_identify_module(struct ov5675 *ov5675) -{ - struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd); - int ret; - u32 val; - - ret = ov5675_read_reg(ov5675, OV5675_REG_CHIP_ID, - OV5675_REG_VALUE_24BIT, &val); - if (ret) - return ret; - - if (val != OV5675_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x", - OV5675_CHIP_ID, val); - return -ENXIO; - } - - return 0; -} - static int ov5675_check_hwcfg(struct device *dev) { struct fwnode_handle *ep; @@ -1154,6 +1166,7 @@ static int ov5675_remove(struct i2c_client *client) static int ov5675_probe(struct i2c_client *client) { struct ov5675 *ov5675; + bool full_power; int ret; ret = ov5675_check_hwcfg(&client->dev); @@ -1168,10 +1181,14 @@ static int ov5675_probe(struct i2c_client *client) return -ENOMEM; v4l2_i2c_subdev_init(&ov5675->sd, client, &ov5675_subdev_ops); - ret = ov5675_identify_module(ov5675); - if (ret) { - dev_err(&client->dev, "failed to find sensor: %d", ret); - return ret; + + full_power = acpi_dev_state_d0(&client->dev); + if (full_power) { + ret = ov5675_identify_module(ov5675); + if (ret) { + dev_err(&client->dev, "failed to find sensor: %d", ret); + return ret; + } } mutex_init(&ov5675->mutex); @@ -1204,7 +1221,10 @@ static int ov5675_probe(struct i2c_client *client) * Device is already turned on by i2c-core with ACPI domain PM. * Enable runtime PM and turn off the device. */ - pm_runtime_set_active(&client->dev); + + /* Set the device's state to active if it's in D0 state. */ + if (full_power) + pm_runtime_set_active(&client->dev); pm_runtime_enable(&client->dev); pm_runtime_idle(&client->dev); @@ -1241,6 +1261,7 @@ static struct i2c_driver ov5675_i2c_driver = { }, .probe_new = ov5675_probe, .remove = ov5675_remove, + .flags = I2C_DRV_ACPI_WAIVE_D0_PROBE, }; module_i2c_driver(ov5675_i2c_driver); diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c new file mode 100644 index 000000000000..2784fcf67f3b --- /dev/null +++ b/drivers/media/i2c/ov5693.c @@ -0,0 +1,1537 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2013 Intel Corporation. All Rights Reserved. + * + * Adapted from the atomisp-ov5693 driver, with contributions from: + * + * Daniel Scally + * Jean-Michel Hautbois + * Fabian Wuthrich + * Tsuchiya Yuto + * Jordan Hand + * Jake Day + */ + +#include <asm/unaligned.h> +#include <linux/acpi.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> + +#define OV5693_REG_8BIT(n) ((1 << 16) | (n)) +#define OV5693_REG_16BIT(n) ((2 << 16) | (n)) +#define OV5693_REG_24BIT(n) ((3 << 16) | (n)) +#define OV5693_REG_SIZE_SHIFT 16 +#define OV5693_REG_ADDR_MASK 0xffff + +/* System Control */ +#define OV5693_SW_RESET_REG OV5693_REG_8BIT(0x0103) +#define OV5693_SW_STREAM_REG OV5693_REG_8BIT(0x0100) +#define OV5693_START_STREAMING 0x01 +#define OV5693_STOP_STREAMING 0x00 +#define OV5693_SW_RESET 0x01 + +#define OV5693_REG_CHIP_ID OV5693_REG_16BIT(0x300a) +/* Yes, this is right. The datasheet for the OV5693 gives its ID as 0x5690 */ +#define OV5693_CHIP_ID 0x5690 + +/* Exposure */ +#define OV5693_EXPOSURE_CTRL_REG OV5693_REG_24BIT(0x3500) +#define OV5693_EXPOSURE_CTRL_MASK GENMASK(19, 4) +#define OV5693_INTEGRATION_TIME_MARGIN 8 +#define OV5693_EXPOSURE_MIN 1 +#define OV5693_EXPOSURE_STEP 1 + +/* Analogue Gain */ +#define OV5693_GAIN_CTRL_REG OV5693_REG_16BIT(0x350a) +#define OV5693_GAIN_CTRL_MASK GENMASK(10, 4) +#define OV5693_GAIN_MIN 1 +#define OV5693_GAIN_MAX 127 +#define OV5693_GAIN_DEF 8 +#define OV5693_GAIN_STEP 1 + +/* Digital Gain */ +#define OV5693_MWB_RED_GAIN_REG OV5693_REG_16BIT(0x3400) +#define OV5693_MWB_GREEN_GAIN_REG OV5693_REG_16BIT(0x3402) +#define OV5693_MWB_BLUE_GAIN_REG OV5693_REG_16BIT(0x3404) +#define OV5693_MWB_GAIN_MASK GENMASK(11, 0) +#define OV5693_MWB_GAIN_MAX 0x0fff +#define OV5693_DIGITAL_GAIN_MIN 1 +#define OV5693_DIGITAL_GAIN_MAX 4095 +#define OV5693_DIGITAL_GAIN_DEF 1024 +#define OV5693_DIGITAL_GAIN_STEP 1 + +/* Timing and Format */ +#define OV5693_CROP_START_X_REG OV5693_REG_16BIT(0x3800) +#define OV5693_CROP_START_Y_REG OV5693_REG_16BIT(0x3802) +#define OV5693_CROP_END_X_REG OV5693_REG_16BIT(0x3804) +#define OV5693_CROP_END_Y_REG OV5693_REG_16BIT(0x3806) +#define OV5693_OUTPUT_SIZE_X_REG OV5693_REG_16BIT(0x3808) +#define OV5693_OUTPUT_SIZE_Y_REG OV5693_REG_16BIT(0x380a) + +#define OV5693_TIMING_HTS_REG OV5693_REG_16BIT(0x380c) +#define OV5693_FIXED_PPL 2688U +#define OV5693_TIMING_VTS_REG OV5693_REG_16BIT(0x380e) +#define OV5693_TIMING_MAX_VTS 0xffff +#define OV5693_TIMING_MIN_VTS 0x04 + +#define OV5693_OFFSET_START_X_REG OV5693_REG_16BIT(0x3810) +#define OV5693_OFFSET_START_Y_REG OV5693_REG_16BIT(0x3812) + +#define OV5693_SUB_INC_X_REG OV5693_REG_8BIT(0x3814) +#define OV5693_SUB_INC_Y_REG OV5693_REG_8BIT(0x3815) + +#define OV5693_FORMAT1_REG OV5693_REG_8BIT(0x3820) +#define OV5693_FORMAT1_FLIP_VERT_ISP_EN BIT(6) +#define OV5693_FORMAT1_FLIP_VERT_SENSOR_EN BIT(1) +#define OV5693_FORMAT1_VBIN_EN BIT(0) +#define OV5693_FORMAT2_REG OV5693_REG_8BIT(0x3821) +#define OV5693_FORMAT2_HDR_EN BIT(7) +#define OV5693_FORMAT2_FLIP_HORZ_ISP_EN BIT(2) +#define OV5693_FORMAT2_FLIP_HORZ_SENSOR_EN BIT(1) +#define OV5693_FORMAT2_HBIN_EN BIT(0) + +#define OV5693_ISP_CTRL2_REG OV5693_REG_8BIT(0x5002) +#define OV5693_ISP_SCALE_ENABLE BIT(7) + +/* Pixel Array */ +#define OV5693_NATIVE_WIDTH 2624 +#define OV5693_NATIVE_HEIGHT 1956 +#define OV5693_NATIVE_START_LEFT 0 +#define OV5693_NATIVE_START_TOP 0 +#define OV5693_ACTIVE_WIDTH 2592 +#define OV5693_ACTIVE_HEIGHT 1944 +#define OV5693_ACTIVE_START_LEFT 16 +#define OV5693_ACTIVE_START_TOP 6 +#define OV5693_MIN_CROP_WIDTH 2 +#define OV5693_MIN_CROP_HEIGHT 2 + +/* Test Pattern */ +#define OV5693_TEST_PATTERN_REG OV5693_REG_8BIT(0x5e00) +#define OV5693_TEST_PATTERN_ENABLE BIT(7) +#define OV5693_TEST_PATTERN_ROLLING BIT(6) +#define OV5693_TEST_PATTERN_RANDOM 0x01 +#define OV5693_TEST_PATTERN_BARS 0x00 + +/* System Frequencies */ +#define OV5693_XVCLK_FREQ 19200000 +#define OV5693_LINK_FREQ_419_2MHZ 419200000 +#define OV5693_PIXEL_RATE 167680000 + +/* Miscellaneous */ +#define OV5693_NUM_SUPPLIES 2 + +#define to_ov5693_sensor(x) container_of(x, struct ov5693_device, sd) + +struct ov5693_reg { + u32 reg; + u8 val; +}; + +struct ov5693_reg_list { + u32 num_regs; + const struct ov5693_reg *regs; +}; + +struct ov5693_device { + struct i2c_client *client; + struct device *dev; + + /* Protect against concurrent changes to controls */ + struct mutex lock; + + struct gpio_desc *reset; + struct gpio_desc *powerdown; + struct regulator_bulk_data supplies[OV5693_NUM_SUPPLIES]; + struct clk *clk; + + struct ov5693_mode { + struct v4l2_rect crop; + struct v4l2_mbus_framefmt format; + bool binning_x; + bool binning_y; + unsigned int inc_x_odd; + unsigned int inc_y_odd; + unsigned int vts; + } mode; + bool streaming; + + struct v4l2_subdev sd; + struct media_pad pad; + + struct ov5693_v4l2_ctrls { + struct v4l2_ctrl_handler handler; + struct v4l2_ctrl *link_freq; + struct v4l2_ctrl *pixel_rate; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *analogue_gain; + struct v4l2_ctrl *digital_gain; + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *test_pattern; + } ctrls; +}; + +static const struct ov5693_reg ov5693_global_regs[] = { + {OV5693_REG_8BIT(0x3016), 0xf0}, + {OV5693_REG_8BIT(0x3017), 0xf0}, + {OV5693_REG_8BIT(0x3018), 0xf0}, + {OV5693_REG_8BIT(0x3022), 0x01}, + {OV5693_REG_8BIT(0x3028), 0x44}, + {OV5693_REG_8BIT(0x3098), 0x02}, + {OV5693_REG_8BIT(0x3099), 0x19}, + {OV5693_REG_8BIT(0x309a), 0x02}, + {OV5693_REG_8BIT(0x309b), 0x01}, + {OV5693_REG_8BIT(0x309c), 0x00}, + {OV5693_REG_8BIT(0x30a0), 0xd2}, + {OV5693_REG_8BIT(0x30a2), 0x01}, + {OV5693_REG_8BIT(0x30b2), 0x00}, + {OV5693_REG_8BIT(0x30b3), 0x83}, + {OV5693_REG_8BIT(0x30b4), 0x03}, + {OV5693_REG_8BIT(0x30b5), 0x04}, + {OV5693_REG_8BIT(0x30b6), 0x01}, + {OV5693_REG_8BIT(0x3080), 0x01}, + {OV5693_REG_8BIT(0x3104), 0x21}, + {OV5693_REG_8BIT(0x3106), 0x00}, + {OV5693_REG_8BIT(0x3406), 0x01}, + {OV5693_REG_8BIT(0x3503), 0x07}, + {OV5693_REG_8BIT(0x350b), 0x40}, + {OV5693_REG_8BIT(0x3601), 0x0a}, + {OV5693_REG_8BIT(0x3602), 0x38}, + {OV5693_REG_8BIT(0x3612), 0x80}, + {OV5693_REG_8BIT(0x3620), 0x54}, + {OV5693_REG_8BIT(0x3621), 0xc7}, + {OV5693_REG_8BIT(0x3622), 0x0f}, + {OV5693_REG_8BIT(0x3625), 0x10}, + {OV5693_REG_8BIT(0x3630), 0x55}, + {OV5693_REG_8BIT(0x3631), 0xf4}, + {OV5693_REG_8BIT(0x3632), 0x00}, + {OV5693_REG_8BIT(0x3633), 0x34}, + {OV5693_REG_8BIT(0x3634), 0x02}, + {OV5693_REG_8BIT(0x364d), 0x0d}, + {OV5693_REG_8BIT(0x364f), 0xdd}, + {OV5693_REG_8BIT(0x3660), 0x04}, + {OV5693_REG_8BIT(0x3662), 0x10}, + {OV5693_REG_8BIT(0x3663), 0xf1}, + {OV5693_REG_8BIT(0x3665), 0x00}, + {OV5693_REG_8BIT(0x3666), 0x20}, + {OV5693_REG_8BIT(0x3667), 0x00}, + {OV5693_REG_8BIT(0x366a), 0x80}, + {OV5693_REG_8BIT(0x3680), 0xe0}, + {OV5693_REG_8BIT(0x3681), 0x00}, + {OV5693_REG_8BIT(0x3700), 0x42}, + {OV5693_REG_8BIT(0x3701), 0x14}, + {OV5693_REG_8BIT(0x3702), 0xa0}, + {OV5693_REG_8BIT(0x3703), 0xd8}, + {OV5693_REG_8BIT(0x3704), 0x78}, + {OV5693_REG_8BIT(0x3705), 0x02}, + {OV5693_REG_8BIT(0x370a), 0x00}, + {OV5693_REG_8BIT(0x370b), 0x20}, + {OV5693_REG_8BIT(0x370c), 0x0c}, + {OV5693_REG_8BIT(0x370d), 0x11}, + {OV5693_REG_8BIT(0x370e), 0x00}, + {OV5693_REG_8BIT(0x370f), 0x40}, + {OV5693_REG_8BIT(0x3710), 0x00}, + {OV5693_REG_8BIT(0x371a), 0x1c}, + {OV5693_REG_8BIT(0x371b), 0x05}, + {OV5693_REG_8BIT(0x371c), 0x01}, + {OV5693_REG_8BIT(0x371e), 0xa1}, + {OV5693_REG_8BIT(0x371f), 0x0c}, + {OV5693_REG_8BIT(0x3721), 0x00}, + {OV5693_REG_8BIT(0x3724), 0x10}, + {OV5693_REG_8BIT(0x3726), 0x00}, + {OV5693_REG_8BIT(0x372a), 0x01}, + {OV5693_REG_8BIT(0x3730), 0x10}, + {OV5693_REG_8BIT(0x3738), 0x22}, + {OV5693_REG_8BIT(0x3739), 0xe5}, + {OV5693_REG_8BIT(0x373a), 0x50}, + {OV5693_REG_8BIT(0x373b), 0x02}, + {OV5693_REG_8BIT(0x373c), 0x41}, + {OV5693_REG_8BIT(0x373f), 0x02}, + {OV5693_REG_8BIT(0x3740), 0x42}, + {OV5693_REG_8BIT(0x3741), 0x02}, + {OV5693_REG_8BIT(0x3742), 0x18}, + {OV5693_REG_8BIT(0x3743), 0x01}, + {OV5693_REG_8BIT(0x3744), 0x02}, + {OV5693_REG_8BIT(0x3747), 0x10}, + {OV5693_REG_8BIT(0x374c), 0x04}, + {OV5693_REG_8BIT(0x3751), 0xf0}, + {OV5693_REG_8BIT(0x3752), 0x00}, + {OV5693_REG_8BIT(0x3753), 0x00}, + {OV5693_REG_8BIT(0x3754), 0xc0}, + {OV5693_REG_8BIT(0x3755), 0x00}, + {OV5693_REG_8BIT(0x3756), 0x1a}, + {OV5693_REG_8BIT(0x3758), 0x00}, + {OV5693_REG_8BIT(0x3759), 0x0f}, + {OV5693_REG_8BIT(0x376b), 0x44}, + {OV5693_REG_8BIT(0x375c), 0x04}, + {OV5693_REG_8BIT(0x3774), 0x10}, + {OV5693_REG_8BIT(0x3776), 0x00}, + {OV5693_REG_8BIT(0x377f), 0x08}, + {OV5693_REG_8BIT(0x3780), 0x22}, + {OV5693_REG_8BIT(0x3781), 0x0c}, + {OV5693_REG_8BIT(0x3784), 0x2c}, + {OV5693_REG_8BIT(0x3785), 0x1e}, + {OV5693_REG_8BIT(0x378f), 0xf5}, + {OV5693_REG_8BIT(0x3791), 0xb0}, + {OV5693_REG_8BIT(0x3795), 0x00}, + {OV5693_REG_8BIT(0x3796), 0x64}, + {OV5693_REG_8BIT(0x3797), 0x11}, + {OV5693_REG_8BIT(0x3798), 0x30}, + {OV5693_REG_8BIT(0x3799), 0x41}, + {OV5693_REG_8BIT(0x379a), 0x07}, + {OV5693_REG_8BIT(0x379b), 0xb0}, + {OV5693_REG_8BIT(0x379c), 0x0c}, + {OV5693_REG_8BIT(0x3a04), 0x06}, + {OV5693_REG_8BIT(0x3a05), 0x14}, + {OV5693_REG_8BIT(0x3e07), 0x20}, + {OV5693_REG_8BIT(0x4000), 0x08}, + {OV5693_REG_8BIT(0x4001), 0x04}, + {OV5693_REG_8BIT(0x4004), 0x08}, + {OV5693_REG_8BIT(0x4006), 0x20}, + {OV5693_REG_8BIT(0x4008), 0x24}, + {OV5693_REG_8BIT(0x4009), 0x10}, + {OV5693_REG_8BIT(0x4058), 0x00}, + {OV5693_REG_8BIT(0x4101), 0xb2}, + {OV5693_REG_8BIT(0x4307), 0x31}, + {OV5693_REG_8BIT(0x4511), 0x05}, + {OV5693_REG_8BIT(0x4512), 0x01}, + {OV5693_REG_8BIT(0x481f), 0x30}, + {OV5693_REG_8BIT(0x4826), 0x2c}, + {OV5693_REG_8BIT(0x4d02), 0xfd}, + {OV5693_REG_8BIT(0x4d03), 0xf5}, + {OV5693_REG_8BIT(0x4d04), 0x0c}, + {OV5693_REG_8BIT(0x4d05), 0xcc}, + {OV5693_REG_8BIT(0x4837), 0x0a}, + {OV5693_REG_8BIT(0x5003), 0x20}, + {OV5693_REG_8BIT(0x5013), 0x00}, + {OV5693_REG_8BIT(0x5842), 0x01}, + {OV5693_REG_8BIT(0x5843), 0x2b}, + {OV5693_REG_8BIT(0x5844), 0x01}, + {OV5693_REG_8BIT(0x5845), 0x92}, + {OV5693_REG_8BIT(0x5846), 0x01}, + {OV5693_REG_8BIT(0x5847), 0x8f}, + {OV5693_REG_8BIT(0x5848), 0x01}, + {OV5693_REG_8BIT(0x5849), 0x0c}, + {OV5693_REG_8BIT(0x5e10), 0x0c}, + {OV5693_REG_8BIT(0x3820), 0x00}, + {OV5693_REG_8BIT(0x3821), 0x1e}, + {OV5693_REG_8BIT(0x5041), 0x14} +}; + +static const struct ov5693_reg_list ov5693_global_setting = { + .num_regs = ARRAY_SIZE(ov5693_global_regs), + .regs = ov5693_global_regs, +}; + +static const struct v4l2_rect ov5693_default_crop = { + .left = OV5693_ACTIVE_START_LEFT, + .top = OV5693_ACTIVE_START_TOP, + .width = OV5693_ACTIVE_WIDTH, + .height = OV5693_ACTIVE_HEIGHT, +}; + +static const struct v4l2_mbus_framefmt ov5693_default_fmt = { + .width = OV5693_ACTIVE_WIDTH, + .height = OV5693_ACTIVE_HEIGHT, + .code = MEDIA_BUS_FMT_SBGGR10_1X10, +}; + +static const s64 link_freq_menu_items[] = { + OV5693_LINK_FREQ_419_2MHZ +}; + +static const char * const ov5693_supply_names[] = { + "avdd", + "dovdd", +}; + +static const char * const ov5693_test_pattern_menu[] = { + "Disabled", + "Random Data", + "Colour Bars", + "Colour Bars with Rolling Bar" +}; + +static const u8 ov5693_test_pattern_bits[] = { + 0, + OV5693_TEST_PATTERN_ENABLE | OV5693_TEST_PATTERN_RANDOM, + OV5693_TEST_PATTERN_ENABLE | OV5693_TEST_PATTERN_BARS, + OV5693_TEST_PATTERN_ENABLE | OV5693_TEST_PATTERN_BARS | + OV5693_TEST_PATTERN_ROLLING, +}; + +/* I2C I/O Operations */ + +static int ov5693_read_reg(struct ov5693_device *ov5693, u32 addr, u32 *value) +{ + struct i2c_client *client = ov5693->client; + __be16 reg; + u8 val[4]; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 2, + .buf = (u8 *)®, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .buf = (u8 *)&val, + }, + }; + unsigned int len = ((addr >> OV5693_REG_SIZE_SHIFT) & 3); + unsigned int i; + int ret; + + reg = cpu_to_be16(addr & OV5693_REG_ADDR_MASK); + + msg[1].len = len; + + ret = i2c_transfer(client->adapter, msg, 2); + if (ret < 0) + return dev_err_probe(&client->dev, ret, + "Failed to read register 0x%04x: %d\n", + addr & OV5693_REG_ADDR_MASK, ret); + + *value = 0; + for (i = 0; i < len; ++i) { + *value <<= 8; + *value |= val[i]; + } + + return 0; +} + +static void ov5693_write_reg(struct ov5693_device *ov5693, u32 addr, u32 value, + int *error) +{ + struct i2c_client *client = ov5693->client; + struct { + __be16 reg; + u8 val[4]; + } __packed buf; + struct i2c_msg msg = { + .addr = client->addr, + .buf = (u8 *)&buf, + }; + unsigned int len = ((addr >> OV5693_REG_SIZE_SHIFT) & 3); + unsigned int i; + int ret; + + if (*error < 0) + return; + + buf.reg = cpu_to_be16(addr & OV5693_REG_ADDR_MASK); + for (i = 0; i < len; ++i) { + buf.val[len - i - 1] = value & 0xff; + value >>= 8; + } + + msg.len = len + 2; + + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret < 0) { + dev_err(&client->dev, "Failed to write register 0x%04x: %d\n", + addr & OV5693_REG_ADDR_MASK, ret); + *error = ret; + } +} + +static int ov5693_write_reg_array(struct ov5693_device *ov5693, + const struct ov5693_reg_list *reglist) +{ + unsigned int i; + int ret = 0; + + for (i = 0; i < reglist->num_regs; i++) + ov5693_write_reg(ov5693, reglist->regs[i].reg, + reglist->regs[i].val, &ret); + + return ret; +} + +static int ov5693_update_bits(struct ov5693_device *ov5693, u32 address, + u32 mask, u32 bits) +{ + u32 value = 0; + int ret; + + ret = ov5693_read_reg(ov5693, address, &value); + if (ret) + return ret; + + value &= ~mask; + value |= bits; + + ov5693_write_reg(ov5693, address, value, &ret); + + return ret; +} + +/* V4L2 Controls Functions */ + +static int ov5693_flip_vert_configure(struct ov5693_device *ov5693, + bool enable) +{ + u8 bits = OV5693_FORMAT1_FLIP_VERT_ISP_EN | + OV5693_FORMAT1_FLIP_VERT_SENSOR_EN; + int ret; + + ret = ov5693_update_bits(ov5693, OV5693_FORMAT1_REG, bits, + enable ? bits : 0); + if (ret) + return ret; + + return 0; +} + +static int ov5693_flip_horz_configure(struct ov5693_device *ov5693, + bool enable) +{ + u8 bits = OV5693_FORMAT2_FLIP_HORZ_ISP_EN | + OV5693_FORMAT2_FLIP_HORZ_SENSOR_EN; + int ret; + + ret = ov5693_update_bits(ov5693, OV5693_FORMAT2_REG, bits, + enable ? bits : 0); + if (ret) + return ret; + + return 0; +} + +static int ov5693_get_exposure(struct ov5693_device *ov5693, s32 *value) +{ + u32 exposure; + int ret; + + ret = ov5693_read_reg(ov5693, OV5693_EXPOSURE_CTRL_REG, &exposure); + if (ret) + return ret; + + /* The lowest 4 bits are unsupported fractional bits */ + *value = exposure >> 4; + + return 0; +} + +static int ov5693_exposure_configure(struct ov5693_device *ov5693, + u32 exposure) +{ + int ret = 0; + + exposure = (exposure << 4) & OV5693_EXPOSURE_CTRL_MASK; + + ov5693_write_reg(ov5693, OV5693_EXPOSURE_CTRL_REG, exposure, &ret); + + return ret; +} + +static int ov5693_get_gain(struct ov5693_device *ov5693, u32 *gain) +{ + u32 value; + int ret; + + ret = ov5693_read_reg(ov5693, OV5693_GAIN_CTRL_REG, &value); + if (ret) + return ret; + + /* As with exposure, the lowest 4 bits are fractional bits. */ + *gain = value >> 4; + + return ret; +} + +static int ov5693_digital_gain_configure(struct ov5693_device *ov5693, + u32 gain) +{ + int ret = 0; + + gain &= OV5693_MWB_GAIN_MASK; + + ov5693_write_reg(ov5693, OV5693_MWB_RED_GAIN_REG, gain, &ret); + ov5693_write_reg(ov5693, OV5693_MWB_GREEN_GAIN_REG, gain, &ret); + ov5693_write_reg(ov5693, OV5693_MWB_BLUE_GAIN_REG, gain, &ret); + + return ret; +} + +static int ov5693_analog_gain_configure(struct ov5693_device *ov5693, u32 gain) +{ + int ret = 0; + + gain = (gain << 4) & OV5693_GAIN_CTRL_MASK; + + ov5693_write_reg(ov5693, OV5693_GAIN_CTRL_REG, gain, &ret); + + return ret; +} + +static int ov5693_vts_configure(struct ov5693_device *ov5693, u32 vblank) +{ + u16 vts = ov5693->mode.format.height + vblank; + int ret = 0; + + ov5693_write_reg(ov5693, OV5693_TIMING_VTS_REG, vts, &ret); + + return ret; +} + +static int ov5693_test_pattern_configure(struct ov5693_device *ov5693, u32 idx) +{ + int ret = 0; + + ov5693_write_reg(ov5693, OV5693_TEST_PATTERN_REG, + ov5693_test_pattern_bits[idx], &ret); + + return ret; +} + +static int ov5693_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov5693_device *ov5693 = + container_of(ctrl->handler, struct ov5693_device, ctrls.handler); + int ret = 0; + + /* If VBLANK is altered we need to update exposure to compensate */ + if (ctrl->id == V4L2_CID_VBLANK) { + int exposure_max; + + exposure_max = ov5693->mode.format.height + ctrl->val - + OV5693_INTEGRATION_TIME_MARGIN; + __v4l2_ctrl_modify_range(ov5693->ctrls.exposure, + ov5693->ctrls.exposure->minimum, + exposure_max, + ov5693->ctrls.exposure->step, + min(ov5693->ctrls.exposure->val, + exposure_max)); + } + + /* Only apply changes to the controls if the device is powered up */ + if (!pm_runtime_get_if_in_use(ov5693->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + ret = ov5693_exposure_configure(ov5693, ctrl->val); + break; + case V4L2_CID_ANALOGUE_GAIN: + ret = ov5693_analog_gain_configure(ov5693, ctrl->val); + break; + case V4L2_CID_DIGITAL_GAIN: + ret = ov5693_digital_gain_configure(ov5693, ctrl->val); + break; + case V4L2_CID_HFLIP: + ret = ov5693_flip_horz_configure(ov5693, !!ctrl->val); + break; + case V4L2_CID_VFLIP: + ret = ov5693_flip_vert_configure(ov5693, !!ctrl->val); + break; + case V4L2_CID_VBLANK: + ret = ov5693_vts_configure(ov5693, ctrl->val); + break; + case V4L2_CID_TEST_PATTERN: + ret = ov5693_test_pattern_configure(ov5693, ctrl->val); + break; + default: + ret = -EINVAL; + } + + pm_runtime_put(ov5693->dev); + + return ret; +} + +static int ov5693_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov5693_device *ov5693 = container_of(ctrl->handler, + struct ov5693_device, + ctrls.handler); + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE_ABSOLUTE: + return ov5693_get_exposure(ov5693, &ctrl->val); + case V4L2_CID_AUTOGAIN: + return ov5693_get_gain(ov5693, &ctrl->val); + default: + return -EINVAL; + } +} + +static const struct v4l2_ctrl_ops ov5693_ctrl_ops = { + .s_ctrl = ov5693_s_ctrl, + .g_volatile_ctrl = ov5693_g_volatile_ctrl +}; + +/* System Control Functions */ + +static int ov5693_mode_configure(struct ov5693_device *ov5693) +{ + const struct ov5693_mode *mode = &ov5693->mode; + int ret = 0; + + /* Crop Start X */ + ov5693_write_reg(ov5693, OV5693_CROP_START_X_REG, mode->crop.left, + &ret); + + /* Offset X */ + ov5693_write_reg(ov5693, OV5693_OFFSET_START_X_REG, 0, &ret); + + /* Output Size X */ + ov5693_write_reg(ov5693, OV5693_OUTPUT_SIZE_X_REG, mode->format.width, + &ret); + + /* Crop End X */ + ov5693_write_reg(ov5693, OV5693_CROP_END_X_REG, + mode->crop.left + mode->crop.width, &ret); + + /* Horizontal Total Size */ + ov5693_write_reg(ov5693, OV5693_TIMING_HTS_REG, OV5693_FIXED_PPL, + &ret); + + /* Crop Start Y */ + ov5693_write_reg(ov5693, OV5693_CROP_START_Y_REG, mode->crop.top, + &ret); + + /* Offset Y */ + ov5693_write_reg(ov5693, OV5693_OFFSET_START_Y_REG, 0, &ret); + + /* Output Size Y */ + ov5693_write_reg(ov5693, OV5693_OUTPUT_SIZE_Y_REG, mode->format.height, + &ret); + + /* Crop End Y */ + ov5693_write_reg(ov5693, OV5693_CROP_END_Y_REG, + mode->crop.top + mode->crop.height, &ret); + + /* Subsample X increase */ + ov5693_write_reg(ov5693, OV5693_SUB_INC_X_REG, + ((mode->inc_x_odd << 4) & 0xf0) | 0x01, &ret); + /* Subsample Y increase */ + ov5693_write_reg(ov5693, OV5693_SUB_INC_Y_REG, + ((mode->inc_y_odd << 4) & 0xf0) | 0x01, &ret); + + if (ret) + return ret; + + /* Binning */ + ret = ov5693_update_bits(ov5693, OV5693_FORMAT1_REG, + OV5693_FORMAT1_VBIN_EN, + mode->binning_y ? OV5693_FORMAT1_VBIN_EN : 0); + if (ret) + return ret; + + ret = ov5693_update_bits(ov5693, OV5693_FORMAT2_REG, + OV5693_FORMAT2_HBIN_EN, + mode->binning_x ? OV5693_FORMAT2_HBIN_EN : 0); + + return ret; +} + +static int ov5693_enable_streaming(struct ov5693_device *ov5693, bool enable) +{ + int ret = 0; + + ov5693_write_reg(ov5693, OV5693_SW_STREAM_REG, + enable ? OV5693_START_STREAMING : + OV5693_STOP_STREAMING, &ret); + + return ret; +} + +static int ov5693_sw_reset(struct ov5693_device *ov5693) +{ + int ret = 0; + + ov5693_write_reg(ov5693, OV5693_SW_RESET_REG, OV5693_SW_RESET, &ret); + + return ret; +} + +static int ov5693_sensor_init(struct ov5693_device *ov5693) +{ + int ret; + + ret = ov5693_sw_reset(ov5693); + if (ret) + return dev_err_probe(ov5693->dev, ret, + "software reset error\n"); + + ret = ov5693_write_reg_array(ov5693, &ov5693_global_setting); + if (ret) + return dev_err_probe(ov5693->dev, ret, + "global settings error\n"); + + ret = ov5693_mode_configure(ov5693); + if (ret) + return dev_err_probe(ov5693->dev, ret, + "mode configure error\n"); + + ret = ov5693_enable_streaming(ov5693, false); + if (ret) + dev_err(ov5693->dev, "stop streaming error\n"); + + return ret; +} + +static void ov5693_sensor_powerdown(struct ov5693_device *ov5693) +{ + gpiod_set_value_cansleep(ov5693->reset, 1); + gpiod_set_value_cansleep(ov5693->powerdown, 1); + + regulator_bulk_disable(OV5693_NUM_SUPPLIES, ov5693->supplies); + + clk_disable_unprepare(ov5693->clk); +} + +static int ov5693_sensor_powerup(struct ov5693_device *ov5693) +{ + int ret; + + gpiod_set_value_cansleep(ov5693->reset, 1); + gpiod_set_value_cansleep(ov5693->powerdown, 1); + + ret = clk_prepare_enable(ov5693->clk); + if (ret) { + dev_err(ov5693->dev, "Failed to enable clk\n"); + goto fail_power; + } + + ret = regulator_bulk_enable(OV5693_NUM_SUPPLIES, ov5693->supplies); + if (ret) { + dev_err(ov5693->dev, "Failed to enable regulators\n"); + goto fail_power; + } + + gpiod_set_value_cansleep(ov5693->powerdown, 0); + gpiod_set_value_cansleep(ov5693->reset, 0); + + usleep_range(5000, 7500); + + return 0; + +fail_power: + ov5693_sensor_powerdown(ov5693); + return ret; +} + +static int __maybe_unused ov5693_sensor_suspend(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov5693_device *ov5693 = to_ov5693_sensor(sd); + + ov5693_sensor_powerdown(ov5693); + + return 0; +} + +static int __maybe_unused ov5693_sensor_resume(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov5693_device *ov5693 = to_ov5693_sensor(sd); + int ret; + + mutex_lock(&ov5693->lock); + + ret = ov5693_sensor_powerup(ov5693); + if (ret) + goto out_unlock; + + ret = ov5693_sensor_init(ov5693); + if (ret) { + dev_err(dev, "ov5693 sensor init failure\n"); + goto err_power; + } + + goto out_unlock; + +err_power: + ov5693_sensor_powerdown(ov5693); +out_unlock: + mutex_unlock(&ov5693->lock); + return ret; +} + +static int ov5693_detect(struct ov5693_device *ov5693) +{ + int ret; + u32 id; + + ret = ov5693_read_reg(ov5693, OV5693_REG_CHIP_ID, &id); + if (ret) + return ret; + + if (id != OV5693_CHIP_ID) + return dev_err_probe(ov5693->dev, -ENODEV, + "sensor ID mismatch. Found 0x%04x\n", id); + + return 0; +} + +/* V4L2 Framework callbacks */ + +static unsigned int __ov5693_calc_vts(u32 height) +{ + /* + * We need to set a sensible default VTS for whatever format height we + * happen to be given from set_fmt(). This function just targets + * an even multiple of 30fps. + */ + + unsigned int tgt_fps; + + tgt_fps = rounddown(OV5693_PIXEL_RATE / OV5693_FIXED_PPL / height, 30); + + return ALIGN_DOWN(OV5693_PIXEL_RATE / OV5693_FIXED_PPL / tgt_fps, 2); +} + +static struct v4l2_mbus_framefmt * +__ov5693_get_pad_format(struct ov5693_device *ov5693, + struct v4l2_subdev_state *state, + unsigned int pad, enum v4l2_subdev_format_whence which) +{ + switch (which) { + case V4L2_SUBDEV_FORMAT_TRY: + return v4l2_subdev_get_try_format(&ov5693->sd, state, pad); + case V4L2_SUBDEV_FORMAT_ACTIVE: + return &ov5693->mode.format; + default: + return NULL; + } +} + +static struct v4l2_rect * +__ov5693_get_pad_crop(struct ov5693_device *ov5693, + struct v4l2_subdev_state *state, + unsigned int pad, enum v4l2_subdev_format_whence which) +{ + switch (which) { + case V4L2_SUBDEV_FORMAT_TRY: + return v4l2_subdev_get_try_crop(&ov5693->sd, state, pad); + case V4L2_SUBDEV_FORMAT_ACTIVE: + return &ov5693->mode.crop; + } + + return NULL; +} + +static int ov5693_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + struct ov5693_device *ov5693 = to_ov5693_sensor(sd); + + format->format = ov5693->mode.format; + + return 0; +} + +static int ov5693_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + struct ov5693_device *ov5693 = to_ov5693_sensor(sd); + const struct v4l2_rect *crop; + struct v4l2_mbus_framefmt *fmt; + unsigned int hratio, vratio; + unsigned int width, height; + unsigned int hblank; + int exposure_max; + int ret = 0; + + crop = __ov5693_get_pad_crop(ov5693, state, format->pad, format->which); + + /* + * Align to two to simplify the binning calculations below, and clamp + * the requested format at the crop rectangle + */ + width = clamp_t(unsigned int, ALIGN(format->format.width, 2), + OV5693_MIN_CROP_WIDTH, crop->width); + height = clamp_t(unsigned int, ALIGN(format->format.height, 2), + OV5693_MIN_CROP_HEIGHT, crop->height); + + /* + * We can only support setting either the dimensions of the crop rect + * or those dimensions binned (separately) by a factor of two. + */ + hratio = clamp_t(unsigned int, + DIV_ROUND_CLOSEST(crop->width, width), 1, 2); + vratio = clamp_t(unsigned int, + DIV_ROUND_CLOSEST(crop->height, height), 1, 2); + + fmt = __ov5693_get_pad_format(ov5693, state, format->pad, + format->which); + + fmt->width = crop->width / hratio; + fmt->height = crop->height / vratio; + fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; + + format->format = *fmt; + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + return ret; + + mutex_lock(&ov5693->lock); + + ov5693->mode.binning_x = hratio > 1 ? true : false; + ov5693->mode.inc_x_odd = hratio > 1 ? 3 : 1; + ov5693->mode.binning_y = vratio > 1 ? true : false; + ov5693->mode.inc_y_odd = vratio > 1 ? 3 : 1; + + ov5693->mode.vts = __ov5693_calc_vts(fmt->height); + + __v4l2_ctrl_modify_range(ov5693->ctrls.vblank, + OV5693_TIMING_MIN_VTS, + OV5693_TIMING_MAX_VTS - fmt->height, + 1, ov5693->mode.vts - fmt->height); + __v4l2_ctrl_s_ctrl(ov5693->ctrls.vblank, + ov5693->mode.vts - fmt->height); + + hblank = OV5693_FIXED_PPL - fmt->width; + __v4l2_ctrl_modify_range(ov5693->ctrls.hblank, hblank, hblank, 1, + hblank); + + exposure_max = ov5693->mode.vts - OV5693_INTEGRATION_TIME_MARGIN; + __v4l2_ctrl_modify_range(ov5693->ctrls.exposure, + ov5693->ctrls.exposure->minimum, exposure_max, + ov5693->ctrls.exposure->step, + min(ov5693->ctrls.exposure->val, + exposure_max)); + + mutex_unlock(&ov5693->lock); + return ret; +} + +static int ov5693_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + struct ov5693_device *ov5693 = to_ov5693_sensor(sd); + + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + mutex_lock(&ov5693->lock); + sel->r = *__ov5693_get_pad_crop(ov5693, state, sel->pad, + sel->which); + mutex_unlock(&ov5693->lock); + break; + case V4L2_SEL_TGT_NATIVE_SIZE: + sel->r.top = 0; + sel->r.left = 0; + sel->r.width = OV5693_NATIVE_WIDTH; + sel->r.height = OV5693_NATIVE_HEIGHT; + break; + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_DEFAULT: + sel->r.top = OV5693_ACTIVE_START_TOP; + sel->r.left = OV5693_ACTIVE_START_LEFT; + sel->r.width = OV5693_ACTIVE_WIDTH; + sel->r.height = OV5693_ACTIVE_HEIGHT; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int ov5693_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + struct ov5693_device *ov5693 = to_ov5693_sensor(sd); + struct v4l2_mbus_framefmt *format; + struct v4l2_rect *__crop; + struct v4l2_rect rect; + + if (sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + /* + * Clamp the boundaries of the crop rectangle to the size of the sensor + * pixel array. Align to multiples of 2 to ensure Bayer pattern isn't + * disrupted. + */ + rect.left = clamp(ALIGN(sel->r.left, 2), OV5693_NATIVE_START_LEFT, + OV5693_NATIVE_WIDTH); + rect.top = clamp(ALIGN(sel->r.top, 2), OV5693_NATIVE_START_TOP, + OV5693_NATIVE_HEIGHT); + rect.width = clamp_t(unsigned int, ALIGN(sel->r.width, 2), + OV5693_MIN_CROP_WIDTH, OV5693_NATIVE_WIDTH); + rect.height = clamp_t(unsigned int, ALIGN(sel->r.height, 2), + OV5693_MIN_CROP_HEIGHT, OV5693_NATIVE_HEIGHT); + + /* Make sure the crop rectangle isn't outside the bounds of the array */ + rect.width = min_t(unsigned int, rect.width, + OV5693_NATIVE_WIDTH - rect.left); + rect.height = min_t(unsigned int, rect.height, + OV5693_NATIVE_HEIGHT - rect.top); + + __crop = __ov5693_get_pad_crop(ov5693, state, sel->pad, sel->which); + + if (rect.width != __crop->width || rect.height != __crop->height) { + /* + * Reset the output image size if the crop rectangle size has + * been modified. + */ + format = __ov5693_get_pad_format(ov5693, state, sel->pad, + sel->which); + format->width = rect.width; + format->height = rect.height; + } + + *__crop = rect; + sel->r = rect; + + return 0; +} + +static int ov5693_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct ov5693_device *ov5693 = to_ov5693_sensor(sd); + int ret; + + if (enable) { + ret = pm_runtime_get_sync(ov5693->dev); + if (ret < 0) + goto err_power_down; + + mutex_lock(&ov5693->lock); + ret = __v4l2_ctrl_handler_setup(&ov5693->ctrls.handler); + if (ret) { + mutex_unlock(&ov5693->lock); + goto err_power_down; + } + + ret = ov5693_enable_streaming(ov5693, true); + mutex_unlock(&ov5693->lock); + } else { + mutex_lock(&ov5693->lock); + ret = ov5693_enable_streaming(ov5693, false); + mutex_unlock(&ov5693->lock); + } + if (ret) + goto err_power_down; + + ov5693->streaming = !!enable; + + if (!enable) + pm_runtime_put(ov5693->dev); + + return 0; +err_power_down: + pm_runtime_put_noidle(ov5693->dev); + return ret; +} + +static int ov5693_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *interval) +{ + struct ov5693_device *ov5693 = to_ov5693_sensor(sd); + unsigned int framesize = OV5693_FIXED_PPL * (ov5693->mode.format.height + + ov5693->ctrls.vblank->val); + unsigned int fps = DIV_ROUND_CLOSEST(OV5693_PIXEL_RATE, framesize); + + interval->interval.numerator = 1; + interval->interval.denominator = fps; + + return 0; +} + +static int ov5693_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code) +{ + /* Only a single mbus format is supported */ + if (code->index > 0) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_SBGGR10_1X10; + return 0; +} + +static int ov5693_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct ov5693_device *ov5693 = to_ov5693_sensor(sd); + struct v4l2_rect *__crop; + + if (fse->index > 1 || fse->code != MEDIA_BUS_FMT_SBGGR10_1X10) + return -EINVAL; + + __crop = __ov5693_get_pad_crop(ov5693, state, fse->pad, fse->which); + if (!__crop) + return -EINVAL; + + fse->min_width = __crop->width / (fse->index + 1); + fse->min_height = __crop->height / (fse->index + 1); + fse->max_width = fse->min_width; + fse->max_height = fse->min_height; + + return 0; +} + +static const struct v4l2_subdev_video_ops ov5693_video_ops = { + .s_stream = ov5693_s_stream, + .g_frame_interval = ov5693_g_frame_interval, +}; + +static const struct v4l2_subdev_pad_ops ov5693_pad_ops = { + .enum_mbus_code = ov5693_enum_mbus_code, + .enum_frame_size = ov5693_enum_frame_size, + .get_fmt = ov5693_get_fmt, + .set_fmt = ov5693_set_fmt, + .get_selection = ov5693_get_selection, + .set_selection = ov5693_set_selection, +}; + +static const struct v4l2_subdev_ops ov5693_ops = { + .video = &ov5693_video_ops, + .pad = &ov5693_pad_ops, +}; + +/* Sensor and Driver Configuration Functions */ + +static int ov5693_init_controls(struct ov5693_device *ov5693) +{ + const struct v4l2_ctrl_ops *ops = &ov5693_ctrl_ops; + struct ov5693_v4l2_ctrls *ctrls = &ov5693->ctrls; + struct v4l2_fwnode_device_properties props; + int vblank_max, vblank_def; + int exposure_max; + int hblank; + int ret; + + ret = v4l2_ctrl_handler_init(&ctrls->handler, 12); + if (ret) + return ret; + + /* link freq */ + ctrls->link_freq = v4l2_ctrl_new_int_menu(&ctrls->handler, + NULL, V4L2_CID_LINK_FREQ, + 0, 0, link_freq_menu_items); + if (ctrls->link_freq) + ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + /* pixel rate */ + ctrls->pixel_rate = v4l2_ctrl_new_std(&ctrls->handler, NULL, + V4L2_CID_PIXEL_RATE, 0, + OV5693_PIXEL_RATE, 1, + OV5693_PIXEL_RATE); + + /* Exposure */ + exposure_max = ov5693->mode.vts - OV5693_INTEGRATION_TIME_MARGIN; + ctrls->exposure = v4l2_ctrl_new_std(&ctrls->handler, ops, + V4L2_CID_EXPOSURE, + OV5693_EXPOSURE_MIN, exposure_max, + OV5693_EXPOSURE_STEP, exposure_max); + + /* Gain */ + ctrls->analogue_gain = v4l2_ctrl_new_std(&ctrls->handler, + ops, V4L2_CID_ANALOGUE_GAIN, + OV5693_GAIN_MIN, + OV5693_GAIN_MAX, + OV5693_GAIN_STEP, + OV5693_GAIN_DEF); + + ctrls->digital_gain = v4l2_ctrl_new_std(&ctrls->handler, ops, + V4L2_CID_DIGITAL_GAIN, + OV5693_DIGITAL_GAIN_MIN, + OV5693_DIGITAL_GAIN_MAX, + OV5693_DIGITAL_GAIN_STEP, + OV5693_DIGITAL_GAIN_DEF); + + /* Flip */ + ctrls->hflip = v4l2_ctrl_new_std(&ctrls->handler, ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + + ctrls->vflip = v4l2_ctrl_new_std(&ctrls->handler, ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + + hblank = OV5693_FIXED_PPL - ov5693->mode.format.width; + ctrls->hblank = v4l2_ctrl_new_std(&ctrls->handler, ops, + V4L2_CID_HBLANK, hblank, + hblank, 1, hblank); + + if (ctrls->hblank) + ctrls->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + vblank_max = OV5693_TIMING_MAX_VTS - ov5693->mode.format.height; + vblank_def = ov5693->mode.vts - ov5693->mode.format.height; + ctrls->vblank = v4l2_ctrl_new_std(&ctrls->handler, ops, + V4L2_CID_VBLANK, + OV5693_TIMING_MIN_VTS, + vblank_max, 1, vblank_def); + + ctrls->test_pattern = v4l2_ctrl_new_std_menu_items( + &ctrls->handler, ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov5693_test_pattern_menu) - 1, + 0, 0, ov5693_test_pattern_menu); + + if (ctrls->handler.error) { + dev_err(ov5693->dev, "Error initialising v4l2 ctrls\n"); + ret = ctrls->handler.error; + goto err_free_handler; + } + + /* set properties from fwnode (e.g. rotation, orientation) */ + ret = v4l2_fwnode_device_parse(ov5693->dev, &props); + if (ret) + goto err_free_handler; + + ret = v4l2_ctrl_new_fwnode_properties(&ctrls->handler, ops, + &props); + if (ret) + goto err_free_handler; + + /* Use same lock for controls as for everything else. */ + ctrls->handler.lock = &ov5693->lock; + ov5693->sd.ctrl_handler = &ctrls->handler; + + return 0; + +err_free_handler: + v4l2_ctrl_handler_free(&ctrls->handler); + return ret; +} + +static int ov5693_configure_gpios(struct ov5693_device *ov5693) +{ + ov5693->reset = devm_gpiod_get_optional(ov5693->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(ov5693->reset)) { + dev_err(ov5693->dev, "Error fetching reset GPIO\n"); + return PTR_ERR(ov5693->reset); + } + + ov5693->powerdown = devm_gpiod_get_optional(ov5693->dev, "powerdown", + GPIOD_OUT_HIGH); + if (IS_ERR(ov5693->powerdown)) { + dev_err(ov5693->dev, "Error fetching powerdown GPIO\n"); + return PTR_ERR(ov5693->powerdown); + } + + return 0; +} + +static int ov5693_get_regulators(struct ov5693_device *ov5693) +{ + unsigned int i; + + for (i = 0; i < OV5693_NUM_SUPPLIES; i++) + ov5693->supplies[i].supply = ov5693_supply_names[i]; + + return devm_regulator_bulk_get(ov5693->dev, OV5693_NUM_SUPPLIES, + ov5693->supplies); +} + +static int ov5693_check_hwcfg(struct ov5693_device *ov5693) +{ + struct fwnode_handle *fwnode = dev_fwnode(ov5693->dev); + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY, + }; + struct fwnode_handle *endpoint; + unsigned int i; + int ret; + + endpoint = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!endpoint) + return -EPROBE_DEFER; /* Could be provided by cio2-bridge */ + + ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &bus_cfg); + fwnode_handle_put(endpoint); + if (ret) + return ret; + + if (bus_cfg.bus.mipi_csi2.num_data_lanes != 2) { + dev_err(ov5693->dev, "only a 2-lane CSI2 config is supported"); + ret = -EINVAL; + goto out_free_bus_cfg; + } + + if (!bus_cfg.nr_of_link_frequencies) { + dev_err(ov5693->dev, "no link frequencies defined\n"); + ret = -EINVAL; + goto out_free_bus_cfg; + } + + for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) + if (bus_cfg.link_frequencies[i] == OV5693_LINK_FREQ_419_2MHZ) + break; + + if (i == bus_cfg.nr_of_link_frequencies) { + dev_err(ov5693->dev, "supported link freq %ull not found\n", + OV5693_LINK_FREQ_419_2MHZ); + ret = -EINVAL; + goto out_free_bus_cfg; + } + +out_free_bus_cfg: + v4l2_fwnode_endpoint_free(&bus_cfg); + + return ret; +} + +static int ov5693_probe(struct i2c_client *client) +{ + struct ov5693_device *ov5693; + u32 clk_rate; + int ret = 0; + + ov5693 = devm_kzalloc(&client->dev, sizeof(*ov5693), GFP_KERNEL); + if (!ov5693) + return -ENOMEM; + + ov5693->client = client; + ov5693->dev = &client->dev; + + ret = ov5693_check_hwcfg(ov5693); + if (ret) + return ret; + + mutex_init(&ov5693->lock); + + v4l2_i2c_subdev_init(&ov5693->sd, client, &ov5693_ops); + + ov5693->clk = devm_clk_get(&client->dev, "xvclk"); + if (IS_ERR(ov5693->clk)) { + dev_err(&client->dev, "Error getting clock\n"); + return PTR_ERR(ov5693->clk); + } + + clk_rate = clk_get_rate(ov5693->clk); + if (clk_rate != OV5693_XVCLK_FREQ) + dev_warn(&client->dev, "Found clk freq %u, expected %u\n", + clk_rate, OV5693_XVCLK_FREQ); + + ret = ov5693_configure_gpios(ov5693); + if (ret) + return ret; + + ret = ov5693_get_regulators(ov5693); + if (ret) + return dev_err_probe(&client->dev, ret, + "Error fetching regulators\n"); + + ov5693->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + ov5693->pad.flags = MEDIA_PAD_FL_SOURCE; + ov5693->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + ov5693->mode.crop = ov5693_default_crop; + ov5693->mode.format = ov5693_default_fmt; + ov5693->mode.vts = __ov5693_calc_vts(ov5693->mode.format.height); + + ret = ov5693_init_controls(ov5693); + if (ret) + return ret; + + ret = media_entity_pads_init(&ov5693->sd.entity, 1, &ov5693->pad); + if (ret) + goto err_ctrl_handler_free; + + /* + * We need the driver to work in the event that pm runtime is disable in + * the kernel, so power up and verify the chip now. In the event that + * runtime pm is disabled this will leave the chip on, so that streaming + * will work. + */ + + ret = ov5693_sensor_powerup(ov5693); + if (ret) + goto err_media_entity_cleanup; + + ret = ov5693_detect(ov5693); + if (ret) + goto err_powerdown; + + pm_runtime_set_active(&client->dev); + pm_runtime_get_noresume(&client->dev); + pm_runtime_enable(&client->dev); + + ret = v4l2_async_register_subdev_sensor(&ov5693->sd); + if (ret) { + dev_err(&client->dev, "failed to register V4L2 subdev: %d", + ret); + goto err_pm_runtime; + } + + pm_runtime_set_autosuspend_delay(&client->dev, 1000); + pm_runtime_use_autosuspend(&client->dev); + pm_runtime_put_autosuspend(&client->dev); + + return ret; + +err_pm_runtime: + pm_runtime_disable(&client->dev); + pm_runtime_put_noidle(&client->dev); +err_powerdown: + ov5693_sensor_powerdown(ov5693); +err_media_entity_cleanup: + media_entity_cleanup(&ov5693->sd.entity); +err_ctrl_handler_free: + v4l2_ctrl_handler_free(&ov5693->ctrls.handler); + + return ret; +} + +static int ov5693_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov5693_device *ov5693 = to_ov5693_sensor(sd); + + v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&ov5693->sd.entity); + v4l2_ctrl_handler_free(&ov5693->ctrls.handler); + mutex_destroy(&ov5693->lock); + + /* + * Disable runtime PM. In case runtime PM is disabled in the kernel, + * make sure to turn power off manually. + */ + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + ov5693_sensor_powerdown(ov5693); + pm_runtime_set_suspended(&client->dev); + + return 0; +} + +static const struct dev_pm_ops ov5693_pm_ops = { + SET_RUNTIME_PM_OPS(ov5693_sensor_suspend, ov5693_sensor_resume, NULL) +}; + +static const struct acpi_device_id ov5693_acpi_match[] = { + {"INT33BE"}, + {}, +}; +MODULE_DEVICE_TABLE(acpi, ov5693_acpi_match); + +static struct i2c_driver ov5693_driver = { + .driver = { + .name = "ov5693", + .acpi_match_table = ov5693_acpi_match, + .pm = &ov5693_pm_ops, + }, + .probe_new = ov5693_probe, + .remove = ov5693_remove, +}; +module_i2c_driver(ov5693_driver); + +MODULE_DESCRIPTION("A low-level driver for OmniVision 5693 sensors"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/ov8856.c b/drivers/media/i2c/ov8856.c index c6c6050cda1a..8785764b7a74 100644 --- a/drivers/media/i2c/ov8856.c +++ b/drivers/media/i2c/ov8856.c @@ -1445,6 +1445,9 @@ struct ov8856 { const struct ov8856_lane_cfg *priv_lane; u8 modes_size; + + /* True if the device has been identified */ + bool identified; }; struct ov8856_lane_cfg { @@ -1685,6 +1688,71 @@ static int ov8856_write_reg_list(struct ov8856 *ov8856, return 0; } +static int ov8856_identify_module(struct ov8856 *ov8856) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov8856->sd); + int ret; + u32 val; + + if (ov8856->identified) + return 0; + + ret = ov8856_read_reg(ov8856, OV8856_REG_CHIP_ID, + OV8856_REG_VALUE_24BIT, &val); + if (ret) + return ret; + + if (val != OV8856_CHIP_ID) { + dev_err(&client->dev, "chip id mismatch: %x!=%x", + OV8856_CHIP_ID, val); + return -ENXIO; + } + + ret = ov8856_write_reg(ov8856, OV8856_REG_MODE_SELECT, + OV8856_REG_VALUE_08BIT, OV8856_MODE_STREAMING); + if (ret) + return ret; + + ret = ov8856_write_reg(ov8856, OV8856_OTP_MODE_CTRL, + OV8856_REG_VALUE_08BIT, OV8856_OTP_MODE_AUTO); + if (ret) { + dev_err(&client->dev, "failed to set otp mode"); + return ret; + } + + ret = ov8856_write_reg(ov8856, OV8856_OTP_LOAD_CTRL, + OV8856_REG_VALUE_08BIT, + OV8856_OTP_LOAD_CTRL_ENABLE); + if (ret) { + dev_err(&client->dev, "failed to enable load control"); + return ret; + } + + ret = ov8856_read_reg(ov8856, OV8856_MODULE_REVISION, + OV8856_REG_VALUE_08BIT, &val); + if (ret) { + dev_err(&client->dev, "failed to read module revision"); + return ret; + } + + dev_info(&client->dev, "OV8856 revision %x (%s) at address 0x%02x\n", + val, + val == OV8856_2A_MODULE ? "2A" : + val == OV8856_1B_MODULE ? "1B" : "unknown revision", + client->addr); + + ret = ov8856_write_reg(ov8856, OV8856_REG_MODE_SELECT, + OV8856_REG_VALUE_08BIT, OV8856_MODE_STANDBY); + if (ret) { + dev_err(&client->dev, "failed to exit streaming mode"); + return ret; + } + + ov8856->identified = true; + + return 0; +} + static int ov8856_update_digital_gain(struct ov8856 *ov8856, u32 d_gain) { int ret; @@ -1969,6 +2037,10 @@ static int ov8856_start_streaming(struct ov8856 *ov8856) const struct ov8856_reg_list *reg_list; int link_freq_index, ret; + ret = ov8856_identify_module(ov8856); + if (ret) + return ret; + link_freq_index = ov8856->cur_mode->link_freq_index; reg_list = &ov8856->priv_lane->link_freq_configs[link_freq_index].reg_list; @@ -2276,65 +2348,6 @@ static const struct v4l2_subdev_internal_ops ov8856_internal_ops = { .open = ov8856_open, }; -static int ov8856_identify_module(struct ov8856 *ov8856) -{ - struct i2c_client *client = v4l2_get_subdevdata(&ov8856->sd); - int ret; - u32 val; - - ret = ov8856_read_reg(ov8856, OV8856_REG_CHIP_ID, - OV8856_REG_VALUE_24BIT, &val); - if (ret) - return ret; - - if (val != OV8856_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x", - OV8856_CHIP_ID, val); - return -ENXIO; - } - - ret = ov8856_write_reg(ov8856, OV8856_REG_MODE_SELECT, - OV8856_REG_VALUE_08BIT, OV8856_MODE_STREAMING); - if (ret) - return ret; - - ret = ov8856_write_reg(ov8856, OV8856_OTP_MODE_CTRL, - OV8856_REG_VALUE_08BIT, OV8856_OTP_MODE_AUTO); - if (ret) { - dev_err(&client->dev, "failed to set otp mode"); - return ret; - } - - ret = ov8856_write_reg(ov8856, OV8856_OTP_LOAD_CTRL, - OV8856_REG_VALUE_08BIT, - OV8856_OTP_LOAD_CTRL_ENABLE); - if (ret) { - dev_err(&client->dev, "failed to enable load control"); - return ret; - } - - ret = ov8856_read_reg(ov8856, OV8856_MODULE_REVISION, - OV8856_REG_VALUE_08BIT, &val); - if (ret) { - dev_err(&client->dev, "failed to read module revision"); - return ret; - } - - dev_info(&client->dev, "OV8856 revision %x (%s) at address 0x%02x\n", - val, - val == OV8856_2A_MODULE ? "2A" : - val == OV8856_1B_MODULE ? "1B" : "unknown revision", - client->addr); - - ret = ov8856_write_reg(ov8856, OV8856_REG_MODE_SELECT, - OV8856_REG_VALUE_08BIT, OV8856_MODE_STANDBY); - if (ret) { - dev_err(&client->dev, "failed to exit streaming mode"); - return ret; - } - - return 0; -} static int ov8856_get_hwcfg(struct ov8856 *ov8856, struct device *dev) { @@ -2458,6 +2471,7 @@ static int ov8856_probe(struct i2c_client *client) { struct ov8856 *ov8856; int ret; + bool full_power; ov8856 = devm_kzalloc(&client->dev, sizeof(*ov8856), GFP_KERNEL); if (!ov8856) @@ -2472,16 +2486,19 @@ static int ov8856_probe(struct i2c_client *client) v4l2_i2c_subdev_init(&ov8856->sd, client, &ov8856_subdev_ops); - ret = __ov8856_power_on(ov8856); - if (ret) { - dev_err(&client->dev, "failed to power on\n"); - return ret; - } + full_power = acpi_dev_state_d0(&client->dev); + if (full_power) { + ret = __ov8856_power_on(ov8856); + if (ret) { + dev_err(&client->dev, "failed to power on\n"); + return ret; + } - ret = ov8856_identify_module(ov8856); - if (ret) { - dev_err(&client->dev, "failed to find sensor: %d", ret); - goto probe_power_off; + ret = ov8856_identify_module(ov8856); + if (ret) { + dev_err(&client->dev, "failed to find sensor: %d", ret); + goto probe_power_off; + } } mutex_init(&ov8856->mutex); @@ -2511,11 +2528,9 @@ static int ov8856_probe(struct i2c_client *client) goto probe_error_media_entity_cleanup; } - /* - * Device is already turned on by i2c-core with ACPI domain PM. - * Enable runtime PM and turn off the device. - */ - pm_runtime_set_active(&client->dev); + /* Set the device's state to active if it's in D0 state. */ + if (full_power) + pm_runtime_set_active(&client->dev); pm_runtime_enable(&client->dev); pm_runtime_idle(&client->dev); @@ -2562,6 +2577,7 @@ static struct i2c_driver ov8856_i2c_driver = { }, .probe_new = ov8856_probe, .remove = ov8856_remove, + .flags = I2C_DRV_ACPI_WAIVE_D0_PROBE, }; module_i2c_driver(ov8856_i2c_driver); diff --git a/drivers/media/i2c/ov8865.c b/drivers/media/i2c/ov8865.c index ce50f3ea87b8..d9d016cfa9ac 100644 --- a/drivers/media/i2c/ov8865.c +++ b/drivers/media/i2c/ov8865.c @@ -9,6 +9,7 @@ #include <linux/delay.h> #include <linux/device.h> #include <linux/i2c.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/of_graph.h> #include <linux/pm_runtime.h> @@ -20,10 +21,6 @@ #include <media/v4l2-image-sizes.h> #include <media/v4l2-mediabus.h> -/* Clock rate */ - -#define OV8865_EXTCLK_RATE 24000000 - /* Register definitions */ /* System */ @@ -146,6 +143,7 @@ #define OV8865_EXPOSURE_CTRL_L_REG 0x3502 #define OV8865_EXPOSURE_CTRL_L(v) ((v) & GENMASK(7, 0)) #define OV8865_EXPOSURE_GAIN_MANUAL_REG 0x3503 +#define OV8865_INTEGRATION_TIME_MARGIN 8 #define OV8865_GAIN_CTRL_H_REG 0x3508 #define OV8865_GAIN_CTRL_H(v) (((v) & GENMASK(12, 8)) >> 8) @@ -186,6 +184,8 @@ #define OV8865_VTS_H(v) (((v) & GENMASK(11, 8)) >> 8) #define OV8865_VTS_L_REG 0x380f #define OV8865_VTS_L(v) ((v) & GENMASK(7, 0)) +#define OV8865_TIMING_MAX_VTS 0xffff +#define OV8865_TIMING_MIN_VTS 0x04 #define OV8865_OFFSET_X_H_REG 0x3810 #define OV8865_OFFSET_X_H(v) (((v) & GENMASK(15, 8)) >> 8) #define OV8865_OFFSET_X_L_REG 0x3811 @@ -453,6 +453,15 @@ #define OV8865_PRE_CTRL0_PATTERN_COLOR_SQUARES 2 #define OV8865_PRE_CTRL0_PATTERN_BLACK 3 +/* Pixel Array */ + +#define OV8865_NATIVE_WIDTH 3296 +#define OV8865_NATIVE_HEIGHT 2528 +#define OV8865_ACTIVE_START_TOP 32 +#define OV8865_ACTIVE_START_LEFT 80 +#define OV8865_ACTIVE_WIDTH 3264 +#define OV8865_ACTIVE_HEIGHT 2448 + /* Macros */ #define ov8865_subdev_sensor(s) \ @@ -566,6 +575,25 @@ struct ov8865_sclk_config { unsigned int sclk_div; }; +struct ov8865_pll_configs { + const struct ov8865_pll1_config *pll1_config; + const struct ov8865_pll2_config *pll2_config_native; + const struct ov8865_pll2_config *pll2_config_binning; +}; + +/* Clock rate */ + +enum extclk_rate { + OV8865_19_2_MHZ, + OV8865_24_MHZ, + OV8865_NUM_SUPPORTED_RATES +}; + +static const unsigned long supported_extclk_rates[] = { + [OV8865_19_2_MHZ] = 19200000, + [OV8865_24_MHZ] = 24000000, +}; + /* * General formulas for (array-centered) mode calculation: * - photo_array_width = 3296 @@ -632,11 +660,7 @@ struct ov8865_mode { unsigned int blc_anchor_right_start; unsigned int blc_anchor_right_end; - struct v4l2_fract frame_interval; - - const struct ov8865_pll1_config *pll1_config; - const struct ov8865_pll2_config *pll2_config; - const struct ov8865_sclk_config *sclk_config; + bool pll2_binning; const struct ov8865_register_value *register_values; unsigned int register_values_count; @@ -652,6 +676,9 @@ struct ov8865_state { struct ov8865_ctrls { struct v4l2_ctrl *link_freq; struct v4l2_ctrl *pixel_rate; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *exposure; struct v4l2_ctrl_handler handler; }; @@ -664,6 +691,9 @@ struct ov8865_sensor { struct regulator *avdd; struct regulator *dvdd; struct regulator *dovdd; + + unsigned long extclk_rate; + const struct ov8865_pll_configs *pll_configs; struct clk *extclk; struct v4l2_fwnode_endpoint endpoint; @@ -679,43 +709,70 @@ struct ov8865_sensor { /* Static definitions */ /* - * EXTCLK = 24 MHz * PHY_SCLK = 720 MHz * MIPI_PCLK = 90 MHz */ -static const struct ov8865_pll1_config ov8865_pll1_config_native = { - .pll_pre_div_half = 1, - .pll_pre_div = 0, - .pll_mul = 30, - .m_div = 1, - .mipi_div = 3, - .pclk_div = 1, - .sys_pre_div = 1, - .sys_div = 2, + +static const struct ov8865_pll1_config ov8865_pll1_config_native_19_2mhz = { + .pll_pre_div_half = 1, + .pll_pre_div = 2, + .pll_mul = 75, + .m_div = 1, + .mipi_div = 3, + .pclk_div = 1, + .sys_pre_div = 1, + .sys_div = 2, +}; + +static const struct ov8865_pll1_config ov8865_pll1_config_native_24mhz = { + .pll_pre_div_half = 1, + .pll_pre_div = 0, + .pll_mul = 30, + .m_div = 1, + .mipi_div = 3, + .pclk_div = 1, + .sys_pre_div = 1, + .sys_div = 2, }; /* - * EXTCLK = 24 MHz * DAC_CLK = 360 MHz * SCLK = 144 MHz */ -static const struct ov8865_pll2_config ov8865_pll2_config_native = { - .pll_pre_div_half = 1, - .pll_pre_div = 0, - .pll_mul = 30, - .dac_div = 2, - .sys_pre_div = 5, - .sys_div = 0, +static const struct ov8865_pll2_config ov8865_pll2_config_native_19_2mhz = { + .pll_pre_div_half = 1, + .pll_pre_div = 5, + .pll_mul = 75, + .dac_div = 1, + .sys_pre_div = 1, + .sys_div = 3, +}; + +static const struct ov8865_pll2_config ov8865_pll2_config_native_24mhz = { + .pll_pre_div_half = 1, + .pll_pre_div = 0, + .pll_mul = 30, + .dac_div = 2, + .sys_pre_div = 5, + .sys_div = 0, }; /* - * EXTCLK = 24 MHz * DAC_CLK = 360 MHz - * SCLK = 80 MHz + * SCLK = 72 MHz */ -static const struct ov8865_pll2_config ov8865_pll2_config_binning = { +static const struct ov8865_pll2_config ov8865_pll2_config_binning_19_2mhz = { + .pll_pre_div_half = 1, + .pll_pre_div = 2, + .pll_mul = 75, + .dac_div = 2, + .sys_pre_div = 10, + .sys_div = 0, +}; + +static const struct ov8865_pll2_config ov8865_pll2_config_binning_24mhz = { .pll_pre_div_half = 1, .pll_pre_div = 0, .pll_mul = 30, @@ -724,6 +781,23 @@ static const struct ov8865_pll2_config ov8865_pll2_config_binning = { .sys_div = 0, }; +static const struct ov8865_pll_configs ov8865_pll_configs_19_2mhz = { + .pll1_config = &ov8865_pll1_config_native_19_2mhz, + .pll2_config_native = &ov8865_pll2_config_native_19_2mhz, + .pll2_config_binning = &ov8865_pll2_config_binning_19_2mhz, +}; + +static const struct ov8865_pll_configs ov8865_pll_configs_24mhz = { + .pll1_config = &ov8865_pll1_config_native_24mhz, + .pll2_config_native = &ov8865_pll2_config_native_24mhz, + .pll2_config_binning = &ov8865_pll2_config_binning_24mhz, +}; + +static const struct ov8865_pll_configs *ov8865_pll_configs[] = { + &ov8865_pll_configs_19_2mhz, + &ov8865_pll_configs_24mhz, +}; + static const struct ov8865_sclk_config ov8865_sclk_config_native = { .sys_sel = 1, .sclk_sel = 0, @@ -890,7 +964,7 @@ static const struct ov8865_mode ov8865_modes[] = { { /* Horizontal */ .output_size_x = 3264, - .hts = 1944, + .hts = 3888, /* Vertical */ .output_size_y = 2448, @@ -929,13 +1003,8 @@ static const struct ov8865_mode ov8865_modes[] = { .blc_anchor_right_start = 1984, .blc_anchor_right_end = 2239, - /* Frame Interval */ - .frame_interval = { 1, 30 }, - /* PLL */ - .pll1_config = &ov8865_pll1_config_native, - .pll2_config = &ov8865_pll2_config_native, - .sclk_config = &ov8865_sclk_config_native, + .pll2_binning = false, /* Registers */ .register_values = ov8865_register_values_native, @@ -946,11 +1015,11 @@ static const struct ov8865_mode ov8865_modes[] = { { /* Horizontal */ .output_size_x = 3264, - .hts = 2582, + .hts = 3888, /* Vertical */ .output_size_y = 1836, - .vts = 2002, + .vts = 2470, .size_auto = true, .size_auto_boundary_x = 8, @@ -985,13 +1054,8 @@ static const struct ov8865_mode ov8865_modes[] = { .blc_anchor_right_start = 1984, .blc_anchor_right_end = 2239, - /* Frame Interval */ - .frame_interval = { 1, 30 }, - /* PLL */ - .pll1_config = &ov8865_pll1_config_native, - .pll2_config = &ov8865_pll2_config_native, - .sclk_config = &ov8865_sclk_config_native, + .pll2_binning = false, /* Registers */ .register_values = ov8865_register_values_native, @@ -1045,13 +1109,8 @@ static const struct ov8865_mode ov8865_modes[] = { .blc_anchor_right_start = 992, .blc_anchor_right_end = 1119, - /* Frame Interval */ - .frame_interval = { 1, 30 }, - /* PLL */ - .pll1_config = &ov8865_pll1_config_native, - .pll2_config = &ov8865_pll2_config_binning, - .sclk_config = &ov8865_sclk_config_native, + .pll2_binning = true, /* Registers */ .register_values = ov8865_register_values_binning, @@ -1111,13 +1170,8 @@ static const struct ov8865_mode ov8865_modes[] = { .blc_anchor_right_start = 992, .blc_anchor_right_end = 1119, - /* Frame Interval */ - .frame_interval = { 1, 90 }, - /* PLL */ - .pll1_config = &ov8865_pll1_config_native, - .pll2_config = &ov8865_pll2_config_binning, - .sclk_config = &ov8865_sclk_config_native, + .pll2_binning = true, /* Registers */ .register_values = ov8865_register_values_binning, @@ -1512,12 +1566,11 @@ static int ov8865_isp_configure(struct ov8865_sensor *sensor) static unsigned long ov8865_mode_pll1_rate(struct ov8865_sensor *sensor, const struct ov8865_mode *mode) { - const struct ov8865_pll1_config *config = mode->pll1_config; - unsigned long extclk_rate; + const struct ov8865_pll1_config *config; unsigned long pll1_rate; - extclk_rate = clk_get_rate(sensor->extclk); - pll1_rate = extclk_rate * config->pll_mul / config->pll_pre_div_half; + config = sensor->pll_configs->pll1_config; + pll1_rate = sensor->extclk_rate * config->pll_mul / config->pll_pre_div_half; switch (config->pll_pre_div) { case 0: @@ -1551,10 +1604,12 @@ static int ov8865_mode_pll1_configure(struct ov8865_sensor *sensor, const struct ov8865_mode *mode, u32 mbus_code) { - const struct ov8865_pll1_config *config = mode->pll1_config; + const struct ov8865_pll1_config *config; u8 value; int ret; + config = sensor->pll_configs->pll1_config; + switch (mbus_code) { case MEDIA_BUS_FMT_SBGGR10_1X10: value = OV8865_MIPI_BIT_SEL(10); @@ -1621,9 +1676,12 @@ static int ov8865_mode_pll1_configure(struct ov8865_sensor *sensor, static int ov8865_mode_pll2_configure(struct ov8865_sensor *sensor, const struct ov8865_mode *mode) { - const struct ov8865_pll2_config *config = mode->pll2_config; + const struct ov8865_pll2_config *config; int ret; + config = mode->pll2_binning ? sensor->pll_configs->pll2_config_binning : + sensor->pll_configs->pll2_config_native; + ret = ov8865_write(sensor, OV8865_PLL_CTRL12_REG, OV8865_PLL_CTRL12_PRE_DIV_HALF(config->pll_pre_div_half) | OV8865_PLL_CTRL12_DAC_DIV(config->dac_div)); @@ -1657,7 +1715,7 @@ static int ov8865_mode_pll2_configure(struct ov8865_sensor *sensor, static int ov8865_mode_sclk_configure(struct ov8865_sensor *sensor, const struct ov8865_mode *mode) { - const struct ov8865_sclk_config *config = mode->sclk_config; + const struct ov8865_sclk_config *config = &ov8865_sclk_config_native; int ret; ret = ov8865_write(sensor, OV8865_CLK_SEL0_REG, @@ -2052,9 +2110,11 @@ static int ov8865_mode_configure(struct ov8865_sensor *sensor, static unsigned long ov8865_mode_mipi_clk_rate(struct ov8865_sensor *sensor, const struct ov8865_mode *mode) { - const struct ov8865_pll1_config *config = mode->pll1_config; + const struct ov8865_pll1_config *config; unsigned long pll1_rate; + config = sensor->pll_configs->pll1_config; + pll1_rate = ov8865_mode_pll1_rate(sensor, mode); return pll1_rate / config->m_div / 2; @@ -2066,6 +2126,9 @@ static int ov8865_exposure_configure(struct ov8865_sensor *sensor, u32 exposure) { int ret; + /* The sensor stores exposure in units of 1/16th of a line */ + exposure *= 16; + ret = ov8865_write(sensor, OV8865_EXPOSURE_CTRL_HH_REG, OV8865_EXPOSURE_CTRL_HH(exposure)); if (ret) @@ -2082,7 +2145,7 @@ static int ov8865_exposure_configure(struct ov8865_sensor *sensor, u32 exposure) /* Gain */ -static int ov8865_gain_configure(struct ov8865_sensor *sensor, u32 gain) +static int ov8865_analog_gain_configure(struct ov8865_sensor *sensor, u32 gain) { int ret; @@ -2157,6 +2220,20 @@ static int ov8865_test_pattern_configure(struct ov8865_sensor *sensor, ov8865_test_pattern_bits[index]); } +/* Blanking */ + +static int ov8865_vts_configure(struct ov8865_sensor *sensor, u32 vblank) +{ + u16 vts = sensor->state.mode->output_size_y + vblank; + int ret; + + ret = ov8865_write(sensor, OV8865_VTS_H_REG, OV8865_VTS_H(vts)); + if (ret) + return ret; + + return ov8865_write(sensor, OV8865_VTS_L_REG, OV8865_VTS_L(vts)); +} + /* State */ static int ov8865_state_mipi_configure(struct ov8865_sensor *sensor, @@ -2330,27 +2407,27 @@ static int ov8865_sensor_power(struct ov8865_sensor *sensor, bool on) if (ret) { dev_err(sensor->dev, "failed to enable DOVDD regulator\n"); - goto disable; + return ret; } ret = regulator_enable(sensor->avdd); if (ret) { dev_err(sensor->dev, "failed to enable AVDD regulator\n"); - goto disable; + goto disable_dovdd; } ret = regulator_enable(sensor->dvdd); if (ret) { dev_err(sensor->dev, "failed to enable DVDD regulator\n"); - goto disable; + goto disable_avdd; } ret = clk_prepare_enable(sensor->extclk); if (ret) { dev_err(sensor->dev, "failed to enable EXTCLK clock\n"); - goto disable; + goto disable_dvdd; } gpiod_set_value_cansleep(sensor->reset, 0); @@ -2359,14 +2436,16 @@ static int ov8865_sensor_power(struct ov8865_sensor *sensor, bool on) /* Time to enter streaming mode according to power timings. */ usleep_range(10000, 12000); } else { -disable: gpiod_set_value_cansleep(sensor->powerdown, 1); gpiod_set_value_cansleep(sensor->reset, 1); clk_disable_unprepare(sensor->extclk); +disable_dvdd: regulator_disable(sensor->dvdd); +disable_avdd: regulator_disable(sensor->avdd); +disable_dovdd: regulator_disable(sensor->dovdd); } @@ -2382,6 +2461,20 @@ static int ov8865_s_ctrl(struct v4l2_ctrl *ctrl) unsigned int index; int ret; + /* If VBLANK is altered we need to update exposure to compensate */ + if (ctrl->id == V4L2_CID_VBLANK) { + int exposure_max; + + exposure_max = sensor->state.mode->output_size_y + ctrl->val - + OV8865_INTEGRATION_TIME_MARGIN; + __v4l2_ctrl_modify_range(sensor->ctrls.exposure, + sensor->ctrls.exposure->minimum, + exposure_max, + sensor->ctrls.exposure->step, + min(sensor->ctrls.exposure->val, + exposure_max)); + } + /* Wait for the sensor to be on before setting controls. */ if (pm_runtime_suspended(sensor->dev)) return 0; @@ -2392,8 +2485,8 @@ static int ov8865_s_ctrl(struct v4l2_ctrl *ctrl) if (ret) return ret; break; - case V4L2_CID_GAIN: - ret = ov8865_gain_configure(sensor, ctrl->val); + case V4L2_CID_ANALOGUE_GAIN: + ret = ov8865_analog_gain_configure(sensor, ctrl->val); if (ret) return ret; break; @@ -2408,6 +2501,8 @@ static int ov8865_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_TEST_PATTERN: index = (unsigned int)ctrl->val; return ov8865_test_pattern_configure(sensor, index); + case V4L2_CID_VBLANK: + return ov8865_vts_configure(sensor, ctrl->val); default: return -EINVAL; } @@ -2424,6 +2519,10 @@ static int ov8865_ctrls_init(struct ov8865_sensor *sensor) struct ov8865_ctrls *ctrls = &sensor->ctrls; struct v4l2_ctrl_handler *handler = &ctrls->handler; const struct v4l2_ctrl_ops *ops = &ov8865_ctrl_ops; + const struct ov8865_mode *mode = &ov8865_modes[0]; + struct v4l2_fwnode_device_properties props; + unsigned int vblank_max, vblank_def; + unsigned int hblank; int ret; v4l2_ctrl_handler_init(handler, 32); @@ -2433,12 +2532,13 @@ static int ov8865_ctrls_init(struct ov8865_sensor *sensor) /* Exposure */ - v4l2_ctrl_new_std(handler, ops, V4L2_CID_EXPOSURE, 16, 1048575, 16, - 512); + ctrls->exposure = v4l2_ctrl_new_std(handler, ops, V4L2_CID_EXPOSURE, 2, + 65535, 1, 32); /* Gain */ - v4l2_ctrl_new_std(handler, ops, V4L2_CID_GAIN, 128, 8191, 128, 128); + v4l2_ctrl_new_std(handler, ops, V4L2_CID_ANALOGUE_GAIN, 128, 2048, 128, + 128); /* White Balance */ @@ -2459,6 +2559,20 @@ static int ov8865_ctrls_init(struct ov8865_sensor *sensor) ARRAY_SIZE(ov8865_test_pattern_menu) - 1, 0, 0, ov8865_test_pattern_menu); + /* Blanking */ + hblank = mode->hts - mode->output_size_x; + ctrls->hblank = v4l2_ctrl_new_std(handler, ops, V4L2_CID_HBLANK, hblank, + hblank, 1, hblank); + + if (ctrls->hblank) + ctrls->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + vblank_max = OV8865_TIMING_MAX_VTS - mode->output_size_y; + vblank_def = mode->vts - mode->output_size_y; + ctrls->vblank = v4l2_ctrl_new_std(handler, ops, V4L2_CID_VBLANK, + OV8865_TIMING_MIN_VTS, vblank_max, 1, + vblank_def); + /* MIPI CSI-2 */ ctrls->link_freq = @@ -2470,6 +2584,15 @@ static int ov8865_ctrls_init(struct ov8865_sensor *sensor) v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1); + /* set properties from fwnode (e.g. rotation, orientation) */ + ret = v4l2_fwnode_device_parse(sensor->dev, &props); + if (ret) + goto error_ctrls; + + ret = v4l2_ctrl_new_fwnode_properties(handler, ops, &props); + if (ret) + goto error_ctrls; + if (handler->error) { ret = handler->error; goto error_ctrls; @@ -2522,11 +2645,18 @@ static int ov8865_g_frame_interval(struct v4l2_subdev *subdev, { struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev); const struct ov8865_mode *mode; + unsigned int framesize; + unsigned int fps; mutex_lock(&sensor->mutex); mode = sensor->state.mode; - interval->interval = mode->frame_interval; + framesize = mode->hts * (mode->output_size_y + + sensor->ctrls.vblank->val); + fps = DIV_ROUND_CLOSEST(sensor->ctrls.pixel_rate->val, framesize); + + interval->interval.numerator = 1; + interval->interval.denominator = fps; mutex_unlock(&sensor->mutex); @@ -2599,7 +2729,9 @@ static int ov8865_set_fmt(struct v4l2_subdev *subdev, struct v4l2_mbus_framefmt *mbus_format = &format->format; const struct ov8865_mode *mode; u32 mbus_code = 0; + unsigned int hblank; unsigned int index; + int exposure_max; int ret = 0; mutex_lock(&sensor->mutex); @@ -2639,6 +2771,21 @@ static int ov8865_set_fmt(struct v4l2_subdev *subdev, sensor->state.mbus_code != mbus_code) ret = ov8865_state_configure(sensor, mode, mbus_code); + __v4l2_ctrl_modify_range(sensor->ctrls.vblank, OV8865_TIMING_MIN_VTS, + OV8865_TIMING_MAX_VTS - mode->output_size_y, + 1, mode->vts - mode->output_size_y); + + hblank = mode->hts - mode->output_size_x; + __v4l2_ctrl_modify_range(sensor->ctrls.hblank, hblank, hblank, 1, + hblank); + + exposure_max = mode->vts - OV8865_INTEGRATION_TIME_MARGIN; + __v4l2_ctrl_modify_range(sensor->ctrls.exposure, + sensor->ctrls.exposure->minimum, exposure_max, + sensor->ctrls.exposure->step, + min(sensor->ctrls.exposure->val, + exposure_max)); + complete: mutex_unlock(&sensor->mutex); @@ -2662,37 +2809,55 @@ static int ov8865_enum_frame_size(struct v4l2_subdev *subdev, return 0; } -static int ov8865_enum_frame_interval(struct v4l2_subdev *subdev, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_frame_interval_enum *interval_enum) +static void +__ov8865_get_pad_crop(struct ov8865_sensor *sensor, + struct v4l2_subdev_state *state, unsigned int pad, + enum v4l2_subdev_format_whence which, struct v4l2_rect *r) { - const struct ov8865_mode *mode = NULL; - unsigned int mode_index; - unsigned int interval_index; - - if (interval_enum->index > 0) - return -EINVAL; - /* - * Multiple modes with the same dimensions may have different frame - * intervals, so look up each relevant mode. - */ - for (mode_index = 0, interval_index = 0; - mode_index < ARRAY_SIZE(ov8865_modes); mode_index++) { - mode = &ov8865_modes[mode_index]; - - if (mode->output_size_x == interval_enum->width && - mode->output_size_y == interval_enum->height) { - if (interval_index == interval_enum->index) - break; + const struct ov8865_mode *mode = sensor->state.mode; - interval_index++; - } + switch (which) { + case V4L2_SUBDEV_FORMAT_TRY: + *r = *v4l2_subdev_get_try_crop(&sensor->subdev, state, pad); + break; + case V4L2_SUBDEV_FORMAT_ACTIVE: + r->height = mode->output_size_y; + r->width = mode->output_size_x; + r->top = (OV8865_NATIVE_HEIGHT - mode->output_size_y) / 2; + r->left = (OV8865_NATIVE_WIDTH - mode->output_size_x) / 2; + break; } +} - if (mode_index == ARRAY_SIZE(ov8865_modes)) - return -EINVAL; +static int ov8865_get_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev); - interval_enum->interval = mode->frame_interval; + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + mutex_lock(&sensor->mutex); + __ov8865_get_pad_crop(sensor, state, sel->pad, + sel->which, &sel->r); + mutex_unlock(&sensor->mutex); + break; + case V4L2_SEL_TGT_NATIVE_SIZE: + sel->r.top = 0; + sel->r.left = 0; + sel->r.width = OV8865_NATIVE_WIDTH; + sel->r.height = OV8865_NATIVE_HEIGHT; + break; + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_DEFAULT: + sel->r.top = OV8865_ACTIVE_START_TOP; + sel->r.left = OV8865_ACTIVE_START_LEFT; + sel->r.width = OV8865_ACTIVE_WIDTH; + sel->r.height = OV8865_ACTIVE_HEIGHT; + break; + default: + return -EINVAL; + } return 0; } @@ -2702,7 +2867,8 @@ static const struct v4l2_subdev_pad_ops ov8865_subdev_pad_ops = { .get_fmt = ov8865_get_fmt, .set_fmt = ov8865_set_fmt, .enum_frame_size = ov8865_enum_frame_size, - .enum_frame_interval = ov8865_enum_frame_interval, + .get_selection = ov8865_get_selection, + .set_selection = ov8865_get_selection, }; static const struct v4l2_subdev_ops ov8865_subdev_ops = { @@ -2782,7 +2948,8 @@ static int ov8865_probe(struct i2c_client *client) struct ov8865_sensor *sensor; struct v4l2_subdev *subdev; struct media_pad *pad; - unsigned long rate; + unsigned int rate = 0; + unsigned int i; int ret; sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); @@ -2792,13 +2959,31 @@ static int ov8865_probe(struct i2c_client *client) sensor->dev = dev; sensor->i2c_client = client; + /* Regulators */ + + /* DVDD: digital core */ + sensor->dvdd = devm_regulator_get(dev, "dvdd"); + if (IS_ERR(sensor->dvdd)) + return dev_err_probe(dev, PTR_ERR(sensor->dvdd), + "cannot get DVDD regulator\n"); + + /* DOVDD: digital I/O */ + sensor->dovdd = devm_regulator_get(dev, "dovdd"); + if (IS_ERR(sensor->dovdd)) + return dev_err_probe(dev, PTR_ERR(sensor->dovdd), + "cannot get DOVDD regulator\n"); + + /* AVDD: analog */ + sensor->avdd = devm_regulator_get(dev, "avdd"); + if (IS_ERR(sensor->avdd)) + return dev_err_probe(dev, PTR_ERR(sensor->avdd), + "cannot get AVDD (analog) regulator\n"); + /* Graph Endpoint */ handle = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); - if (!handle) { - dev_err(dev, "unable to find endpoint node\n"); - return -EINVAL; - } + if (!handle) + return -EPROBE_DEFER; sensor->endpoint.bus_type = V4L2_MBUS_CSI2_DPHY; @@ -2824,48 +3009,54 @@ static int ov8865_probe(struct i2c_client *client) goto error_endpoint; } - /* Regulators */ - - /* DVDD: digital core */ - sensor->dvdd = devm_regulator_get(dev, "dvdd"); - if (IS_ERR(sensor->dvdd)) { - dev_err(dev, "cannot get DVDD (digital core) regulator\n"); - ret = PTR_ERR(sensor->dvdd); - goto error_endpoint; - } + /* External Clock */ - /* DOVDD: digital I/O */ - sensor->dovdd = devm_regulator_get(dev, "dovdd"); - if (IS_ERR(sensor->dovdd)) { - dev_err(dev, "cannot get DOVDD (digital I/O) regulator\n"); - ret = PTR_ERR(sensor->dovdd); + sensor->extclk = devm_clk_get(dev, NULL); + if (PTR_ERR(sensor->extclk) == -ENOENT) { + dev_info(dev, "no external clock found, continuing...\n"); + sensor->extclk = NULL; + } else if (IS_ERR(sensor->extclk)) { + dev_err(dev, "failed to get external clock\n"); + ret = PTR_ERR(sensor->extclk); goto error_endpoint; } - /* AVDD: analog */ - sensor->avdd = devm_regulator_get(dev, "avdd"); - if (IS_ERR(sensor->avdd)) { - dev_err(dev, "cannot get AVDD (analog) regulator\n"); - ret = PTR_ERR(sensor->avdd); - goto error_endpoint; + /* + * We could have either a 24MHz or 19.2MHz clock rate from either dt or + * ACPI...but we also need to support the weird IPU3 case which will + * have an external clock AND a clock-frequency property. Check for the + * clock-frequency property and if found, set that rate if we managed + * to acquire a clock. This should cover the ACPI case. If the system + * uses devicetree then the configured rate should already be set, so + * we can just read it. + */ + ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", + &rate); + if (!ret && sensor->extclk) { + ret = clk_set_rate(sensor->extclk, rate); + if (ret) + return dev_err_probe(dev, ret, + "failed to set clock rate\n"); + } else if (ret && !sensor->extclk) { + return dev_err_probe(dev, ret, "invalid clock config\n"); } - /* External Clock */ + sensor->extclk_rate = rate ? rate : clk_get_rate(sensor->extclk); - sensor->extclk = devm_clk_get(dev, NULL); - if (IS_ERR(sensor->extclk)) { - dev_err(dev, "failed to get external clock\n"); - ret = PTR_ERR(sensor->extclk); - goto error_endpoint; + for (i = 0; i < ARRAY_SIZE(supported_extclk_rates); i++) { + if (sensor->extclk_rate == supported_extclk_rates[i]) + break; } - rate = clk_get_rate(sensor->extclk); - if (rate != OV8865_EXTCLK_RATE) { - dev_err(dev, "clock rate %lu Hz is unsupported\n", rate); + if (i == ARRAY_SIZE(supported_extclk_rates)) { + dev_err(dev, "clock rate %lu Hz is unsupported\n", + sensor->extclk_rate); ret = -EINVAL; goto error_endpoint; } + sensor->pll_configs = ov8865_pll_configs[i]; + /* Subdev, entity and pad */ subdev = &sensor->subdev; @@ -2891,14 +3082,16 @@ static int ov8865_probe(struct i2c_client *client) if (ret) goto error_mutex; + mutex_lock(&sensor->mutex); ret = ov8865_state_init(sensor); + mutex_unlock(&sensor->mutex); if (ret) goto error_ctrls; /* Runtime PM */ - pm_runtime_enable(sensor->dev); pm_runtime_set_suspended(sensor->dev); + pm_runtime_enable(sensor->dev); /* V4L2 subdev register */ @@ -2946,6 +3139,12 @@ static const struct dev_pm_ops ov8865_pm_ops = { SET_RUNTIME_PM_OPS(ov8865_suspend, ov8865_resume, NULL) }; +static const struct acpi_device_id ov8865_acpi_match[] = { + {"INT347A"}, + { } +}; +MODULE_DEVICE_TABLE(acpi, ov8865_acpi_match); + static const struct of_device_id ov8865_of_match[] = { { .compatible = "ovti,ov8865" }, { } @@ -2956,6 +3155,7 @@ static struct i2c_driver ov8865_driver = { .driver = { .name = "ov8865", .of_match_table = ov8865_of_match, + .acpi_match_table = ov8865_acpi_match, .pm = &ov8865_pm_ops, }, .probe_new = ov8865_probe, diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-spi.c b/drivers/media/i2c/s5c73m3/s5c73m3-spi.c index c102c6bbc118..7fe61187a2f8 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-spi.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-spi.c @@ -130,16 +130,10 @@ static int s5c73m3_spi_probe(struct spi_device *spi) return 0; } -static int s5c73m3_spi_remove(struct spi_device *spi) -{ - return 0; -} - int s5c73m3_register_spi_driver(struct s5c73m3 *state) { struct spi_driver *spidrv = &state->spidrv; - spidrv->remove = s5c73m3_spi_remove; spidrv->probe = s5c73m3_spi_probe; spidrv->driver.name = S5C73M3_SPI_DRV_NAME; spidrv->driver.of_match_table = s5c73m3_spi_ids; diff --git a/drivers/media/mc/mc-devnode.c b/drivers/media/mc/mc-devnode.c index f11382afe23b..680fbb3a9340 100644 --- a/drivers/media/mc/mc-devnode.c +++ b/drivers/media/mc/mc-devnode.c @@ -217,7 +217,7 @@ int __must_check media_devnode_register(struct media_device *mdev, /* Part 1: Find a free minor number */ mutex_lock(&media_devnode_lock); - minor = find_next_zero_bit(media_devnode_nums, MEDIA_NUM_DEVICES, 0); + minor = find_first_zero_bit(media_devnode_nums, MEDIA_NUM_DEVICES); if (minor == MEDIA_NUM_DEVICES) { mutex_unlock(&media_devnode_lock); pr_err("could not get a free minor\n"); diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c index f40f41977142..b411f9796191 100644 --- a/drivers/media/mc/mc-entity.c +++ b/drivers/media/mc/mc-entity.c @@ -14,22 +14,6 @@ #include <media/media-entity.h> #include <media/media-device.h> -static inline const char *gobj_type(enum media_gobj_type type) -{ - switch (type) { - case MEDIA_GRAPH_ENTITY: - return "entity"; - case MEDIA_GRAPH_PAD: - return "pad"; - case MEDIA_GRAPH_LINK: - return "link"; - case MEDIA_GRAPH_INTF_DEVNODE: - return "intf-devnode"; - default: - return "unknown"; - } -} - static inline const char *intf_type(struct media_interface *intf) { switch (intf->type) { @@ -64,12 +48,10 @@ __must_check int __media_entity_enum_init(struct media_entity_enum *ent_enum, int idx_max) { idx_max = ALIGN(idx_max, BITS_PER_LONG); - ent_enum->bmap = kcalloc(idx_max / BITS_PER_LONG, sizeof(long), - GFP_KERNEL); + ent_enum->bmap = bitmap_zalloc(idx_max, GFP_KERNEL); if (!ent_enum->bmap) return -ENOMEM; - bitmap_zero(ent_enum->bmap, idx_max); ent_enum->idx_max = idx_max; return 0; @@ -78,7 +60,7 @@ EXPORT_SYMBOL_GPL(__media_entity_enum_init); void media_entity_enum_cleanup(struct media_entity_enum *ent_enum) { - kfree(ent_enum->bmap); + bitmap_free(ent_enum->bmap); } EXPORT_SYMBOL_GPL(media_entity_enum_cleanup); diff --git a/drivers/media/pci/b2c2/flexcop-pci.c b/drivers/media/pci/b2c2/flexcop-pci.c index 6a4c7cb0ad0f..486c8ec0fa60 100644 --- a/drivers/media/pci/b2c2/flexcop-pci.c +++ b/drivers/media/pci/b2c2/flexcop-pci.c @@ -185,6 +185,8 @@ static irqreturn_t flexcop_pci_isr(int irq, void *dev_id) dma_addr_t cur_addr = fc->read_ibi_reg(fc,dma1_008).dma_0x8.dma_cur_addr << 2; u32 cur_pos = cur_addr - fc_pci->dma[0].dma_addr0; + if (cur_pos > fc_pci->dma[0].size * 2) + goto error; deb_irq("%u irq: %08x cur_addr: %llx: cur_pos: %08x, last_cur_pos: %08x ", jiffies_to_usecs(jiffies - fc_pci->last_irq), @@ -225,6 +227,7 @@ static irqreturn_t flexcop_pci_isr(int irq, void *dev_id) ret = IRQ_NONE; } +error: spin_unlock_irqrestore(&fc_pci->irq_lock, flags); return ret; } diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 0e9df8b35ac6..8cc9bec43688 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -170,14 +170,14 @@ MODULE_VERSION(BTTV_VERSION); /* ----------------------------------------------------------------------- */ /* sysfs */ -static ssize_t show_card(struct device *cd, +static ssize_t card_show(struct device *cd, struct device_attribute *attr, char *buf) { struct video_device *vfd = to_video_device(cd); struct bttv *btv = video_get_drvdata(vfd); return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET); } -static DEVICE_ATTR(card, S_IRUGO, show_card, NULL); +static DEVICE_ATTR_RO(card); /* ----------------------------------------------------------------------- */ /* dvb auto-load setup */ diff --git a/drivers/media/pci/cobalt/cobalt-cpld.c b/drivers/media/pci/cobalt/cobalt-cpld.c index 3d8026483ac3..fad882459d23 100644 --- a/drivers/media/pci/cobalt/cobalt-cpld.c +++ b/drivers/media/pci/cobalt/cobalt-cpld.c @@ -236,7 +236,6 @@ bool cobalt_cpld_set_freq(struct cobalt *cobalt, unsigned f_out) u8 n1, hsdiv; u8 regs[6]; int found = 0; - u16 clock_ctrl; int retries = 3; for (i = 0; i < ARRAY_SIZE(multipliers); i++) { @@ -260,9 +259,7 @@ bool cobalt_cpld_set_freq(struct cobalt *cobalt, unsigned f_out) hsdiv = multipliers[i_best].hsdiv - 4; rfreq = div_u64(dco << 28, f_xtal); - clock_ctrl = cpld_read(cobalt, SI570_CLOCK_CTRL); - clock_ctrl |= S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_FPGA_CTRL; - clock_ctrl |= S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_EN; + cpld_read(cobalt, SI570_CLOCK_CTRL); regs[0] = (hsdiv << 5) | (n1 >> 2); regs[1] = ((n1 & 0x3) << 6) | (rfreq >> 32); diff --git a/drivers/media/pci/cx18/cx18-alsa-main.c b/drivers/media/pci/cx18/cx18-alsa-main.c index 9a82e68303b6..9dc361886284 100644 --- a/drivers/media/pci/cx18/cx18-alsa-main.c +++ b/drivers/media/pci/cx18/cx18-alsa-main.c @@ -51,12 +51,6 @@ struct snd_cx18_card *to_snd_cx18_card(struct v4l2_device *v4l2_dev) return to_cx18(v4l2_dev)->alsa; } -static inline -struct snd_cx18_card *p_to_snd_cx18_card(struct v4l2_device **v4l2_dev) -{ - return container_of(v4l2_dev, struct snd_cx18_card, v4l2_dev); -} - static void snd_cx18_card_free(struct snd_cx18_card *cxsc) { if (cxsc == NULL) diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index 40c10ca94def..3078a39f0b95 100644 --- a/drivers/media/pci/cx25821/cx25821-core.c +++ b/drivers/media/pci/cx25821/cx25821-core.c @@ -337,13 +337,6 @@ static int cx25821_risc_decode(u32 risc) return incr[risc >> 28] ? incr[risc >> 28] : 1; } -static inline int i2c_slave_did_ack(struct i2c_adapter *i2c_adap) -{ - struct cx25821_i2c *bus = i2c_adap->algo_data; - struct cx25821_dev *dev = bus->dev; - return cx_read(bus->reg_stat) & 0x01; -} - static void cx25821_registers_init(struct cx25821_dev *dev) { u32 tmp; diff --git a/drivers/media/pci/intel/ipu3/cio2-bridge.c b/drivers/media/pci/intel/ipu3/cio2-bridge.c index 67c467d3c81f..7ccb7b6eaa82 100644 --- a/drivers/media/pci/intel/ipu3/cio2-bridge.c +++ b/drivers/media/pci/intel/ipu3/cio2-bridge.c @@ -3,6 +3,7 @@ #include <linux/acpi.h> #include <linux/device.h> +#include <linux/i2c.h> #include <linux/pci.h> #include <linux/property.h> #include <media/v4l2-fwnode.h> @@ -21,7 +22,9 @@ */ static const struct cio2_sensor_config cio2_supported_sensors[] = { /* Omnivision OV5693 */ - CIO2_SENSOR_CONFIG("INT33BE", 0), + CIO2_SENSOR_CONFIG("INT33BE", 1, 419200000), + /* Omnivision OV8865 */ + CIO2_SENSOR_CONFIG("INT347A", 1, 360000000), /* Omnivision OV2680 */ CIO2_SENSOR_CONFIG("OVTI2680", 0), }; @@ -36,6 +39,18 @@ static const struct cio2_property_names prop_names = { .link_frequencies = "link-frequencies", }; +static const char * const cio2_vcm_types[] = { + "ad5823", + "dw9714", + "ad5816", + "dw9719", + "dw9718", + "dw9806b", + "wv517s", + "lc898122xa", + "lc898212axb", +}; + static int cio2_bridge_read_acpi_buffer(struct acpi_device *adev, char *id, void *data, u32 size) { @@ -132,6 +147,12 @@ static void cio2_bridge_create_fwnode_properties( sensor->dev_properties[2] = PROPERTY_ENTRY_U32( sensor->prop_names.orientation, orientation); + if (sensor->ssdb.vcmtype) { + sensor->vcm_ref[0] = + SOFTWARE_NODE_REFERENCE(&sensor->swnodes[SWNODE_VCM]); + sensor->dev_properties[3] = + PROPERTY_ENTRY_REF_ARRAY("lens-focus", sensor->vcm_ref); + } sensor->ep_properties[0] = PROPERTY_ENTRY_U32( sensor->prop_names.bus_type, @@ -193,6 +214,33 @@ static void cio2_bridge_create_connection_swnodes(struct cio2_bridge *bridge, sensor->node_names.endpoint, &nodes[SWNODE_CIO2_PORT], sensor->cio2_properties); + if (sensor->ssdb.vcmtype) + nodes[SWNODE_VCM] = + NODE_VCM(cio2_vcm_types[sensor->ssdb.vcmtype - 1]); +} + +static void cio2_bridge_instantiate_vcm_i2c_client(struct cio2_sensor *sensor) +{ + struct i2c_board_info board_info = { }; + char name[16]; + + if (!sensor->ssdb.vcmtype) + return; + + snprintf(name, sizeof(name), "%s-VCM", acpi_dev_name(sensor->adev)); + board_info.dev_name = name; + strscpy(board_info.type, cio2_vcm_types[sensor->ssdb.vcmtype - 1], + ARRAY_SIZE(board_info.type)); + board_info.swnode = &sensor->swnodes[SWNODE_VCM]; + + sensor->vcm_i2c_client = + i2c_acpi_new_device_by_fwnode(acpi_fwnode_handle(sensor->adev), + 1, &board_info); + if (IS_ERR(sensor->vcm_i2c_client)) { + dev_warn(&sensor->adev->dev, "Error instantiation VCM i2c-client: %ld\n", + PTR_ERR(sensor->vcm_i2c_client)); + sensor->vcm_i2c_client = NULL; + } } static void cio2_bridge_unregister_sensors(struct cio2_bridge *bridge) @@ -205,6 +253,7 @@ static void cio2_bridge_unregister_sensors(struct cio2_bridge *bridge) software_node_unregister_nodes(sensor->swnodes); ACPI_FREE(sensor->pld); acpi_dev_put(sensor->adev); + i2c_unregister_device(sensor->vcm_i2c_client); } } @@ -237,9 +286,17 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg, if (ret) goto err_put_adev; + if (sensor->ssdb.vcmtype > ARRAY_SIZE(cio2_vcm_types)) { + dev_warn(&adev->dev, "Unknown VCM type %d\n", + sensor->ssdb.vcmtype); + sensor->ssdb.vcmtype = 0; + } + status = acpi_get_physical_device_location(adev->handle, &sensor->pld); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status)) { + ret = -ENODEV; goto err_put_adev; + } if (sensor->ssdb.lanes > CIO2_MAX_LANES) { dev_err(&adev->dev, @@ -265,6 +322,8 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg, sensor->adev = acpi_dev_get(adev); adev->fwnode.secondary = fwnode; + cio2_bridge_instantiate_vcm_i2c_client(sensor); + dev_info(&cio2->dev, "Found supported sensor %s\n", acpi_dev_name(adev)); @@ -304,6 +363,40 @@ err_unregister_sensors: return ret; } +/* + * The VCM cannot be probed until the PMIC is completely setup. We cannot rely + * on -EPROBE_DEFER for this, since the consumer<->supplier relations between + * the VCM and regulators/clks are not described in ACPI, instead they are + * passed as board-data to the PMIC drivers. Since -PROBE_DEFER does not work + * for the clks/regulators the VCM i2c-clients must not be instantiated until + * the PMIC is fully setup. + * + * The sensor/VCM ACPI device has an ACPI _DEP on the PMIC, check this using the + * acpi_dev_ready_for_enumeration() helper, like the i2c-core-acpi code does + * for the sensors. + */ +static int cio2_bridge_sensors_are_ready(void) +{ + struct acpi_device *adev; + bool ready = true; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(cio2_supported_sensors); i++) { + const struct cio2_sensor_config *cfg = + &cio2_supported_sensors[i]; + + for_each_acpi_dev_match(adev, cfg->hid, NULL, -1) { + if (!adev->status.enabled) + continue; + + if (!acpi_dev_ready_for_enumeration(adev)) + ready = false; + } + } + + return ready; +} + int cio2_bridge_init(struct pci_dev *cio2) { struct device *dev = &cio2->dev; @@ -312,6 +405,9 @@ int cio2_bridge_init(struct pci_dev *cio2) unsigned int i; int ret; + if (!cio2_bridge_sensors_are_ready()) + return -EPROBE_DEFER; + bridge = kzalloc(sizeof(*bridge), GFP_KERNEL); if (!bridge) return -ENOMEM; diff --git a/drivers/media/pci/intel/ipu3/cio2-bridge.h b/drivers/media/pci/intel/ipu3/cio2-bridge.h index 202c7d494f7a..4418cbd08208 100644 --- a/drivers/media/pci/intel/ipu3/cio2-bridge.h +++ b/drivers/media/pci/intel/ipu3/cio2-bridge.h @@ -8,6 +8,8 @@ #include "ipu3-cio2.h" +struct i2c_client; + #define CIO2_HID "INT343E" #define CIO2_MAX_LANES 4 #define MAX_NUM_LINK_FREQS 3 @@ -42,12 +44,19 @@ .properties = _PROPS, \ } +#define NODE_VCM(_TYPE) \ + (const struct software_node) { \ + .name = _TYPE, \ + } + enum cio2_sensor_swnodes { SWNODE_SENSOR_HID, SWNODE_SENSOR_PORT, SWNODE_SENSOR_ENDPOINT, SWNODE_CIO2_PORT, SWNODE_CIO2_ENDPOINT, + /* Must be last because it is optional / maybe empty */ + SWNODE_VCM, SWNODE_COUNT }; @@ -106,8 +115,10 @@ struct cio2_sensor_config { struct cio2_sensor { char name[ACPI_ID_LEN]; struct acpi_device *adev; + struct i2c_client *vcm_i2c_client; - struct software_node swnodes[6]; + /* SWNODE_COUNT + 1 for terminating empty node */ + struct software_node swnodes[SWNODE_COUNT + 1]; struct cio2_node_names node_names; struct cio2_sensor_ssdb ssdb; @@ -115,10 +126,11 @@ struct cio2_sensor { struct cio2_property_names prop_names; struct property_entry ep_properties[5]; - struct property_entry dev_properties[4]; + struct property_entry dev_properties[5]; struct property_entry cio2_properties[3]; struct software_node_ref_args local_ref[1]; struct software_node_ref_args remote_ref[1]; + struct software_node_ref_args vcm_ref[1]; }; struct cio2_bridge { diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c index 356ea966cf8d..0e9b0503b62a 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c @@ -1713,11 +1713,6 @@ static int cio2_pci_probe(struct pci_dev *pci_dev, struct cio2_device *cio2; int r; - cio2 = devm_kzalloc(dev, sizeof(*cio2), GFP_KERNEL); - if (!cio2) - return -ENOMEM; - cio2->pci_dev = pci_dev; - /* * On some platforms no connections to sensors are defined in firmware, * if the device has no endpoints then we can try to build those as @@ -1735,6 +1730,11 @@ static int cio2_pci_probe(struct pci_dev *pci_dev, return r; } + cio2 = devm_kzalloc(dev, sizeof(*cio2), GFP_KERNEL); + if (!cio2) + return -ENOMEM; + cio2->pci_dev = pci_dev; + r = pcim_enable_device(pci_dev); if (r) { dev_err(dev, "failed to enable device (%d)\n", r); @@ -1966,12 +1966,19 @@ static int __maybe_unused cio2_suspend(struct device *dev) struct pci_dev *pci_dev = to_pci_dev(dev); struct cio2_device *cio2 = pci_get_drvdata(pci_dev); struct cio2_queue *q = cio2->cur_queue; + int r; dev_dbg(dev, "cio2 suspend\n"); if (!cio2->streaming) return 0; /* Stop stream */ + r = v4l2_subdev_call(q->sensor, video, s_stream, 0); + if (r) { + dev_err(dev, "failed to stop sensor streaming\n"); + return r; + } + cio2_hw_exit(cio2, q); synchronize_irq(pci_dev->irq); @@ -2005,8 +2012,16 @@ static int __maybe_unused cio2_resume(struct device *dev) } r = cio2_hw_init(cio2, q); - if (r) + if (r) { dev_err(dev, "fail to init cio2 hw\n"); + return r; + } + + r = v4l2_subdev_call(q->sensor, video, s_stream, 1); + if (r) { + dev_err(dev, "fail to start sensor streaming\n"); + cio2_hw_exit(cio2, q); + } return r; } diff --git a/drivers/media/pci/ivtv/ivtv-alsa-main.c b/drivers/media/pci/ivtv/ivtv-alsa-main.c index 4cefdb2e4d40..9e13a7128a53 100644 --- a/drivers/media/pci/ivtv/ivtv-alsa-main.c +++ b/drivers/media/pci/ivtv/ivtv-alsa-main.c @@ -48,12 +48,6 @@ struct snd_ivtv_card *to_snd_ivtv_card(struct v4l2_device *v4l2_dev) return to_ivtv(v4l2_dev)->alsa; } -static inline -struct snd_ivtv_card *p_to_snd_ivtv_card(struct v4l2_device **v4l2_dev) -{ - return container_of(v4l2_dev, struct snd_ivtv_card, v4l2_dev); -} - static void snd_ivtv_card_free(struct snd_ivtv_card *itvsc) { if (itvsc == NULL) diff --git a/drivers/media/pci/ivtv/ivtvfb.c b/drivers/media/pci/ivtv/ivtvfb.c index 2c43ebf83966..00ac94d4ab19 100644 --- a/drivers/media/pci/ivtv/ivtvfb.c +++ b/drivers/media/pci/ivtv/ivtvfb.c @@ -42,7 +42,7 @@ /* card parameters */ static int ivtvfb_card_id = -1; -static int ivtvfb_debug = 0; +static int ivtvfb_debug; static bool ivtvfb_force_pat = IS_ENABLED(CONFIG_VIDEO_FB_IVTV_FORCE_PAT); static bool osd_laced; static int osd_depth; diff --git a/drivers/media/pci/pt3/pt3.c b/drivers/media/pci/pt3/pt3.c index c0bc86793355..0d51bdf01f43 100644 --- a/drivers/media/pci/pt3/pt3.c +++ b/drivers/media/pci/pt3/pt3.c @@ -685,12 +685,6 @@ static void pt3_remove(struct pci_dev *pdev) for (i = PT3_NUM_FE - 1; i >= 0; i--) pt3_cleanup_adapter(pt3, i); i2c_del_adapter(&pt3->i2c_adap); - kfree(pt3->i2c_buf); - pci_iounmap(pt3->pdev, pt3->regs[0]); - pci_iounmap(pt3->pdev, pt3->regs[1]); - pci_release_regions(pdev); - pci_disable_device(pdev); - kfree(pt3); } static int pt3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -704,14 +698,14 @@ static int pt3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (pci_read_config_byte(pdev, PCI_REVISION_ID, &rev) || rev != 1) return -ENODEV; - ret = pci_enable_device(pdev); + ret = pcim_enable_device(pdev); if (ret < 0) return -ENODEV; pci_set_master(pdev); - ret = pci_request_regions(pdev, DRV_NAME); + ret = pcim_iomap_regions(pdev, BIT(0) | BIT(2), DRV_NAME); if (ret < 0) - goto err_disable_device; + return ret; ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)); if (ret == 0) @@ -722,42 +716,32 @@ static int pt3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); else { dev_err(&pdev->dev, "Failed to set DMA mask\n"); - goto err_release_regions; + return ret; } dev_info(&pdev->dev, "Use 32bit DMA\n"); } - pt3 = kzalloc(sizeof(*pt3), GFP_KERNEL); - if (!pt3) { - ret = -ENOMEM; - goto err_release_regions; - } + pt3 = devm_kzalloc(&pdev->dev, sizeof(*pt3), GFP_KERNEL); + if (!pt3) + return -ENOMEM; pci_set_drvdata(pdev, pt3); pt3->pdev = pdev; mutex_init(&pt3->lock); - pt3->regs[0] = pci_ioremap_bar(pdev, 0); - pt3->regs[1] = pci_ioremap_bar(pdev, 2); - if (pt3->regs[0] == NULL || pt3->regs[1] == NULL) { - dev_err(&pdev->dev, "Failed to ioremap\n"); - ret = -ENOMEM; - goto err_kfree; - } + pt3->regs[0] = pcim_iomap_table(pdev)[0]; + pt3->regs[1] = pcim_iomap_table(pdev)[2]; ver = ioread32(pt3->regs[0] + REG_VERSION); if ((ver >> 16) != 0x0301) { dev_warn(&pdev->dev, "PT%d, I/F-ver.:%d not supported\n", ver >> 24, (ver & 0x00ff0000) >> 16); - ret = -ENODEV; - goto err_iounmap; + return -ENODEV; } pt3->num_bufs = clamp_val(num_bufs, MIN_DATA_BUFS, MAX_DATA_BUFS); - pt3->i2c_buf = kmalloc(sizeof(*pt3->i2c_buf), GFP_KERNEL); - if (pt3->i2c_buf == NULL) { - ret = -ENOMEM; - goto err_iounmap; - } + pt3->i2c_buf = devm_kmalloc(&pdev->dev, sizeof(*pt3->i2c_buf), GFP_KERNEL); + if (!pt3->i2c_buf) + return -ENOMEM; i2c = &pt3->i2c_adap; i2c->owner = THIS_MODULE; i2c->algo = &pt3_i2c_algo; @@ -767,7 +751,7 @@ static int pt3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) i2c_set_adapdata(i2c, pt3); ret = i2c_add_adapter(i2c); if (ret < 0) - goto err_i2cbuf; + return ret; for (i = 0; i < PT3_NUM_FE; i++) { ret = pt3_alloc_adapter(pt3, i); @@ -799,21 +783,7 @@ err_cleanup_adapters: while (i >= 0) pt3_cleanup_adapter(pt3, i--); i2c_del_adapter(i2c); -err_i2cbuf: - kfree(pt3->i2c_buf); -err_iounmap: - if (pt3->regs[0]) - pci_iounmap(pdev, pt3->regs[0]); - if (pt3->regs[1]) - pci_iounmap(pdev, pt3->regs[1]); -err_kfree: - kfree(pt3); -err_release_regions: - pci_release_regions(pdev); -err_disable_device: - pci_disable_device(pdev); return ret; - } static const struct pci_device_id pt3_id_table[] = { diff --git a/drivers/media/pci/saa7134/saa7134-go7007.c b/drivers/media/pci/saa7134/saa7134-go7007.c index f319edb39c0e..da83893ffee9 100644 --- a/drivers/media/pci/saa7134/saa7134-go7007.c +++ b/drivers/media/pci/saa7134/saa7134-go7007.c @@ -56,11 +56,6 @@ struct saa7134_go7007 { dma_addr_t bottom_dma; }; -static inline struct saa7134_go7007 *to_state(struct v4l2_subdev *sd) -{ - return container_of(sd, struct saa7134_go7007, sd); -} - static const struct go7007_board_info board_voyager = { .flags = 0, .sensor_flags = GO7007_SENSOR_656 | @@ -385,7 +380,7 @@ MODULE_FIRMWARE("go7007/go7007tv.bin"); static int saa7134_go7007_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) { #if 0 - struct saa7134_go7007 *saa = to_state(sd); + struct saa7134_go7007 *saa = container_of(sd, struct saa7134_go7007, sd); struct saa7134_dev *dev = saa->dev; return saa7134_s_std_internal(dev, NULL, norm); diff --git a/drivers/media/pci/saa7146/hexium_gemini.c b/drivers/media/pci/saa7146/hexium_gemini.c index 2214c74bbbf1..3947701cd6c7 100644 --- a/drivers/media/pci/saa7146/hexium_gemini.c +++ b/drivers/media/pci/saa7146/hexium_gemini.c @@ -284,7 +284,12 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d hexium_set_input(hexium, 0); hexium->cur_input = 0; - saa7146_vv_init(dev, &vv_data); + ret = saa7146_vv_init(dev, &vv_data); + if (ret) { + i2c_del_adapter(&hexium->i2c_adapter); + kfree(hexium); + return ret; + } vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input; vv_data.vid_ops.vidioc_g_input = vidioc_g_input; diff --git a/drivers/media/pci/saa7146/hexium_orion.c b/drivers/media/pci/saa7146/hexium_orion.c index 39d14c179d22..2eb4bee16b71 100644 --- a/drivers/media/pci/saa7146/hexium_orion.c +++ b/drivers/media/pci/saa7146/hexium_orion.c @@ -355,10 +355,16 @@ static struct saa7146_ext_vv vv_data; static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) { struct hexium *hexium = (struct hexium *) dev->ext_priv; + int ret; DEB_EE("\n"); - saa7146_vv_init(dev, &vv_data); + ret = saa7146_vv_init(dev, &vv_data); + if (ret) { + pr_err("Error in saa7146_vv_init()\n"); + return ret; + } + vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input; vv_data.vid_ops.vidioc_g_input = vidioc_g_input; vv_data.vid_ops.vidioc_s_input = vidioc_s_input; diff --git a/drivers/media/pci/saa7146/mxb.c b/drivers/media/pci/saa7146/mxb.c index 73fc901ecf3d..7ded8f5b05cb 100644 --- a/drivers/media/pci/saa7146/mxb.c +++ b/drivers/media/pci/saa7146/mxb.c @@ -340,7 +340,7 @@ static int mxb_init_done(struct saa7146_dev* dev) struct tuner_setup tun_setup; v4l2_std_id std = V4L2_STD_PAL_BG; - int i = 0, err = 0; + int i, err = 0; /* mute audio on tea6420s */ tea6420_route(mxb, 6); @@ -349,7 +349,6 @@ static int mxb_init_done(struct saa7146_dev* dev) saa7111a_call(mxb, video, s_std, std); /* select tuner-output on saa7111a */ - i = 0; saa7111a_call(mxb, video, s_routing, SAA7115_COMPOSITE0, SAA7111_FMT_CCIR, 0); @@ -683,10 +682,16 @@ static struct saa7146_ext_vv vv_data; static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) { struct mxb *mxb; + int ret; DEB_EE("dev:%p\n", dev); - saa7146_vv_init(dev, &vv_data); + ret = saa7146_vv_init(dev, &vv_data); + if (ret) { + ERR("Error in saa7146_vv_init()"); + return ret; + } + if (mxb_probe(dev)) { saa7146_vv_release(dev); return -1; diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c index 0abcad4e84fa..7766cadb73ea 100644 --- a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c +++ b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c @@ -391,12 +391,12 @@ static int solo_send_desc(struct solo_enc_dev *solo_enc, int skip, } /* Extract values from VOP header - VE_STATUSxx */ -static inline int vop_interlaced(const vop_header *vh) +static inline __always_unused int vop_interlaced(const vop_header *vh) { return (__le32_to_cpu((*vh)[0]) >> 30) & 1; } -static inline u8 vop_channel(const vop_header *vh) +static inline __always_unused u8 vop_channel(const vop_header *vh) { return (__le32_to_cpu((*vh)[0]) >> 24) & 0x1F; } @@ -411,12 +411,12 @@ static inline u32 vop_mpeg_size(const vop_header *vh) return __le32_to_cpu((*vh)[0]) & 0xFFFFF; } -static inline u8 vop_hsize(const vop_header *vh) +static inline u8 __always_unused vop_hsize(const vop_header *vh) { return (__le32_to_cpu((*vh)[1]) >> 8) & 0xFF; } -static inline u8 vop_vsize(const vop_header *vh) +static inline u8 __always_unused vop_vsize(const vop_header *vh) { return __le32_to_cpu((*vh)[1]) & 0xFF; } @@ -436,12 +436,12 @@ static inline u32 vop_jpeg_size(const vop_header *vh) return __le32_to_cpu((*vh)[4]) & 0xFFFFF; } -static inline u32 vop_sec(const vop_header *vh) +static inline u32 __always_unused vop_sec(const vop_header *vh) { return __le32_to_cpu((*vh)[5]); } -static inline u32 vop_usec(const vop_header *vh) +static inline __always_unused u32 vop_usec(const vop_header *vh) { return __le32_to_cpu((*vh)[6]); } diff --git a/drivers/media/pci/tw5864/tw5864-core.c b/drivers/media/pci/tw5864/tw5864-core.c index 23d3cae54a5d..5cae73e6fb9c 100644 --- a/drivers/media/pci/tw5864/tw5864-core.c +++ b/drivers/media/pci/tw5864/tw5864-core.c @@ -333,11 +333,10 @@ static void tw5864_finidev(struct pci_dev *pci_dev) /* release resources */ iounmap(dev->mmio); - release_mem_region(pci_resource_start(pci_dev, 0), - pci_resource_len(pci_dev, 0)); + pci_release_regions(pci_dev); + pci_disable_device(pci_dev); v4l2_device_unregister(&dev->v4l2_dev); - devm_kfree(&pci_dev->dev, dev); } static struct pci_driver tw5864_pci_driver = { diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index cf4adc64c953..9fbdba0fd1e7 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -492,6 +492,18 @@ config VIDEO_STI_DELTA_DRIVER endif # VIDEO_STI_DELTA +config VIDEO_STM32_DMA2D + tristate "STM32 Chrom-Art Accelerator (DMA2D)" + depends on VIDEO_DEV && VIDEO_V4L2 + depends on ARCH_STM32 || COMPILE_TEST + select VIDEOBUF2_DMA_CONTIG + select V4L2_MEM2MEM_DEV + help + Enables DMA2D hardware support on stm32. + + The STM32 DMA2D is a memory-to-memory engine for pixel conversion + and specialized DMA dedicated to image manipulation. + config VIDEO_RENESAS_FDP1 tristate "Renesas Fine Display Processor" depends on VIDEO_DEV && VIDEO_V4L2 diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index a148553babfc..19bcbced7382 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -71,6 +71,7 @@ obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel/ obj-$(CONFIG_VIDEO_ATMEL_XISC) += atmel/ obj-$(CONFIG_VIDEO_STM32_DCMI) += stm32/ +obj-$(CONFIG_VIDEO_STM32_DMA2D) += stm32/ obj-$(CONFIG_VIDEO_MEDIATEK_VPU) += mtk-vpu/ diff --git a/drivers/media/platform/allegro-dvt/allegro-core.c b/drivers/media/platform/allegro-dvt/allegro-core.c index c8156da33043..4a3d06c70e34 100644 --- a/drivers/media/platform/allegro-dvt/allegro-core.c +++ b/drivers/media/platform/allegro-dvt/allegro-core.c @@ -2815,7 +2815,7 @@ static void allegro_buf_queue(struct vb2_buffer *vb) unsigned int i; for (i = 0; i < vb->num_planes; i++) - vb->planes[i].bytesused = 0; + vb2_set_plane_payload(vb, i, 0); vbuf->field = V4L2_FIELD_NONE; vbuf->sequence = channel->csequence++; diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c index cad3f97515ae..7a24daf7165a 100644 --- a/drivers/media/platform/aspeed-video.c +++ b/drivers/media/platform/aspeed-video.c @@ -539,6 +539,10 @@ static void aspeed_video_enable_mode_detect(struct aspeed_video *video) aspeed_video_update(video, VE_INTERRUPT_CTRL, 0, VE_INTERRUPT_MODE_DETECT); + /* Disable mode detect in order to re-trigger */ + aspeed_video_update(video, VE_SEQ_CTRL, + VE_SEQ_CTRL_TRIG_MODE_DET, 0); + /* Trigger mode detect */ aspeed_video_update(video, VE_SEQ_CTRL, 0, VE_SEQ_CTRL_TRIG_MODE_DET); } @@ -591,6 +595,8 @@ static void aspeed_video_irq_res_change(struct aspeed_video *video, ulong delay) set_bit(VIDEO_RES_CHANGE, &video->flags); clear_bit(VIDEO_FRAME_INPRG, &video->flags); + video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL; + aspeed_video_off(video); aspeed_video_bufs_done(video, VB2_BUF_STATE_ERROR); @@ -824,10 +830,6 @@ static void aspeed_video_get_resolution(struct aspeed_video *video) return; } - /* Disable mode detect in order to re-trigger */ - aspeed_video_update(video, VE_SEQ_CTRL, - VE_SEQ_CTRL_TRIG_MODE_DET, 0); - aspeed_video_check_and_set_polarity(video); aspeed_video_enable_mode_detect(video); @@ -1375,7 +1377,6 @@ static void aspeed_video_resolution_work(struct work_struct *work) struct delayed_work *dwork = to_delayed_work(work); struct aspeed_video *video = container_of(dwork, struct aspeed_video, res_work); - u32 input_status = video->v4l2_input_status; aspeed_video_on(video); @@ -1388,8 +1389,7 @@ static void aspeed_video_resolution_work(struct work_struct *work) aspeed_video_get_resolution(video); if (video->detected_timings.width != video->active_timings.width || - video->detected_timings.height != video->active_timings.height || - input_status != video->v4l2_input_status) { + video->detected_timings.height != video->active_timings.height) { static const struct v4l2_event ev = { .type = V4L2_EVENT_SOURCE_CHANGE, .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 0e312b0842d7..3cd47ba26357 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -43,7 +43,7 @@ #define CODA_NAME "coda" #define CODADX6_MAX_INSTANCES 4 -#define CODA_MAX_FORMATS 4 +#define CODA_MAX_FORMATS 5 #define CODA_ISRAM_SIZE (2048 * 2) @@ -247,6 +247,7 @@ static const struct coda_video_device coda9_jpeg_encoder = { V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_YVU420, V4L2_PIX_FMT_YUV422P, + V4L2_PIX_FMT_GREY, }, .dst_formats = { V4L2_PIX_FMT_JPEG, @@ -626,6 +627,11 @@ static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec, f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height * 2; break; + case V4L2_PIX_FMT_GREY: + /* keep 16 pixel alignment of 8-bit pixel data */ + f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16); + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; + break; case V4L2_PIX_FMT_JPEG: case V4L2_PIX_FMT_H264: case V4L2_PIX_FMT_MPEG4: @@ -1537,11 +1543,13 @@ static void coda_pic_run_work(struct work_struct *work) if (!wait_for_completion_timeout(&ctx->completion, msecs_to_jiffies(1000))) { - dev_err(dev->dev, "CODA PIC_RUN timeout\n"); + if (ctx->use_bit) { + dev_err(dev->dev, "CODA PIC_RUN timeout\n"); - ctx->hold = true; + ctx->hold = true; - coda_hw_reset(ctx); + coda_hw_reset(ctx); + } if (ctx->ops->run_timeout) ctx->ops->run_timeout(ctx); diff --git a/drivers/media/platform/coda/coda-jpeg.c b/drivers/media/platform/coda/coda-jpeg.c index b11cfbe166dd..a72f4655e5ad 100644 --- a/drivers/media/platform/coda/coda-jpeg.c +++ b/drivers/media/platform/coda/coda-jpeg.c @@ -1127,7 +1127,8 @@ static int coda9_jpeg_prepare_encode(struct coda_ctx *ctx) coda_write(dev, 0, CODA9_REG_JPEG_GBU_BT_PTR); coda_write(dev, 0, CODA9_REG_JPEG_GBU_WD_PTR); coda_write(dev, 0, CODA9_REG_JPEG_GBU_BBSR); - coda_write(dev, 0, CODA9_REG_JPEG_BBC_STRM_CTRL); + coda_write(dev, BIT(31) | ((end_addr - start_addr - header_len) / 256), + CODA9_REG_JPEG_BBC_STRM_CTRL); coda_write(dev, 0, CODA9_REG_JPEG_GBU_CTRL); coda_write(dev, 0, CODA9_REG_JPEG_GBU_FF_RPTR); coda_write(dev, 127, CODA9_REG_JPEG_GBU_BBER); @@ -1257,6 +1258,23 @@ static void coda9_jpeg_finish_encode(struct coda_ctx *ctx) coda_hw_reset(ctx); } +static void coda9_jpeg_encode_timeout(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + u32 end_addr, wr_ptr; + + /* Handle missing BBC overflow interrupt via timeout */ + end_addr = coda_read(dev, CODA9_REG_JPEG_BBC_END_ADDR); + wr_ptr = coda_read(dev, CODA9_REG_JPEG_BBC_WR_PTR); + if (wr_ptr >= end_addr - 256) { + v4l2_err(&dev->v4l2_dev, "JPEG too large for capture buffer\n"); + coda9_jpeg_finish_encode(ctx); + return; + } + + coda_hw_reset(ctx); +} + static void coda9_jpeg_release(struct coda_ctx *ctx) { int i; @@ -1276,6 +1294,7 @@ const struct coda_context_ops coda9_jpeg_encode_ops = { .start_streaming = coda9_jpeg_start_encoding, .prepare_run = coda9_jpeg_prepare_encode, .finish_run = coda9_jpeg_finish_encode, + .run_timeout = coda9_jpeg_encode_timeout, .release = coda9_jpeg_release, }; diff --git a/drivers/media/platform/coda/imx-vdoa.c b/drivers/media/platform/coda/imx-vdoa.c index 6996d4571e36..00643f37b3e6 100644 --- a/drivers/media/platform/coda/imx-vdoa.c +++ b/drivers/media/platform/coda/imx-vdoa.c @@ -287,7 +287,11 @@ static int vdoa_probe(struct platform_device *pdev) struct resource *res; int ret; - dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); + ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(&pdev->dev, "DMA enable failed\n"); + return ret; + } vdoa = devm_kzalloc(&pdev->dev, sizeof(*vdoa), GFP_KERNEL); if (!vdoa) diff --git a/drivers/media/platform/davinci/vpbe_osd.c b/drivers/media/platform/davinci/vpbe_osd.c index 91b571a0ac2c..32f7ef547c82 100644 --- a/drivers/media/platform/davinci/vpbe_osd.c +++ b/drivers/media/platform/davinci/vpbe_osd.c @@ -45,7 +45,7 @@ static const struct platform_device_id vpbe_osd_devtype[] = { MODULE_DEVICE_TABLE(platform, vpbe_osd_devtype); /* register access routines */ -static inline u32 osd_read(struct osd_state *sd, u32 offset) +static inline u32 __always_unused osd_read(struct osd_state *sd, u32 offset) { struct osd_state *osd = sd; diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index ae92e2c206d0..8fe55374c5a3 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -619,17 +619,6 @@ static void vpif_calculate_offsets(struct channel_obj *ch) } /** - * vpif_get_default_field() - Get default field type based on interface - * @iface: ptr to vpif interface - */ -static inline enum v4l2_field vpif_get_default_field( - struct vpif_interface *iface) -{ - return (iface->if_type == VPIF_IF_RAW_BAYER) ? V4L2_FIELD_NONE : - V4L2_FIELD_INTERLACED; -} - -/** * vpif_config_addr() - function to configure buffer address in vpif * @ch: channel ptr * @muxmode: channel mux mode @@ -1478,7 +1467,6 @@ probe_out: for (k = 0; k < j; k++) { /* Get the pointer to the channel object */ ch = vpif_obj.dev[k]; - common = &ch->common[k]; /* Unregister video device */ video_unregister_device(&ch->video_dev); } diff --git a/drivers/media/platform/imx-pxp.c b/drivers/media/platform/imx-pxp.c index 723b096fedd1..689ae5e6ac62 100644 --- a/drivers/media/platform/imx-pxp.c +++ b/drivers/media/platform/imx-pxp.c @@ -211,6 +211,7 @@ struct pxp_ctx { /* Processing mode */ int mode; u8 alpha_component; + u8 rotation; enum v4l2_colorspace colorspace; enum v4l2_xfer_func xfer_func; @@ -767,14 +768,20 @@ static int pxp_start(struct pxp_ctx *ctx, struct vb2_v4l2_buffer *in_vb, V4L2_BUF_FLAG_BFRAME | V4L2_BUF_FLAG_TSTAMP_SRC_MASK); - /* Rotation disabled, 8x8 block size */ + /* 8x8 block size */ ctrl = BF_PXP_CTRL_VFLIP0(!!(ctx->mode & MEM2MEM_VFLIP)) | - BF_PXP_CTRL_HFLIP0(!!(ctx->mode & MEM2MEM_HFLIP)); + BF_PXP_CTRL_HFLIP0(!!(ctx->mode & MEM2MEM_HFLIP)) | + BF_PXP_CTRL_ROTATE0(ctx->rotation); /* Always write alpha value as V4L2_CID_ALPHA_COMPONENT */ out_ctrl = BF_PXP_OUT_CTRL_ALPHA(ctx->alpha_component) | BF_PXP_OUT_CTRL_ALPHA_OUTPUT(1) | pxp_v4l2_pix_fmt_to_out_format(dst_fourcc); out_buf = p_out; + + if (ctx->rotation == BV_PXP_CTRL_ROTATE0__ROT_90 || + ctx->rotation == BV_PXP_CTRL_ROTATE0__ROT_270) + swap(dst_width, dst_height); + switch (dst_fourcc) { case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV21: @@ -1297,6 +1304,21 @@ static int pxp_s_fmt_vid_out(struct file *file, void *priv, return 0; } +static u8 pxp_degrees_to_rot_mode(u32 degrees) +{ + switch (degrees) { + case 90: + return BV_PXP_CTRL_ROTATE0__ROT_90; + case 180: + return BV_PXP_CTRL_ROTATE0__ROT_180; + case 270: + return BV_PXP_CTRL_ROTATE0__ROT_270; + case 0: + default: + return BV_PXP_CTRL_ROTATE0__ROT_0; + } +} + static int pxp_s_ctrl(struct v4l2_ctrl *ctrl) { struct pxp_ctx *ctx = @@ -1317,6 +1339,10 @@ static int pxp_s_ctrl(struct v4l2_ctrl *ctrl) ctx->mode &= ~MEM2MEM_VFLIP; break; + case V4L2_CID_ROTATE: + ctx->rotation = pxp_degrees_to_rot_mode(ctrl->val); + break; + case V4L2_CID_ALPHA_COMPONENT: ctx->alpha_component = ctrl->val; break; @@ -1524,6 +1550,7 @@ static int pxp_open(struct file *file) v4l2_ctrl_handler_init(hdl, 4); v4l2_ctrl_new_std(hdl, &pxp_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0); v4l2_ctrl_new_std(hdl, &pxp_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(hdl, &pxp_ctrl_ops, V4L2_CID_ROTATE, 0, 270, 90, 0); v4l2_ctrl_new_std(hdl, &pxp_ctrl_ops, V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 255); if (hdl->error) { @@ -1659,6 +1686,8 @@ static int pxp_probe(struct platform_device *pdev) if (irq < 0) return irq; + spin_lock_init(&dev->irqlock); + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, pxp_irq_handler, IRQF_ONESHOT, dev_name(&pdev->dev), dev); if (ret < 0) { @@ -1676,8 +1705,6 @@ static int pxp_probe(struct platform_device *pdev) goto err_clk; } - spin_lock_init(&dev->irqlock); - ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); if (ret) goto err_clk; diff --git a/drivers/media/platform/marvell-ccic/cafe-driver.c b/drivers/media/platform/marvell-ccic/cafe-driver.c index b61b9d9551af..03dcf8bf705e 100644 --- a/drivers/media/platform/marvell-ccic/cafe-driver.c +++ b/drivers/media/platform/marvell-ccic/cafe-driver.c @@ -139,13 +139,6 @@ struct cafe_camera { */ #define CAFE_SMBUS_TIMEOUT (HZ) /* generous */ -static inline struct cafe_camera *to_cam(struct v4l2_device *dev) -{ - struct mcam_camera *m = container_of(dev, struct mcam_camera, v4l2_dev); - return container_of(m, struct cafe_camera, mcam); -} - - static int cafe_smbus_write_done(struct mcam_camera *mcam) { unsigned long flags; diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c index af994b9913a6..f332beb06d51 100644 --- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c @@ -1361,10 +1361,8 @@ static int mtk_jpeg_probe(struct platform_device *pdev) } jpeg_irq = platform_get_irq(pdev, 0); - if (jpeg_irq < 0) { - dev_err(&pdev->dev, "Failed to get jpeg_irq %d.\n", jpeg_irq); + if (jpeg_irq < 0) return jpeg_irq; - } ret = devm_request_irq(&pdev->dev, jpeg_irq, jpeg->variant->irq_handler, 0, pdev->name, jpeg); diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_core.c b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c index 976aa1f4829b..3d38793aaa25 100644 --- a/drivers/media/platform/mtk-mdp/mtk_mdp_core.c +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c @@ -148,7 +148,7 @@ static int mtk_mdp_probe(struct platform_device *pdev) continue; } - comp_type = (enum mtk_mdp_comp_type)of_id->data; + comp_type = (uintptr_t)of_id->data; comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL); if (!comp) { diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h index 46783516b84a..e08886a600a3 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h @@ -11,6 +11,7 @@ #include <media/videobuf2-core.h> #include <media/v4l2-mem2mem.h> +#define VCODEC_DEC_ALIGNED_64 64 #define VCODEC_CAPABILITY_4K_DISABLED 0x10 #define VCODEC_DEC_4K_CODED_WIDTH 4096U #define VCODEC_DEC_4K_CODED_HEIGHT 2304U diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c index e6e6a8203eeb..40c39e1e596b 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c @@ -28,9 +28,6 @@ #define VDEC_IRQ_CLR 0x10 #define VDEC_IRQ_CFG_REG 0xa4 -module_param(mtk_v4l2_dbg_level, int, 0644); -module_param(mtk_vcodec_dbg, bool, 0644); - /* Wake up context wait_queue */ static void wake_up_ctx(struct mtk_vcodec_ctx *ctx) { @@ -358,6 +355,8 @@ err_media_reg: if (dev->vdec_pdata->uses_stateless_api) v4l2_m2m_unregister_media_controller(dev->m2m_dev_dec); err_reg_cont: + if (dev->vdec_pdata->uses_stateless_api) + media_device_cleanup(&dev->mdev_dec); destroy_workqueue(dev->decode_workqueue); err_event_workq: v4l2_m2m_release(dev->m2m_dev_dec); @@ -390,7 +389,6 @@ static int mtk_vcodec_dec_remove(struct platform_device *pdev) { struct mtk_vcodec_dev *dev = platform_get_drvdata(pdev); - flush_workqueue(dev->decode_workqueue); destroy_workqueue(dev->decode_workqueue); if (media_devnode_is_registered(dev->mdev_dec.devnode)) { diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c index 8f4a1f0a0769..3d9f47555884 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_stateless.c @@ -133,7 +133,6 @@ static struct vdec_fb *vdec_get_cap_buffer(struct mtk_vcodec_ctx *ctx, struct vdec_fb *pfb = &framebuf->frame_buffer; struct vb2_buffer *dst_buf = &vb2_v4l2->vb2_buf; - pfb = &framebuf->frame_buffer; pfb->base_y.va = NULL; pfb->base_y.dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); pfb->base_y.size = ctx->q_data[MTK_Q_DATA_DST].sizeimage[0]; diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c index 7457451ebff0..ffb046eec610 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c @@ -104,6 +104,13 @@ static int vidioc_venc_s_ctrl(struct v4l2_ctrl *ctrl) p->gop_size = ctrl->val; ctx->param_change |= MTK_ENCODE_PARAM_GOP_SIZE; break; + case V4L2_CID_MPEG_VIDEO_VP8_PROFILE: + /* + * FIXME - what vp8 profiles are actually supported? + * The ctrl is added (with only profile 0 supported) for now. + */ + mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_VP8_PROFILE val = %d", ctrl->val); + break; case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME"); p->force_intra = 1; @@ -257,87 +264,82 @@ static struct mtk_q_data *mtk_venc_get_q_data(struct mtk_vcodec_ctx *ctx, return &ctx->q_data[MTK_Q_DATA_DST]; } +static void vidioc_try_fmt_cap(struct v4l2_format *f) +{ + f->fmt.pix_mp.field = V4L2_FIELD_NONE; + f->fmt.pix_mp.num_planes = 1; + f->fmt.pix_mp.plane_fmt[0].bytesperline = 0; + f->fmt.pix_mp.flags = 0; +} + /* V4L2 specification suggests the driver corrects the format struct if any of * the dimensions is unsupported */ -static int vidioc_try_fmt(struct mtk_vcodec_ctx *ctx, struct v4l2_format *f, - const struct mtk_video_fmt *fmt) +static int vidioc_try_fmt_out(struct mtk_vcodec_ctx *ctx, struct v4l2_format *f, + const struct mtk_video_fmt *fmt) { struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; + int tmp_w, tmp_h; + unsigned int max_width, max_height; pix_fmt_mp->field = V4L2_FIELD_NONE; - if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - pix_fmt_mp->num_planes = 1; - pix_fmt_mp->plane_fmt[0].bytesperline = 0; - } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - int tmp_w, tmp_h; - unsigned int max_width, max_height; - - if (ctx->dev->enc_capability & MTK_VENC_4K_CAPABILITY_ENABLE) { - max_width = MTK_VENC_4K_MAX_W; - max_height = MTK_VENC_4K_MAX_H; - } else { - max_width = MTK_VENC_HD_MAX_W; - max_height = MTK_VENC_HD_MAX_H; - } + if (ctx->dev->enc_capability & MTK_VENC_4K_CAPABILITY_ENABLE) { + max_width = MTK_VENC_4K_MAX_W; + max_height = MTK_VENC_4K_MAX_H; + } else { + max_width = MTK_VENC_HD_MAX_W; + max_height = MTK_VENC_HD_MAX_H; + } - pix_fmt_mp->height = clamp(pix_fmt_mp->height, - MTK_VENC_MIN_H, - max_height); - pix_fmt_mp->width = clamp(pix_fmt_mp->width, - MTK_VENC_MIN_W, - max_width); + pix_fmt_mp->height = clamp(pix_fmt_mp->height, MTK_VENC_MIN_H, max_height); + pix_fmt_mp->width = clamp(pix_fmt_mp->width, MTK_VENC_MIN_W, max_width); - /* find next closer width align 16, heign align 32, size align - * 64 rectangle - */ - tmp_w = pix_fmt_mp->width; - tmp_h = pix_fmt_mp->height; - v4l_bound_align_image(&pix_fmt_mp->width, - MTK_VENC_MIN_W, - max_width, 4, - &pix_fmt_mp->height, - MTK_VENC_MIN_H, - max_height, 5, 6); - - if (pix_fmt_mp->width < tmp_w && - (pix_fmt_mp->width + 16) <= max_width) - pix_fmt_mp->width += 16; - if (pix_fmt_mp->height < tmp_h && - (pix_fmt_mp->height + 32) <= max_height) - pix_fmt_mp->height += 32; - - mtk_v4l2_debug(0, - "before resize width=%d, height=%d, after resize width=%d, height=%d, sizeimage=%d %d", - tmp_w, tmp_h, pix_fmt_mp->width, - pix_fmt_mp->height, - pix_fmt_mp->plane_fmt[0].sizeimage, - pix_fmt_mp->plane_fmt[1].sizeimage); - - pix_fmt_mp->num_planes = fmt->num_planes; - pix_fmt_mp->plane_fmt[0].sizeimage = - pix_fmt_mp->width * pix_fmt_mp->height + - ((ALIGN(pix_fmt_mp->width, 16) * 2) * 16); - pix_fmt_mp->plane_fmt[0].bytesperline = pix_fmt_mp->width; - - if (pix_fmt_mp->num_planes == 2) { - pix_fmt_mp->plane_fmt[1].sizeimage = - (pix_fmt_mp->width * pix_fmt_mp->height) / 2 + - (ALIGN(pix_fmt_mp->width, 16) * 16); - pix_fmt_mp->plane_fmt[2].sizeimage = 0; - pix_fmt_mp->plane_fmt[1].bytesperline = - pix_fmt_mp->width; - pix_fmt_mp->plane_fmt[2].bytesperline = 0; - } else if (pix_fmt_mp->num_planes == 3) { - pix_fmt_mp->plane_fmt[1].sizeimage = - pix_fmt_mp->plane_fmt[2].sizeimage = - (pix_fmt_mp->width * pix_fmt_mp->height) / 4 + - ((ALIGN(pix_fmt_mp->width, 16) / 2) * 16); - pix_fmt_mp->plane_fmt[1].bytesperline = - pix_fmt_mp->plane_fmt[2].bytesperline = - pix_fmt_mp->width / 2; - } + /* find next closer width align 16, heign align 32, size align + * 64 rectangle + */ + tmp_w = pix_fmt_mp->width; + tmp_h = pix_fmt_mp->height; + v4l_bound_align_image(&pix_fmt_mp->width, + MTK_VENC_MIN_W, + max_width, 4, + &pix_fmt_mp->height, + MTK_VENC_MIN_H, + max_height, 5, 6); + + if (pix_fmt_mp->width < tmp_w && (pix_fmt_mp->width + 16) <= max_width) + pix_fmt_mp->width += 16; + if (pix_fmt_mp->height < tmp_h && (pix_fmt_mp->height + 32) <= max_height) + pix_fmt_mp->height += 32; + + mtk_v4l2_debug(0, "before resize w=%d, h=%d, after resize w=%d, h=%d, sizeimage=%d %d", + tmp_w, tmp_h, pix_fmt_mp->width, + pix_fmt_mp->height, + pix_fmt_mp->plane_fmt[0].sizeimage, + pix_fmt_mp->plane_fmt[1].sizeimage); + + pix_fmt_mp->num_planes = fmt->num_planes; + pix_fmt_mp->plane_fmt[0].sizeimage = + pix_fmt_mp->width * pix_fmt_mp->height + + ((ALIGN(pix_fmt_mp->width, 16) * 2) * 16); + pix_fmt_mp->plane_fmt[0].bytesperline = pix_fmt_mp->width; + + if (pix_fmt_mp->num_planes == 2) { + pix_fmt_mp->plane_fmt[1].sizeimage = + (pix_fmt_mp->width * pix_fmt_mp->height) / 2 + + (ALIGN(pix_fmt_mp->width, 16) * 16); + pix_fmt_mp->plane_fmt[2].sizeimage = 0; + pix_fmt_mp->plane_fmt[1].bytesperline = + pix_fmt_mp->width; + pix_fmt_mp->plane_fmt[2].bytesperline = 0; + } else if (pix_fmt_mp->num_planes == 3) { + pix_fmt_mp->plane_fmt[1].sizeimage = + pix_fmt_mp->plane_fmt[2].sizeimage = + (pix_fmt_mp->width * pix_fmt_mp->height) / 4 + + ((ALIGN(pix_fmt_mp->width, 16) / 2) * 16); + pix_fmt_mp->plane_fmt[1].bytesperline = + pix_fmt_mp->plane_fmt[2].bytesperline = + pix_fmt_mp->width / 2; } pix_fmt_mp->flags = 0; @@ -398,7 +400,7 @@ static int vidioc_venc_s_fmt_cap(struct file *file, void *priv, struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); const struct mtk_vcodec_enc_pdata *pdata = ctx->dev->venc_pdata; struct vb2_queue *vq; - struct mtk_q_data *q_data; + struct mtk_q_data *q_data = mtk_venc_get_q_data(ctx, f->type); int i, ret; const struct mtk_video_fmt *fmt; @@ -413,12 +415,6 @@ static int vidioc_venc_s_fmt_cap(struct file *file, void *priv, return -EBUSY; } - q_data = mtk_venc_get_q_data(ctx, f->type); - if (!q_data) { - mtk_v4l2_err("fail to get q data"); - return -EINVAL; - } - fmt = mtk_venc_find_format(f->fmt.pix.pixelformat, pdata); if (!fmt) { fmt = &ctx->dev->venc_pdata->capture_formats[0]; @@ -426,9 +422,7 @@ static int vidioc_venc_s_fmt_cap(struct file *file, void *priv, } q_data->fmt = fmt; - ret = vidioc_try_fmt(ctx, f, q_data->fmt); - if (ret) - return ret; + vidioc_try_fmt_cap(f); q_data->coded_width = f->fmt.pix_mp.width; q_data->coded_height = f->fmt.pix_mp.height; @@ -461,7 +455,7 @@ static int vidioc_venc_s_fmt_out(struct file *file, void *priv, struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); const struct mtk_vcodec_enc_pdata *pdata = ctx->dev->venc_pdata; struct vb2_queue *vq; - struct mtk_q_data *q_data; + struct mtk_q_data *q_data = mtk_venc_get_q_data(ctx, f->type); int ret, i; const struct mtk_video_fmt *fmt; @@ -476,19 +470,13 @@ static int vidioc_venc_s_fmt_out(struct file *file, void *priv, return -EBUSY; } - q_data = mtk_venc_get_q_data(ctx, f->type); - if (!q_data) { - mtk_v4l2_err("fail to get q data"); - return -EINVAL; - } - fmt = mtk_venc_find_format(f->fmt.pix.pixelformat, pdata); if (!fmt) { fmt = &ctx->dev->venc_pdata->output_formats[0]; f->fmt.pix.pixelformat = fmt->fourcc; } - ret = vidioc_try_fmt(ctx, f, fmt); + ret = vidioc_try_fmt_out(ctx, f, fmt); if (ret) return ret; @@ -521,14 +509,13 @@ static int vidioc_venc_g_fmt(struct file *file, void *priv, struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); struct vb2_queue *vq; - struct mtk_q_data *q_data; + struct mtk_q_data *q_data = mtk_venc_get_q_data(ctx, f->type); int i; vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); if (!vq) return -EINVAL; - q_data = mtk_venc_get_q_data(ctx, f->type); pix->width = q_data->coded_width; pix->height = q_data->coded_height; @@ -566,7 +553,9 @@ static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, f->fmt.pix_mp.quantization = ctx->quantization; f->fmt.pix_mp.xfer_func = ctx->xfer_func; - return vidioc_try_fmt(ctx, f, fmt); + vidioc_try_fmt_cap(f); + + return 0; } static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, @@ -588,22 +577,18 @@ static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT; } - return vidioc_try_fmt(ctx, f, fmt); + return vidioc_try_fmt_out(ctx, f, fmt); } static int vidioc_venc_g_selection(struct file *file, void *priv, struct v4l2_selection *s) { struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); - struct mtk_q_data *q_data; + struct mtk_q_data *q_data = mtk_venc_get_q_data(ctx, s->type); if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) return -EINVAL; - q_data = mtk_venc_get_q_data(ctx, s->type); - if (!q_data) - return -EINVAL; - switch (s->target) { case V4L2_SEL_TGT_CROP_DEFAULT: case V4L2_SEL_TGT_CROP_BOUNDS: @@ -629,15 +614,11 @@ static int vidioc_venc_s_selection(struct file *file, void *priv, struct v4l2_selection *s) { struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); - struct mtk_q_data *q_data; + struct mtk_q_data *q_data = mtk_venc_get_q_data(ctx, s->type); if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) return -EINVAL; - q_data = mtk_venc_get_q_data(ctx, s->type); - if (!q_data) - return -EINVAL; - switch (s->target) { case V4L2_SEL_TGT_CROP: /* Only support crop from (0,0) */ @@ -804,11 +785,9 @@ static int vb2ops_venc_queue_setup(struct vb2_queue *vq, struct device *alloc_devs[]) { struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vq); - struct mtk_q_data *q_data; + struct mtk_q_data *q_data = mtk_venc_get_q_data(ctx, vq->type); unsigned int i; - q_data = mtk_venc_get_q_data(ctx, vq->type); - if (q_data == NULL) return -EINVAL; @@ -828,11 +807,9 @@ static int vb2ops_venc_queue_setup(struct vb2_queue *vq, static int vb2ops_venc_buf_prepare(struct vb2_buffer *vb) { struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - struct mtk_q_data *q_data; + struct mtk_q_data *q_data = mtk_venc_get_q_data(ctx, vb->vb2_queue->type); int i; - q_data = mtk_venc_get_q_data(ctx, vb->vb2_queue->type); - for (i = 0; i < q_data->fmt->num_planes; i++) { if (vb2_plane_size(vb, i) < q_data->sizeimage[i]) { mtk_v4l2_err("data will not fit into plane %d (%lu < %d)", @@ -959,7 +936,7 @@ static void vb2ops_venc_stop_streaming(struct vb2_queue *q) if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { while ((dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx))) { - dst_buf->vb2_buf.planes[0].bytesused = 0; + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0); v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); } /* STREAMOFF on the CAPTURE queue completes any ongoing flush */ @@ -1068,7 +1045,7 @@ static int mtk_venc_encode_header(void *priv) NULL, &bs_buf, &enc_result); if (ret) { - dst_buf->vb2_buf.planes[0].bytesused = 0; + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0); ctx->state = MTK_STATE_ABORT; v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); mtk_v4l2_err("venc_if_encode failed=%d", ret); @@ -1083,7 +1060,7 @@ static int mtk_venc_encode_header(void *priv) } ctx->state = MTK_STATE_HEADER; - dst_buf->vb2_buf.planes[0].bytesused = enc_result.bs_size; + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, enc_result.bs_size); v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); return 0; @@ -1232,12 +1209,12 @@ static void mtk_venc_worker(struct work_struct *work) if (ret) { v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); - dst_buf->vb2_buf.planes[0].bytesused = 0; + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0); v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); mtk_v4l2_err("venc_if_encode failed=%d", ret); } else { v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); - dst_buf->vb2_buf.planes[0].bytesused = enc_result.bs_size; + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, enc_result.bs_size); v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); mtk_v4l2_debug(2, "venc_if_encode bs size=%d", enc_result.bs_size); @@ -1395,6 +1372,9 @@ int mtk_vcodec_enc_ctrls_setup(struct mtk_vcodec_ctx *ctx) v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_H264_LEVEL, h264_max_level, 0, V4L2_MPEG_VIDEO_H264_LEVEL_4_0); + v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_VP8_PROFILE, + V4L2_MPEG_VIDEO_VP8_PROFILE_0, 0, V4L2_MPEG_VIDEO_VP8_PROFILE_0); + if (handler->error) { mtk_v4l2_err("Init control handler fail %d", 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 eed67394cf46..aeaecb8d416e 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c @@ -23,9 +23,6 @@ #include "mtk_vcodec_util.h" #include "mtk_vcodec_fw.h" -module_param(mtk_v4l2_dbg_level, int, S_IRUGO | S_IWUSR); -module_param(mtk_vcodec_dbg, bool, S_IRUGO | S_IWUSR); - static const struct mtk_video_fmt mtk_video_formats_output[] = { { .fourcc = V4L2_PIX_FMT_NV12M, @@ -214,11 +211,11 @@ static int fops_vcodec_release(struct file *file) mtk_v4l2_debug(1, "[%d] encoder", ctx->id); mutex_lock(&dev->dev_mutex); + v4l2_m2m_ctx_release(ctx->m2m_ctx); mtk_vcodec_enc_release(ctx); v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); v4l2_ctrl_handler_free(&ctx->ctrl_hdl); - v4l2_m2m_ctx_release(ctx->m2m_ctx); list_del_init(&ctx->list); kfree(ctx); @@ -461,7 +458,6 @@ static int mtk_vcodec_enc_remove(struct platform_device *pdev) struct mtk_vcodec_dev *dev = platform_get_drvdata(pdev); mtk_v4l2_debug_enter(); - flush_workqueue(dev->encode_workqueue); destroy_workqueue(dev->encode_workqueue); if (dev->m2m_dev_enc) v4l2_m2m_release(dev->m2m_dev_enc); diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c index ac5973b6735f..5bac820a47fc 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c @@ -10,16 +10,6 @@ #include "mtk_vcodec_drv.h" #include "mtk_vcodec_util.h" -/* For encoder, this will enable logs in venc/*/ -bool mtk_vcodec_dbg; -EXPORT_SYMBOL(mtk_vcodec_dbg); - -/* The log level of v4l2 encoder or decoder driver. - * That is, files under mtk-vcodec/. - */ -int mtk_v4l2_dbg_level; -EXPORT_SYMBOL(mtk_v4l2_dbg_level); - void __iomem *mtk_vcodec_get_reg_addr(struct mtk_vcodec_ctx *data, unsigned int reg_idx) { diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h index b999d7b84ed1..87c3d6d4bfa7 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h @@ -25,54 +25,29 @@ struct mtk_vcodec_fb { struct mtk_vcodec_ctx; struct mtk_vcodec_dev; -extern int mtk_v4l2_dbg_level; -extern bool mtk_vcodec_dbg; - +#undef pr_fmt +#define pr_fmt(fmt) "%s(),%d: " fmt, __func__, __LINE__ #define mtk_v4l2_err(fmt, args...) \ - pr_err("[MTK_V4L2][ERROR] %s:%d: " fmt "\n", __func__, __LINE__, \ - ##args) - -#define mtk_vcodec_err(h, fmt, args...) \ - pr_err("[MTK_VCODEC][ERROR][%d]: %s() " fmt "\n", \ - ((struct mtk_vcodec_ctx *)h->ctx)->id, __func__, ##args) + pr_err("[MTK_V4L2][ERROR] " fmt "\n", ##args) +#define mtk_vcodec_err(h, fmt, args...) \ + pr_err("[MTK_VCODEC][ERROR][%d]: " fmt "\n", \ + ((struct mtk_vcodec_ctx *)(h)->ctx)->id, ##args) -#if defined(DEBUG) -#define mtk_v4l2_debug(level, fmt, args...) \ - do { \ - if (mtk_v4l2_dbg_level >= level) \ - pr_info("[MTK_V4L2] level=%d %s(),%d: " fmt "\n",\ - level, __func__, __LINE__, ##args); \ - } while (0) +#define mtk_v4l2_debug(level, fmt, args...) pr_debug(fmt, ##args) #define mtk_v4l2_debug_enter() mtk_v4l2_debug(3, "+") #define mtk_v4l2_debug_leave() mtk_v4l2_debug(3, "-") -#define mtk_vcodec_debug(h, fmt, args...) \ - do { \ - if (mtk_vcodec_dbg) \ - pr_info("[MTK_VCODEC][%d]: %s() " fmt "\n", \ - ((struct mtk_vcodec_ctx *)h->ctx)->id, \ - __func__, ##args); \ - } while (0) +#define mtk_vcodec_debug(h, fmt, args...) \ + pr_debug("[MTK_VCODEC][%d]: " fmt "\n", \ + ((struct mtk_vcodec_ctx *)(h)->ctx)->id, ##args) #define mtk_vcodec_debug_enter(h) mtk_vcodec_debug(h, "+") #define mtk_vcodec_debug_leave(h) mtk_vcodec_debug(h, "-") -#else - -#define mtk_v4l2_debug(level, fmt, args...) {} -#define mtk_v4l2_debug_enter() {} -#define mtk_v4l2_debug_leave() {} - -#define mtk_vcodec_debug(h, fmt, args...) {} -#define mtk_vcodec_debug_enter(h) {} -#define mtk_vcodec_debug_leave(h) {} - -#endif - void __iomem *mtk_vcodec_get_reg_addr(struct mtk_vcodec_ctx *data, unsigned int reg_idx); int mtk_vcodec_mem_alloc(struct mtk_vcodec_ctx *data, diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_req_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_req_if.c index 946c23088308..fada4d146703 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_req_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_req_if.c @@ -527,7 +527,7 @@ static int alloc_mv_buf(struct vdec_h264_slice_inst *inst, struct mtk_vcodec_mem *mem = NULL; unsigned int buf_sz = get_mv_buf_size(pic->buf_w, pic->buf_h); - mtk_v4l2_debug(3, "size = 0x%lx", buf_sz); + mtk_v4l2_debug(3, "size = 0x%x", buf_sz); for (i = 0; i < H264_MAX_MV_NUM; i++) { mem = &inst->mv_buf[i]; if (mem->va) @@ -562,8 +562,8 @@ static void get_pic_info(struct vdec_h264_slice_inst *inst, { struct mtk_vcodec_ctx *ctx = inst->ctx; - ctx->picinfo.buf_w = (ctx->picinfo.pic_w + 15) & 0xFFFFFFF0; - ctx->picinfo.buf_h = (ctx->picinfo.pic_h + 31) & 0xFFFFFFE0; + ctx->picinfo.buf_w = ALIGN(ctx->picinfo.pic_w, VCODEC_DEC_ALIGNED_64); + ctx->picinfo.buf_h = ALIGN(ctx->picinfo.pic_h, VCODEC_DEC_ALIGNED_64); ctx->picinfo.fb_sz[0] = ctx->picinfo.buf_w * ctx->picinfo.buf_h; ctx->picinfo.fb_sz[1] = ctx->picinfo.fb_sz[0] >> 1; inst->vsi_ctx.dec.cap_num_planes = @@ -637,7 +637,7 @@ static int vdec_h264_slice_init(struct mtk_vcodec_ctx *ctx) if (err) goto error_deinit; - mtk_vcodec_debug(inst, "struct size = %d,%d,%d,%d\n", + mtk_vcodec_debug(inst, "struct size = %zu,%zu,%zu,%zu\n", sizeof(struct mtk_h264_sps_param), sizeof(struct mtk_h264_pps_param), sizeof(struct mtk_h264_dec_slice_param), diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c index b6a4f2074fa5..bf03888a824f 100644 --- a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c +++ b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c @@ -367,8 +367,7 @@ static int h264_encode_sps(struct venc_h264_inst *inst, mtk_vcodec_debug_enter(inst); - ret = vpu_enc_encode(&inst->vpu_inst, H264_BS_MODE_SPS, NULL, - bs_buf, bs_size, NULL); + ret = vpu_enc_encode(&inst->vpu_inst, H264_BS_MODE_SPS, NULL, bs_buf, NULL); if (ret) return ret; @@ -394,8 +393,7 @@ static int h264_encode_pps(struct venc_h264_inst *inst, mtk_vcodec_debug_enter(inst); - ret = vpu_enc_encode(&inst->vpu_inst, H264_BS_MODE_PPS, NULL, - bs_buf, bs_size, NULL); + ret = vpu_enc_encode(&inst->vpu_inst, H264_BS_MODE_PPS, NULL, bs_buf, NULL); if (ret) return ret; @@ -451,8 +449,7 @@ static int h264_encode_frame(struct venc_h264_inst *inst, mtk_vcodec_debug(inst, "frm_count = %d,skip_frm_count =%d,frm_type=%d.\n", frame_info.frm_count, frame_info.skip_frm_count, frame_info.frm_type); - ret = vpu_enc_encode(&inst->vpu_inst, H264_BS_MODE_FRAME, frm_buf, - bs_buf, bs_size, &frame_info); + ret = vpu_enc_encode(&inst->vpu_inst, H264_BS_MODE_FRAME, frm_buf, bs_buf, &frame_info); if (ret) return ret; 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 8267a9c4fd25..6b66957d5192 100644 --- a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c +++ b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c @@ -302,8 +302,7 @@ static int vp8_enc_encode_frame(struct venc_vp8_inst *inst, mtk_vcodec_debug(inst, "->frm_cnt=%d", inst->frm_cnt); - ret = vpu_enc_encode(&inst->vpu_inst, 0, frm_buf, bs_buf, bs_size, - NULL); + ret = vpu_enc_encode(&inst->vpu_inst, 0, frm_buf, bs_buf, NULL); if (ret) return ret; diff --git a/drivers/media/platform/mtk-vcodec/venc_vpu_if.c b/drivers/media/platform/mtk-vcodec/venc_vpu_if.c index be6d8790a41e..e7899d8a3e4e 100644 --- a/drivers/media/platform/mtk-vcodec/venc_vpu_if.c +++ b/drivers/media/platform/mtk-vcodec/venc_vpu_if.c @@ -225,7 +225,6 @@ int vpu_enc_set_param(struct venc_vpu_inst *vpu, int vpu_enc_encode(struct venc_vpu_inst *vpu, unsigned int bs_mode, struct venc_frm_buf *frm_buf, struct mtk_vcodec_mem *bs_buf, - unsigned int *bs_size, struct venc_frame_info *frame_info) { const bool is_ext = MTK_ENC_CTX_IS_EXT(vpu->ctx); diff --git a/drivers/media/platform/mtk-vcodec/venc_vpu_if.h b/drivers/media/platform/mtk-vcodec/venc_vpu_if.h index f9be9cab7ff7..f83bc1b3f2bf 100644 --- a/drivers/media/platform/mtk-vcodec/venc_vpu_if.h +++ b/drivers/media/platform/mtk-vcodec/venc_vpu_if.h @@ -45,7 +45,6 @@ int vpu_enc_set_param(struct venc_vpu_inst *vpu, int vpu_enc_encode(struct venc_vpu_inst *vpu, unsigned int bs_mode, struct venc_frm_buf *frm_buf, struct mtk_vcodec_mem *bs_buf, - unsigned int *bs_size, struct venc_frame_info *frame_info); int vpu_enc_deinit(struct venc_vpu_inst *vpu); diff --git a/drivers/media/platform/mtk-vpu/mtk_vpu.c b/drivers/media/platform/mtk-vpu/mtk_vpu.c index 7f1647da0ade..7bd715fc844d 100644 --- a/drivers/media/platform/mtk-vpu/mtk_vpu.c +++ b/drivers/media/platform/mtk-vpu/mtk_vpu.c @@ -964,10 +964,8 @@ static int mtk_vpu_remove(struct platform_device *pdev) #ifdef CONFIG_DEBUG_FS debugfs_remove(vpu_debugfs); #endif - if (vpu->wdt.wq) { - flush_workqueue(vpu->wdt.wq); + if (vpu->wdt.wq) destroy_workqueue(vpu->wdt.wq); - } vpu_free_ext_mem(vpu, P_FW); vpu_free_ext_mem(vpu, D_FW); mutex_destroy(&vpu->vpu_mutex); diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 6de377ce281d..4c937f3f323e 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -476,7 +476,8 @@ void omap3isp_hist_dma_done(struct isp_device *isp) } } -static inline void isp_isr_dbg(struct isp_device *isp, u32 irqstatus) +static inline void __maybe_unused isp_isr_dbg(struct isp_device *isp, + u32 irqstatus) { static const char *name[] = { "CSIA_IRQ", diff --git a/drivers/media/platform/omap3isp/isph3a_af.c b/drivers/media/platform/omap3isp/isph3a_af.c index a65cfdfa9637..de7b116d0122 100644 --- a/drivers/media/platform/omap3isp/isph3a_af.c +++ b/drivers/media/platform/omap3isp/isph3a_af.c @@ -21,7 +21,7 @@ #include "ispstat.h" #define IS_OUT_OF_BOUNDS(value, min, max) \ - (((value) < (min)) || ((value) > (max))) + ((((unsigned int)value) < (min)) || (((unsigned int)value) > (max))) static void h3a_af_setup_regs(struct ispstat *af, void *priv) { diff --git a/drivers/media/platform/omap3isp/omap3isp.h b/drivers/media/platform/omap3isp/omap3isp.h index 214f94c46a9d..4a003c8263ed 100644 --- a/drivers/media/platform/omap3isp/omap3isp.h +++ b/drivers/media/platform/omap3isp/omap3isp.h @@ -95,6 +95,8 @@ struct isp_csiphy_lanes_cfg { * ISP_CCP2_PHY_DATA_CLOCK - Data/clock physical layer * ISP_CCP2_PHY_DATA_STROBE - Data/strobe physical layer * @vpclk_div: Video port output clock control + * @vp_clk_pol: Video port output clock polarity + * @lanecfg: CCP2/CSI2 lane configuration */ struct isp_ccp2_cfg { unsigned int strobe_clk_pol:1; diff --git a/drivers/media/platform/qcom/camss/camss-vfe-170.c b/drivers/media/platform/qcom/camss/camss-vfe-170.c index 5c083d70d495..f524af712a84 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-170.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-170.c @@ -191,13 +191,6 @@ static u32 vfe_hw_version(struct vfe_device *vfe) return hw_version; } -static inline void vfe_reg_clr(struct vfe_device *vfe, u32 reg, u32 clr_bits) -{ - u32 bits = readl_relaxed(vfe->base + reg); - - writel_relaxed(bits & ~clr_bits, vfe->base + reg); -} - static inline void vfe_reg_set(struct vfe_device *vfe, u32 reg, u32 set_bits) { u32 bits = readl_relaxed(vfe->base + reg); diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index f5fa81896012..877eca125803 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -350,11 +350,11 @@ static int venus_probe(struct platform_device *pdev) ret = venus_firmware_init(core); if (ret) - goto err_runtime_disable; + goto err_of_depopulate; ret = venus_boot(core); if (ret) - goto err_runtime_disable; + goto err_firmware_deinit; ret = hfi_core_resume(core, true); if (ret) @@ -386,6 +386,10 @@ err_dev_unregister: v4l2_device_unregister(&core->v4l2_dev); err_venus_shutdown: venus_shutdown(core); +err_firmware_deinit: + venus_firmware_deinit(core); +err_of_depopulate: + of_platform_depopulate(dev); err_runtime_disable: pm_runtime_put_noidle(dev); pm_runtime_set_suspended(dev); @@ -473,7 +477,8 @@ static __maybe_unused int venus_runtime_suspend(struct device *dev) err_video_path: icc_set_bw(core->cpucfg_path, kbps_to_icc(1000), 0); err_cpucfg_path: - pm_ops->core_power(core, POWER_ON); + if (pm_ops->core_power) + pm_ops->core_power(core, POWER_ON); return ret; } diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c index cedc664ba755..cb48c5ff3dee 100644 --- a/drivers/media/platform/qcom/venus/pm_helpers.c +++ b/drivers/media/platform/qcom/venus/pm_helpers.c @@ -163,14 +163,12 @@ static u32 load_per_type(struct venus_core *core, u32 session_type) struct venus_inst *inst = NULL; u32 mbs_per_sec = 0; - mutex_lock(&core->lock); list_for_each_entry(inst, &core->instances, list) { if (inst->session_type != session_type) continue; mbs_per_sec += load_per_instance(inst); } - mutex_unlock(&core->lock); return mbs_per_sec; } @@ -219,14 +217,12 @@ static int load_scale_bw(struct venus_core *core) struct venus_inst *inst = NULL; u32 mbs_per_sec, avg, peak, total_avg = 0, total_peak = 0; - mutex_lock(&core->lock); list_for_each_entry(inst, &core->instances, list) { mbs_per_sec = load_per_instance(inst); mbs_to_bw(inst, mbs_per_sec, &avg, &peak); total_avg += avg; total_peak += peak; } - mutex_unlock(&core->lock); /* * keep minimum bandwidth vote for "video-mem" path, @@ -253,8 +249,9 @@ static int load_scale_v1(struct venus_inst *inst) struct device *dev = core->dev; u32 mbs_per_sec; unsigned int i; - int ret; + int ret = 0; + mutex_lock(&core->lock); mbs_per_sec = load_per_type(core, VIDC_SESSION_TYPE_ENC) + load_per_type(core, VIDC_SESSION_TYPE_DEC); @@ -279,17 +276,19 @@ set_freq: if (ret) { dev_err(dev, "failed to set clock rate %lu (%d)\n", freq, ret); - return ret; + goto exit; } ret = load_scale_bw(core); if (ret) { dev_err(dev, "failed to set bandwidth (%d)\n", ret); - return ret; + goto exit; } - return 0; +exit: + mutex_unlock(&core->lock); + return ret; } static int core_get_v1(struct venus_core *core) @@ -587,8 +586,8 @@ min_loaded_core(struct venus_inst *inst, u32 *min_coreid, u32 *min_load, bool lo if (inst->session_type == VIDC_SESSION_TYPE_DEC) vpp_freq = inst_pos->clk_data.vpp_freq; else if (inst->session_type == VIDC_SESSION_TYPE_ENC) - vpp_freq = low_power ? inst_pos->clk_data.vpp_freq : - inst_pos->clk_data.low_power_freq; + vpp_freq = low_power ? inst_pos->clk_data.low_power_freq : + inst_pos->clk_data.vpp_freq; else continue; @@ -1116,13 +1115,13 @@ static int load_scale_v4(struct venus_inst *inst) struct device *dev = core->dev; unsigned long freq = 0, freq_core1 = 0, freq_core2 = 0; unsigned long filled_len = 0; - int i, ret; + int i, ret = 0; for (i = 0; i < inst->num_input_bufs; i++) filled_len = max(filled_len, inst->payloads[i]); if (inst->session_type == VIDC_SESSION_TYPE_DEC && !filled_len) - return 0; + return ret; freq = calculate_inst_freq(inst, filled_len); inst->clk_data.freq = freq; @@ -1138,7 +1137,6 @@ static int load_scale_v4(struct venus_inst *inst) freq_core2 += inst->clk_data.freq; } } - mutex_unlock(&core->lock); freq = max(freq_core1, freq_core2); @@ -1163,17 +1161,19 @@ set_freq: if (ret) { dev_err(dev, "failed to set clock rate %lu (%d)\n", freq, ret); - return ret; + goto exit; } ret = load_scale_bw(core); if (ret) { dev_err(dev, "failed to set bandwidth (%d)\n", ret); - return ret; + goto exit; } - return 0; +exit: + mutex_unlock(&core->lock); + return ret; } static const struct venus_pm_ops pm_ops_v4 = { diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index 1d92cc8ede8f..0186ae235113 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -349,12 +349,10 @@ out: static void rvin_group_notifier_cleanup(struct rvin_dev *vin) { - mutex_lock(&vin->group->lock); if (&vin->v4l2_dev == vin->group->notifier.v4l2_dev) { v4l2_async_nf_unregister(&vin->group->notifier); v4l2_async_nf_cleanup(&vin->group->notifier); } - mutex_unlock(&vin->group->lock); } static int rvin_group_notifier_init(struct rvin_dev *vin, unsigned int port, @@ -1620,6 +1618,7 @@ static SIMPLE_DEV_PM_OPS(rvin_pm_ops, rvin_suspend, rvin_resume); static struct platform_driver rcar_vin_driver = { .driver = { .name = "rcar-vin", + .suppress_bind_attrs = true, .pm = &rvin_pm_ops, .of_match_table = rvin_of_id_table, }, diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c index 11848d0c4a55..8c939cb3073d 100644 --- a/drivers/media/platform/rcar-vin/rcar-csi2.c +++ b/drivers/media/platform/rcar-vin/rcar-csi2.c @@ -542,16 +542,27 @@ static int rcsi2_wait_phy_start(struct rcar_csi2 *priv, static int rcsi2_set_phypll(struct rcar_csi2 *priv, unsigned int mbps) { const struct rcsi2_mbps_reg *hsfreq; + const struct rcsi2_mbps_reg *hsfreq_prev = NULL; - for (hsfreq = priv->info->hsfreqrange; hsfreq->mbps != 0; hsfreq++) + if (mbps < priv->info->hsfreqrange->mbps) + dev_warn(priv->dev, "%u Mbps less than min PHY speed %u Mbps", + mbps, priv->info->hsfreqrange->mbps); + + for (hsfreq = priv->info->hsfreqrange; hsfreq->mbps != 0; hsfreq++) { if (hsfreq->mbps >= mbps) break; + hsfreq_prev = hsfreq; + } if (!hsfreq->mbps) { dev_err(priv->dev, "Unsupported PHY speed (%u Mbps)", mbps); return -ERANGE; } + if (hsfreq_prev && + ((mbps - hsfreq_prev->mbps) <= (hsfreq->mbps - mbps))) + hsfreq = hsfreq_prev; + rcsi2_write(priv, PHYPLL_REG, PHYPLL_HSFREQRANGE(hsfreq->reg)); return 0; @@ -1097,10 +1108,17 @@ static int rcsi2_phtw_write_mbps(struct rcar_csi2 *priv, unsigned int mbps, const struct rcsi2_mbps_reg *values, u16 code) { const struct rcsi2_mbps_reg *value; + const struct rcsi2_mbps_reg *prev_value = NULL; - for (value = values; value->mbps; value++) + for (value = values; value->mbps; value++) { if (value->mbps >= mbps) break; + prev_value = value; + } + + if (prev_value && + ((mbps - prev_value->mbps) <= (value->mbps - mbps))) + value = prev_value; if (!value->mbps) { dev_err(priv->dev, "Unsupported PHY speed (%u Mbps)", mbps); @@ -1498,6 +1516,7 @@ static struct platform_driver rcar_csi2_pdrv = { .probe = rcsi2_probe, .driver = { .name = "rcar-csi2", + .suppress_bind_attrs = true, .of_match_table = rcar_csi2_of_table, }, }; diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c index 25ead9333d00..8136bc75e7c4 100644 --- a/drivers/media/platform/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/rcar-vin/rcar-dma.c @@ -111,6 +111,9 @@ #define VNIE_FIE (1 << 4) #define VNIE_EFE (1 << 1) +/* Video n Interrupt Status Register bits */ +#define VNINTS_FIS (1 << 4) + /* Video n Data Mode Register bits */ #define VNDMR_A8BIT(n) (((n) & 0xff) << 24) #define VNDMR_A8BIT_MASK (0xff << 24) @@ -1005,6 +1008,10 @@ static irqreturn_t rvin_irq(int irq, void *data) rvin_ack_interrupt(vin); handled = 1; + /* Nothing to do if nothing was captured. */ + if (!(int_status & VNINTS_FIS)) + goto done; + /* Nothing to do if capture status is 'STOPPED' */ if (vin->state == STOPPED) { vin_dbg(vin, "IRQ while state stopped\n"); @@ -1371,6 +1378,16 @@ void rvin_stop_streaming(struct rvin_dev *vin) spin_unlock_irqrestore(&vin->qlock, flags); + /* If something went wrong, free buffers with an error. */ + if (!buffersFreed) { + return_unused_buffers(vin, VB2_BUF_STATE_ERROR); + for (i = 0; i < HW_BUFFER_NUM; i++) { + if (vin->buf_hw[i].buffer) + vb2_buffer_done(&vin->buf_hw[i].buffer->vb2_buf, + VB2_BUF_STATE_ERROR); + } + } + rvin_set_stream(vin, 0); /* disable interrupts */ diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c index a5bfa76fdac6..2e60b9fce03b 100644 --- a/drivers/media/platform/rcar-vin/rcar-v4l2.c +++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c @@ -179,20 +179,27 @@ static void rvin_format_align(struct rvin_dev *vin, struct v4l2_pix_format *pix) break; } - /* HW limit width to a multiple of 32 (2^5) for NV12/16 else 2 (2^1) */ + /* Hardware limits width alignment based on format. */ switch (pix->pixelformat) { + /* Multiple of 32 (2^5) for NV12/16. */ case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV16: walign = 5; break; - default: + /* Multiple of 2 (2^1) for YUV. */ + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: walign = 1; break; + /* No multiple for RGB. */ + default: + walign = 0; + break; } /* Limit to VIN capabilities */ - v4l_bound_align_image(&pix->width, 2, vin->info->max_width, walign, - &pix->height, 4, vin->info->max_height, 2, 0); + v4l_bound_align_image(&pix->width, 5, vin->info->max_width, walign, + &pix->height, 2, vin->info->max_height, 0, 0); pix->bytesperline = rvin_format_bytesperline(vin, pix); pix->sizeimage = rvin_format_sizeimage(pix); diff --git a/drivers/media/platform/rcar_fdp1.c b/drivers/media/platform/rcar_fdp1.c index 19de3c19bcca..37ecf489d112 100644 --- a/drivers/media/platform/rcar_fdp1.c +++ b/drivers/media/platform/rcar_fdp1.c @@ -2287,11 +2287,10 @@ static int fdp1_probe(struct platform_device *pdev) return PTR_ERR(fdp1->regs); /* Interrupt service routine registration */ - fdp1->irq = ret = platform_get_irq(pdev, 0); - if (ret < 0) { - dev_err(&pdev->dev, "cannot find IRQ\n"); + ret = platform_get_irq(pdev, 0); + if (ret < 0) return ret; - } + fdp1->irq = ret; ret = devm_request_irq(&pdev->dev, fdp1->irq, fdp1_irq_handler, 0, dev_name(&pdev->dev), fdp1); diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c index 50b166c49a03..3f5cfa7eb937 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c @@ -462,7 +462,7 @@ static void rkisp1_debug_init(struct rkisp1_device *rkisp1) { struct rkisp1_debug *debug = &rkisp1->debug; - debug->debugfs_dir = debugfs_create_dir(RKISP1_DRIVER_NAME, NULL); + debug->debugfs_dir = debugfs_create_dir(dev_name(rkisp1->dev), NULL); debugfs_create_ulong("data_loss", 0444, debug->debugfs_dir, &debug->data_loss); debugfs_create_ulong("outform_size_err", 0444, debug->debugfs_dir, diff --git a/drivers/media/platform/s3c-camif/camif-core.c b/drivers/media/platform/s3c-camif/camif-core.c index 32892ab359ee..6e8ef86566b7 100644 --- a/drivers/media/platform/s3c-camif/camif-core.c +++ b/drivers/media/platform/s3c-camif/camif-core.c @@ -291,7 +291,6 @@ static void camif_unregister_media_entities(struct camif_dev *camif) { camif_unregister_video_nodes(camif); camif_unregister_sensor(camif); - s3c_camif_unregister_subdev(camif); } /* @@ -520,6 +519,7 @@ static int s3c_camif_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); camif_clk_put(camif); + s3c_camif_unregister_subdev(camif); pdata->gpio_put(); return 0; diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index ebdfd24e9cd5..a8d9159d5ed8 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c @@ -2425,17 +2425,17 @@ static int s5p_jpeg_job_ready(void *priv) return 1; } -static struct v4l2_m2m_ops s5p_jpeg_m2m_ops = { +static const struct v4l2_m2m_ops s5p_jpeg_m2m_ops = { .device_run = s5p_jpeg_device_run, .job_ready = s5p_jpeg_job_ready, }; -static struct v4l2_m2m_ops exynos3250_jpeg_m2m_ops = { +static const struct v4l2_m2m_ops exynos3250_jpeg_m2m_ops = { .device_run = exynos3250_jpeg_device_run, .job_ready = s5p_jpeg_job_ready, }; -static struct v4l2_m2m_ops exynos4_jpeg_m2m_ops = { +static const struct v4l2_m2m_ops exynos4_jpeg_m2m_ops = { .device_run = exynos4_jpeg_device_run, .job_ready = s5p_jpeg_job_ready, }; diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.h b/drivers/media/platform/s5p-jpeg/jpeg-core.h index 8473a019bb5f..4a5fb1b15455 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.h +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.h @@ -142,7 +142,7 @@ struct s5p_jpeg_variant { unsigned int hw3250_compat:1; unsigned int htbl_reinit:1; unsigned int hw_ex4_compat:1; - struct v4l2_m2m_ops *m2m_ops; + const struct v4l2_m2m_ops *m2m_ops; irqreturn_t (*jpeg_irq)(int irq, void *priv); const char *clk_names[JPEG_MAX_CLOCKS]; int num_clocks; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index fc85e4e2d020..f6732f031e96 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1185,7 +1185,6 @@ static int s5p_mfc_configure_common_memory(struct s5p_mfc_dev *mfc_dev) { struct device *dev = &mfc_dev->plat_dev->dev; unsigned long mem_size = SZ_4M; - unsigned int bitmap_size; if (IS_ENABLED(CONFIG_DMA_CMA) || exynos_is_iommu_available(dev)) mem_size = SZ_8M; @@ -1193,16 +1192,14 @@ static int s5p_mfc_configure_common_memory(struct s5p_mfc_dev *mfc_dev) if (mfc_mem_size) mem_size = memparse(mfc_mem_size, NULL); - bitmap_size = BITS_TO_LONGS(mem_size >> PAGE_SHIFT) * sizeof(long); - - mfc_dev->mem_bitmap = kzalloc(bitmap_size, GFP_KERNEL); + mfc_dev->mem_bitmap = bitmap_zalloc(mem_size >> PAGE_SHIFT, GFP_KERNEL); if (!mfc_dev->mem_bitmap) return -ENOMEM; mfc_dev->mem_virt = dma_alloc_coherent(dev, mem_size, &mfc_dev->mem_base, GFP_KERNEL); if (!mfc_dev->mem_virt) { - kfree(mfc_dev->mem_bitmap); + bitmap_free(mfc_dev->mem_bitmap); dev_err(dev, "failed to preallocate %ld MiB for the firmware and context buffers\n", (mem_size / SZ_1M)); return -ENOMEM; @@ -1241,7 +1238,7 @@ static void s5p_mfc_unconfigure_common_memory(struct s5p_mfc_dev *mfc_dev) dma_free_coherent(dev, mfc_dev->mem_size, mfc_dev->mem_virt, mfc_dev->mem_base); - kfree(mfc_dev->mem_bitmap); + bitmap_free(mfc_dev->mem_bitmap); vb2_dma_contig_clear_max_seg_size(dev); } diff --git a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c index 7d467f2ba072..01ce7b711774 100644 --- a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c +++ b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c @@ -1394,6 +1394,7 @@ err_filter: err_pm: pm_runtime_put(dev); err_remove: + pm_runtime_disable(dev); bdisp_debugfs_remove(bdisp); v4l2_device_unregister(&bdisp->v4l2_dev); err_clk: diff --git a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c index 02dc78bd7fab..7bb1384e4bad 100644 --- a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c +++ b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c @@ -925,17 +925,12 @@ static int c8sectpfe_remove(struct platform_device *pdev) static int configure_channels(struct c8sectpfei *fei) { int index = 0, ret; - struct channel_info *tsin; struct device_node *child, *np = fei->dev->of_node; /* iterate round each tsin and configure memdma descriptor and IB hw */ for_each_child_of_node(np, child) { - - tsin = fei->channel_data[index]; - ret = configure_memdma_and_inputblock(fei, fei->channel_data[index]); - if (ret) { dev_err(fei->dev, "configure_memdma_and_inputblock failed\n"); @@ -947,10 +942,9 @@ static int configure_channels(struct c8sectpfei *fei) return 0; err_unmap: - for (index = 0; index < fei->tsin_count; index++) { - tsin = fei->channel_data[index]; - free_input_block(fei, tsin); - } + while (--index >= 0) + free_input_block(fei, fei->channel_data[index]); + return ret; } diff --git a/drivers/media/platform/sti/hva/hva-hw.c b/drivers/media/platform/sti/hva/hva-hw.c index 15e8f83b1b56..fe4ea2e7f37e 100644 --- a/drivers/media/platform/sti/hva/hva-hw.c +++ b/drivers/media/platform/sti/hva/hva-hw.c @@ -385,7 +385,7 @@ int hva_hw_probe(struct platform_device *pdev, struct hva_dev *hva) ret = pm_runtime_resume_and_get(dev); if (ret < 0) { dev_err(dev, "%s failed to set PM\n", HVA_PREFIX); - goto err_clk; + goto err_disable; } /* check IP hardware version */ @@ -403,6 +403,8 @@ int hva_hw_probe(struct platform_device *pdev, struct hva_dev *hva) err_pm: pm_runtime_put(dev); +err_disable: + pm_runtime_disable(dev); err_clk: if (hva->clk) clk_unprepare(hva->clk); diff --git a/drivers/media/platform/stm32/Makefile b/drivers/media/platform/stm32/Makefile index 48b36db2c2e2..896ef98a73ab 100644 --- a/drivers/media/platform/stm32/Makefile +++ b/drivers/media/platform/stm32/Makefile @@ -1,2 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_VIDEO_STM32_DCMI) += stm32-dcmi.o +stm32-dma2d-objs := dma2d/dma2d.o dma2d/dma2d-hw.o +obj-$(CONFIG_VIDEO_STM32_DMA2D) += stm32-dma2d.o diff --git a/drivers/media/platform/stm32/dma2d/dma2d-hw.c b/drivers/media/platform/stm32/dma2d/dma2d-hw.c new file mode 100644 index 000000000000..ea4cc84d8a39 --- /dev/null +++ b/drivers/media/platform/stm32/dma2d/dma2d-hw.c @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * ST stm32 Chrom-Art - 2D Graphics Accelerator Driver + * + * Copyright (c) 2021 Dillon Min + * Dillon Min, <dillon.minfei@gmail.com> + * + * based on s5p-g2d + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * Kamil Debski, <k.debski@samsung.com> + */ + +#include <linux/io.h> + +#include "dma2d.h" +#include "dma2d-regs.h" + +static inline u32 reg_read(void __iomem *base, u32 reg) +{ + return readl_relaxed(base + reg); +} + +static inline void reg_write(void __iomem *base, u32 reg, u32 val) +{ + writel_relaxed(val, base + reg); +} + +static inline void reg_update_bits(void __iomem *base, u32 reg, u32 mask, + u32 val) +{ + reg_write(base, reg, (reg_read(base, reg) & ~mask) | val); +} + +void dma2d_start(struct dma2d_dev *d) +{ + reg_update_bits(d->regs, DMA2D_CR_REG, CR_START, CR_START); +} + +u32 dma2d_get_int(struct dma2d_dev *d) +{ + return reg_read(d->regs, DMA2D_ISR_REG); +} + +void dma2d_clear_int(struct dma2d_dev *d) +{ + u32 isr_val = reg_read(d->regs, DMA2D_ISR_REG); + + reg_write(d->regs, DMA2D_IFCR_REG, isr_val & 0x003f); +} + +void dma2d_config_common(struct dma2d_dev *d, enum dma2d_op_mode op_mode, + u16 width, u16 height) +{ + reg_update_bits(d->regs, DMA2D_CR_REG, CR_MODE_MASK, + op_mode << CR_MODE_SHIFT); + + reg_write(d->regs, DMA2D_NLR_REG, (width << 16) | height); +} + +void dma2d_config_out(struct dma2d_dev *d, struct dma2d_frame *frm, + dma_addr_t o_addr) +{ + reg_update_bits(d->regs, DMA2D_CR_REG, CR_CEIE, CR_CEIE); + reg_update_bits(d->regs, DMA2D_CR_REG, CR_CTCIE, CR_CTCIE); + reg_update_bits(d->regs, DMA2D_CR_REG, CR_CAEIE, CR_CAEIE); + reg_update_bits(d->regs, DMA2D_CR_REG, CR_TCIE, CR_TCIE); + reg_update_bits(d->regs, DMA2D_CR_REG, CR_TEIE, CR_TEIE); + + if (frm->fmt->cmode >= CM_MODE_ARGB8888 && + frm->fmt->cmode <= CM_MODE_ARGB4444) + reg_update_bits(d->regs, DMA2D_OPFCCR_REG, OPFCCR_CM_MASK, + frm->fmt->cmode); + + reg_write(d->regs, DMA2D_OMAR_REG, o_addr); + + reg_write(d->regs, DMA2D_OCOLR_REG, + (frm->a_rgb[3] << 24) | + (frm->a_rgb[2] << 16) | + (frm->a_rgb[1] << 8) | + frm->a_rgb[0]); + + reg_update_bits(d->regs, DMA2D_OOR_REG, OOR_LO_MASK, + frm->line_offset & 0x3fff); +} + +void dma2d_config_fg(struct dma2d_dev *d, struct dma2d_frame *frm, + dma_addr_t f_addr) +{ + reg_write(d->regs, DMA2D_FGMAR_REG, f_addr); + reg_update_bits(d->regs, DMA2D_FGOR_REG, FGOR_LO_MASK, + frm->line_offset); + + if (frm->fmt->cmode >= CM_MODE_ARGB8888 && + frm->fmt->cmode <= CM_MODE_A4) + reg_update_bits(d->regs, DMA2D_FGPFCCR_REG, FGPFCCR_CM_MASK, + frm->fmt->cmode); + + reg_update_bits(d->regs, DMA2D_FGPFCCR_REG, FGPFCCR_AM_MASK, + (frm->a_mode << 16) & 0x03); + + reg_update_bits(d->regs, DMA2D_FGPFCCR_REG, FGPFCCR_ALPHA_MASK, + frm->a_rgb[3] << 24); + + reg_write(d->regs, DMA2D_FGCOLR_REG, + (frm->a_rgb[2] << 16) | + (frm->a_rgb[1] << 8) | + frm->a_rgb[0]); +} + +void dma2d_config_bg(struct dma2d_dev *d, struct dma2d_frame *frm, + dma_addr_t b_addr) +{ + reg_write(d->regs, DMA2D_BGMAR_REG, b_addr); + reg_update_bits(d->regs, DMA2D_BGOR_REG, BGOR_LO_MASK, + frm->line_offset); + + if (frm->fmt->cmode >= CM_MODE_ARGB8888 && + frm->fmt->cmode <= CM_MODE_A4) + reg_update_bits(d->regs, DMA2D_BGPFCCR_REG, BGPFCCR_CM_MASK, + frm->fmt->cmode); + + reg_update_bits(d->regs, DMA2D_BGPFCCR_REG, BGPFCCR_AM_MASK, + (frm->a_mode << 16) & 0x03); + + reg_update_bits(d->regs, DMA2D_BGPFCCR_REG, BGPFCCR_ALPHA_MASK, + frm->a_rgb[3] << 24); + + reg_write(d->regs, DMA2D_BGCOLR_REG, + (frm->a_rgb[2] << 16) | + (frm->a_rgb[1] << 8) | + frm->a_rgb[0]); +} diff --git a/drivers/media/platform/stm32/dma2d/dma2d-regs.h b/drivers/media/platform/stm32/dma2d/dma2d-regs.h new file mode 100644 index 000000000000..6444592d415b --- /dev/null +++ b/drivers/media/platform/stm32/dma2d/dma2d-regs.h @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * ST stm32 Chrom-Art - 2D Graphics Accelerator Driver + * + * Copyright (c) 2021 Dillon Min + * Dillon Min, <dillon.minfei@gmail.com> + * + * based on s5p-g2d + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * Kamil Debski, <k.debski@samsung.com> + */ + +#ifndef __DMA2D_REGS_H__ +#define __DMA2D_REGS_H__ + +#define DMA2D_CR_REG 0x0000 +#define CR_MODE_MASK GENMASK(17, 16) +#define CR_MODE_SHIFT 16 +#define CR_M2M 0x0000 +#define CR_M2M_PFC BIT(16) +#define CR_M2M_BLEND BIT(17) +#define CR_R2M (BIT(17) | BIT(16)) +#define CR_CEIE BIT(13) +#define CR_CTCIE BIT(12) +#define CR_CAEIE BIT(11) +#define CR_TWIE BIT(10) +#define CR_TCIE BIT(9) +#define CR_TEIE BIT(8) +#define CR_ABORT BIT(2) +#define CR_SUSP BIT(1) +#define CR_START BIT(0) + +#define DMA2D_ISR_REG 0x0004 +#define ISR_CEIF BIT(5) +#define ISR_CTCIF BIT(4) +#define ISR_CAEIF BIT(3) +#define ISR_TWIF BIT(2) +#define ISR_TCIF BIT(1) +#define ISR_TEIF BIT(0) + +#define DMA2D_IFCR_REG 0x0008 +#define IFCR_CCEIF BIT(5) +#define IFCR_CCTCIF BIT(4) +#define IFCR_CAECIF BIT(3) +#define IFCR_CTWIF BIT(2) +#define IFCR_CTCIF BIT(1) +#define IFCR_CTEIF BIT(0) + +#define DMA2D_FGMAR_REG 0x000c +#define DMA2D_FGOR_REG 0x0010 +#define FGOR_LO_MASK GENMASK(13, 0) + +#define DMA2D_BGMAR_REG 0x0014 +#define DMA2D_BGOR_REG 0x0018 +#define BGOR_LO_MASK GENMASK(13, 0) + +#define DMA2D_FGPFCCR_REG 0x001c +#define FGPFCCR_ALPHA_MASK GENMASK(31, 24) +#define FGPFCCR_AM_MASK GENMASK(17, 16) +#define FGPFCCR_CS_MASK GENMASK(15, 8) +#define FGPFCCR_START BIT(5) +#define FGPFCCR_CCM_RGB888 BIT(4) +#define FGPFCCR_CM_MASK GENMASK(3, 0) + +#define DMA2D_FGCOLR_REG 0x0020 +#define FGCOLR_REG_MASK GENMASK(23, 16) +#define FGCOLR_GREEN_MASK GENMASK(15, 8) +#define FGCOLR_BLUE_MASK GENMASK(7, 0) + +#define DMA2D_BGPFCCR_REG 0x0024 +#define BGPFCCR_ALPHA_MASK GENMASK(31, 24) +#define BGPFCCR_AM_MASK GENMASK(17, 16) +#define BGPFCCR_CS_MASK GENMASK(15, 8) +#define BGPFCCR_START BIT(5) +#define BGPFCCR_CCM_RGB888 BIT(4) +#define BGPFCCR_CM_MASK GENMASK(3, 0) + +#define DMA2D_BGCOLR_REG 0x0028 +#define BGCOLR_REG_MASK GENMASK(23, 16) +#define BGCOLR_GREEN_MASK GENMASK(15, 8) +#define BGCOLR_BLUE_MASK GENMASK(7, 0) + +#define DMA2D_OPFCCR_REG 0x0034 +#define OPFCCR_CM_MASK GENMASK(2, 0) + +#define DMA2D_OCOLR_REG 0x0038 +#define OCOLR_ALPHA_MASK GENMASK(31, 24) +#define OCOLR_RED_MASK GENMASK(23, 16) +#define OCOLR_GREEN_MASK GENMASK(15, 8) +#define OCOLR_BLUE_MASK GENMASK(7, 0) + +#define DMA2D_OMAR_REG 0x003c + +#define DMA2D_OOR_REG 0x0040 +#define OOR_LO_MASK GENMASK(13, 0) + +#define DMA2D_NLR_REG 0x0044 +#define NLR_PL_MASK GENMASK(29, 16) +#define NLR_NL_MASK GENMASK(15, 0) + +/* Hardware limits */ +#define MAX_WIDTH 2592 +#define MAX_HEIGHT 2592 + +#define DEFAULT_WIDTH 240 +#define DEFAULT_HEIGHT 320 +#define DEFAULT_SIZE 307200 + +#define CM_MODE_ARGB8888 0x00 +#define CM_MODE_ARGB4444 0x04 +#define CM_MODE_A4 0x0a +#endif /* __DMA2D_REGS_H__ */ diff --git a/drivers/media/platform/stm32/dma2d/dma2d.c b/drivers/media/platform/stm32/dma2d/dma2d.c new file mode 100644 index 000000000000..17af90d86898 --- /dev/null +++ b/drivers/media/platform/stm32/dma2d/dma2d.c @@ -0,0 +1,739 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * STM32 DMA2D - 2D Graphics Accelerator Driver + * + * Copyright (c) 2021 Dillon Min + * Dillon Min, <dillon.minfei@gmail.com> + * + * based on s5p-g2d + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * Kamil Debski, <k.debski@samsung.com> + */ + +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/timer.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/clk.h> +#include <linux/interrupt.h> +#include <linux/of.h> + +#include <linux/platform_device.h> +#include <media/v4l2-mem2mem.h> +#include <media/v4l2-device.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-event.h> +#include <media/videobuf2-v4l2.h> +#include <media/videobuf2-dma-contig.h> + +#include "dma2d.h" +#include "dma2d-regs.h" + +/* + * This V4L2 subdev m2m driver enables Chrom-Art Accelerator unit + * of STMicroelectronics STM32 SoC series. + * + * Currently support r2m, m2m, m2m_pfc. + * + * - r2m, Filling a part or the whole of a destination image with a specific + * color. + * - m2m, Copying a part or the whole of a source image into a part or the + * whole of a destination. + * - m2m_pfc, Copying a part or the whole of a source image into a part or the + * whole of a destination image with a pixel format conversion. + */ + +#define fh2ctx(__fh) container_of(__fh, struct dma2d_ctx, fh) + +static const struct dma2d_fmt formats[] = { + { + .fourcc = V4L2_PIX_FMT_ARGB32, + .cmode = DMA2D_CMODE_ARGB8888, + .depth = 32, + }, + { + .fourcc = V4L2_PIX_FMT_RGB24, + .cmode = DMA2D_CMODE_RGB888, + .depth = 24, + }, + { + .fourcc = V4L2_PIX_FMT_RGB565, + .cmode = DMA2D_CMODE_RGB565, + .depth = 16, + }, + { + .fourcc = V4L2_PIX_FMT_ARGB555, + .cmode = DMA2D_CMODE_ARGB1555, + .depth = 16, + }, + { + .fourcc = V4L2_PIX_FMT_ARGB444, + .cmode = DMA2D_CMODE_ARGB4444, + .depth = 16, + }, +}; + +#define NUM_FORMATS ARRAY_SIZE(formats) + +static const struct dma2d_frame def_frame = { + .width = DEFAULT_WIDTH, + .height = DEFAULT_HEIGHT, + .line_offset = 0, + .a_rgb = {0x00, 0x00, 0x00, 0xff}, + .a_mode = DMA2D_ALPHA_MODE_NO_MODIF, + .fmt = (struct dma2d_fmt *)&formats[0], + .size = DEFAULT_SIZE, +}; + +static struct dma2d_fmt *find_fmt(int pixelformat) +{ + unsigned int i; + + for (i = 0; i < NUM_FORMATS; i++) { + if (formats[i].fourcc == pixelformat) + return (struct dma2d_fmt *)&formats[i]; + } + + return NULL; +} + +static struct dma2d_frame *get_frame(struct dma2d_ctx *ctx, + enum v4l2_buf_type type) +{ + return V4L2_TYPE_IS_OUTPUT(type) ? &ctx->cap : &ctx->out; +} + +static int dma2d_queue_setup(struct vb2_queue *vq, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], struct device *alloc_devs[]) +{ + struct dma2d_ctx *ctx = vb2_get_drv_priv(vq); + struct dma2d_frame *f = get_frame(ctx, vq->type); + + if (*nplanes) + return sizes[0] < f->size ? -EINVAL : 0; + + sizes[0] = f->size; + *nplanes = 1; + + return 0; +} + +static int dma2d_buf_out_validate(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + + if (vbuf->field == V4L2_FIELD_ANY) + vbuf->field = V4L2_FIELD_NONE; + if (vbuf->field != V4L2_FIELD_NONE) + return -EINVAL; + + return 0; +} + +static int dma2d_buf_prepare(struct vb2_buffer *vb) +{ + struct dma2d_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct dma2d_frame *f = get_frame(ctx, vb->vb2_queue->type); + + if (vb2_plane_size(vb, 0) < f->size) + return -EINVAL; + + vb2_set_plane_payload(vb, 0, f->size); + + return 0; +} + +static void dma2d_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct dma2d_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); +} + +static int dma2d_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct dma2d_ctx *ctx = vb2_get_drv_priv(q); + struct dma2d_frame *f = get_frame(ctx, q->type); + + f->sequence = 0; + return 0; +} + +static void dma2d_stop_streaming(struct vb2_queue *q) +{ + struct dma2d_ctx *ctx = vb2_get_drv_priv(q); + struct vb2_v4l2_buffer *vbuf; + + for (;;) { + if (V4L2_TYPE_IS_OUTPUT(q->type)) + vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + else + vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + if (!vbuf) + return; + v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); + } +} + +static const struct vb2_ops dma2d_qops = { + .queue_setup = dma2d_queue_setup, + .buf_out_validate = dma2d_buf_out_validate, + .buf_prepare = dma2d_buf_prepare, + .buf_queue = dma2d_buf_queue, + .start_streaming = dma2d_start_streaming, + .stop_streaming = dma2d_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +static int queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + struct dma2d_ctx *ctx = priv; + int ret; + + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + src_vq->io_modes = VB2_MMAP | VB2_DMABUF; + src_vq->drv_priv = ctx; + src_vq->ops = &dma2d_qops; + src_vq->mem_ops = &vb2_dma_contig_memops; + src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->lock = &ctx->dev->mutex; + src_vq->dev = ctx->dev->v4l2_dev.dev; + + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; + dst_vq->drv_priv = ctx; + dst_vq->ops = &dma2d_qops; + dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->lock = &ctx->dev->mutex; + dst_vq->dev = ctx->dev->v4l2_dev.dev; + + return vb2_queue_init(dst_vq); +} + +static int dma2d_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct dma2d_frame *frm; + struct dma2d_ctx *ctx = container_of(ctrl->handler, struct dma2d_ctx, + ctrl_handler); + unsigned long flags; + + spin_lock_irqsave(&ctx->dev->ctrl_lock, flags); + switch (ctrl->id) { + case V4L2_CID_COLORFX: + if (ctrl->val == V4L2_COLORFX_SET_RGB) + ctx->op_mode = DMA2D_MODE_R2M; + else if (ctrl->val == V4L2_COLORFX_NONE) + ctx->op_mode = DMA2D_MODE_M2M; + break; + case V4L2_CID_COLORFX_RGB: + frm = get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + frm->a_rgb[2] = (ctrl->val >> 16) & 0xff; + frm->a_rgb[1] = (ctrl->val >> 8) & 0xff; + frm->a_rgb[0] = (ctrl->val >> 0) & 0xff; + break; + default: + spin_unlock_irqrestore(&ctx->dev->ctrl_lock, flags); + return -EINVAL; + } + spin_unlock_irqrestore(&ctx->dev->ctrl_lock, flags); + + return 0; +} + +static const struct v4l2_ctrl_ops dma2d_ctrl_ops = { + .s_ctrl = dma2d_s_ctrl, +}; + +static int dma2d_setup_ctrls(struct dma2d_ctx *ctx) +{ + struct v4l2_ctrl_handler *handler = &ctx->ctrl_handler; + + v4l2_ctrl_handler_init(handler, 2); + + v4l2_ctrl_new_std_menu(handler, &dma2d_ctrl_ops, V4L2_CID_COLORFX, + V4L2_COLORFX_SET_RGB, ~0x10001, + V4L2_COLORFX_NONE); + + v4l2_ctrl_new_std(handler, &dma2d_ctrl_ops, V4L2_CID_COLORFX_RGB, 0, + 0xffffff, 1, 0); + + return 0; +} + +static int dma2d_open(struct file *file) +{ + struct dma2d_dev *dev = video_drvdata(file); + struct dma2d_ctx *ctx = NULL; + int ret = 0; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + ctx->dev = dev; + /* Set default formats */ + ctx->cap = def_frame; + ctx->bg = def_frame; + ctx->out = def_frame; + ctx->op_mode = DMA2D_MODE_M2M_FPC; + ctx->colorspace = V4L2_COLORSPACE_REC709; + if (mutex_lock_interruptible(&dev->mutex)) { + kfree(ctx); + return -ERESTARTSYS; + } + + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init); + if (IS_ERR(ctx->fh.m2m_ctx)) { + ret = PTR_ERR(ctx->fh.m2m_ctx); + mutex_unlock(&dev->mutex); + kfree(ctx); + return ret; + } + + v4l2_fh_init(&ctx->fh, video_devdata(file)); + file->private_data = &ctx->fh; + v4l2_fh_add(&ctx->fh); + + dma2d_setup_ctrls(ctx); + + /* Write the default values to the ctx struct */ + v4l2_ctrl_handler_setup(&ctx->ctrl_handler); + + ctx->fh.ctrl_handler = &ctx->ctrl_handler; + mutex_unlock(&dev->mutex); + + return 0; +} + +static int dma2d_release(struct file *file) +{ + struct dma2d_dev *dev = video_drvdata(file); + struct dma2d_ctx *ctx = fh2ctx(file->private_data); + + mutex_lock(&dev->mutex); + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); + mutex_unlock(&dev->mutex); + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + kfree(ctx); + + return 0; +} + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strscpy(cap->driver, DMA2D_NAME, sizeof(cap->driver)); + strscpy(cap->card, DMA2D_NAME, sizeof(cap->card)); + strscpy(cap->bus_info, BUS_INFO, sizeof(cap->bus_info)); + + return 0; +} + +static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f) +{ + if (f->index >= NUM_FORMATS) + return -EINVAL; + + f->pixelformat = formats[f->index].fourcc; + return 0; +} + +static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f) +{ + struct dma2d_ctx *ctx = prv; + struct vb2_queue *vq; + struct dma2d_frame *frm; + + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (!vq) + return -EINVAL; + + frm = get_frame(ctx, f->type); + f->fmt.pix.width = frm->width; + f->fmt.pix.height = frm->height; + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.pixelformat = frm->fmt->fourcc; + f->fmt.pix.bytesperline = (frm->width * frm->fmt->depth) >> 3; + f->fmt.pix.sizeimage = frm->size; + f->fmt.pix.colorspace = ctx->colorspace; + f->fmt.pix.xfer_func = ctx->xfer_func; + f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc; + f->fmt.pix.quantization = ctx->quant; + + return 0; +} + +static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f) +{ + struct dma2d_ctx *ctx = prv; + struct dma2d_fmt *fmt; + enum v4l2_field *field; + u32 fourcc = f->fmt.pix.pixelformat; + + fmt = find_fmt(fourcc); + if (!fmt) { + f->fmt.pix.pixelformat = formats[0].fourcc; + fmt = find_fmt(f->fmt.pix.pixelformat); + } + + field = &f->fmt.pix.field; + if (*field == V4L2_FIELD_ANY) + *field = V4L2_FIELD_NONE; + else if (*field != V4L2_FIELD_NONE) + return -EINVAL; + + if (f->fmt.pix.width > MAX_WIDTH) + f->fmt.pix.width = MAX_WIDTH; + if (f->fmt.pix.height > MAX_HEIGHT) + f->fmt.pix.height = MAX_HEIGHT; + + if (f->fmt.pix.width < 1) + f->fmt.pix.width = 1; + if (f->fmt.pix.height < 1) + f->fmt.pix.height = 1; + + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && !f->fmt.pix.colorspace) { + f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709; + } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + f->fmt.pix.colorspace = ctx->colorspace; + f->fmt.pix.xfer_func = ctx->xfer_func; + f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc; + f->fmt.pix.quantization = ctx->quant; + } + f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; + f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + + return 0; +} + +static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) +{ + struct dma2d_ctx *ctx = prv; + struct vb2_queue *vq; + struct dma2d_frame *frm; + struct dma2d_fmt *fmt; + int ret = 0; + + /* Adjust all values accordingly to the hardware capabilities + * and chosen format. + */ + ret = vidioc_try_fmt(file, prv, f); + if (ret) + return ret; + + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (vb2_is_busy(vq)) + return -EBUSY; + + fmt = find_fmt(f->fmt.pix.pixelformat); + if (!fmt) + return -EINVAL; + + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + ctx->colorspace = f->fmt.pix.colorspace; + ctx->xfer_func = f->fmt.pix.xfer_func; + ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc; + ctx->quant = f->fmt.pix.quantization; + } + + frm = get_frame(ctx, f->type); + frm->width = f->fmt.pix.width; + frm->height = f->fmt.pix.height; + frm->size = f->fmt.pix.sizeimage; + /* Reset crop settings */ + frm->o_width = 0; + frm->o_height = 0; + frm->c_width = frm->width; + frm->c_height = frm->height; + frm->right = frm->width; + frm->bottom = frm->height; + frm->fmt = fmt; + frm->line_offset = 0; + + return 0; +} + +static void device_run(void *prv) +{ + struct dma2d_ctx *ctx = prv; + struct dma2d_dev *dev = ctx->dev; + struct dma2d_frame *frm_out, *frm_cap; + struct vb2_v4l2_buffer *src, *dst; + unsigned long flags; + + spin_lock_irqsave(&dev->ctrl_lock, flags); + dev->curr = ctx; + + src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + if (!dst || !src) + goto end; + + frm_cap = get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + frm_out = get_frame(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + if (!frm_cap || !frm_out) + goto end; + + src->sequence = frm_out->sequence++; + dst->sequence = frm_cap->sequence++; + v4l2_m2m_buf_copy_metadata(src, dst, true); + + clk_enable(dev->gate); + + dma2d_config_fg(dev, frm_out, + vb2_dma_contig_plane_dma_addr(&src->vb2_buf, 0)); + + /* TODO: add M2M_BLEND handler here */ + + if (ctx->op_mode != DMA2D_MODE_R2M) { + if (frm_out->fmt->fourcc == frm_cap->fmt->fourcc) + ctx->op_mode = DMA2D_MODE_M2M; + else + ctx->op_mode = DMA2D_MODE_M2M_FPC; + } + + dma2d_config_out(dev, frm_cap, + vb2_dma_contig_plane_dma_addr(&dst->vb2_buf, 0)); + dma2d_config_common(dev, ctx->op_mode, frm_cap->width, frm_cap->height); + + dma2d_start(dev); +end: + spin_unlock_irqrestore(&dev->ctrl_lock, flags); +} + +static irqreturn_t dma2d_isr(int irq, void *prv) +{ + struct dma2d_dev *dev = prv; + struct dma2d_ctx *ctx = dev->curr; + struct vb2_v4l2_buffer *src, *dst; + u32 s = dma2d_get_int(dev); + + dma2d_clear_int(dev); + if (s & ISR_TCIF || s == 0) { + clk_disable(dev->gate); + + WARN_ON(!ctx); + + src = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + dst = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + + WARN_ON(!dst); + WARN_ON(!src); + + v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE); + v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE); + v4l2_m2m_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx); + + dev->curr = NULL; + } + + return IRQ_HANDLED; +} + +static const struct v4l2_file_operations dma2d_fops = { + .owner = THIS_MODULE, + .open = dma2d_open, + .release = dma2d_release, + .poll = v4l2_m2m_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = v4l2_m2m_fop_mmap, +#ifndef CONFIG_MMU + .get_unmapped_area = v4l2_m2m_get_unmapped_area, +#endif +}; + +static const struct v4l2_ioctl_ops dma2d_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt, + + .vidioc_enum_fmt_vid_out = vidioc_enum_fmt, + .vidioc_g_fmt_vid_out = vidioc_g_fmt, + .vidioc_try_fmt_vid_out = vidioc_try_fmt, + .vidioc_s_fmt_vid_out = vidioc_s_fmt, + + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static const struct video_device dma2d_videodev = { + .name = DMA2D_NAME, + .fops = &dma2d_fops, + .ioctl_ops = &dma2d_ioctl_ops, + .minor = -1, + .release = video_device_release, + .vfl_dir = VFL_DIR_M2M, +}; + +static const struct v4l2_m2m_ops dma2d_m2m_ops = { + .device_run = device_run, +}; + +static const struct of_device_id stm32_dma2d_match[]; + +static int dma2d_probe(struct platform_device *pdev) +{ + struct dma2d_dev *dev; + struct video_device *vfd; + struct resource *res; + int ret = 0; + + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + spin_lock_init(&dev->ctrl_lock); + mutex_init(&dev->mutex); + atomic_set(&dev->num_inst, 0); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + dev->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(dev->regs)) + return PTR_ERR(dev->regs); + + dev->gate = clk_get(&pdev->dev, "dma2d"); + if (IS_ERR(dev->gate)) { + dev_err(&pdev->dev, "failed to get dma2d clock gate\n"); + ret = -ENXIO; + return ret; + } + + ret = clk_prepare(dev->gate); + if (ret) { + dev_err(&pdev->dev, "failed to prepare dma2d clock gate\n"); + goto put_clk_gate; + } + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(&pdev->dev, "failed to find IRQ\n"); + ret = -ENXIO; + goto unprep_clk_gate; + } + + dev->irq = res->start; + + ret = devm_request_irq(&pdev->dev, dev->irq, dma2d_isr, + 0, pdev->name, dev); + if (ret) { + dev_err(&pdev->dev, "failed to install IRQ\n"); + goto unprep_clk_gate; + } + + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); + if (ret) + goto unprep_clk_gate; + + vfd = video_device_alloc(); + if (!vfd) { + v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n"); + ret = -ENOMEM; + goto unreg_v4l2_dev; + } + + *vfd = dma2d_videodev; + vfd->lock = &dev->mutex; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; + + platform_set_drvdata(pdev, dev); + dev->m2m_dev = v4l2_m2m_init(&dma2d_m2m_ops); + if (IS_ERR(dev->m2m_dev)) { + v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n"); + ret = PTR_ERR(dev->m2m_dev); + goto rel_vdev; + } + + ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); + if (ret) { + v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); + goto free_m2m; + } + + video_set_drvdata(vfd, dev); + dev->vfd = vfd; + v4l2_info(&dev->v4l2_dev, "device registered as /dev/video%d\n", + vfd->num); + return 0; + +free_m2m: + v4l2_m2m_release(dev->m2m_dev); +rel_vdev: + video_device_release(vfd); +unreg_v4l2_dev: + v4l2_device_unregister(&dev->v4l2_dev); +unprep_clk_gate: + clk_unprepare(dev->gate); +put_clk_gate: + clk_put(dev->gate); + + return ret; +} + +static int dma2d_remove(struct platform_device *pdev) +{ + struct dma2d_dev *dev = platform_get_drvdata(pdev); + + v4l2_info(&dev->v4l2_dev, "Removing " DMA2D_NAME); + v4l2_m2m_release(dev->m2m_dev); + video_unregister_device(dev->vfd); + v4l2_device_unregister(&dev->v4l2_dev); + vb2_dma_contig_clear_max_seg_size(&pdev->dev); + clk_unprepare(dev->gate); + clk_put(dev->gate); + + return 0; +} + +static const struct of_device_id stm32_dma2d_match[] = { + { + .compatible = "st,stm32-dma2d", + .data = NULL, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, stm32_dma2d_match); + +static struct platform_driver dma2d_pdrv = { + .probe = dma2d_probe, + .remove = dma2d_remove, + .driver = { + .name = DMA2D_NAME, + .of_match_table = stm32_dma2d_match, + }, +}; + +module_platform_driver(dma2d_pdrv); + +MODULE_AUTHOR("Dillon Min <dillon.minfei@gmail.com>"); +MODULE_DESCRIPTION("STM32 Chrom-Art Accelerator DMA2D driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/stm32/dma2d/dma2d.h b/drivers/media/platform/stm32/dma2d/dma2d.h new file mode 100644 index 000000000000..3f03a7ca9ee3 --- /dev/null +++ b/drivers/media/platform/stm32/dma2d/dma2d.h @@ -0,0 +1,135 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * ST stm32 DMA2D - 2D Graphics Accelerator Driver + * + * Copyright (c) 2021 Dillon Min + * Dillon Min, <dillon.minfei@gmail.com> + * + * based on s5p-g2d + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * Kamil Debski, <k.debski@samsung.com> + */ + +#ifndef __DMA2D_H__ +#define __DMA2D_H__ + +#include <linux/platform_device.h> +#include <media/v4l2-device.h> +#include <media/v4l2-ctrls.h> + +#define DMA2D_NAME "stm-dma2d" +#define BUS_INFO "platform:stm-dma2d" +enum dma2d_op_mode { + DMA2D_MODE_M2M, + DMA2D_MODE_M2M_FPC, + DMA2D_MODE_M2M_BLEND, + DMA2D_MODE_R2M +}; + +enum dma2d_cmode { + /* output pfc cmode from ARGB888 to ARGB4444 */ + DMA2D_CMODE_ARGB8888, + DMA2D_CMODE_RGB888, + DMA2D_CMODE_RGB565, + DMA2D_CMODE_ARGB1555, + DMA2D_CMODE_ARGB4444, + /* bg or fg pfc cmode from L8 to A4 */ + DMA2D_CMODE_L8, + DMA2D_CMODE_AL44, + DMA2D_CMODE_AL88, + DMA2D_CMODE_L4, + DMA2D_CMODE_A8, + DMA2D_CMODE_A4 +}; + +enum dma2d_alpha_mode { + DMA2D_ALPHA_MODE_NO_MODIF, + DMA2D_ALPHA_MODE_REPLACE, + DMA2D_ALPHA_MODE_COMBINE +}; + +struct dma2d_fmt { + u32 fourcc; + int depth; + enum dma2d_cmode cmode; +}; + +struct dma2d_frame { + /* Original dimensions */ + u32 width; + u32 height; + /* Crop size */ + u32 c_width; + u32 c_height; + /* Offset */ + u32 o_width; + u32 o_height; + u32 bottom; + u32 right; + u16 line_offset; + /* Image format */ + struct dma2d_fmt *fmt; + /* [0]: blue + * [1]: green + * [2]: red + * [3]: alpha + */ + u8 a_rgb[4]; + /* + * AM[1:0] of DMA2D_FGPFCCR + */ + enum dma2d_alpha_mode a_mode; + u32 size; + unsigned int sequence; +}; + +struct dma2d_ctx { + struct v4l2_fh fh; + struct dma2d_dev *dev; + struct dma2d_frame cap; + struct dma2d_frame out; + struct dma2d_frame bg; + /* fb_buf always point to bg address */ + struct v4l2_framebuffer fb_buf; + /* + * MODE[17:16] of DMA2D_CR + */ + enum dma2d_op_mode op_mode; + struct v4l2_ctrl_handler ctrl_handler; + enum v4l2_colorspace colorspace; + enum v4l2_ycbcr_encoding ycbcr_enc; + enum v4l2_xfer_func xfer_func; + enum v4l2_quantization quant; +}; + +struct dma2d_dev { + struct v4l2_device v4l2_dev; + struct v4l2_m2m_dev *m2m_dev; + struct video_device *vfd; + /* for device open/close etc */ + struct mutex mutex; + /* to avoid the conflict with device running and user setting + * at the same time + */ + spinlock_t ctrl_lock; + atomic_t num_inst; + void __iomem *regs; + struct clk *gate; + struct dma2d_ctx *curr; + int irq; +}; + +void dma2d_start(struct dma2d_dev *d); +u32 dma2d_get_int(struct dma2d_dev *d); +void dma2d_clear_int(struct dma2d_dev *d); +void dma2d_config_out(struct dma2d_dev *d, struct dma2d_frame *frm, + dma_addr_t o_addr); +void dma2d_config_fg(struct dma2d_dev *d, struct dma2d_frame *frm, + dma_addr_t f_addr); +void dma2d_config_bg(struct dma2d_dev *d, struct dma2d_frame *frm, + dma_addr_t b_addr); +void dma2d_config_common(struct dma2d_dev *d, enum dma2d_op_mode op_mode, + u16 width, u16 height); + +#endif /* __DMA2D_H__ */ diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c index b39a68f83c5f..0bf99e1cd1d8 100644 --- a/drivers/media/radio/radio-si476x.c +++ b/drivers/media/radio/radio-si476x.c @@ -313,12 +313,6 @@ struct si476x_radio { }; static inline struct si476x_radio * -v4l2_dev_to_radio(struct v4l2_device *d) -{ - return container_of(d, struct si476x_radio, v4l2dev); -} - -static inline struct si476x_radio * v4l2_ctrl_handler_to_radio(struct v4l2_ctrl_handler *d) { return container_of(d, struct si476x_radio, ctrl_handler); diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index a972c0705ac7..59b3d77e282d 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -334,7 +334,6 @@ static int si470x_i2c_probe(struct i2c_client *client) { struct si470x_device *radio; int retval = 0; - unsigned char version_warning = 0; /* private data allocation and initialization */ radio = devm_kzalloc(&client->dev, sizeof(*radio), GFP_KERNEL); @@ -368,7 +367,7 @@ static int si470x_i2c_probe(struct i2c_client *client) if (radio->hdl.error) { retval = radio->hdl.error; dev_err(&client->dev, "couldn't register control\n"); - goto err_dev; + goto err_all; } /* video device initialization */ @@ -410,20 +409,10 @@ static int si470x_i2c_probe(struct i2c_client *client) radio->registers[DEVICEID], radio->registers[SI_CHIPID]); if ((radio->registers[SI_CHIPID] & SI_CHIPID_FIRMWARE) < RADIO_FW_VERSION) { dev_warn(&client->dev, - "This driver is known to work with firmware version %hu,\n", - RADIO_FW_VERSION); - dev_warn(&client->dev, - "but the device has firmware version %hu.\n", + "This driver is known to work with firmware version %u, but the device has firmware version %u.\n" + "If you have some trouble using this driver, please report to V4L ML at linux-media@vger.kernel.org\n", + RADIO_FW_VERSION, radio->registers[SI_CHIPID] & SI_CHIPID_FIRMWARE); - version_warning = 1; - } - - /* give out version warning */ - if (version_warning == 1) { - dev_warn(&client->dev, - "If you have some trouble using this driver,\n"); - dev_warn(&client->dev, - "please report to V4L ML at linux-media@vger.kernel.org\n"); } /* set initial frequency */ @@ -463,7 +452,6 @@ static int si470x_i2c_probe(struct i2c_client *client) return 0; err_all: v4l2_ctrl_handler_free(&radio->hdl); -err_dev: v4l2_device_unregister(&radio->v4l2_dev); err_initial: return retval; diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c index 3f8634a46573..6b2768623c88 100644 --- a/drivers/media/radio/si470x/radio-si470x-usb.c +++ b/drivers/media/radio/si470x/radio-si470x-usb.c @@ -681,10 +681,8 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, radio->registers[DEVICEID], radio->registers[SI_CHIPID]); if ((radio->registers[SI_CHIPID] & SI_CHIPID_FIRMWARE) < RADIO_FW_VERSION) { dev_warn(&intf->dev, - "This driver is known to work with firmware version %hu,\n", - RADIO_FW_VERSION); - dev_warn(&intf->dev, - "but the device has firmware version %hu.\n", + "This driver is known to work with firmware version %u, but the device has firmware version %u.\n", + RADIO_FW_VERSION, radio->registers[SI_CHIPID] & SI_CHIPID_FIRMWARE); version_warning = 1; } @@ -698,10 +696,8 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, radio->software_version, radio->hardware_version); if (radio->hardware_version < RADIO_HW_VERSION) { dev_warn(&intf->dev, - "This driver is known to work with hardware version %hu,\n", - RADIO_HW_VERSION); - dev_warn(&intf->dev, - "but the device has hardware version %hu.\n", + "This driver is known to work with hardware version %u, but the device has hardware version %u.\n", + RADIO_HW_VERSION, radio->hardware_version); version_warning = 1; } @@ -709,9 +705,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, /* give out version warning */ if (version_warning == 1) { dev_warn(&intf->dev, - "If you have some trouble using this driver,\n"); - dev_warn(&intf->dev, - "please report to V4L ML at linux-media@vger.kernel.org\n"); + "If you have some trouble using this driver, please report to V4L ML at linux-media@vger.kernel.org\n"); } /* set led to connect state */ diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 9506baf3c4c1..c111af820ae4 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -175,7 +175,7 @@ config IR_ENE config IR_HIX5HD2 tristate "Hisilicon hix5hd2 IR remote control" - depends on OF || COMPILE_TEST + depends on (OF && HAS_IOMEM) || COMPILE_TEST help Say Y here if you want to use hisilicon hix5hd2 remote control. To compile this driver as a module, choose M here: the module will be diff --git a/drivers/media/rc/igorplugusb.c b/drivers/media/rc/igorplugusb.c index effaa5751d6c..3e9988ee785f 100644 --- a/drivers/media/rc/igorplugusb.c +++ b/drivers/media/rc/igorplugusb.c @@ -64,9 +64,11 @@ static void igorplugusb_irdata(struct igorplugusb *ir, unsigned len) if (start >= len) { dev_err(ir->dev, "receive overflow invalid: %u", overflow); } else { - if (overflow > 0) + if (overflow > 0) { dev_warn(ir->dev, "receive overflow, at least %u lost", overflow); + ir_raw_event_reset(ir->rc); + } do { rawir.duration = ir->buf_in[i] * 85; diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c index 84949baf9f6b..f8d080e41f4c 100644 --- a/drivers/media/rc/iguanair.c +++ b/drivers/media/rc/iguanair.c @@ -262,9 +262,6 @@ static int iguanair_receiver(struct iguanair *ir, bool enable) ir->packet->header.direction = DIR_OUT; ir->packet->header.cmd = enable ? CMD_RECEIVER_ON : CMD_RECEIVER_OFF; - if (enable) - ir_raw_event_reset(ir->rc); - return iguanair_send(ir, sizeof(ir->packet->header)); } diff --git a/drivers/media/rc/ir-rx51.c b/drivers/media/rc/ir-rx51.c index a0d9c02a7588..a3b145183260 100644 --- a/drivers/media/rc/ir-rx51.c +++ b/drivers/media/rc/ir-rx51.c @@ -19,6 +19,7 @@ struct ir_rx51 { struct rc_dev *rcdev; struct pwm_device *pwm; + struct pwm_state state; struct hrtimer timer; struct device *dev; wait_queue_head_t wqueue; @@ -32,22 +33,20 @@ struct ir_rx51 { static inline void ir_rx51_on(struct ir_rx51 *ir_rx51) { - pwm_enable(ir_rx51->pwm); + ir_rx51->state.enabled = true; + pwm_apply_state(ir_rx51->pwm, &ir_rx51->state); } static inline void ir_rx51_off(struct ir_rx51 *ir_rx51) { - pwm_disable(ir_rx51->pwm); + ir_rx51->state.enabled = false; + pwm_apply_state(ir_rx51->pwm, &ir_rx51->state); } static int init_timing_params(struct ir_rx51 *ir_rx51) { - struct pwm_device *pwm = ir_rx51->pwm; - int duty, period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, ir_rx51->freq); - - duty = DIV_ROUND_CLOSEST(ir_rx51->duty_cycle * period, 100); - - pwm_config(pwm, duty, period); + ir_rx51->state.period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, ir_rx51->freq); + pwm_set_relative_duty_cycle(&ir_rx51->state, ir_rx51->duty_cycle, 100); return 0; } @@ -242,6 +241,7 @@ static int ir_rx51_probe(struct platform_device *dev) /* Use default, in case userspace does not set the carrier */ ir_rx51.freq = DIV_ROUND_CLOSEST_ULL(pwm_get_period(pwm), NSEC_PER_SEC); + pwm_init_state(pwm, &ir_rx51.state); pwm_put(pwm); hrtimer_init(&ir_rx51.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); diff --git a/drivers/media/rc/ir-spi.c b/drivers/media/rc/ir-spi.c index c58f2d38a458..51aa55a84bb5 100644 --- a/drivers/media/rc/ir-spi.c +++ b/drivers/media/rc/ir-spi.c @@ -152,11 +152,6 @@ static int ir_spi_probe(struct spi_device *spi) return devm_rc_register_device(&spi->dev, idata->rc); } -static int ir_spi_remove(struct spi_device *spi) -{ - return 0; -} - static const struct of_device_id ir_spi_of_match[] = { { .compatible = "ir-spi-led" }, {}, @@ -165,7 +160,6 @@ MODULE_DEVICE_TABLE(of, ir_spi_of_match); static struct spi_driver ir_spi_driver = { .probe = ir_spi_probe, - .remove = ir_spi_remove, .driver = { .name = IR_SPI_DRIVER_NAME, .of_match_table = ir_spi_of_match, diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index 7f591ff5269d..c7c5157725f8 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -102,8 +102,6 @@ void lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev) spin_lock_irqsave(&dev->lirc_fh_lock, flags); list_for_each_entry(fh, &dev->lirc_fh, list) { - if (LIRC_IS_TIMEOUT(sample) && !fh->send_timeout_reports) - continue; if (kfifo_put(&fh->rawir, sample)) wake_up_poll(&fh->wait_poll, EPOLLIN | EPOLLRDNORM); } @@ -166,7 +164,6 @@ static int lirc_open(struct inode *inode, struct file *file) fh->send_mode = LIRC_MODE_PULSE; fh->rc = dev; - fh->send_timeout_reports = true; if (dev->driver_type == RC_DRIVER_SCANCODE) fh->rec_mode = LIRC_MODE_SCANCODE; @@ -570,8 +567,6 @@ static long lirc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case LIRC_SET_REC_TIMEOUT_REPORTS: if (dev->driver_type != RC_DRIVER_IR_RAW) ret = -ENOTTY; - else - fh->send_timeout_reports = !!val; break; default: diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index d09bee82c04c..2dc810f5a73f 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -1430,7 +1430,7 @@ static void mceusb_gen1_init(struct mceusb_dev *ir) */ ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), USB_REQ_SET_ADDRESS, USB_TYPE_VENDOR, 0, 0, - data, USB_CTRL_MSG_SZ, HZ * 3); + data, USB_CTRL_MSG_SZ, 3000); dev_dbg(dev, "set address - ret = %d", ret); dev_dbg(dev, "set address - data[0] = %d, data[1] = %d", data[0], data[1]); @@ -1438,20 +1438,20 @@ static void mceusb_gen1_init(struct mceusb_dev *ir) /* set feature: bit rate 38400 bps */ ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), USB_REQ_SET_FEATURE, USB_TYPE_VENDOR, - 0xc04e, 0x0000, NULL, 0, HZ * 3); + 0xc04e, 0x0000, NULL, 0, 3000); dev_dbg(dev, "set feature - ret = %d", ret); /* bRequest 4: set char length to 8 bits */ ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), 4, USB_TYPE_VENDOR, - 0x0808, 0x0000, NULL, 0, HZ * 3); + 0x0808, 0x0000, NULL, 0, 3000); dev_dbg(dev, "set char length - retB = %d", ret); /* bRequest 2: set handshaking to use DTR/DSR */ ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), 2, USB_TYPE_VENDOR, - 0x0000, 0x0100, NULL, 0, HZ * 3); + 0x0000, 0x0100, NULL, 0, 3000); dev_dbg(dev, "set handshake - retC = %d", ret); /* device resume */ diff --git a/drivers/media/rc/pwm-ir-tx.c b/drivers/media/rc/pwm-ir-tx.c index 4bc28d2c9cc9..105a9c24f1e3 100644 --- a/drivers/media/rc/pwm-ir-tx.c +++ b/drivers/media/rc/pwm-ir-tx.c @@ -53,22 +53,21 @@ static int pwm_ir_tx(struct rc_dev *dev, unsigned int *txbuf, { struct pwm_ir *pwm_ir = dev->priv; struct pwm_device *pwm = pwm_ir->pwm; - int i, duty, period; + struct pwm_state state; + int i; ktime_t edge; long delta; - period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, pwm_ir->carrier); - duty = DIV_ROUND_CLOSEST(pwm_ir->duty_cycle * period, 100); + pwm_init_state(pwm, &state); - pwm_config(pwm, duty, period); + state.period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, pwm_ir->carrier); + pwm_set_relative_duty_cycle(&state, pwm_ir->duty_cycle, 100); edge = ktime_get(); for (i = 0; i < count; i++) { - if (i % 2) // space - pwm_disable(pwm); - else - pwm_enable(pwm); + state.enabled = !(i % 2); + pwm_apply_state(pwm, &state); edge = ktime_add_us(edge, txbuf[i]); delta = ktime_us_delta(edge, ktime_get()); @@ -76,7 +75,8 @@ static int pwm_ir_tx(struct rc_dev *dev, unsigned int *txbuf, usleep_range(delta, delta + 10); } - pwm_disable(pwm); + state.enabled = false; + pwm_apply_state(pwm, &state); return count; } diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index ac85464864b9..cb22316b3f00 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -404,7 +404,7 @@ static int redrat3_send_cmd(int cmd, struct redrat3_dev *rr3) udev = rr3->udev; res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), cmd, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x0000, 0x0000, data, sizeof(u8), HZ * 10); + 0x0000, 0x0000, data, sizeof(u8), 10000); if (res < 0) { dev_err(rr3->dev, "%s: Error sending rr3 cmd res %d, data %d", @@ -480,7 +480,7 @@ static u32 redrat3_get_timeout(struct redrat3_dev *rr3) pipe = usb_rcvctrlpipe(rr3->udev, 0); ret = usb_control_msg(rr3->udev, pipe, RR3_GET_IR_PARAM, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - RR3_IR_IO_SIG_TIMEOUT, 0, tmp, len, HZ * 5); + RR3_IR_IO_SIG_TIMEOUT, 0, tmp, len, 5000); if (ret != len) dev_warn(rr3->dev, "Failed to read timeout from hardware\n"); else { @@ -510,7 +510,7 @@ static int redrat3_set_timeout(struct rc_dev *rc_dev, unsigned int timeoutus) ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), RR3_SET_IR_PARAM, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, RR3_IR_IO_SIG_TIMEOUT, 0, timeout, sizeof(*timeout), - HZ * 25); + 25000); dev_dbg(dev, "set ir parm timeout %d ret 0x%02x\n", be32_to_cpu(*timeout), ret); @@ -542,32 +542,32 @@ static void redrat3_reset(struct redrat3_dev *rr3) *val = 0x01; rc = usb_control_msg(udev, rxpipe, RR3_RESET, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - RR3_CPUCS_REG_ADDR, 0, val, len, HZ * 25); + RR3_CPUCS_REG_ADDR, 0, val, len, 25000); dev_dbg(dev, "reset returned 0x%02x\n", rc); *val = length_fuzz; rc = usb_control_msg(udev, txpipe, RR3_SET_IR_PARAM, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, - RR3_IR_IO_LENGTH_FUZZ, 0, val, len, HZ * 25); + RR3_IR_IO_LENGTH_FUZZ, 0, val, len, 25000); dev_dbg(dev, "set ir parm len fuzz %d rc 0x%02x\n", *val, rc); *val = (65536 - (minimum_pause * 2000)) / 256; rc = usb_control_msg(udev, txpipe, RR3_SET_IR_PARAM, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, - RR3_IR_IO_MIN_PAUSE, 0, val, len, HZ * 25); + RR3_IR_IO_MIN_PAUSE, 0, val, len, 25000); dev_dbg(dev, "set ir parm min pause %d rc 0x%02x\n", *val, rc); *val = periods_measure_carrier; rc = usb_control_msg(udev, txpipe, RR3_SET_IR_PARAM, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, - RR3_IR_IO_PERIODS_MF, 0, val, len, HZ * 25); + RR3_IR_IO_PERIODS_MF, 0, val, len, 25000); dev_dbg(dev, "set ir parm periods measure carrier %d rc 0x%02x", *val, rc); *val = RR3_DRIVER_MAXLENS; rc = usb_control_msg(udev, txpipe, RR3_SET_IR_PARAM, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, - RR3_IR_IO_MAX_LENGTHS, 0, val, len, HZ * 25); + RR3_IR_IO_MAX_LENGTHS, 0, val, len, 25000); dev_dbg(dev, "set ir parm max lens %d rc 0x%02x\n", *val, rc); kfree(val); @@ -585,7 +585,7 @@ static void redrat3_get_firmware_rev(struct redrat3_dev *rr3) rc = usb_control_msg(rr3->udev, usb_rcvctrlpipe(rr3->udev, 0), RR3_FW_VERSION, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0, 0, buffer, RR3_FW_VERSION_LEN, HZ * 5); + 0, 0, buffer, RR3_FW_VERSION_LEN, 5000); if (rc >= 0) dev_info(rr3->dev, "Firmware rev: %s", buffer); @@ -825,14 +825,14 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf, pipe = usb_sndbulkpipe(rr3->udev, rr3->ep_out->bEndpointAddress); ret = usb_bulk_msg(rr3->udev, pipe, irdata, - sendbuf_len, &ret_len, 10 * HZ); + sendbuf_len, &ret_len, 10000); dev_dbg(dev, "sent %d bytes, (ret %d)\n", ret_len, ret); /* now tell the hardware to transmit what we sent it */ pipe = usb_rcvctrlpipe(rr3->udev, 0); ret = usb_control_msg(rr3->udev, pipe, RR3_TX_SEND_SIGNAL, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0, 0, irdata, 2, HZ * 10); + 0, 0, irdata, 2, 10000); if (ret < 0) dev_err(dev, "Error: control msg send failed, rc %d\n", ret); diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c index 1cc5ebb85b6c..16ba85d7c090 100644 --- a/drivers/media/rc/streamzap.c +++ b/drivers/media/rc/streamzap.c @@ -21,12 +21,10 @@ #include <linux/device.h> #include <linux/module.h> #include <linux/slab.h> -#include <linux/ktime.h> #include <linux/usb.h> #include <linux/usb/input.h> #include <media/rc-core.h> -#define DRIVER_VERSION "1.61" #define DRIVER_NAME "streamzap" #define DRIVER_DESC "Streamzap Remote Control driver" @@ -67,9 +65,6 @@ struct streamzap_ir { struct device *dev; /* usb */ - struct usb_device *usbdev; - struct usb_interface *interface; - struct usb_endpoint_descriptor *endpoint; struct urb *urb_in; /* buffer & dma */ @@ -79,16 +74,7 @@ struct streamzap_ir { /* track what state we're in */ enum StreamzapDecoderState decoder_state; - /* tracks whether we are currently receiving some signal */ - bool idle; - /* sum of signal lengths received since signal start */ - unsigned long sum; - /* start time of signal; necessary for gap tracking */ - ktime_t signal_last; - ktime_t signal_start; - bool timeout_enabled; - - char name[128]; + char phys[64]; }; @@ -121,37 +107,11 @@ static void sz_push(struct streamzap_ir *sz, struct ir_raw_event rawir) static void sz_push_full_pulse(struct streamzap_ir *sz, unsigned char value) { - struct ir_raw_event rawir = {}; - - if (sz->idle) { - int delta; - - sz->signal_last = sz->signal_start; - sz->signal_start = ktime_get_real(); - - delta = ktime_us_delta(sz->signal_start, sz->signal_last); - rawir.pulse = false; - if (delta > (15 * USEC_PER_SEC)) { - /* really long time */ - rawir.duration = IR_MAX_DURATION; - } else { - rawir.duration = delta; - rawir.duration -= sz->sum; - rawir.duration = (rawir.duration > IR_MAX_DURATION) ? - IR_MAX_DURATION : rawir.duration; - } - sz_push(sz, rawir); + struct ir_raw_event rawir = { + .pulse = true, + .duration = value * SZ_RESOLUTION + SZ_RESOLUTION / 2, + }; - sz->idle = false; - sz->sum = 0; - } - - rawir.pulse = true; - rawir.duration = ((int) value) * SZ_RESOLUTION; - rawir.duration += SZ_RESOLUTION / 2; - sz->sum += rawir.duration; - rawir.duration = (rawir.duration > IR_MAX_DURATION) ? - IR_MAX_DURATION : rawir.duration; sz_push(sz, rawir); } @@ -164,12 +124,11 @@ static void sz_push_half_pulse(struct streamzap_ir *sz, static void sz_push_full_space(struct streamzap_ir *sz, unsigned char value) { - struct ir_raw_event rawir = {}; + struct ir_raw_event rawir = { + .pulse = false, + .duration = value * SZ_RESOLUTION + SZ_RESOLUTION / 2, + }; - rawir.pulse = false; - rawir.duration = ((int) value) * SZ_RESOLUTION; - rawir.duration += SZ_RESOLUTION / 2; - sz->sum += rawir.duration; sz_push(sz, rawir); } @@ -241,11 +200,7 @@ static void streamzap_callback(struct urb *urb) .pulse = false, .duration = sz->rdev->timeout }; - sz->idle = true; - if (sz->timeout_enabled) - sz_push(sz, rawir); - ir_raw_event_handle(sz->rdev); - ir_raw_event_reset(sz->rdev); + sz_push(sz, rawir); } else { sz_push_full_space(sz, sz->buf_in[i]); } @@ -267,27 +222,23 @@ static void streamzap_callback(struct urb *urb) usb_submit_urb(urb, GFP_ATOMIC); } -static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz) +static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz, + struct usb_device *usbdev) { struct rc_dev *rdev; struct device *dev = sz->dev; int ret; rdev = rc_allocate_device(RC_DRIVER_IR_RAW); - if (!rdev) { - dev_err(dev, "remote dev allocation failed\n"); + if (!rdev) goto out; - } - snprintf(sz->name, sizeof(sz->name), "Streamzap PC Remote Infrared Receiver (%04x:%04x)", - le16_to_cpu(sz->usbdev->descriptor.idVendor), - le16_to_cpu(sz->usbdev->descriptor.idProduct)); - usb_make_path(sz->usbdev, sz->phys, sizeof(sz->phys)); + usb_make_path(usbdev, sz->phys, sizeof(sz->phys)); strlcat(sz->phys, "/input0", sizeof(sz->phys)); - rdev->device_name = sz->name; + rdev->device_name = "Streamzap PC Remote Infrared Receiver"; rdev->input_phys = sz->phys; - usb_to_input_id(sz->usbdev, &rdev->input_id); + usb_to_input_id(usbdev, &rdev->input_id); rdev->dev.parent = dev; rdev->priv = sz; rdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; @@ -319,9 +270,9 @@ static int streamzap_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *usbdev = interface_to_usbdev(intf); + struct usb_endpoint_descriptor *endpoint; struct usb_host_interface *iface_host; struct streamzap_ir *sz = NULL; - char buf[63], name[128] = ""; int retval = -ENOMEM; int pipe, maxp; @@ -330,9 +281,6 @@ static int streamzap_probe(struct usb_interface *intf, if (!sz) return -ENOMEM; - sz->usbdev = usbdev; - sz->interface = intf; - /* Check to ensure endpoint information matches requirements */ iface_host = intf->cur_altsetting; @@ -343,22 +291,22 @@ static int streamzap_probe(struct usb_interface *intf, goto free_sz; } - sz->endpoint = &(iface_host->endpoint[0].desc); - if (!usb_endpoint_dir_in(sz->endpoint)) { + endpoint = &iface_host->endpoint[0].desc; + if (!usb_endpoint_dir_in(endpoint)) { dev_err(&intf->dev, "%s: endpoint doesn't match input device 02%02x\n", - __func__, sz->endpoint->bEndpointAddress); + __func__, endpoint->bEndpointAddress); retval = -ENODEV; goto free_sz; } - if (!usb_endpoint_xfer_int(sz->endpoint)) { + if (!usb_endpoint_xfer_int(endpoint)) { dev_err(&intf->dev, "%s: endpoint attributes don't match xfer 02%02x\n", - __func__, sz->endpoint->bmAttributes); + __func__, endpoint->bmAttributes); retval = -ENODEV; goto free_sz; } - pipe = usb_rcvintpipe(usbdev, sz->endpoint->bEndpointAddress); + pipe = usb_rcvintpipe(usbdev, endpoint->bEndpointAddress); maxp = usb_maxpacket(usbdev, pipe, usb_pipeout(pipe)); if (maxp == 0) { @@ -380,25 +328,12 @@ static int streamzap_probe(struct usb_interface *intf, sz->dev = &intf->dev; sz->buf_in_len = maxp; - if (usbdev->descriptor.iManufacturer - && usb_string(usbdev, usbdev->descriptor.iManufacturer, - buf, sizeof(buf)) > 0) - strscpy(name, buf, sizeof(name)); - - if (usbdev->descriptor.iProduct - && usb_string(usbdev, usbdev->descriptor.iProduct, - buf, sizeof(buf)) > 0) - snprintf(name + strlen(name), sizeof(name) - strlen(name), - " %s", buf); - - sz->rdev = streamzap_init_rc_dev(sz); + sz->rdev = streamzap_init_rc_dev(sz, usbdev); if (!sz->rdev) goto rc_dev_fail; - sz->idle = true; sz->decoder_state = PulseSpace; /* FIXME: don't yet have a way to set this */ - sz->timeout_enabled = true; sz->rdev->timeout = SZ_TIMEOUT * SZ_RESOLUTION; #if 0 /* not yet supported, depends on patches from maxim */ @@ -407,12 +342,9 @@ static int streamzap_probe(struct usb_interface *intf, sz->max_timeout = SZ_TIMEOUT * SZ_RESOLUTION; #endif - sz->signal_start = ktime_get_real(); - /* Complete final initialisations */ usb_fill_int_urb(sz->urb_in, usbdev, pipe, sz->buf_in, - maxp, (usb_complete_t)streamzap_callback, - sz, sz->endpoint->bInterval); + maxp, streamzap_callback, sz, endpoint->bInterval); sz->urb_in->transfer_dma = sz->dma_in; sz->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; @@ -421,9 +353,6 @@ static int streamzap_probe(struct usb_interface *intf, if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) dev_err(sz->dev, "urb submit failed\n"); - dev_info(sz->dev, "Registered %s on usb%d:%d\n", name, - usbdev->bus->busnum, usbdev->devnum); - return 0; rc_dev_fail: @@ -456,7 +385,6 @@ static void streamzap_disconnect(struct usb_interface *interface) if (!sz) return; - sz->usbdev = NULL; rc_unregister_device(sz->rdev); usb_kill_urb(sz->urb_in); usb_free_urb(sz->urb_in); diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c index aed23ca0fa6c..94efb035d21b 100644 --- a/drivers/media/rc/winbond-cir.c +++ b/drivers/media/rc/winbond-cir.c @@ -997,7 +997,6 @@ wbcir_resume(struct pnp_dev *device) struct wbcir_data *data = pnp_get_drvdata(device); wbcir_init_hw(data); - ir_raw_event_reset(data->dev); enable_irq(data->irq); led_classdev_resume(&data->led); diff --git a/drivers/media/spi/cxd2880-spi.c b/drivers/media/spi/cxd2880-spi.c index 506f52c1af10..6f2a66bc87fb 100644 --- a/drivers/media/spi/cxd2880-spi.c +++ b/drivers/media/spi/cxd2880-spi.c @@ -628,19 +628,8 @@ fail_regulator: static int cxd2880_spi_remove(struct spi_device *spi) { - struct cxd2880_dvb_spi *dvb_spi; + struct cxd2880_dvb_spi *dvb_spi = spi_get_drvdata(spi); - if (!spi) { - pr_err("invalid arg\n"); - return -EINVAL; - } - - dvb_spi = spi_get_drvdata(spi); - - if (!dvb_spi) { - pr_err("failed\n"); - return -EINVAL; - } dvb_spi->demux.dmx.remove_frontend(&dvb_spi->demux.dmx, &dvb_spi->dmx_fe); dvb_dmxdev_release(&dvb_spi->dmxdev); diff --git a/drivers/media/test-drivers/vicodec/vicodec-core.c b/drivers/media/test-drivers/vicodec/vicodec-core.c index 33f1c893c1b6..be43f7d32df9 100644 --- a/drivers/media/test-drivers/vicodec/vicodec-core.c +++ b/drivers/media/test-drivers/vicodec/vicodec-core.c @@ -1443,7 +1443,7 @@ static void vicodec_buf_queue(struct vb2_buffer *vb) unsigned int i; for (i = 0; i < vb->num_planes; i++) - vb->planes[i].bytesused = 0; + vb2_set_plane_payload(vb, i, 0); vbuf->field = V4L2_FIELD_NONE; vbuf->sequence = diff --git a/drivers/media/test-drivers/vidtv/vidtv_psi.c b/drivers/media/test-drivers/vidtv/vidtv_psi.c index c11ac8dca73d..a5875380ef40 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_psi.c +++ b/drivers/media/test-drivers/vidtv/vidtv_psi.c @@ -94,34 +94,28 @@ static void vidtv_psi_update_version_num(struct vidtv_psi_table_header *h) static u16 vidtv_psi_get_sec_len(struct vidtv_psi_table_header *h) { u16 mask; - u16 ret; mask = GENMASK(11, 0); - ret = be16_to_cpu(h->bitfield) & mask; - return ret; + return be16_to_cpu(h->bitfield) & mask; } u16 vidtv_psi_get_pat_program_pid(struct vidtv_psi_table_pat_program *p) { u16 mask; - u16 ret; mask = GENMASK(12, 0); - ret = be16_to_cpu(p->bitfield) & mask; - return ret; + return be16_to_cpu(p->bitfield) & mask; } u16 vidtv_psi_pmt_stream_get_elem_pid(struct vidtv_psi_table_pmt_stream *s) { u16 mask; - u16 ret; mask = GENMASK(12, 0); - ret = be16_to_cpu(s->bitfield) & mask; - return ret; + return be16_to_cpu(s->bitfield) & mask; } static void vidtv_psi_set_desc_loop_len(__be16 *bitfield, u16 new_len, diff --git a/drivers/media/tuners/msi001.c b/drivers/media/tuners/msi001.c index 78e6fd600d8e..44247049a319 100644 --- a/drivers/media/tuners/msi001.c +++ b/drivers/media/tuners/msi001.c @@ -442,6 +442,13 @@ static int msi001_probe(struct spi_device *spi) V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1); dev->bandwidth = v4l2_ctrl_new_std(&dev->hdl, &msi001_ctrl_ops, V4L2_CID_RF_TUNER_BANDWIDTH, 200000, 8000000, 1, 200000); + if (dev->hdl.error) { + ret = dev->hdl.error; + dev_err(&spi->dev, "Could not initialize controls\n"); + /* control init failed, free handler */ + goto err_ctrl_handler_free; + } + v4l2_ctrl_auto_cluster(2, &dev->bandwidth_auto, 0, false); dev->lna_gain = v4l2_ctrl_new_std(&dev->hdl, &msi001_ctrl_ops, V4L2_CID_RF_TUNER_LNA_GAIN, 0, 1, 1, 1); diff --git a/drivers/media/tuners/mxl5005s.c b/drivers/media/tuners/mxl5005s.c index f6e82a8e7d37..ab4c43df9d18 100644 --- a/drivers/media/tuners/mxl5005s.c +++ b/drivers/media/tuners/mxl5005s.c @@ -3414,9 +3414,8 @@ static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum, u32 value, u16 controlGroup) { struct mxl5005s_state *state = fe->tuner_priv; - u16 i, j, k; + u16 i, j; u32 highLimit; - u32 ctrlVal; if (controlGroup == 1) /* Initial Control */ { @@ -3432,9 +3431,6 @@ static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum, (u8)(state->Init_Ctrl[i].bit[j]), (u8)((value>>j) & 0x01)); } - ctrlVal = 0; - for (k = 0; k < state->Init_Ctrl[i].size; k++) - ctrlVal += state->Init_Ctrl[i].val[k] * (1 << k); } else return -1; } @@ -3454,9 +3450,6 @@ static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum, (u8)(state->CH_Ctrl[i].bit[j]), (u8)((value>>j) & 0x01)); } - ctrlVal = 0; - for (k = 0; k < state->CH_Ctrl[i].size; k++) - ctrlVal += state->CH_Ctrl[i].val[k] * (1 << k); } else return -1; } @@ -3477,11 +3470,6 @@ static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum, (u8)(state->MXL_Ctrl[i].bit[j]), (u8)((value>>j) & 0x01)); } - ctrlVal = 0; - for (k = 0; k < state->MXL_Ctrl[i].size; k++) - ctrlVal += state-> - MXL_Ctrl[i].val[k] * - (1 << k); } else return -1; } diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index aed2f130ec74..b9a7590aeec6 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -326,6 +326,26 @@ static int r820t_xtal_capacitor[][2] = { { 0x10, XTAL_HIGH_CAP_0P }, }; +static const char *r820t_chip_enum_to_str(enum r820t_chip chip) +{ + switch (chip) { + case CHIP_R820T: + return "R820T"; + case CHIP_R620D: + return "R620D"; + case CHIP_R828D: + return "R828D"; + case CHIP_R828: + return "R828"; + case CHIP_R828S: + return "R828S"; + case CHIP_R820C: + return "R820C"; + default: + return "<unknown>"; + } +} + /* * I2C read/write code and shadow registers logic */ @@ -2355,7 +2375,9 @@ struct dvb_frontend *r820t_attach(struct dvb_frontend *fe, if (rc < 0) goto err; - tuner_info("Rafael Micro r820t successfully identified\n"); + tuner_info( + "Rafael Micro r820t successfully identified, chip type: %s\n", + r820t_chip_enum_to_str(cfg->rafael_chip)); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c index fefb2625f655..47029746b89e 100644 --- a/drivers/media/tuners/si2157.c +++ b/drivers/media/tuners/si2157.c @@ -76,21 +76,156 @@ err_mutex_unlock: return ret; } -static int si2157_init(struct dvb_frontend *fe) +static const struct si2157_tuner_info si2157_tuners[] = { + { SI2141, false, 0x60, SI2141_60_FIRMWARE, SI2141_A10_FIRMWARE }, + { SI2141, false, 0x61, SI2141_61_FIRMWARE, SI2141_A10_FIRMWARE }, + { SI2146, false, 0x11, SI2146_11_FIRMWARE, NULL }, + { SI2147, false, 0x50, SI2147_50_FIRMWARE, NULL }, + { SI2148, true, 0x32, SI2148_32_FIRMWARE, SI2158_A20_FIRMWARE }, + { SI2148, true, 0x33, SI2148_33_FIRMWARE, SI2158_A20_FIRMWARE }, + { SI2157, false, 0x50, SI2157_50_FIRMWARE, SI2157_A30_FIRMWARE }, + { SI2158, false, 0x50, SI2158_50_FIRMWARE, SI2158_A20_FIRMWARE }, + { SI2158, false, 0x51, SI2158_51_FIRMWARE, SI2158_A20_FIRMWARE }, + { SI2177, false, 0x50, SI2177_50_FIRMWARE, SI2157_A30_FIRMWARE }, +}; + +static int si2157_load_firmware(struct dvb_frontend *fe, + const char *fw_name) +{ + struct i2c_client *client = fe->tuner_priv; + const struct firmware *fw; + int ret, len, remaining; + struct si2157_cmd cmd; + + /* request the firmware, this will block and timeout */ + ret = firmware_request_nowarn(&fw, fw_name, &client->dev); + if (ret) + return ret; + + /* firmware should be n chunks of 17 bytes */ + if (fw->size % 17 != 0) { + dev_err(&client->dev, "firmware file '%s' is invalid\n", + fw_name); + ret = -EINVAL; + goto err_release_firmware; + } + + dev_info(&client->dev, "downloading firmware from file '%s'\n", + fw_name); + + for (remaining = fw->size; remaining > 0; remaining -= 17) { + len = fw->data[fw->size - remaining]; + if (len > SI2157_ARGLEN) { + dev_err(&client->dev, "Bad firmware length\n"); + ret = -EINVAL; + goto err_release_firmware; + } + memcpy(cmd.args, &fw->data[(fw->size - remaining) + 1], len); + cmd.wlen = len; + cmd.rlen = 1; + ret = si2157_cmd_execute(client, &cmd); + if (ret) { + dev_err(&client->dev, "firmware download failed %d\n", + ret); + goto err_release_firmware; + } + } + +err_release_firmware: + release_firmware(fw); + + return ret; +} + +static int si2157_find_and_load_firmware(struct dvb_frontend *fe) { struct i2c_client *client = fe->tuner_priv; struct si2157_dev *dev = i2c_get_clientdata(client); + const char *fw_alt_name = NULL; + unsigned char part_id, rom_id; + const char *fw_name = NULL; + struct si2157_cmd cmd; + bool required = true; + int ret, i; + + if (dev->dont_load_firmware) { + dev_info(&client->dev, + "device is buggy, skipping firmware download\n"); + return 0; + } + + /* query chip revision */ + memcpy(cmd.args, "\x02", 1); + cmd.wlen = 1; + cmd.rlen = 13; + ret = si2157_cmd_execute(client, &cmd); + if (ret) + return ret; + + part_id = cmd.args[2]; + rom_id = cmd.args[12]; + + for (i = 0; i < ARRAY_SIZE(si2157_tuners); i++) { + if (si2157_tuners[i].part_id != part_id) + continue; + required = si2157_tuners[i].required; + fw_alt_name = si2157_tuners[i].fw_alt_name; + + /* Both part and rom ID match */ + if (si2157_tuners[i].rom_id == rom_id) { + fw_name = si2157_tuners[i].fw_name; + break; + } + } + + if (!fw_name && !fw_alt_name) { + dev_err(&client->dev, + "unknown chip version Si21%d-%c%c%c ROM 0x%02x\n", + part_id, cmd.args[1], cmd.args[3], cmd.args[4], rom_id); + return -EINVAL; + } + + /* Update the part id based on device's report */ + dev->part_id = part_id; + + dev_info(&client->dev, + "found a 'Silicon Labs Si21%d-%c%c%c ROM 0x%02x'\n", + part_id, cmd.args[1], cmd.args[3], cmd.args[4], rom_id); + + if (fw_name) + ret = si2157_load_firmware(fe, fw_name); + else + ret = -ENOENT; + + /* Try alternate name, if any */ + if (ret == -ENOENT && fw_alt_name) + ret = si2157_load_firmware(fe, fw_alt_name); + + if (ret == -ENOENT) { + if (!required) { + dev_info(&client->dev, "Using ROM firmware.\n"); + return 0; + } + dev_err(&client->dev, "Can't continue without a firmware.\n"); + } else if (ret < 0) { + dev_err(&client->dev, "error %d when loading firmware\n", ret); + } + return ret; +} + +static int si2157_init(struct dvb_frontend *fe) +{ struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret, len, remaining; + struct i2c_client *client = fe->tuner_priv; + struct si2157_dev *dev = i2c_get_clientdata(client); + unsigned int xtal_trim; struct si2157_cmd cmd; - const struct firmware *fw; - const char *fw_name; - unsigned int chip_id, xtal_trim; + int ret; dev_dbg(&client->dev, "\n"); /* Try to get Xtal trim property, to verify tuner still running */ - memcpy(cmd.args, "\x15\x00\x04\x02", 4); + memcpy(cmd.args, "\x15\x00\x02\x04", 4); cmd.wlen = 4; cmd.rlen = 4; ret = si2157_cmd_execute(client, &cmd); @@ -103,10 +238,12 @@ static int si2157_init(struct dvb_frontend *fe) dev->if_frequency = 0; /* we no longer know current tuner state */ /* power up */ - if (dev->chiptype == SI2157_CHIPTYPE_SI2146) { + if (dev->part_id == SI2146) { + /* clock_mode = XTAL, clock_freq = 24MHz */ memcpy(cmd.args, "\xc0\x05\x01\x00\x00\x0b\x00\x00\x01", 9); cmd.wlen = 9; - } else if (dev->chiptype == SI2157_CHIPTYPE_SI2141) { + } else if (dev->part_id == SI2141) { + /* clock_mode: XTAL, xout enabled */ memcpy(cmd.args, "\xc0\x00\x0d\x0e\x00\x01\x01\x01\x01\x03", 10); cmd.wlen = 10; } else { @@ -115,11 +252,11 @@ static int si2157_init(struct dvb_frontend *fe) } cmd.rlen = 1; ret = si2157_cmd_execute(client, &cmd); - if (ret && (dev->chiptype != SI2157_CHIPTYPE_SI2141 || ret != -EAGAIN)) + if (ret && (dev->part_id != SI2141 || ret != -EAGAIN)) goto err; - /* Si2141 needs a second command before it answers the revision query */ - if (dev->chiptype == SI2157_CHIPTYPE_SI2141) { + /* Si2141 needs a wake up command */ + if (dev->part_id == SI2141) { memcpy(cmd.args, "\xc0\x08\x01\x02\x00\x00\x01", 7); cmd.wlen = 7; ret = si2157_cmd_execute(client, &cmd); @@ -127,100 +264,11 @@ static int si2157_init(struct dvb_frontend *fe) goto err; } - if (dev->dont_load_firmware) { - dev_info(&client->dev, "device is buggy, skipping firmware download\n"); - goto skip_fw_download; - } - - /* query chip revision */ - memcpy(cmd.args, "\x02", 1); - cmd.wlen = 1; - cmd.rlen = 13; - ret = si2157_cmd_execute(client, &cmd); - if (ret) + /* Try to load the firmware */ + ret = si2157_find_and_load_firmware(fe); + if (ret < 0) goto err; - chip_id = cmd.args[1] << 24 | cmd.args[2] << 16 | cmd.args[3] << 8 | - cmd.args[4] << 0; - - #define SI2177_A30 ('A' << 24 | 77 << 16 | '3' << 8 | '0' << 0) - #define SI2158_A20 ('A' << 24 | 58 << 16 | '2' << 8 | '0' << 0) - #define SI2148_A20 ('A' << 24 | 48 << 16 | '2' << 8 | '0' << 0) - #define SI2157_A30 ('A' << 24 | 57 << 16 | '3' << 8 | '0' << 0) - #define SI2147_A30 ('A' << 24 | 47 << 16 | '3' << 8 | '0' << 0) - #define SI2146_A10 ('A' << 24 | 46 << 16 | '1' << 8 | '0' << 0) - #define SI2141_A10 ('A' << 24 | 41 << 16 | '1' << 8 | '0' << 0) - - switch (chip_id) { - case SI2158_A20: - case SI2148_A20: - fw_name = SI2158_A20_FIRMWARE; - break; - case SI2141_A10: - fw_name = SI2141_A10_FIRMWARE; - break; - case SI2177_A30: - fw_name = SI2157_A30_FIRMWARE; - break; - case SI2157_A30: - case SI2147_A30: - case SI2146_A10: - fw_name = NULL; - break; - default: - dev_err(&client->dev, "unknown chip version Si21%d-%c%c%c\n", - cmd.args[2], cmd.args[1], - cmd.args[3], cmd.args[4]); - ret = -EINVAL; - goto err; - } - - dev_info(&client->dev, "found a 'Silicon Labs Si21%d-%c%c%c'\n", - cmd.args[2], cmd.args[1], cmd.args[3], cmd.args[4]); - - if (fw_name == NULL) - goto skip_fw_download; - - /* request the firmware, this will block and timeout */ - ret = request_firmware(&fw, fw_name, &client->dev); - if (ret) { - dev_err(&client->dev, "firmware file '%s' not found\n", - fw_name); - goto err; - } - - /* firmware should be n chunks of 17 bytes */ - if (fw->size % 17 != 0) { - dev_err(&client->dev, "firmware file '%s' is invalid\n", - fw_name); - ret = -EINVAL; - goto err_release_firmware; - } - - dev_info(&client->dev, "downloading firmware from file '%s'\n", - fw_name); - - for (remaining = fw->size; remaining > 0; remaining -= 17) { - len = fw->data[fw->size - remaining]; - if (len > SI2157_ARGLEN) { - dev_err(&client->dev, "Bad firmware length\n"); - ret = -EINVAL; - goto err_release_firmware; - } - memcpy(cmd.args, &fw->data[(fw->size - remaining) + 1], len); - cmd.wlen = len; - cmd.rlen = 1; - ret = si2157_cmd_execute(client, &cmd); - if (ret) { - dev_err(&client->dev, "firmware download failed %d\n", - ret); - goto err_release_firmware; - } - } - - release_firmware(fw); - -skip_fw_download: /* reboot the tuner with new firmware? */ memcpy(cmd.args, "\x01\x01", 2); cmd.wlen = 2; @@ -270,8 +318,7 @@ warm: dev->active = true; return 0; -err_release_firmware: - release_firmware(fw); + err: dev_dbg(&client->dev, "failed=%d\n", ret); return ret; @@ -399,7 +446,8 @@ static int si2157_set_params(struct dvb_frontend *fe) struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; struct si2157_cmd cmd; - u8 bandwidth, delivery_system; + u8 bw, delivery_system; + u32 bandwidth; u32 if_frequency = 5000000; dev_dbg(&client->dev, @@ -411,14 +459,22 @@ static int si2157_set_params(struct dvb_frontend *fe) goto err; } - if (c->bandwidth_hz <= 6000000) - bandwidth = 0x06; - else if (c->bandwidth_hz <= 7000000) - bandwidth = 0x07; - else if (c->bandwidth_hz <= 8000000) - bandwidth = 0x08; - else - bandwidth = 0x0f; + if (SUPPORTS_1700KHz(dev) && c->bandwidth_hz <= 1700000) { + bandwidth = 1700000; + bw = 9; + } else if (c->bandwidth_hz <= 6000000) { + bandwidth = 6000000; + bw = 6; + } else if (SUPPORTS_1700KHz(dev) && c->bandwidth_hz <= 6100000) { + bandwidth = 6100000; + bw = 10; + } else if (c->bandwidth_hz <= 7000000) { + bandwidth = 7000000; + bw = 7; + } else { + bandwidth = 8000000; + bw = 8; + } switch (c->delivery_system) { case SYS_ATSC: @@ -434,15 +490,22 @@ static int si2157_set_params(struct dvb_frontend *fe) delivery_system = 0x20; break; case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: delivery_system = 0x30; break; + case SYS_ISDBT: + delivery_system = 0x40; + break; + case SYS_DTMB: + delivery_system = 0x60; + break; default: ret = -EINVAL; goto err; } memcpy(cmd.args, "\x14\x00\x03\x07\x00\x00", 6); - cmd.args[4] = delivery_system | bandwidth; + cmd.args[4] = delivery_system | bw; if (dev->inversion) cmd.args[5] = 0x01; cmd.wlen = 6; @@ -451,7 +514,8 @@ static int si2157_set_params(struct dvb_frontend *fe) if (ret) goto err; - if (dev->chiptype == SI2157_CHIPTYPE_SI2146) + /* On SI2146, set DTV AGC source to DLIF_AGC_3DB */ + if (dev->part_id == SI2146) memcpy(cmd.args, "\x14\x00\x02\x07\x00\x01", 6); else memcpy(cmd.args, "\x14\x00\x02\x07\x00\x00", 6); @@ -518,9 +582,9 @@ static int si2157_set_analog_params(struct dvb_frontend *fe, u8 color = 0; /* 0=NTSC/PAL, 0x10=SECAM */ u8 invert_analog = 1; /* analog tuner spectrum; 0=normal, 1=inverted */ - if (dev->chiptype != SI2157_CHIPTYPE_SI2157) { - dev_info(&client->dev, "Analog tuning not supported for chiptype=%u\n", - dev->chiptype); + if (!SUPPORTS_ATV_IF(dev)) { + dev_info(&client->dev, "Analog tuning not supported yet for Si21%d\n", + dev->part_id); ret = -EINVAL; goto err; } @@ -832,7 +896,7 @@ static int si2157_probe(struct i2c_client *client, dev->inversion = cfg->inversion; dev->dont_load_firmware = cfg->dont_load_firmware; dev->if_port = cfg->if_port; - dev->chiptype = (u8)id->driver_data; + dev->part_id = (u8)id->driver_data; dev->if_frequency = 5000000; /* default value of property 0x0706 */ mutex_init(&dev->i2c_mutex); INIT_DELAYED_WORK(&dev->stat_work, si2157_stat_work); @@ -875,10 +939,8 @@ static int si2157_probe(struct i2c_client *client, } #endif - dev_info(&client->dev, "Silicon Labs %s successfully attached\n", - dev->chiptype == SI2157_CHIPTYPE_SI2141 ? "Si2141" : - dev->chiptype == SI2157_CHIPTYPE_SI2146 ? - "Si2146" : "Si2147/2148/2157/2158"); + dev_info(&client->dev, "Silicon Labs Si21%d successfully attached\n", + dev->part_id); return 0; @@ -911,11 +973,16 @@ static int si2157_remove(struct i2c_client *client) return 0; } +/* + * The part_id used here will only be used on buggy devices that don't + * accept firmware uploads. Non-buggy devices should just use "si2157" for + * all SiLabs TER tuners, as the driver should auto-detect it. + */ static const struct i2c_device_id si2157_id_table[] = { - {"si2157", SI2157_CHIPTYPE_SI2157}, - {"si2146", SI2157_CHIPTYPE_SI2146}, - {"si2141", SI2157_CHIPTYPE_SI2141}, - {"si2177", SI2157_CHIPTYPE_SI2177}, + {"si2157", SI2157}, + {"si2146", SI2146}, + {"si2141", SI2141}, + {"si2177", SI2177}, {} }; MODULE_DEVICE_TABLE(i2c, si2157_id_table); @@ -938,3 +1005,13 @@ MODULE_LICENSE("GPL"); MODULE_FIRMWARE(SI2158_A20_FIRMWARE); MODULE_FIRMWARE(SI2141_A10_FIRMWARE); MODULE_FIRMWARE(SI2157_A30_FIRMWARE); +MODULE_FIRMWARE(SI2141_60_FIRMWARE); +MODULE_FIRMWARE(SI2141_61_FIRMWARE); +MODULE_FIRMWARE(SI2146_11_FIRMWARE); +MODULE_FIRMWARE(SI2147_50_FIRMWARE); +MODULE_FIRMWARE(SI2148_32_FIRMWARE); +MODULE_FIRMWARE(SI2148_33_FIRMWARE); +MODULE_FIRMWARE(SI2157_50_FIRMWARE); +MODULE_FIRMWARE(SI2158_50_FIRMWARE); +MODULE_FIRMWARE(SI2158_51_FIRMWARE); +MODULE_FIRMWARE(SI2177_50_FIRMWARE); diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h index ef4796098931..8579e80f7af7 100644 --- a/drivers/media/tuners/si2157_priv.h +++ b/drivers/media/tuners/si2157_priv.h @@ -26,7 +26,7 @@ struct si2157_dev { unsigned int active:1; unsigned int inversion:1; unsigned int dont_load_firmware:1; - u8 chiptype; + u8 part_id; u8 if_port; u32 if_frequency; u32 bandwidth; @@ -41,10 +41,22 @@ struct si2157_dev { }; -#define SI2157_CHIPTYPE_SI2157 0 -#define SI2157_CHIPTYPE_SI2146 1 -#define SI2157_CHIPTYPE_SI2141 2 -#define SI2157_CHIPTYPE_SI2177 3 +enum si2157_part_id { + SI2141 = 41, + SI2146 = 46, + SI2147 = 47, + SI2148 = 48, + SI2157 = 57, + SI2158 = 58, + SI2177 = 77, +}; + +struct si2157_tuner_info { + enum si2157_part_id part_id; + unsigned char rom_id; + bool required; + const char *fw_name, *fw_alt_name; +}; /* firmware command struct */ #define SI2157_ARGLEN 30 @@ -54,7 +66,29 @@ struct si2157_cmd { unsigned rlen; }; +#define SUPPORTS_1700KHz(dev) (((dev)->part_id == SI2141) || \ + ((dev)->part_id == SI2147) || \ + ((dev)->part_id == SI2157) || \ + ((dev)->part_id == SI2177)) + +#define SUPPORTS_ATV_IF(dev) (((dev)->part_id == SI2157) || \ + ((dev)->part_id == SI2158)) + +/* Old firmware namespace */ #define SI2158_A20_FIRMWARE "dvb-tuner-si2158-a20-01.fw" #define SI2141_A10_FIRMWARE "dvb-tuner-si2141-a10-01.fw" #define SI2157_A30_FIRMWARE "dvb-tuner-si2157-a30-01.fw" + +/* New firmware namespace */ +#define SI2141_60_FIRMWARE "dvb_driver_si2141_rom60.fw" +#define SI2141_61_FIRMWARE "dvb_driver_si2141_rom61.fw" +#define SI2146_11_FIRMWARE "dvb_driver_si2146_rom11.fw" +#define SI2147_50_FIRMWARE "dvb_driver_si2147_rom50.fw" +#define SI2148_32_FIRMWARE "dvb_driver_si2148_rom32.fw" +#define SI2148_33_FIRMWARE "dvb_driver_si2148_rom33.fw" +#define SI2157_50_FIRMWARE "dvb_driver_si2157_rom50.fw" +#define SI2158_50_FIRMWARE "dvb_driver_si2178_rom50.fw" +#define SI2158_51_FIRMWARE "dvb_driver_si2158_rom51.fw" +#define SI2177_50_FIRMWARE "dvb_driver_si2177_rom50.fw" + #endif diff --git a/drivers/media/tuners/tua9001.c b/drivers/media/tuners/tua9001.c index 5e3625e75620..af7d5ea1f77e 100644 --- a/drivers/media/tuners/tua9001.c +++ b/drivers/media/tuners/tua9001.c @@ -240,14 +240,10 @@ static int tua9001_remove(struct i2c_client *client) DVB_FRONTEND_COMPONENT_TUNER, TUA9001_CMD_CEN, 0); if (ret) - goto err_kfree; + dev_err(&client->dev, "Tuner disable failed (%pe)\n", ERR_PTR(ret)); } kfree(dev); return 0; -err_kfree: - kfree(dev); - dev_dbg(&client->dev, "failed=%d\n", ret); - return ret; } static const struct i2c_device_id tua9001_id_table[] = { diff --git a/drivers/media/usb/au0828/au0828-i2c.c b/drivers/media/usb/au0828/au0828-i2c.c index 708f01ab47fa..749f90d73b5b 100644 --- a/drivers/media/usb/au0828/au0828-i2c.c +++ b/drivers/media/usb/au0828/au0828-i2c.c @@ -23,13 +23,6 @@ MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); #define I2C_WAIT_DELAY 25 #define I2C_WAIT_RETRY 1000 -static inline int i2c_slave_did_write_ack(struct i2c_adapter *i2c_adap) -{ - struct au0828_dev *dev = i2c_adap->algo_data; - return au0828_read(dev, AU0828_I2C_STATUS_201) & - AU0828_I2C_STATUS_NO_WRITE_ACK ? 0 : 1; -} - static inline int i2c_slave_did_read_ack(struct i2c_adapter *i2c_adap) { struct au0828_dev *dev = i2c_adap->algo_data; diff --git a/drivers/media/usb/b2c2/flexcop-usb.c b/drivers/media/usb/b2c2/flexcop-usb.c index 5d38171b7638..7835bb0f32fc 100644 --- a/drivers/media/usb/b2c2/flexcop-usb.c +++ b/drivers/media/usb/b2c2/flexcop-usb.c @@ -87,7 +87,7 @@ static int flexcop_usb_readwrite_dw(struct flexcop_device *fc, u16 wRegOffsPCI, 0, fc_usb->data, sizeof(u32), - B2C2_WAIT_FOR_OPERATION_RDW * HZ); + B2C2_WAIT_FOR_OPERATION_RDW); if (ret != sizeof(u32)) { err("error while %s dword from %d (%d).", read ? "reading" : @@ -155,7 +155,7 @@ static int flexcop_usb_v8_memory_req(struct flexcop_usb *fc_usb, wIndex, fc_usb->data, buflen, - nWaitTime * HZ); + nWaitTime); if (ret != buflen) ret = -EIO; @@ -171,7 +171,7 @@ static int flexcop_usb_v8_memory_req(struct flexcop_usb *fc_usb, return ret; } -#define bytes_left_to_read_on_page(paddr,buflen) \ +#define bytes_left_to_read_on_page(paddr, buflen) \ ((V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK)) > buflen \ ? buflen : (V8_MEMORY_PAGE_SIZE - (paddr & V8_MEMORY_PAGE_MASK))) @@ -179,11 +179,11 @@ static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb, flexcop_usb_request_t req, flexcop_usb_mem_page_t page_start, u32 addr, int extended, u8 *buf, u32 len) { - int i,ret = 0; + int i, ret = 0; u16 wMax; u32 pagechunk = 0; - switch(req) { + switch (req) { case B2C2_USB_READ_V8_MEM: wMax = USB_MEM_READ_MAX; break; @@ -248,13 +248,13 @@ static int flexcop_usb_i2c_req(struct flexcop_i2c_adapter *i2c, /* DKT 020208 - add this to support special case of DiSEqC */ case USB_FUNC_I2C_CHECKWRITE: pipe = B2C2_USB_CTRL_PIPE_OUT; - nWaitTime = 2; + nWaitTime = 2000; request_type |= USB_DIR_OUT; break; case USB_FUNC_I2C_READ: case USB_FUNC_I2C_REPEATREAD: pipe = B2C2_USB_CTRL_PIPE_IN; - nWaitTime = 2; + nWaitTime = 2000; request_type |= USB_DIR_IN; break; default: @@ -281,7 +281,7 @@ static int flexcop_usb_i2c_req(struct flexcop_i2c_adapter *i2c, wIndex, fc_usb->data, buflen, - nWaitTime * HZ); + nWaitTime); if (ret != buflen) ret = -EIO; @@ -341,8 +341,8 @@ static void flexcop_usb_process_frame(struct flexcop_usb *fc_usb, b = fc_usb->tmp_buffer; l = fc_usb->tmp_buffer_length; } else { - b=buffer; - l=buffer_length; + b = buffer; + l = buffer_length; } while (l >= 190) { @@ -368,7 +368,7 @@ static void flexcop_usb_process_frame(struct flexcop_usb *fc_usb, } } - if (l>0) + if (l > 0) memcpy(fc_usb->tmp_buffer, b, l); fc_usb->tmp_buffer_length = l; } @@ -399,7 +399,7 @@ static void flexcop_usb_urb_complete(struct urb *urb) urb->iso_frame_desc[i].status = 0; urb->iso_frame_desc[i].actual_length = 0; } - usb_submit_urb(urb,GFP_ATOMIC); + usb_submit_urb(urb, GFP_ATOMIC); } static int flexcop_usb_stream_control(struct flexcop_device *fc, int onoff) @@ -413,7 +413,7 @@ static void flexcop_usb_transfer_exit(struct flexcop_usb *fc_usb) int i; for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) if (fc_usb->iso_urb[i] != NULL) { - deb_ts("unlinking/killing urb no. %d\n",i); + deb_ts("unlinking/killing urb no. %d\n", i); usb_kill_urb(fc_usb->iso_urb[i]); usb_free_urb(fc_usb->iso_urb[i]); } @@ -483,7 +483,7 @@ static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb) err("submitting urb %d failed with %d.", i, ret); goto urb_error; } - deb_ts("submitted urb no. %d.\n",i); + deb_ts("submitted urb no. %d.\n", i); } /* SRAM */ diff --git a/drivers/media/usb/b2c2/flexcop-usb.h b/drivers/media/usb/b2c2/flexcop-usb.h index 2f230bf72252..c7cca1a5ee59 100644 --- a/drivers/media/usb/b2c2/flexcop-usb.h +++ b/drivers/media/usb/b2c2/flexcop-usb.h @@ -91,13 +91,13 @@ typedef enum { UTILITY_SRAM_TESTVERIFY = 0x16, } flexcop_usb_utility_function_t; -#define B2C2_WAIT_FOR_OPERATION_RW (1*HZ) -#define B2C2_WAIT_FOR_OPERATION_RDW (3*HZ) -#define B2C2_WAIT_FOR_OPERATION_WDW (1*HZ) +#define B2C2_WAIT_FOR_OPERATION_RW 1000 +#define B2C2_WAIT_FOR_OPERATION_RDW 3000 +#define B2C2_WAIT_FOR_OPERATION_WDW 1000 -#define B2C2_WAIT_FOR_OPERATION_V8READ (3*HZ) -#define B2C2_WAIT_FOR_OPERATION_V8WRITE (3*HZ) -#define B2C2_WAIT_FOR_OPERATION_V8FLASH (3*HZ) +#define B2C2_WAIT_FOR_OPERATION_V8READ 3000 +#define B2C2_WAIT_FOR_OPERATION_V8WRITE 3000 +#define B2C2_WAIT_FOR_OPERATION_V8FLASH 3000 typedef enum { V8_MEMORY_PAGE_DVB_CI = 0x20, diff --git a/drivers/media/usb/cpia2/cpia2_usb.c b/drivers/media/usb/cpia2/cpia2_usb.c index 76aac06f9fb8..cba03b286473 100644 --- a/drivers/media/usb/cpia2/cpia2_usb.c +++ b/drivers/media/usb/cpia2/cpia2_usb.c @@ -550,7 +550,7 @@ static int write_packet(struct usb_device *udev, 0, /* index */ buf, /* buffer */ size, - HZ); + 1000); kfree(buf); return ret; @@ -582,7 +582,7 @@ static int read_packet(struct usb_device *udev, 0, /* index */ buf, /* buffer */ size, - HZ); + 1000); if (ret >= 0) memcpy(registers, buf, size); diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c index fe4d886442a4..8a34e6c0d6a6 100644 --- a/drivers/media/usb/dvb-usb-v2/lmedm04.c +++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c @@ -423,6 +423,9 @@ static int lme2510_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) mutex_unlock(&d->i2c_mutex); + if (ret) + return -EREMOTEIO; + return 0; } diff --git a/drivers/media/usb/dvb-usb/dib0700_core.c b/drivers/media/usb/dvb-usb/dib0700_core.c index 70219b3e8566..1caabb51ea47 100644 --- a/drivers/media/usb/dvb-usb/dib0700_core.c +++ b/drivers/media/usb/dvb-usb/dib0700_core.c @@ -583,7 +583,7 @@ out: int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) { struct dib0700_state *st = adap->dev->priv; - int ret; + int ret, adapt_nr; if ((onoff != 0) && (st->fw_version >= 0x10201)) { /* for firmware later than 1.20.1, @@ -610,26 +610,24 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) st->buf[3] = 0x00; - deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id); - - st->channel_state &= ~0x3; if ((adap->fe_adap[0].stream.props.endpoint != 2) - && (adap->fe_adap[0].stream.props.endpoint != 3)) { - deb_info("the endpoint number (%i) is not correct, use the adapter id instead", adap->fe_adap[0].stream.props.endpoint); - if (onoff) - st->channel_state |= 1 << (adap->id); - else - st->channel_state |= 1 << ~(adap->id); + && (adap->fe_adap[0].stream.props.endpoint != 3)) { + deb_info("the endpoint number (%i) is not correct, use the adapter id instead\n", + adap->fe_adap[0].stream.props.endpoint); + adapt_nr = adap->id; } else { - if (onoff) - st->channel_state |= 1 << (adap->fe_adap[0].stream.props.endpoint-2); - else - st->channel_state |= 1 << (3-adap->fe_adap[0].stream.props.endpoint); + adapt_nr = adap->fe_adap[0].stream.props.endpoint - 2; } + if (onoff) + st->channel_state |= 1 << adapt_nr; + else + st->channel_state &= ~(1 << adapt_nr); + st->buf[2] |= st->channel_state; - deb_info("data for streaming: %x %x\n", st->buf[1], st->buf[2]); + deb_info("adapter %d, streaming %s: %*ph\n", + adapt_nr, onoff ? "ON" : "OFF", 3, st->buf); ret = dib0700_ctrl_wr(adap->dev, st->buf, 4); mutex_unlock(&adap->dev->usb_mutex); diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c index f0e686b05dc6..ca75ebdc10b3 100644 --- a/drivers/media/usb/dvb-usb/dw2102.c +++ b/drivers/media/usb/dvb-usb/dw2102.c @@ -2150,46 +2150,153 @@ static struct dvb_usb_device_properties s6x0_properties = { } }; -static const struct dvb_usb_device_description d1100 = { - "Prof 1100 USB ", - {&dw2102_table[PROF_1100], NULL}, - {NULL}, -}; +static struct dvb_usb_device_properties p1100_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = DEVICE_SPECIFIC, + .size_of_priv = sizeof(struct dw2102_state), + .firmware = P1100_FIRMWARE, + .no_reconnect = 1, -static const struct dvb_usb_device_description d660 = { - "TeVii S660 USB", - {&dw2102_table[TEVII_S660], NULL}, - {NULL}, -}; + .i2c_algo = &s6x0_i2c_algo, + .rc.core = { + .rc_interval = 150, + .rc_codes = RC_MAP_TBS_NEC, + .module_name = "dw2102", + .allowed_protos = RC_PROTO_BIT_NEC, + .rc_query = prof_rc_query, + }, -static const struct dvb_usb_device_description d480_1 = { - "TeVii S480.1 USB", - {&dw2102_table[TEVII_S480_1], NULL}, - {NULL}, + .generic_bulk_ctrl_endpoint = 0x81, + .num_adapters = 1, + .download_firmware = dw2102_load_firmware, + .read_mac_address = s6x0_read_mac_address, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .frontend_attach = stv0288_frontend_attach, + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + } }, + } + }, + .num_device_descs = 1, + .devices = { + {"Prof 1100 USB ", + {&dw2102_table[PROF_1100], NULL}, + {NULL}, + }, + } }; -static const struct dvb_usb_device_description d480_2 = { - "TeVii S480.2 USB", - {&dw2102_table[TEVII_S480_2], NULL}, - {NULL}, -}; +static struct dvb_usb_device_properties s660_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = DEVICE_SPECIFIC, + .size_of_priv = sizeof(struct dw2102_state), + .firmware = S660_FIRMWARE, + .no_reconnect = 1, -static const struct dvb_usb_device_description d7500 = { - "Prof 7500 USB DVB-S2", - {&dw2102_table[PROF_7500], NULL}, - {NULL}, -}; + .i2c_algo = &s6x0_i2c_algo, + .rc.core = { + .rc_interval = 150, + .rc_codes = RC_MAP_TEVII_NEC, + .module_name = "dw2102", + .allowed_protos = RC_PROTO_BIT_NEC, + .rc_query = dw2102_rc_query, + }, -static const struct dvb_usb_device_description d421 = { - "TeVii S421 PCI", - {&dw2102_table[TEVII_S421], NULL}, - {NULL}, + .generic_bulk_ctrl_endpoint = 0x81, + .num_adapters = 1, + .download_firmware = dw2102_load_firmware, + .read_mac_address = s6x0_read_mac_address, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .frontend_attach = ds3000_frontend_attach, + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + } }, + } + }, + .num_device_descs = 3, + .devices = { + {"TeVii S660 USB", + {&dw2102_table[TEVII_S660], NULL}, + {NULL}, + }, + {"TeVii S480.1 USB", + {&dw2102_table[TEVII_S480_1], NULL}, + {NULL}, + }, + {"TeVii S480.2 USB", + {&dw2102_table[TEVII_S480_2], NULL}, + {NULL}, + }, + } }; -static const struct dvb_usb_device_description d632 = { - "TeVii S632 USB", - {&dw2102_table[TEVII_S632], NULL}, - {NULL}, +static struct dvb_usb_device_properties p7500_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = DEVICE_SPECIFIC, + .size_of_priv = sizeof(struct dw2102_state), + .firmware = P7500_FIRMWARE, + .no_reconnect = 1, + + .i2c_algo = &s6x0_i2c_algo, + .rc.core = { + .rc_interval = 150, + .rc_codes = RC_MAP_TBS_NEC, + .module_name = "dw2102", + .allowed_protos = RC_PROTO_BIT_NEC, + .rc_query = prof_rc_query, + }, + + .generic_bulk_ctrl_endpoint = 0x81, + .num_adapters = 1, + .download_firmware = dw2102_load_firmware, + .read_mac_address = s6x0_read_mac_address, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .frontend_attach = prof_7500_frontend_attach, + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + } }, + } + }, + .num_device_descs = 1, + .devices = { + {"Prof 7500 USB DVB-S2", + {&dw2102_table[PROF_7500], NULL}, + {NULL}, + }, + } }; static struct dvb_usb_device_properties su3000_properties = { @@ -2273,6 +2380,59 @@ static struct dvb_usb_device_properties su3000_properties = { } }; +static struct dvb_usb_device_properties s421_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = DEVICE_SPECIFIC, + .size_of_priv = sizeof(struct dw2102_state), + .power_ctrl = su3000_power_ctrl, + .num_adapters = 1, + .identify_state = su3000_identify_state, + .i2c_algo = &su3000_i2c_algo, + + .rc.core = { + .rc_interval = 150, + .rc_codes = RC_MAP_SU3000, + .module_name = "dw2102", + .allowed_protos = RC_PROTO_BIT_RC5, + .rc_query = su3000_rc_query, + }, + + .read_mac_address = su3000_read_mac_address, + + .generic_bulk_ctrl_endpoint = 0x01, + + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .streaming_ctrl = su3000_streaming_ctrl, + .frontend_attach = m88rs2000_frontend_attach, + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 4096, + } + } + } + } }, + } + }, + .num_device_descs = 2, + .devices = { + { "TeVii S421 PCI", + { &dw2102_table[TEVII_S421], NULL }, + { NULL }, + }, + { "TeVii S632 USB", + { &dw2102_table[TEVII_S632], NULL }, + { NULL }, + }, + } +}; + static struct dvb_usb_device_properties t220_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = DEVICE_SPECIFIC, @@ -2390,101 +2550,33 @@ static struct dvb_usb_device_properties tt_s2_4600_properties = { static int dw2102_probe(struct usb_interface *intf, const struct usb_device_id *id) { - int retval = -ENOMEM; - struct dvb_usb_device_properties *p1100; - struct dvb_usb_device_properties *s660; - struct dvb_usb_device_properties *p7500; - struct dvb_usb_device_properties *s421; - - p1100 = kmemdup(&s6x0_properties, - sizeof(struct dvb_usb_device_properties), GFP_KERNEL); - if (!p1100) - goto err0; - - /* copy default structure */ - /* fill only different fields */ - p1100->firmware = P1100_FIRMWARE; - p1100->devices[0] = d1100; - p1100->rc.core.rc_query = prof_rc_query; - p1100->rc.core.rc_codes = RC_MAP_TBS_NEC; - p1100->adapter->fe[0].frontend_attach = stv0288_frontend_attach; - - s660 = kmemdup(&s6x0_properties, - sizeof(struct dvb_usb_device_properties), GFP_KERNEL); - if (!s660) - goto err1; - - s660->firmware = S660_FIRMWARE; - s660->num_device_descs = 3; - s660->devices[0] = d660; - s660->devices[1] = d480_1; - s660->devices[2] = d480_2; - s660->adapter->fe[0].frontend_attach = ds3000_frontend_attach; - - p7500 = kmemdup(&s6x0_properties, - sizeof(struct dvb_usb_device_properties), GFP_KERNEL); - if (!p7500) - goto err2; - - p7500->firmware = P7500_FIRMWARE; - p7500->devices[0] = d7500; - p7500->rc.core.rc_query = prof_rc_query; - p7500->rc.core.rc_codes = RC_MAP_TBS_NEC; - p7500->adapter->fe[0].frontend_attach = prof_7500_frontend_attach; - - - s421 = kmemdup(&su3000_properties, - sizeof(struct dvb_usb_device_properties), GFP_KERNEL); - if (!s421) - goto err3; - - s421->num_device_descs = 2; - s421->devices[0] = d421; - s421->devices[1] = d632; - s421->adapter->fe[0].frontend_attach = m88rs2000_frontend_attach; - - if (0 == dvb_usb_device_init(intf, &dw2102_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &dw2104_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &dw3101_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &s6x0_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, p1100, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, s660, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, p7500, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, s421, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &su3000_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &t220_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &tt_s2_4600_properties, - THIS_MODULE, NULL, adapter_nr)) { - - /* clean up copied properties */ - kfree(s421); - kfree(p7500); - kfree(s660); - kfree(p1100); + if (!(dvb_usb_device_init(intf, &dw2102_properties, + THIS_MODULE, NULL, adapter_nr) && + dvb_usb_device_init(intf, &dw2104_properties, + THIS_MODULE, NULL, adapter_nr) && + dvb_usb_device_init(intf, &dw3101_properties, + THIS_MODULE, NULL, adapter_nr) && + dvb_usb_device_init(intf, &s6x0_properties, + THIS_MODULE, NULL, adapter_nr) && + dvb_usb_device_init(intf, &p1100_properties, + THIS_MODULE, NULL, adapter_nr) && + dvb_usb_device_init(intf, &s660_properties, + THIS_MODULE, NULL, adapter_nr) && + dvb_usb_device_init(intf, &p7500_properties, + THIS_MODULE, NULL, adapter_nr) && + dvb_usb_device_init(intf, &s421_properties, + THIS_MODULE, NULL, adapter_nr) && + dvb_usb_device_init(intf, &su3000_properties, + THIS_MODULE, NULL, adapter_nr) && + dvb_usb_device_init(intf, &t220_properties, + THIS_MODULE, NULL, adapter_nr) && + dvb_usb_device_init(intf, &tt_s2_4600_properties, + THIS_MODULE, NULL, adapter_nr))) { return 0; } - retval = -ENODEV; - kfree(s421); -err3: - kfree(p7500); -err2: - kfree(s660); -err1: - kfree(p1100); -err0: - return retval; + return -ENODEV; } static void dw2102_disconnect(struct usb_interface *intf) diff --git a/drivers/media/usb/dvb-usb/m920x.c b/drivers/media/usb/dvb-usb/m920x.c index 4bb5b82599a7..691e05833db1 100644 --- a/drivers/media/usb/dvb-usb/m920x.c +++ b/drivers/media/usb/dvb-usb/m920x.c @@ -274,6 +274,13 @@ static int m920x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int nu /* Should check for ack here, if we knew how. */ } if (msg[i].flags & I2C_M_RD) { + char *read = kmalloc(1, GFP_KERNEL); + if (!read) { + ret = -ENOMEM; + kfree(read); + goto unlock; + } + for (j = 0; j < msg[i].len; j++) { /* Last byte of transaction? * Send STOP, otherwise send ACK. */ @@ -281,9 +288,12 @@ static int m920x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int nu if ((ret = m920x_read(d->udev, M9206_I2C, 0x0, 0x20 | stop, - &msg[i].buf[j], 1)) != 0) + read, 1)) != 0) goto unlock; + msg[i].buf[j] = read[0]; } + + kfree(read); } else { for (j = 0; j < msg[i].len; j++) { /* Last byte of transaction? Then send STOP. */ diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index b207f34af5c6..b451ce3cb169 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -3630,8 +3630,10 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, if (dev->is_audio_only) { retval = em28xx_audio_setup(dev); - if (retval) - return -ENODEV; + if (retval) { + retval = -ENODEV; + goto err_deinit_media; + } em28xx_init_extension(dev); return 0; @@ -3650,7 +3652,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, dev_err(&dev->intf->dev, "%s: em28xx_i2c_register bus 0 - error [%d]!\n", __func__, retval); - return retval; + goto err_deinit_media; } /* register i2c bus 1 */ @@ -3666,9 +3668,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, "%s: em28xx_i2c_register bus 1 - error [%d]!\n", __func__, retval); - em28xx_i2c_unregister(dev, 0); - - return retval; + goto err_unreg_i2c; } } @@ -3676,6 +3676,12 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, em28xx_card_setup(dev); return 0; + +err_unreg_i2c: + em28xx_i2c_unregister(dev, 0); +err_deinit_media: + em28xx_unregister_media_device(dev); + return retval; } static int em28xx_duplicate_dev(struct em28xx *dev) diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index acc0bf7dbe2b..c837cc528a33 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -89,7 +89,7 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, mutex_lock(&dev->ctrl_urb_lock); ret = usb_control_msg(udev, pipe, req, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x0000, reg, dev->urb_buf, len, HZ); + 0x0000, reg, dev->urb_buf, len, 1000); if (ret < 0) { em28xx_regdbg("(pipe 0x%08x): IN: %02x %02x %02x %02x %02x %02x %02x %02x failed with error %i\n", pipe, @@ -158,7 +158,7 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, memcpy(dev->urb_buf, buf, len); ret = usb_control_msg(udev, pipe, req, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x0000, reg, dev->urb_buf, len, HZ); + 0x0000, reg, dev->urb_buf, len, 1000); mutex_unlock(&dev->ctrl_urb_lock); if (ret < 0) { diff --git a/drivers/media/usb/go7007/go7007-driver.c b/drivers/media/usb/go7007/go7007-driver.c index 6650eab913d8..0c24e2984304 100644 --- a/drivers/media/usb/go7007/go7007-driver.c +++ b/drivers/media/usb/go7007/go7007-driver.c @@ -516,7 +516,7 @@ void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length) if (vb && vb->vb.vb2_buf.planes[0].bytesused >= GO7007_BUF_SIZE - 3) { v4l2_info(&go->v4l2_dev, "dropping oversized frame\n"); - vb->vb.vb2_buf.planes[0].bytesused = 0; + vb2_set_plane_payload(&vb->vb.vb2_buf, 0, 0); vb->frame_offset = 0; vb->modet_active = 0; vb = go->active_buf = NULL; diff --git a/drivers/media/usb/gspca/m5602/m5602_s5k83a.c b/drivers/media/usb/gspca/m5602/m5602_s5k83a.c index bc4008d5d116..8ef010a87445 100644 --- a/drivers/media/usb/gspca/m5602/m5602_s5k83a.c +++ b/drivers/media/usb/gspca/m5602/m5602_s5k83a.c @@ -339,14 +339,13 @@ int s5k83a_start(struct sd *sd) /* Create another thread, polling the GPIO ports of the camera to check if it got rotated. This is how the windows driver does it so we have to assume that there is no better way of accomplishing this */ - sd->rotation_thread = kthread_create(rotation_thread_function, - sd, "rotation thread"); + sd->rotation_thread = kthread_run(rotation_thread_function, + sd, "rotation thread"); if (IS_ERR(sd->rotation_thread)) { err = PTR_ERR(sd->rotation_thread); sd->rotation_thread = NULL; return err; } - wake_up_process(sd->rotation_thread); /* Preinit the sensor */ for (i = 0; i < ARRAY_SIZE(start_s5k83a) && !err; i++) { @@ -408,25 +407,21 @@ static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val) static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val) { - int err; u8 data[1]; struct sd *sd = (struct sd *) gspca_dev; data[0] = val; - err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 1); - return err; + return m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 1); } static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val) { - int err; u8 data[2]; struct sd *sd = (struct sd *) gspca_dev; data[0] = 0; data[1] = val; - err = m5602_write_sensor(sd, S5K83A_EXPOSURE, data, 2); - return err; + return m5602_write_sensor(sd, S5K83A_EXPOSURE, data, 2); } static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev, diff --git a/drivers/media/usb/pvrusb2/pvrusb2-encoder.c b/drivers/media/usb/pvrusb2/pvrusb2-encoder.c index f6005d1296ef..c8102772344b 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-encoder.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-encoder.c @@ -188,8 +188,8 @@ static int pvr2_encoder_cmd(void *ctxt, } - LOCK_TAKE(hdw->ctl_lock); while (1) { - + LOCK_TAKE(hdw->ctl_lock); + while (1) { if (!hdw->state_encoder_ok) { ret = -EIO; break; diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c index d38dee1792e4..cd7b118d5929 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c @@ -1467,7 +1467,7 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw) for (address = 0; address < fwsize; address += 0x800) { memcpy(fw_ptr, fw_entry->data + address, 0x800); ret += usb_control_msg(hdw->usb_dev, pipe, 0xa0, 0x40, address, - 0, fw_ptr, 0x800, HZ); + 0, fw_ptr, 0x800, 1000); } trace_firmware("Upload done, releasing device's CPU"); @@ -1605,7 +1605,7 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw) ((u32 *)fw_ptr)[icnt] = swab32(((u32 *)fw_ptr)[icnt]); ret |= usb_bulk_msg(hdw->usb_dev, pipe, fw_ptr,bcnt, - &actual_length, HZ); + &actual_length, 1000); ret |= (actual_length != bcnt); if (ret) break; fw_done += bcnt; @@ -1718,16 +1718,16 @@ int pvr2_hdw_get_streaming(struct pvr2_hdw *hdw) int pvr2_hdw_set_streaming(struct pvr2_hdw *hdw,int enable_flag) { int ret,st; - LOCK_TAKE(hdw->big_lock); do { - pvr2_hdw_untrip_unlocked(hdw); - if ((!enable_flag) != !(hdw->state_pipeline_req)) { - hdw->state_pipeline_req = enable_flag != 0; - pvr2_trace(PVR2_TRACE_START_STOP, - "/*--TRACE_STREAM--*/ %s", - enable_flag ? "enable" : "disable"); - } - pvr2_hdw_state_sched(hdw); - } while (0); LOCK_GIVE(hdw->big_lock); + LOCK_TAKE(hdw->big_lock); + pvr2_hdw_untrip_unlocked(hdw); + if (!enable_flag != !hdw->state_pipeline_req) { + hdw->state_pipeline_req = enable_flag != 0; + pvr2_trace(PVR2_TRACE_START_STOP, + "/*--TRACE_STREAM--*/ %s", + enable_flag ? "enable" : "disable"); + } + pvr2_hdw_state_sched(hdw); + LOCK_GIVE(hdw->big_lock); if ((ret = pvr2_hdw_wait(hdw,0)) < 0) return ret; if (enable_flag) { while ((st = hdw->master_state) != PVR2_STATE_RUN) { @@ -3394,7 +3394,8 @@ void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, int ret; u16 address; unsigned int pipe; - LOCK_TAKE(hdw->big_lock); do { + LOCK_TAKE(hdw->big_lock); + do { if ((hdw->fw_buffer == NULL) == !enable_flag) break; if (!enable_flag) { @@ -3438,7 +3439,7 @@ void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, 0xa0,0xc0, address,0, hdw->fw_buffer+address, - 0x800,HZ); + 0x800,1000); if (ret < 0) break; } @@ -3457,8 +3458,8 @@ void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, pvr2_trace(PVR2_TRACE_FIRMWARE, "Done sucking down EEPROM contents"); } - - } while (0); LOCK_GIVE(hdw->big_lock); + } while (0); + LOCK_GIVE(hdw->big_lock); } @@ -3473,7 +3474,8 @@ int pvr2_hdw_cpufw_get(struct pvr2_hdw *hdw,unsigned int offs, char *buf,unsigned int cnt) { int ret = -EINVAL; - LOCK_TAKE(hdw->big_lock); do { + LOCK_TAKE(hdw->big_lock); + do { if (!buf) break; if (!cnt) break; @@ -3498,7 +3500,8 @@ int pvr2_hdw_cpufw_get(struct pvr2_hdw *hdw,unsigned int offs, "Read firmware data offs=%d cnt=%d", offs,cnt); ret = cnt; - } while (0); LOCK_GIVE(hdw->big_lock); + } while (0); + LOCK_GIVE(hdw->big_lock); return ret; } @@ -3977,7 +3980,7 @@ void pvr2_hdw_cpureset_assert(struct pvr2_hdw *hdw,int val) /* Write the CPUCS register on the 8051. The lsb of the register is the reset bit; a 1 asserts reset while a 0 clears it. */ pipe = usb_sndctrlpipe(hdw->usb_dev, 0); - ret = usb_control_msg(hdw->usb_dev,pipe,0xa0,0x40,0xe600,0,da,1,HZ); + ret = usb_control_msg(hdw->usb_dev,pipe,0xa0,0x40,0xe600,0,da,1,1000); if (ret < 0) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, "cpureset_assert(%d) error=%d",val,ret); diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 3b0e4ed75d99..acf18e2251a5 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -1882,7 +1882,7 @@ static long s2255_vendor_req(struct s2255_dev *dev, unsigned char Request, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, Value, Index, buf, - TransferBufferLength, HZ * 5); + TransferBufferLength, USB_CTRL_SET_TIMEOUT); if (r >= 0) memcpy(TransferBuffer, buf, TransferBufferLength); @@ -1891,7 +1891,7 @@ static long s2255_vendor_req(struct s2255_dev *dev, unsigned char Request, r = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), Request, USB_TYPE_VENDOR | USB_RECIP_DEVICE, Value, Index, buf, - TransferBufferLength, HZ * 5); + TransferBufferLength, USB_CTRL_SET_TIMEOUT); } kfree(buf); return r; diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c index df4c5dcba39c..fe9c7b3a950e 100644 --- a/drivers/media/usb/siano/smsusb.c +++ b/drivers/media/usb/siano/smsusb.c @@ -661,10 +661,6 @@ static const struct usb_device_id smsusb_id_table[] = { .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, { USB_DEVICE(0x2040, 0x5590), .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, - { USB_DEVICE(0x187f, 0x0202), - .driver_info = SMS1XXX_BOARD_SIANO_NICE }, - { USB_DEVICE(0x187f, 0x0301), - .driver_info = SMS1XXX_BOARD_SIANO_VENICE }, { USB_DEVICE(0x2040, 0xb900), .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, { USB_DEVICE(0x2040, 0xb910), diff --git a/drivers/media/usb/stk1160/stk1160-core.c b/drivers/media/usb/stk1160/stk1160-core.c index b4f8bc5db138..4e1698f78818 100644 --- a/drivers/media/usb/stk1160/stk1160-core.c +++ b/drivers/media/usb/stk1160/stk1160-core.c @@ -65,7 +65,7 @@ int stk1160_read_reg(struct stk1160 *dev, u16 reg, u8 *value) return -ENOMEM; ret = usb_control_msg(dev->udev, pipe, 0x00, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x00, reg, buf, sizeof(u8), HZ); + 0x00, reg, buf, sizeof(u8), 1000); if (ret < 0) { stk1160_err("read failed on reg 0x%x (%d)\n", reg, ret); @@ -85,7 +85,7 @@ int stk1160_write_reg(struct stk1160 *dev, u16 reg, u16 value) ret = usb_control_msg(dev->udev, pipe, 0x01, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, reg, NULL, 0, HZ); + value, reg, NULL, 0, 1000); if (ret < 0) { stk1160_err("write failed on reg 0x%x (%d)\n", reg, ret); diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index 30bfe9069a1f..b4f6edf968bc 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -1638,8 +1638,8 @@ static int uvc_ctrl_find_ctrl_idx(struct uvc_entity *entity, struct v4l2_ext_controls *ctrls, struct uvc_control *uvc_control) { - struct uvc_control_mapping *mapping; - struct uvc_control *ctrl_found; + struct uvc_control_mapping *mapping = NULL; + struct uvc_control *ctrl_found = NULL; unsigned int i; if (!entity) diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 7c007426e082..5f394d4efc21 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -256,7 +256,7 @@ static struct uvc_format_desc *uvc_format_by_guid(const u8 guid[16]) static enum v4l2_colorspace uvc_colorspace(const u8 primaries) { static const enum v4l2_colorspace colorprimaries[] = { - V4L2_COLORSPACE_DEFAULT, /* Unspecified */ + V4L2_COLORSPACE_SRGB, /* Unspecified */ V4L2_COLORSPACE_SRGB, V4L2_COLORSPACE_470_SYSTEM_M, V4L2_COLORSPACE_470_SYSTEM_BG, @@ -267,7 +267,7 @@ static enum v4l2_colorspace uvc_colorspace(const u8 primaries) if (primaries < ARRAY_SIZE(colorprimaries)) return colorprimaries[primaries]; - return V4L2_COLORSPACE_DEFAULT; /* Reserved */ + return V4L2_COLORSPACE_SRGB; /* Reserved */ } static enum v4l2_xfer_func uvc_xfer_func(const u8 transfer_characteristics) @@ -769,6 +769,8 @@ static int uvc_parse_format(struct uvc_device *dev, buflen -= buffer[0]; buffer += buffer[0]; + } else { + format->colorspace = V4L2_COLORSPACE_SRGB; } return buffer - start; @@ -2193,7 +2195,6 @@ int uvc_register_video_device(struct uvc_device *dev, const struct v4l2_file_operations *fops, const struct v4l2_ioctl_ops *ioctl_ops) { - const char *name; int ret; /* Initialize the video buffers queue. */ @@ -2222,20 +2223,16 @@ int uvc_register_video_device(struct uvc_device *dev, case V4L2_BUF_TYPE_VIDEO_CAPTURE: default: vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - name = "Video Capture"; break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: vdev->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; - name = "Video Output"; break; case V4L2_BUF_TYPE_META_CAPTURE: vdev->device_caps = V4L2_CAP_META_CAPTURE | V4L2_CAP_STREAMING; - name = "Metadata"; break; } - snprintf(vdev->name, sizeof(vdev->name), "%s %u", name, - stream->header.bTerminalLink); + strscpy(vdev->name, dev->name, sizeof(vdev->name)); /* * Set the driver data before calling video_register_device, otherwise diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index f4e4aff8ddf7..711556d13d03 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -44,8 +44,10 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain, if (v4l2_ctrl_get_name(map->id) == NULL) { map->name = kmemdup(xmap->name, sizeof(xmap->name), GFP_KERNEL); - if (!map->name) - return -ENOMEM; + if (!map->name) { + ret = -ENOMEM; + goto free_map; + } } memcpy(map->entity, xmap->entity, sizeof(map->entity)); map->selector = xmap->selector; diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 9f37eaf28ce7..1b4cc934109e 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -1963,6 +1963,10 @@ static int uvc_video_start_transfer(struct uvc_streaming *stream, if (ep == NULL) return -EIO; + /* Reject broken descriptors. */ + if (usb_endpoint_maxp(&ep->desc) == 0) + return -EIO; + ret = uvc_init_video_bulk(stream, ep, gfp_flags); } diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 2e5366143b81..143230b3275b 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -189,7 +189,7 @@ /* Maximum status buffer size in bytes of interrupt URB. */ #define UVC_MAX_STATUS_SIZE 16 -#define UVC_CTRL_CONTROL_TIMEOUT 500 +#define UVC_CTRL_CONTROL_TIMEOUT 5000 #define UVC_CTRL_STREAMING_TIMEOUT 5000 /* Maximum allowed number of control mappings per device */ diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig index 02dc1787e953..6ee75c6c820e 100644 --- a/drivers/media/v4l2-core/Kconfig +++ b/drivers/media/v4l2-core/Kconfig @@ -52,6 +52,10 @@ config V4L2_JPEG_HELPER config V4L2_H264 tristate +# Used by drivers that need v4l2-vp9.ko +config V4L2_VP9 + tristate + # Used by drivers that need v4l2-mem2mem.ko config V4L2_MEM2MEM_DEV tristate diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile index 66a78c556c98..83fac5c746f5 100644 --- a/drivers/media/v4l2-core/Makefile +++ b/drivers/media/v4l2-core/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_VIDEO_TUNER) += tuner.o obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o obj-$(CONFIG_V4L2_H264) += v4l2-h264.o +obj-$(CONFIG_V4L2_VP9) += v4l2-vp9.o obj-$(CONFIG_V4L2_FLASH_LED_CLASS) += v4l2-flash-led-class.o diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c index 70adfc1b9c81..54abe5245dcc 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-core.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c @@ -283,6 +283,12 @@ static void std_log(const struct v4l2_ctrl *ctrl) case V4L2_CTRL_TYPE_MPEG2_PICTURE: pr_cont("MPEG2_PICTURE"); break; + case V4L2_CTRL_TYPE_VP9_COMPRESSED_HDR: + pr_cont("VP9_COMPRESSED_HDR"); + break; + case V4L2_CTRL_TYPE_VP9_FRAME: + pr_cont("VP9_FRAME"); + break; default: pr_cont("unknown type %d", ctrl->type); break; @@ -317,6 +323,168 @@ static void std_log(const struct v4l2_ctrl *ctrl) #define zero_reserved(s) \ memset(&(s).reserved, 0, sizeof((s).reserved)) +static int +validate_vp9_lf_params(struct v4l2_vp9_loop_filter *lf) +{ + unsigned int i; + + if (lf->flags & ~(V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED | + V4L2_VP9_LOOP_FILTER_FLAG_DELTA_UPDATE)) + return -EINVAL; + + /* That all values are in the accepted range. */ + if (lf->level > GENMASK(5, 0)) + return -EINVAL; + + if (lf->sharpness > GENMASK(2, 0)) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(lf->ref_deltas); i++) + if (lf->ref_deltas[i] < -63 || lf->ref_deltas[i] > 63) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(lf->mode_deltas); i++) + if (lf->mode_deltas[i] < -63 || lf->mode_deltas[i] > 63) + return -EINVAL; + + zero_reserved(*lf); + return 0; +} + +static int +validate_vp9_quant_params(struct v4l2_vp9_quantization *quant) +{ + if (quant->delta_q_y_dc < -15 || quant->delta_q_y_dc > 15 || + quant->delta_q_uv_dc < -15 || quant->delta_q_uv_dc > 15 || + quant->delta_q_uv_ac < -15 || quant->delta_q_uv_ac > 15) + return -EINVAL; + + zero_reserved(*quant); + return 0; +} + +static int +validate_vp9_seg_params(struct v4l2_vp9_segmentation *seg) +{ + unsigned int i, j; + + if (seg->flags & ~(V4L2_VP9_SEGMENTATION_FLAG_ENABLED | + V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP | + V4L2_VP9_SEGMENTATION_FLAG_TEMPORAL_UPDATE | + V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA | + V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE)) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(seg->feature_enabled); i++) { + if (seg->feature_enabled[i] & + ~V4L2_VP9_SEGMENT_FEATURE_ENABLED_MASK) + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(seg->feature_data); i++) { + const int range[] = { 255, 63, 3, 0 }; + + for (j = 0; j < ARRAY_SIZE(seg->feature_data[j]); j++) { + if (seg->feature_data[i][j] < -range[j] || + seg->feature_data[i][j] > range[j]) + return -EINVAL; + } + } + + zero_reserved(*seg); + return 0; +} + +static int +validate_vp9_compressed_hdr(struct v4l2_ctrl_vp9_compressed_hdr *hdr) +{ + if (hdr->tx_mode > V4L2_VP9_TX_MODE_SELECT) + return -EINVAL; + + return 0; +} + +static int +validate_vp9_frame(struct v4l2_ctrl_vp9_frame *frame) +{ + int ret; + + /* Make sure we're not passed invalid flags. */ + if (frame->flags & ~(V4L2_VP9_FRAME_FLAG_KEY_FRAME | + V4L2_VP9_FRAME_FLAG_SHOW_FRAME | + V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT | + V4L2_VP9_FRAME_FLAG_INTRA_ONLY | + V4L2_VP9_FRAME_FLAG_ALLOW_HIGH_PREC_MV | + V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX | + V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE | + V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING | + V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING | + V4L2_VP9_FRAME_FLAG_COLOR_RANGE_FULL_SWING)) + return -EINVAL; + + if (frame->flags & V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT && + frame->flags & V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX) + return -EINVAL; + + if (frame->profile > V4L2_VP9_PROFILE_MAX) + return -EINVAL; + + if (frame->reset_frame_context > V4L2_VP9_RESET_FRAME_CTX_ALL) + return -EINVAL; + + if (frame->frame_context_idx >= V4L2_VP9_NUM_FRAME_CTX) + return -EINVAL; + + /* + * Profiles 0 and 1 only support 8-bit depth, profiles 2 and 3 only 10 + * and 12 bit depths. + */ + if ((frame->profile < 2 && frame->bit_depth != 8) || + (frame->profile >= 2 && + (frame->bit_depth != 10 && frame->bit_depth != 12))) + return -EINVAL; + + /* Profile 0 and 2 only accept YUV 4:2:0. */ + if ((frame->profile == 0 || frame->profile == 2) && + (!(frame->flags & V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING) || + !(frame->flags & V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING))) + return -EINVAL; + + /* Profile 1 and 3 only accept YUV 4:2:2, 4:4:0 and 4:4:4. */ + if ((frame->profile == 1 || frame->profile == 3) && + ((frame->flags & V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING) && + (frame->flags & V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING))) + return -EINVAL; + + if (frame->interpolation_filter > V4L2_VP9_INTERP_FILTER_SWITCHABLE) + return -EINVAL; + + /* + * According to the spec, tile_cols_log2 shall be less than or equal + * to 6. + */ + if (frame->tile_cols_log2 > 6) + return -EINVAL; + + if (frame->reference_mode > V4L2_VP9_REFERENCE_MODE_SELECT) + return -EINVAL; + + ret = validate_vp9_lf_params(&frame->lf); + if (ret) + return ret; + + ret = validate_vp9_quant_params(&frame->quant); + if (ret) + return ret; + + ret = validate_vp9_seg_params(&frame->seg); + if (ret) + return ret; + + zero_reserved(*frame); + return 0; +} + /* * Compound controls validation requires setting unused fields/flags to zero * in order to properly detect unchanged controls with std_equal's memcmp. @@ -690,6 +858,12 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, case V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX: break; + case V4L2_CTRL_TYPE_VP9_COMPRESSED_HDR: + return validate_vp9_compressed_hdr(p); + + case V4L2_CTRL_TYPE_VP9_FRAME: + return validate_vp9_frame(p); + case V4L2_CTRL_TYPE_AREA: area = p; if (!area->width || !area->height) @@ -1255,6 +1429,12 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, case V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY: elem_size = sizeof(struct v4l2_ctrl_hdr10_mastering_display); break; + case V4L2_CTRL_TYPE_VP9_COMPRESSED_HDR: + elem_size = sizeof(struct v4l2_ctrl_vp9_compressed_hdr); + break; + case V4L2_CTRL_TYPE_VP9_FRAME: + elem_size = sizeof(struct v4l2_ctrl_vp9_frame); + break; case V4L2_CTRL_TYPE_AREA: elem_size = sizeof(struct v4l2_area); break; diff --git a/drivers/media/v4l2-core/v4l2-ctrls-defs.c b/drivers/media/v4l2-core/v4l2-ctrls-defs.c index ebe82b6ba6e6..54ca4e6b820b 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-defs.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-defs.c @@ -785,6 +785,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: return "Min Number of Output Buffers"; case V4L2_CID_ALPHA_COMPONENT: return "Alpha Component"; case V4L2_CID_COLORFX_CBCR: return "Color Effects, CbCr"; + case V4L2_CID_COLORFX_RGB: return "Color Effects, RGB"; /* * Codec controls @@ -1177,6 +1178,8 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_STATELESS_MPEG2_SEQUENCE: return "MPEG-2 Sequence Header"; case V4L2_CID_STATELESS_MPEG2_PICTURE: return "MPEG-2 Picture Header"; case V4L2_CID_STATELESS_MPEG2_QUANTISATION: return "MPEG-2 Quantisation Matrices"; + case V4L2_CID_STATELESS_VP9_COMPRESSED_HDR: return "VP9 Probabilities Updates"; + case V4L2_CID_STATELESS_VP9_FRAME: return "VP9 Frame Decode Parameters"; /* Colorimetry controls */ /* Keep the order of the 'case's the same as in v4l2-controls.h! */ @@ -1394,11 +1397,18 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, *min = *max = *step = *def = 0; break; case V4L2_CID_BG_COLOR: + case V4L2_CID_COLORFX_RGB: *type = V4L2_CTRL_TYPE_INTEGER; *step = 1; *min = 0; - /* Max is calculated as RGB888 that is 2^24 */ - *max = 0xFFFFFF; + /* Max is calculated as RGB888 that is 2^24 - 1 */ + *max = 0xffffff; + break; + case V4L2_CID_COLORFX_CBCR: + *type = V4L2_CTRL_TYPE_INTEGER; + *step = 1; + *min = 0; + *max = 0xffff; break; case V4L2_CID_FLASH_FAULT: case V4L2_CID_JPEG_ACTIVE_MARKER: @@ -1498,6 +1508,12 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS: *type = V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS; break; + case V4L2_CID_STATELESS_VP9_COMPRESSED_HDR: + *type = V4L2_CTRL_TYPE_VP9_COMPRESSED_HDR; + break; + case V4L2_CID_STATELESS_VP9_FRAME: + *type = V4L2_CTRL_TYPE_VP9_FRAME; + break; case V4L2_CID_UNIT_CELL_SIZE: *type = V4L2_CTRL_TYPE_AREA; *flags |= V4L2_CTRL_FLAG_READ_ONLY; diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 31d0109ce5a8..9ac557b8e146 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1413,6 +1413,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_VP8: descr = "VP8"; break; case V4L2_PIX_FMT_VP8_FRAME: descr = "VP8 Frame"; break; case V4L2_PIX_FMT_VP9: descr = "VP9"; break; + case V4L2_PIX_FMT_VP9_FRAME: descr = "VP9 Frame"; break; case V4L2_PIX_FMT_HEVC: descr = "HEVC"; break; /* aka H.265 */ case V4L2_PIX_FMT_HEVC_SLICE: descr = "HEVC Parsed Slice Data"; break; case V4L2_PIX_FMT_FWHT: descr = "FWHT"; break; /* used in vicodec */ @@ -2090,6 +2091,7 @@ static int v4l_prepare_buf(const struct v4l2_ioctl_ops *ops, static int v4l_g_parm(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { + struct video_device *vfd = video_devdata(file); struct v4l2_streamparm *p = arg; v4l2_std_id std; int ret = check_fmt(file, p->type); @@ -2101,7 +2103,8 @@ static int v4l_g_parm(const struct v4l2_ioctl_ops *ops, if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) return -EINVAL; - p->parm.capture.readbuffers = 2; + if (vfd->device_caps & V4L2_CAP_READWRITE) + p->parm.capture.readbuffers = 2; ret = ops->vidioc_g_std(file, fh, &std); if (ret == 0) v4l2_video_std_frame_period(std, &p->parm.capture.timeperframe); diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index e7f4bf5bc8dd..e2654b422334 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -966,6 +966,27 @@ int v4l2_m2m_mmap(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, } EXPORT_SYMBOL(v4l2_m2m_mmap); +#ifndef CONFIG_MMU +unsigned long v4l2_m2m_get_unmapped_area(struct file *file, unsigned long addr, + unsigned long len, unsigned long pgoff, + unsigned long flags) +{ + struct v4l2_fh *fh = file->private_data; + unsigned long offset = pgoff << PAGE_SHIFT; + struct vb2_queue *vq; + + if (offset < DST_QUEUE_OFF_BASE) { + vq = v4l2_m2m_get_src_vq(fh->m2m_ctx); + } else { + vq = v4l2_m2m_get_dst_vq(fh->m2m_ctx); + pgoff -= (DST_QUEUE_OFF_BASE >> PAGE_SHIFT); + } + + return vb2_get_unmapped_area(vq, addr, len, pgoff, flags); +} +EXPORT_SYMBOL_GPL(v4l2_m2m_get_unmapped_area); +#endif + #if defined(CONFIG_MEDIA_CONTROLLER) void v4l2_m2m_unregister_media_controller(struct v4l2_m2m_dev *m2m_dev) { diff --git a/drivers/media/v4l2-core/v4l2-vp9.c b/drivers/media/v4l2-core/v4l2-vp9.c new file mode 100644 index 000000000000..859589f1fd35 --- /dev/null +++ b/drivers/media/v4l2-core/v4l2-vp9.c @@ -0,0 +1,1850 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * V4L2 VP9 helpers. + * + * Copyright (C) 2021 Collabora, Ltd. + * + * Author: Andrzej Pietrasiewicz <andrzej.p@collabora.com> + */ + +#include <linux/module.h> + +#include <media/v4l2-vp9.h> + +const u8 v4l2_vp9_kf_y_mode_prob[10][10][9] = { + { + /* above = dc */ + { 137, 30, 42, 148, 151, 207, 70, 52, 91 }, /*left = dc */ + { 92, 45, 102, 136, 116, 180, 74, 90, 100 }, /*left = v */ + { 73, 32, 19, 187, 222, 215, 46, 34, 100 }, /*left = h */ + { 91, 30, 32, 116, 121, 186, 93, 86, 94 }, /*left = d45 */ + { 72, 35, 36, 149, 68, 206, 68, 63, 105 }, /*left = d135*/ + { 73, 31, 28, 138, 57, 124, 55, 122, 151 }, /*left = d117*/ + { 67, 23, 21, 140, 126, 197, 40, 37, 171 }, /*left = d153*/ + { 86, 27, 28, 128, 154, 212, 45, 43, 53 }, /*left = d207*/ + { 74, 32, 27, 107, 86, 160, 63, 134, 102 }, /*left = d63 */ + { 59, 67, 44, 140, 161, 202, 78, 67, 119 }, /*left = tm */ + }, { /* above = v */ + { 63, 36, 126, 146, 123, 158, 60, 90, 96 }, /*left = dc */ + { 43, 46, 168, 134, 107, 128, 69, 142, 92 }, /*left = v */ + { 44, 29, 68, 159, 201, 177, 50, 57, 77 }, /*left = h */ + { 58, 38, 76, 114, 97, 172, 78, 133, 92 }, /*left = d45 */ + { 46, 41, 76, 140, 63, 184, 69, 112, 57 }, /*left = d135*/ + { 38, 32, 85, 140, 46, 112, 54, 151, 133 }, /*left = d117*/ + { 39, 27, 61, 131, 110, 175, 44, 75, 136 }, /*left = d153*/ + { 52, 30, 74, 113, 130, 175, 51, 64, 58 }, /*left = d207*/ + { 47, 35, 80, 100, 74, 143, 64, 163, 74 }, /*left = d63 */ + { 36, 61, 116, 114, 128, 162, 80, 125, 82 }, /*left = tm */ + }, { /* above = h */ + { 82, 26, 26, 171, 208, 204, 44, 32, 105 }, /*left = dc */ + { 55, 44, 68, 166, 179, 192, 57, 57, 108 }, /*left = v */ + { 42, 26, 11, 199, 241, 228, 23, 15, 85 }, /*left = h */ + { 68, 42, 19, 131, 160, 199, 55, 52, 83 }, /*left = d45 */ + { 58, 50, 25, 139, 115, 232, 39, 52, 118 }, /*left = d135*/ + { 50, 35, 33, 153, 104, 162, 64, 59, 131 }, /*left = d117*/ + { 44, 24, 16, 150, 177, 202, 33, 19, 156 }, /*left = d153*/ + { 55, 27, 12, 153, 203, 218, 26, 27, 49 }, /*left = d207*/ + { 53, 49, 21, 110, 116, 168, 59, 80, 76 }, /*left = d63 */ + { 38, 72, 19, 168, 203, 212, 50, 50, 107 }, /*left = tm */ + }, { /* above = d45 */ + { 103, 26, 36, 129, 132, 201, 83, 80, 93 }, /*left = dc */ + { 59, 38, 83, 112, 103, 162, 98, 136, 90 }, /*left = v */ + { 62, 30, 23, 158, 200, 207, 59, 57, 50 }, /*left = h */ + { 67, 30, 29, 84, 86, 191, 102, 91, 59 }, /*left = d45 */ + { 60, 32, 33, 112, 71, 220, 64, 89, 104 }, /*left = d135*/ + { 53, 26, 34, 130, 56, 149, 84, 120, 103 }, /*left = d117*/ + { 53, 21, 23, 133, 109, 210, 56, 77, 172 }, /*left = d153*/ + { 77, 19, 29, 112, 142, 228, 55, 66, 36 }, /*left = d207*/ + { 61, 29, 29, 93, 97, 165, 83, 175, 162 }, /*left = d63 */ + { 47, 47, 43, 114, 137, 181, 100, 99, 95 }, /*left = tm */ + }, { /* above = d135 */ + { 69, 23, 29, 128, 83, 199, 46, 44, 101 }, /*left = dc */ + { 53, 40, 55, 139, 69, 183, 61, 80, 110 }, /*left = v */ + { 40, 29, 19, 161, 180, 207, 43, 24, 91 }, /*left = h */ + { 60, 34, 19, 105, 61, 198, 53, 64, 89 }, /*left = d45 */ + { 52, 31, 22, 158, 40, 209, 58, 62, 89 }, /*left = d135*/ + { 44, 31, 29, 147, 46, 158, 56, 102, 198 }, /*left = d117*/ + { 35, 19, 12, 135, 87, 209, 41, 45, 167 }, /*left = d153*/ + { 55, 25, 21, 118, 95, 215, 38, 39, 66 }, /*left = d207*/ + { 51, 38, 25, 113, 58, 164, 70, 93, 97 }, /*left = d63 */ + { 47, 54, 34, 146, 108, 203, 72, 103, 151 }, /*left = tm */ + }, { /* above = d117 */ + { 64, 19, 37, 156, 66, 138, 49, 95, 133 }, /*left = dc */ + { 46, 27, 80, 150, 55, 124, 55, 121, 135 }, /*left = v */ + { 36, 23, 27, 165, 149, 166, 54, 64, 118 }, /*left = h */ + { 53, 21, 36, 131, 63, 163, 60, 109, 81 }, /*left = d45 */ + { 40, 26, 35, 154, 40, 185, 51, 97, 123 }, /*left = d135*/ + { 35, 19, 34, 179, 19, 97, 48, 129, 124 }, /*left = d117*/ + { 36, 20, 26, 136, 62, 164, 33, 77, 154 }, /*left = d153*/ + { 45, 18, 32, 130, 90, 157, 40, 79, 91 }, /*left = d207*/ + { 45, 26, 28, 129, 45, 129, 49, 147, 123 }, /*left = d63 */ + { 38, 44, 51, 136, 74, 162, 57, 97, 121 }, /*left = tm */ + }, { /* above = d153 */ + { 75, 17, 22, 136, 138, 185, 32, 34, 166 }, /*left = dc */ + { 56, 39, 58, 133, 117, 173, 48, 53, 187 }, /*left = v */ + { 35, 21, 12, 161, 212, 207, 20, 23, 145 }, /*left = h */ + { 56, 29, 19, 117, 109, 181, 55, 68, 112 }, /*left = d45 */ + { 47, 29, 17, 153, 64, 220, 59, 51, 114 }, /*left = d135*/ + { 46, 16, 24, 136, 76, 147, 41, 64, 172 }, /*left = d117*/ + { 34, 17, 11, 108, 152, 187, 13, 15, 209 }, /*left = d153*/ + { 51, 24, 14, 115, 133, 209, 32, 26, 104 }, /*left = d207*/ + { 55, 30, 18, 122, 79, 179, 44, 88, 116 }, /*left = d63 */ + { 37, 49, 25, 129, 168, 164, 41, 54, 148 }, /*left = tm */ + }, { /* above = d207 */ + { 82, 22, 32, 127, 143, 213, 39, 41, 70 }, /*left = dc */ + { 62, 44, 61, 123, 105, 189, 48, 57, 64 }, /*left = v */ + { 47, 25, 17, 175, 222, 220, 24, 30, 86 }, /*left = h */ + { 68, 36, 17, 106, 102, 206, 59, 74, 74 }, /*left = d45 */ + { 57, 39, 23, 151, 68, 216, 55, 63, 58 }, /*left = d135*/ + { 49, 30, 35, 141, 70, 168, 82, 40, 115 }, /*left = d117*/ + { 51, 25, 15, 136, 129, 202, 38, 35, 139 }, /*left = d153*/ + { 68, 26, 16, 111, 141, 215, 29, 28, 28 }, /*left = d207*/ + { 59, 39, 19, 114, 75, 180, 77, 104, 42 }, /*left = d63 */ + { 40, 61, 26, 126, 152, 206, 61, 59, 93 }, /*left = tm */ + }, { /* above = d63 */ + { 78, 23, 39, 111, 117, 170, 74, 124, 94 }, /*left = dc */ + { 48, 34, 86, 101, 92, 146, 78, 179, 134 }, /*left = v */ + { 47, 22, 24, 138, 187, 178, 68, 69, 59 }, /*left = h */ + { 56, 25, 33, 105, 112, 187, 95, 177, 129 }, /*left = d45 */ + { 48, 31, 27, 114, 63, 183, 82, 116, 56 }, /*left = d135*/ + { 43, 28, 37, 121, 63, 123, 61, 192, 169 }, /*left = d117*/ + { 42, 17, 24, 109, 97, 177, 56, 76, 122 }, /*left = d153*/ + { 58, 18, 28, 105, 139, 182, 70, 92, 63 }, /*left = d207*/ + { 46, 23, 32, 74, 86, 150, 67, 183, 88 }, /*left = d63 */ + { 36, 38, 48, 92, 122, 165, 88, 137, 91 }, /*left = tm */ + }, { /* above = tm */ + { 65, 70, 60, 155, 159, 199, 61, 60, 81 }, /*left = dc */ + { 44, 78, 115, 132, 119, 173, 71, 112, 93 }, /*left = v */ + { 39, 38, 21, 184, 227, 206, 42, 32, 64 }, /*left = h */ + { 58, 47, 36, 124, 137, 193, 80, 82, 78 }, /*left = d45 */ + { 49, 50, 35, 144, 95, 205, 63, 78, 59 }, /*left = d135*/ + { 41, 53, 52, 148, 71, 142, 65, 128, 51 }, /*left = d117*/ + { 40, 36, 28, 143, 143, 202, 40, 55, 137 }, /*left = d153*/ + { 52, 34, 29, 129, 183, 227, 42, 35, 43 }, /*left = d207*/ + { 42, 44, 44, 104, 105, 164, 64, 130, 80 }, /*left = d63 */ + { 43, 81, 53, 140, 169, 204, 68, 84, 72 }, /*left = tm */ + } +}; +EXPORT_SYMBOL_GPL(v4l2_vp9_kf_y_mode_prob); + +const u8 v4l2_vp9_kf_partition_probs[16][3] = { + /* 8x8 -> 4x4 */ + { 158, 97, 94 }, /* a/l both not split */ + { 93, 24, 99 }, /* a split, l not split */ + { 85, 119, 44 }, /* l split, a not split */ + { 62, 59, 67 }, /* a/l both split */ + /* 16x16 -> 8x8 */ + { 149, 53, 53 }, /* a/l both not split */ + { 94, 20, 48 }, /* a split, l not split */ + { 83, 53, 24 }, /* l split, a not split */ + { 52, 18, 18 }, /* a/l both split */ + /* 32x32 -> 16x16 */ + { 150, 40, 39 }, /* a/l both not split */ + { 78, 12, 26 }, /* a split, l not split */ + { 67, 33, 11 }, /* l split, a not split */ + { 24, 7, 5 }, /* a/l both split */ + /* 64x64 -> 32x32 */ + { 174, 35, 49 }, /* a/l both not split */ + { 68, 11, 27 }, /* a split, l not split */ + { 57, 15, 9 }, /* l split, a not split */ + { 12, 3, 3 }, /* a/l both split */ +}; +EXPORT_SYMBOL_GPL(v4l2_vp9_kf_partition_probs); + +const u8 v4l2_vp9_kf_uv_mode_prob[10][9] = { + { 144, 11, 54, 157, 195, 130, 46, 58, 108 }, /* y = dc */ + { 118, 15, 123, 148, 131, 101, 44, 93, 131 }, /* y = v */ + { 113, 12, 23, 188, 226, 142, 26, 32, 125 }, /* y = h */ + { 120, 11, 50, 123, 163, 135, 64, 77, 103 }, /* y = d45 */ + { 113, 9, 36, 155, 111, 157, 32, 44, 161 }, /* y = d135 */ + { 116, 9, 55, 176, 76, 96, 37, 61, 149 }, /* y = d117 */ + { 115, 9, 28, 141, 161, 167, 21, 25, 193 }, /* y = d153 */ + { 120, 12, 32, 145, 195, 142, 32, 38, 86 }, /* y = d207 */ + { 116, 12, 64, 120, 140, 125, 49, 115, 121 }, /* y = d63 */ + { 102, 19, 66, 162, 182, 122, 35, 59, 128 } /* y = tm */ +}; +EXPORT_SYMBOL_GPL(v4l2_vp9_kf_uv_mode_prob); + +const struct v4l2_vp9_frame_context v4l2_vp9_default_probs = { + .tx8 = { + { 100 }, + { 66 }, + }, + .tx16 = { + { 20, 152 }, + { 15, 101 }, + }, + .tx32 = { + { 3, 136, 37 }, + { 5, 52, 13 }, + }, + .coef = { + { /* tx = 4x4 */ + { /* block Type 0 */ + { /* Intra */ + { /* Coeff Band 0 */ + { 195, 29, 183 }, + { 84, 49, 136 }, + { 8, 42, 71 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + }, + { /* Coeff Band 1 */ + { 31, 107, 169 }, + { 35, 99, 159 }, + { 17, 82, 140 }, + { 8, 66, 114 }, + { 2, 44, 76 }, + { 1, 19, 32 }, + }, + { /* Coeff Band 2 */ + { 40, 132, 201 }, + { 29, 114, 187 }, + { 13, 91, 157 }, + { 7, 75, 127 }, + { 3, 58, 95 }, + { 1, 28, 47 }, + }, + { /* Coeff Band 3 */ + { 69, 142, 221 }, + { 42, 122, 201 }, + { 15, 91, 159 }, + { 6, 67, 121 }, + { 1, 42, 77 }, + { 1, 17, 31 }, + }, + { /* Coeff Band 4 */ + { 102, 148, 228 }, + { 67, 117, 204 }, + { 17, 82, 154 }, + { 6, 59, 114 }, + { 2, 39, 75 }, + { 1, 15, 29 }, + }, + { /* Coeff Band 5 */ + { 156, 57, 233 }, + { 119, 57, 212 }, + { 58, 48, 163 }, + { 29, 40, 124 }, + { 12, 30, 81 }, + { 3, 12, 31 } + }, + }, + { /* Inter */ + { /* Coeff Band 0 */ + { 191, 107, 226 }, + { 124, 117, 204 }, + { 25, 99, 155 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + }, + { /* Coeff Band 1 */ + { 29, 148, 210 }, + { 37, 126, 194 }, + { 8, 93, 157 }, + { 2, 68, 118 }, + { 1, 39, 69 }, + { 1, 17, 33 }, + }, + { /* Coeff Band 2 */ + { 41, 151, 213 }, + { 27, 123, 193 }, + { 3, 82, 144 }, + { 1, 58, 105 }, + { 1, 32, 60 }, + { 1, 13, 26 }, + }, + { /* Coeff Band 3 */ + { 59, 159, 220 }, + { 23, 126, 198 }, + { 4, 88, 151 }, + { 1, 66, 114 }, + { 1, 38, 71 }, + { 1, 18, 34 }, + }, + { /* Coeff Band 4 */ + { 114, 136, 232 }, + { 51, 114, 207 }, + { 11, 83, 155 }, + { 3, 56, 105 }, + { 1, 33, 65 }, + { 1, 17, 34 }, + }, + { /* Coeff Band 5 */ + { 149, 65, 234 }, + { 121, 57, 215 }, + { 61, 49, 166 }, + { 28, 36, 114 }, + { 12, 25, 76 }, + { 3, 16, 42 }, + }, + }, + }, + { /* block Type 1 */ + { /* Intra */ + { /* Coeff Band 0 */ + { 214, 49, 220 }, + { 132, 63, 188 }, + { 42, 65, 137 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + }, + { /* Coeff Band 1 */ + { 85, 137, 221 }, + { 104, 131, 216 }, + { 49, 111, 192 }, + { 21, 87, 155 }, + { 2, 49, 87 }, + { 1, 16, 28 }, + }, + { /* Coeff Band 2 */ + { 89, 163, 230 }, + { 90, 137, 220 }, + { 29, 100, 183 }, + { 10, 70, 135 }, + { 2, 42, 81 }, + { 1, 17, 33 }, + }, + { /* Coeff Band 3 */ + { 108, 167, 237 }, + { 55, 133, 222 }, + { 15, 97, 179 }, + { 4, 72, 135 }, + { 1, 45, 85 }, + { 1, 19, 38 }, + }, + { /* Coeff Band 4 */ + { 124, 146, 240 }, + { 66, 124, 224 }, + { 17, 88, 175 }, + { 4, 58, 122 }, + { 1, 36, 75 }, + { 1, 18, 37 }, + }, + { /* Coeff Band 5 */ + { 141, 79, 241 }, + { 126, 70, 227 }, + { 66, 58, 182 }, + { 30, 44, 136 }, + { 12, 34, 96 }, + { 2, 20, 47 }, + }, + }, + { /* Inter */ + { /* Coeff Band 0 */ + { 229, 99, 249 }, + { 143, 111, 235 }, + { 46, 109, 192 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + }, + { /* Coeff Band 1 */ + { 82, 158, 236 }, + { 94, 146, 224 }, + { 25, 117, 191 }, + { 9, 87, 149 }, + { 3, 56, 99 }, + { 1, 33, 57 }, + }, + { /* Coeff Band 2 */ + { 83, 167, 237 }, + { 68, 145, 222 }, + { 10, 103, 177 }, + { 2, 72, 131 }, + { 1, 41, 79 }, + { 1, 20, 39 }, + }, + { /* Coeff Band 3 */ + { 99, 167, 239 }, + { 47, 141, 224 }, + { 10, 104, 178 }, + { 2, 73, 133 }, + { 1, 44, 85 }, + { 1, 22, 47 }, + }, + { /* Coeff Band 4 */ + { 127, 145, 243 }, + { 71, 129, 228 }, + { 17, 93, 177 }, + { 3, 61, 124 }, + { 1, 41, 84 }, + { 1, 21, 52 }, + }, + { /* Coeff Band 5 */ + { 157, 78, 244 }, + { 140, 72, 231 }, + { 69, 58, 184 }, + { 31, 44, 137 }, + { 14, 38, 105 }, + { 8, 23, 61 }, + }, + }, + }, + }, + { /* tx = 8x8 */ + { /* block Type 0 */ + { /* Intra */ + { /* Coeff Band 0 */ + { 125, 34, 187 }, + { 52, 41, 133 }, + { 6, 31, 56 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + }, + { /* Coeff Band 1 */ + { 37, 109, 153 }, + { 51, 102, 147 }, + { 23, 87, 128 }, + { 8, 67, 101 }, + { 1, 41, 63 }, + { 1, 19, 29 }, + }, + { /* Coeff Band 2 */ + { 31, 154, 185 }, + { 17, 127, 175 }, + { 6, 96, 145 }, + { 2, 73, 114 }, + { 1, 51, 82 }, + { 1, 28, 45 }, + }, + { /* Coeff Band 3 */ + { 23, 163, 200 }, + { 10, 131, 185 }, + { 2, 93, 148 }, + { 1, 67, 111 }, + { 1, 41, 69 }, + { 1, 14, 24 }, + }, + { /* Coeff Band 4 */ + { 29, 176, 217 }, + { 12, 145, 201 }, + { 3, 101, 156 }, + { 1, 69, 111 }, + { 1, 39, 63 }, + { 1, 14, 23 }, + }, + { /* Coeff Band 5 */ + { 57, 192, 233 }, + { 25, 154, 215 }, + { 6, 109, 167 }, + { 3, 78, 118 }, + { 1, 48, 69 }, + { 1, 21, 29 }, + }, + }, + { /* Inter */ + { /* Coeff Band 0 */ + { 202, 105, 245 }, + { 108, 106, 216 }, + { 18, 90, 144 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + }, + { /* Coeff Band 1 */ + { 33, 172, 219 }, + { 64, 149, 206 }, + { 14, 117, 177 }, + { 5, 90, 141 }, + { 2, 61, 95 }, + { 1, 37, 57 }, + }, + { /* Coeff Band 2 */ + { 33, 179, 220 }, + { 11, 140, 198 }, + { 1, 89, 148 }, + { 1, 60, 104 }, + { 1, 33, 57 }, + { 1, 12, 21 }, + }, + { /* Coeff Band 3 */ + { 30, 181, 221 }, + { 8, 141, 198 }, + { 1, 87, 145 }, + { 1, 58, 100 }, + { 1, 31, 55 }, + { 1, 12, 20 }, + }, + { /* Coeff Band 4 */ + { 32, 186, 224 }, + { 7, 142, 198 }, + { 1, 86, 143 }, + { 1, 58, 100 }, + { 1, 31, 55 }, + { 1, 12, 22 }, + }, + { /* Coeff Band 5 */ + { 57, 192, 227 }, + { 20, 143, 204 }, + { 3, 96, 154 }, + { 1, 68, 112 }, + { 1, 42, 69 }, + { 1, 19, 32 }, + }, + }, + }, + { /* block Type 1 */ + { /* Intra */ + { /* Coeff Band 0 */ + { 212, 35, 215 }, + { 113, 47, 169 }, + { 29, 48, 105 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + }, + { /* Coeff Band 1 */ + { 74, 129, 203 }, + { 106, 120, 203 }, + { 49, 107, 178 }, + { 19, 84, 144 }, + { 4, 50, 84 }, + { 1, 15, 25 }, + }, + { /* Coeff Band 2 */ + { 71, 172, 217 }, + { 44, 141, 209 }, + { 15, 102, 173 }, + { 6, 76, 133 }, + { 2, 51, 89 }, + { 1, 24, 42 }, + }, + { /* Coeff Band 3 */ + { 64, 185, 231 }, + { 31, 148, 216 }, + { 8, 103, 175 }, + { 3, 74, 131 }, + { 1, 46, 81 }, + { 1, 18, 30 }, + }, + { /* Coeff Band 4 */ + { 65, 196, 235 }, + { 25, 157, 221 }, + { 5, 105, 174 }, + { 1, 67, 120 }, + { 1, 38, 69 }, + { 1, 15, 30 }, + }, + { /* Coeff Band 5 */ + { 65, 204, 238 }, + { 30, 156, 224 }, + { 7, 107, 177 }, + { 2, 70, 124 }, + { 1, 42, 73 }, + { 1, 18, 34 }, + }, + }, + { /* Inter */ + { /* Coeff Band 0 */ + { 225, 86, 251 }, + { 144, 104, 235 }, + { 42, 99, 181 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + }, + { /* Coeff Band 1 */ + { 85, 175, 239 }, + { 112, 165, 229 }, + { 29, 136, 200 }, + { 12, 103, 162 }, + { 6, 77, 123 }, + { 2, 53, 84 }, + }, + { /* Coeff Band 2 */ + { 75, 183, 239 }, + { 30, 155, 221 }, + { 3, 106, 171 }, + { 1, 74, 128 }, + { 1, 44, 76 }, + { 1, 17, 28 }, + }, + { /* Coeff Band 3 */ + { 73, 185, 240 }, + { 27, 159, 222 }, + { 2, 107, 172 }, + { 1, 75, 127 }, + { 1, 42, 73 }, + { 1, 17, 29 }, + }, + { /* Coeff Band 4 */ + { 62, 190, 238 }, + { 21, 159, 222 }, + { 2, 107, 172 }, + { 1, 72, 122 }, + { 1, 40, 71 }, + { 1, 18, 32 }, + }, + { /* Coeff Band 5 */ + { 61, 199, 240 }, + { 27, 161, 226 }, + { 4, 113, 180 }, + { 1, 76, 129 }, + { 1, 46, 80 }, + { 1, 23, 41 }, + }, + }, + }, + }, + { /* tx = 16x16 */ + { /* block Type 0 */ + { /* Intra */ + { /* Coeff Band 0 */ + { 7, 27, 153 }, + { 5, 30, 95 }, + { 1, 16, 30 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + }, + { /* Coeff Band 1 */ + { 50, 75, 127 }, + { 57, 75, 124 }, + { 27, 67, 108 }, + { 10, 54, 86 }, + { 1, 33, 52 }, + { 1, 12, 18 }, + }, + { /* Coeff Band 2 */ + { 43, 125, 151 }, + { 26, 108, 148 }, + { 7, 83, 122 }, + { 2, 59, 89 }, + { 1, 38, 60 }, + { 1, 17, 27 }, + }, + { /* Coeff Band 3 */ + { 23, 144, 163 }, + { 13, 112, 154 }, + { 2, 75, 117 }, + { 1, 50, 81 }, + { 1, 31, 51 }, + { 1, 14, 23 }, + }, + { /* Coeff Band 4 */ + { 18, 162, 185 }, + { 6, 123, 171 }, + { 1, 78, 125 }, + { 1, 51, 86 }, + { 1, 31, 54 }, + { 1, 14, 23 }, + }, + { /* Coeff Band 5 */ + { 15, 199, 227 }, + { 3, 150, 204 }, + { 1, 91, 146 }, + { 1, 55, 95 }, + { 1, 30, 53 }, + { 1, 11, 20 }, + } + }, + { /* Inter */ + { /* Coeff Band 0 */ + { 19, 55, 240 }, + { 19, 59, 196 }, + { 3, 52, 105 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + }, + { /* Coeff Band 1 */ + { 41, 166, 207 }, + { 104, 153, 199 }, + { 31, 123, 181 }, + { 14, 101, 152 }, + { 5, 72, 106 }, + { 1, 36, 52 }, + }, + { /* Coeff Band 2 */ + { 35, 176, 211 }, + { 12, 131, 190 }, + { 2, 88, 144 }, + { 1, 60, 101 }, + { 1, 36, 60 }, + { 1, 16, 28 }, + }, + { /* Coeff Band 3 */ + { 28, 183, 213 }, + { 8, 134, 191 }, + { 1, 86, 142 }, + { 1, 56, 96 }, + { 1, 30, 53 }, + { 1, 12, 20 }, + }, + { /* Coeff Band 4 */ + { 20, 190, 215 }, + { 4, 135, 192 }, + { 1, 84, 139 }, + { 1, 53, 91 }, + { 1, 28, 49 }, + { 1, 11, 20 }, + }, + { /* Coeff Band 5 */ + { 13, 196, 216 }, + { 2, 137, 192 }, + { 1, 86, 143 }, + { 1, 57, 99 }, + { 1, 32, 56 }, + { 1, 13, 24 }, + }, + }, + }, + { /* block Type 1 */ + { /* Intra */ + { /* Coeff Band 0 */ + { 211, 29, 217 }, + { 96, 47, 156 }, + { 22, 43, 87 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + }, + { /* Coeff Band 1 */ + { 78, 120, 193 }, + { 111, 116, 186 }, + { 46, 102, 164 }, + { 15, 80, 128 }, + { 2, 49, 76 }, + { 1, 18, 28 }, + }, + { /* Coeff Band 2 */ + { 71, 161, 203 }, + { 42, 132, 192 }, + { 10, 98, 150 }, + { 3, 69, 109 }, + { 1, 44, 70 }, + { 1, 18, 29 }, + }, + { /* Coeff Band 3 */ + { 57, 186, 211 }, + { 30, 140, 196 }, + { 4, 93, 146 }, + { 1, 62, 102 }, + { 1, 38, 65 }, + { 1, 16, 27 }, + }, + { /* Coeff Band 4 */ + { 47, 199, 217 }, + { 14, 145, 196 }, + { 1, 88, 142 }, + { 1, 57, 98 }, + { 1, 36, 62 }, + { 1, 15, 26 }, + }, + { /* Coeff Band 5 */ + { 26, 219, 229 }, + { 5, 155, 207 }, + { 1, 94, 151 }, + { 1, 60, 104 }, + { 1, 36, 62 }, + { 1, 16, 28 }, + } + }, + { /* Inter */ + { /* Coeff Band 0 */ + { 233, 29, 248 }, + { 146, 47, 220 }, + { 43, 52, 140 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + }, + { /* Coeff Band 1 */ + { 100, 163, 232 }, + { 179, 161, 222 }, + { 63, 142, 204 }, + { 37, 113, 174 }, + { 26, 89, 137 }, + { 18, 68, 97 }, + }, + { /* Coeff Band 2 */ + { 85, 181, 230 }, + { 32, 146, 209 }, + { 7, 100, 164 }, + { 3, 71, 121 }, + { 1, 45, 77 }, + { 1, 18, 30 }, + }, + { /* Coeff Band 3 */ + { 65, 187, 230 }, + { 20, 148, 207 }, + { 2, 97, 159 }, + { 1, 68, 116 }, + { 1, 40, 70 }, + { 1, 14, 29 }, + }, + { /* Coeff Band 4 */ + { 40, 194, 227 }, + { 8, 147, 204 }, + { 1, 94, 155 }, + { 1, 65, 112 }, + { 1, 39, 66 }, + { 1, 14, 26 }, + }, + { /* Coeff Band 5 */ + { 16, 208, 228 }, + { 3, 151, 207 }, + { 1, 98, 160 }, + { 1, 67, 117 }, + { 1, 41, 74 }, + { 1, 17, 31 }, + }, + }, + }, + }, + { /* tx = 32x32 */ + { /* block Type 0 */ + { /* Intra */ + { /* Coeff Band 0 */ + { 17, 38, 140 }, + { 7, 34, 80 }, + { 1, 17, 29 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + }, + { /* Coeff Band 1 */ + { 37, 75, 128 }, + { 41, 76, 128 }, + { 26, 66, 116 }, + { 12, 52, 94 }, + { 2, 32, 55 }, + { 1, 10, 16 }, + }, + { /* Coeff Band 2 */ + { 50, 127, 154 }, + { 37, 109, 152 }, + { 16, 82, 121 }, + { 5, 59, 85 }, + { 1, 35, 54 }, + { 1, 13, 20 }, + }, + { /* Coeff Band 3 */ + { 40, 142, 167 }, + { 17, 110, 157 }, + { 2, 71, 112 }, + { 1, 44, 72 }, + { 1, 27, 45 }, + { 1, 11, 17 }, + }, + { /* Coeff Band 4 */ + { 30, 175, 188 }, + { 9, 124, 169 }, + { 1, 74, 116 }, + { 1, 48, 78 }, + { 1, 30, 49 }, + { 1, 11, 18 }, + }, + { /* Coeff Band 5 */ + { 10, 222, 223 }, + { 2, 150, 194 }, + { 1, 83, 128 }, + { 1, 48, 79 }, + { 1, 27, 45 }, + { 1, 11, 17 }, + }, + }, + { /* Inter */ + { /* Coeff Band 0 */ + { 36, 41, 235 }, + { 29, 36, 193 }, + { 10, 27, 111 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + }, + { /* Coeff Band 1 */ + { 85, 165, 222 }, + { 177, 162, 215 }, + { 110, 135, 195 }, + { 57, 113, 168 }, + { 23, 83, 120 }, + { 10, 49, 61 }, + }, + { /* Coeff Band 2 */ + { 85, 190, 223 }, + { 36, 139, 200 }, + { 5, 90, 146 }, + { 1, 60, 103 }, + { 1, 38, 65 }, + { 1, 18, 30 }, + }, + { /* Coeff Band 3 */ + { 72, 202, 223 }, + { 23, 141, 199 }, + { 2, 86, 140 }, + { 1, 56, 97 }, + { 1, 36, 61 }, + { 1, 16, 27 }, + }, + { /* Coeff Band 4 */ + { 55, 218, 225 }, + { 13, 145, 200 }, + { 1, 86, 141 }, + { 1, 57, 99 }, + { 1, 35, 61 }, + { 1, 13, 22 }, + }, + { /* Coeff Band 5 */ + { 15, 235, 212 }, + { 1, 132, 184 }, + { 1, 84, 139 }, + { 1, 57, 97 }, + { 1, 34, 56 }, + { 1, 14, 23 }, + }, + }, + }, + { /* block Type 1 */ + { /* Intra */ + { /* Coeff Band 0 */ + { 181, 21, 201 }, + { 61, 37, 123 }, + { 10, 38, 71 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + }, + { /* Coeff Band 1 */ + { 47, 106, 172 }, + { 95, 104, 173 }, + { 42, 93, 159 }, + { 18, 77, 131 }, + { 4, 50, 81 }, + { 1, 17, 23 }, + }, + { /* Coeff Band 2 */ + { 62, 147, 199 }, + { 44, 130, 189 }, + { 28, 102, 154 }, + { 18, 75, 115 }, + { 2, 44, 65 }, + { 1, 12, 19 }, + }, + { /* Coeff Band 3 */ + { 55, 153, 210 }, + { 24, 130, 194 }, + { 3, 93, 146 }, + { 1, 61, 97 }, + { 1, 31, 50 }, + { 1, 10, 16 }, + }, + { /* Coeff Band 4 */ + { 49, 186, 223 }, + { 17, 148, 204 }, + { 1, 96, 142 }, + { 1, 53, 83 }, + { 1, 26, 44 }, + { 1, 11, 17 }, + }, + { /* Coeff Band 5 */ + { 13, 217, 212 }, + { 2, 136, 180 }, + { 1, 78, 124 }, + { 1, 50, 83 }, + { 1, 29, 49 }, + { 1, 14, 23 }, + }, + }, + { /* Inter */ + { /* Coeff Band 0 */ + { 197, 13, 247 }, + { 82, 17, 222 }, + { 25, 17, 162 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + }, + { /* Coeff Band 1 */ + { 126, 186, 247 }, + { 234, 191, 243 }, + { 176, 177, 234 }, + { 104, 158, 220 }, + { 66, 128, 186 }, + { 55, 90, 137 }, + }, + { /* Coeff Band 2 */ + { 111, 197, 242 }, + { 46, 158, 219 }, + { 9, 104, 171 }, + { 2, 65, 125 }, + { 1, 44, 80 }, + { 1, 17, 91 }, + }, + { /* Coeff Band 3 */ + { 104, 208, 245 }, + { 39, 168, 224 }, + { 3, 109, 162 }, + { 1, 79, 124 }, + { 1, 50, 102 }, + { 1, 43, 102 }, + }, + { /* Coeff Band 4 */ + { 84, 220, 246 }, + { 31, 177, 231 }, + { 2, 115, 180 }, + { 1, 79, 134 }, + { 1, 55, 77 }, + { 1, 60, 79 }, + }, + { /* Coeff Band 5 */ + { 43, 243, 240 }, + { 8, 180, 217 }, + { 1, 115, 166 }, + { 1, 84, 121 }, + { 1, 51, 67 }, + { 1, 16, 6 }, + }, + }, + }, + }, + }, + + .skip = { 192, 128, 64 }, + .inter_mode = { + { 2, 173, 34 }, + { 7, 145, 85 }, + { 7, 166, 63 }, + { 7, 94, 66 }, + { 8, 64, 46 }, + { 17, 81, 31 }, + { 25, 29, 30 }, + }, + .interp_filter = { + { 235, 162 }, + { 36, 255 }, + { 34, 3 }, + { 149, 144 }, + }, + .is_inter = { 9, 102, 187, 225 }, + .comp_mode = { 239, 183, 119, 96, 41 }, + .single_ref = { + { 33, 16 }, + { 77, 74 }, + { 142, 142 }, + { 172, 170 }, + { 238, 247 }, + }, + .comp_ref = { 50, 126, 123, 221, 226 }, + .y_mode = { + { 65, 32, 18, 144, 162, 194, 41, 51, 98 }, + { 132, 68, 18, 165, 217, 196, 45, 40, 78 }, + { 173, 80, 19, 176, 240, 193, 64, 35, 46 }, + { 221, 135, 38, 194, 248, 121, 96, 85, 29 }, + }, + .uv_mode = { + { 120, 7, 76, 176, 208, 126, 28, 54, 103 } /* y = dc */, + { 48, 12, 154, 155, 139, 90, 34, 117, 119 } /* y = v */, + { 67, 6, 25, 204, 243, 158, 13, 21, 96 } /* y = h */, + { 97, 5, 44, 131, 176, 139, 48, 68, 97 } /* y = d45 */, + { 83, 5, 42, 156, 111, 152, 26, 49, 152 } /* y = d135 */, + { 80, 5, 58, 178, 74, 83, 33, 62, 145 } /* y = d117 */, + { 86, 5, 32, 154, 192, 168, 14, 22, 163 } /* y = d153 */, + { 85, 5, 32, 156, 216, 148, 19, 29, 73 } /* y = d207 */, + { 77, 7, 64, 116, 132, 122, 37, 126, 120 } /* y = d63 */, + { 101, 21, 107, 181, 192, 103, 19, 67, 125 } /* y = tm */ + }, + .partition = { + /* 8x8 -> 4x4 */ + { 199, 122, 141 } /* a/l both not split */, + { 147, 63, 159 } /* a split, l not split */, + { 148, 133, 118 } /* l split, a not split */, + { 121, 104, 114 } /* a/l both split */, + /* 16x16 -> 8x8 */ + { 174, 73, 87 } /* a/l both not split */, + { 92, 41, 83 } /* a split, l not split */, + { 82, 99, 50 } /* l split, a not split */, + { 53, 39, 39 } /* a/l both split */, + /* 32x32 -> 16x16 */ + { 177, 58, 59 } /* a/l both not split */, + { 68, 26, 63 } /* a split, l not split */, + { 52, 79, 25 } /* l split, a not split */, + { 17, 14, 12 } /* a/l both split */, + /* 64x64 -> 32x32 */ + { 222, 34, 30 } /* a/l both not split */, + { 72, 16, 44 } /* a split, l not split */, + { 58, 32, 12 } /* l split, a not split */, + { 10, 7, 6 } /* a/l both split */, + }, + + .mv = { + .joint = { 32, 64, 96 }, + .sign = { 128, 128 }, + .classes = { + { 224, 144, 192, 168, 192, 176, 192, 198, 198, 245 }, + { 216, 128, 176, 160, 176, 176, 192, 198, 198, 208 }, + }, + .class0_bit = { 216, 208 }, + .bits = { + { 136, 140, 148, 160, 176, 192, 224, 234, 234, 240}, + { 136, 140, 148, 160, 176, 192, 224, 234, 234, 240}, + }, + .class0_fr = { + { + { 128, 128, 64 }, + { 96, 112, 64 }, + }, + { + { 128, 128, 64 }, + { 96, 112, 64 }, + }, + }, + .fr = { + { 64, 96, 64 }, + { 64, 96, 64 }, + }, + .class0_hp = { 160, 160 }, + .hp = { 128, 128 }, + }, +}; +EXPORT_SYMBOL_GPL(v4l2_vp9_default_probs); + +static u32 fastdiv(u32 dividend, u16 divisor) +{ +#define DIV_INV(d) ((u32)(((1ULL << 32) + ((d) - 1)) / (d))) +#define DIVS_INV(d0, d1, d2, d3, d4, d5, d6, d7, d8, d9) \ + DIV_INV(d0), DIV_INV(d1), DIV_INV(d2), DIV_INV(d3), \ + DIV_INV(d4), DIV_INV(d5), DIV_INV(d6), DIV_INV(d7), \ + DIV_INV(d8), DIV_INV(d9) + + static const u32 inv[] = { + DIV_INV(2), DIV_INV(3), DIV_INV(4), DIV_INV(5), + DIV_INV(6), DIV_INV(7), DIV_INV(8), DIV_INV(9), + DIVS_INV(10, 11, 12, 13, 14, 15, 16, 17, 18, 19), + DIVS_INV(20, 21, 22, 23, 24, 25, 26, 27, 28, 29), + DIVS_INV(30, 31, 32, 33, 34, 35, 36, 37, 38, 39), + DIVS_INV(40, 41, 42, 43, 44, 45, 46, 47, 48, 49), + DIVS_INV(50, 51, 52, 53, 54, 55, 56, 57, 58, 59), + DIVS_INV(60, 61, 62, 63, 64, 65, 66, 67, 68, 69), + DIVS_INV(70, 71, 72, 73, 74, 75, 76, 77, 78, 79), + DIVS_INV(80, 81, 82, 83, 84, 85, 86, 87, 88, 89), + DIVS_INV(90, 91, 92, 93, 94, 95, 96, 97, 98, 99), + DIVS_INV(100, 101, 102, 103, 104, 105, 106, 107, 108, 109), + DIVS_INV(110, 111, 112, 113, 114, 115, 116, 117, 118, 119), + DIVS_INV(120, 121, 122, 123, 124, 125, 126, 127, 128, 129), + DIVS_INV(130, 131, 132, 133, 134, 135, 136, 137, 138, 139), + DIVS_INV(140, 141, 142, 143, 144, 145, 146, 147, 148, 149), + DIVS_INV(150, 151, 152, 153, 154, 155, 156, 157, 158, 159), + DIVS_INV(160, 161, 162, 163, 164, 165, 166, 167, 168, 169), + DIVS_INV(170, 171, 172, 173, 174, 175, 176, 177, 178, 179), + DIVS_INV(180, 181, 182, 183, 184, 185, 186, 187, 188, 189), + DIVS_INV(190, 191, 192, 193, 194, 195, 196, 197, 198, 199), + DIVS_INV(200, 201, 202, 203, 204, 205, 206, 207, 208, 209), + DIVS_INV(210, 211, 212, 213, 214, 215, 216, 217, 218, 219), + DIVS_INV(220, 221, 222, 223, 224, 225, 226, 227, 228, 229), + DIVS_INV(230, 231, 232, 233, 234, 235, 236, 237, 238, 239), + DIVS_INV(240, 241, 242, 243, 244, 245, 246, 247, 248, 249), + DIV_INV(250), DIV_INV(251), DIV_INV(252), DIV_INV(253), + DIV_INV(254), DIV_INV(255), DIV_INV(256), + }; + + if (divisor == 0) + return 0; + else if (divisor == 1) + return dividend; + + if (WARN_ON(divisor - 2 >= ARRAY_SIZE(inv))) + return dividend; + + return ((u64)dividend * inv[divisor - 2]) >> 32; +} + +/* 6.3.6 inv_recenter_nonneg(v, m) */ +static int inv_recenter_nonneg(int v, int m) +{ + if (v > 2 * m) + return v; + + if (v & 1) + return m - ((v + 1) >> 1); + + return m + (v >> 1); +} + +/* + * part of 6.3.5 inv_remap_prob(deltaProb, prob) + * delta = inv_map_table[deltaProb] done by userspace + */ +static int update_prob(int delta, int prob) +{ + if (!delta) + return prob; + + return prob <= 128 ? + 1 + inv_recenter_nonneg(delta, prob - 1) : + 255 - inv_recenter_nonneg(delta, 255 - prob); +} + +/* Counterpart to 6.3.2 tx_mode_probs() */ +static void update_tx_probs(struct v4l2_vp9_frame_context *probs, + const struct v4l2_ctrl_vp9_compressed_hdr *deltas) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(probs->tx8); i++) { + u8 *p8x8 = probs->tx8[i]; + u8 *p16x16 = probs->tx16[i]; + u8 *p32x32 = probs->tx32[i]; + const u8 *d8x8 = deltas->tx8[i]; + const u8 *d16x16 = deltas->tx16[i]; + const u8 *d32x32 = deltas->tx32[i]; + + p8x8[0] = update_prob(d8x8[0], p8x8[0]); + p16x16[0] = update_prob(d16x16[0], p16x16[0]); + p16x16[1] = update_prob(d16x16[1], p16x16[1]); + p32x32[0] = update_prob(d32x32[0], p32x32[0]); + p32x32[1] = update_prob(d32x32[1], p32x32[1]); + p32x32[2] = update_prob(d32x32[2], p32x32[2]); + } +} + +#define BAND_6(band) ((band) == 0 ? 3 : 6) + +static void update_coeff(const u8 deltas[6][6][3], u8 probs[6][6][3]) +{ + int l, m, n; + + for (l = 0; l < 6; l++) + for (m = 0; m < BAND_6(l); m++) { + u8 *p = probs[l][m]; + const u8 *d = deltas[l][m]; + + for (n = 0; n < 3; n++) + p[n] = update_prob(d[n], p[n]); + } +} + +/* Counterpart to 6.3.7 read_coef_probs() */ +static void update_coef_probs(struct v4l2_vp9_frame_context *probs, + const struct v4l2_ctrl_vp9_compressed_hdr *deltas, + const struct v4l2_ctrl_vp9_frame *dec_params) +{ + int i, j, k; + + for (i = 0; i < ARRAY_SIZE(probs->coef); i++) { + for (j = 0; j < ARRAY_SIZE(probs->coef[0]); j++) + for (k = 0; k < ARRAY_SIZE(probs->coef[0][0]); k++) + update_coeff(deltas->coef[i][j][k], probs->coef[i][j][k]); + + if (deltas->tx_mode == i) + break; + } +} + +/* Counterpart to 6.3.8 read_skip_prob() */ +static void update_skip_probs(struct v4l2_vp9_frame_context *probs, + const struct v4l2_ctrl_vp9_compressed_hdr *deltas) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(probs->skip); i++) + probs->skip[i] = update_prob(deltas->skip[i], probs->skip[i]); +} + +/* Counterpart to 6.3.9 read_inter_mode_probs() */ +static void update_inter_mode_probs(struct v4l2_vp9_frame_context *probs, + const struct v4l2_ctrl_vp9_compressed_hdr *deltas) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(probs->inter_mode); i++) { + u8 *p = probs->inter_mode[i]; + const u8 *d = deltas->inter_mode[i]; + + p[0] = update_prob(d[0], p[0]); + p[1] = update_prob(d[1], p[1]); + p[2] = update_prob(d[2], p[2]); + } +} + +/* Counterpart to 6.3.10 read_interp_filter_probs() */ +static void update_interp_filter_probs(struct v4l2_vp9_frame_context *probs, + const struct v4l2_ctrl_vp9_compressed_hdr *deltas) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(probs->interp_filter); i++) { + u8 *p = probs->interp_filter[i]; + const u8 *d = deltas->interp_filter[i]; + + p[0] = update_prob(d[0], p[0]); + p[1] = update_prob(d[1], p[1]); + } +} + +/* Counterpart to 6.3.11 read_is_inter_probs() */ +static void update_is_inter_probs(struct v4l2_vp9_frame_context *probs, + const struct v4l2_ctrl_vp9_compressed_hdr *deltas) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(probs->is_inter); i++) + probs->is_inter[i] = update_prob(deltas->is_inter[i], probs->is_inter[i]); +} + +/* 6.3.12 frame_reference_mode() done entirely in userspace */ + +/* Counterpart to 6.3.13 frame_reference_mode_probs() */ +static void +update_frame_reference_mode_probs(unsigned int reference_mode, + struct v4l2_vp9_frame_context *probs, + const struct v4l2_ctrl_vp9_compressed_hdr *deltas) +{ + int i; + + if (reference_mode == V4L2_VP9_REFERENCE_MODE_SELECT) + for (i = 0; i < ARRAY_SIZE(probs->comp_mode); i++) + probs->comp_mode[i] = update_prob(deltas->comp_mode[i], + probs->comp_mode[i]); + + if (reference_mode != V4L2_VP9_REFERENCE_MODE_COMPOUND_REFERENCE) + for (i = 0; i < ARRAY_SIZE(probs->single_ref); i++) { + u8 *p = probs->single_ref[i]; + const u8 *d = deltas->single_ref[i]; + + p[0] = update_prob(d[0], p[0]); + p[1] = update_prob(d[1], p[1]); + } + + if (reference_mode != V4L2_VP9_REFERENCE_MODE_SINGLE_REFERENCE) + for (i = 0; i < ARRAY_SIZE(probs->comp_ref); i++) + probs->comp_ref[i] = update_prob(deltas->comp_ref[i], probs->comp_ref[i]); +} + +/* Counterpart to 6.3.14 read_y_mode_probs() */ +static void update_y_mode_probs(struct v4l2_vp9_frame_context *probs, + const struct v4l2_ctrl_vp9_compressed_hdr *deltas) +{ + int i, j; + + for (i = 0; i < ARRAY_SIZE(probs->y_mode); i++) + for (j = 0; j < ARRAY_SIZE(probs->y_mode[0]); ++j) + probs->y_mode[i][j] = + update_prob(deltas->y_mode[i][j], probs->y_mode[i][j]); +} + +/* Counterpart to 6.3.15 read_partition_probs() */ +static void update_partition_probs(struct v4l2_vp9_frame_context *probs, + const struct v4l2_ctrl_vp9_compressed_hdr *deltas) +{ + int i, j; + + for (i = 0; i < 4; i++) + for (j = 0; j < 4; j++) { + u8 *p = probs->partition[i * 4 + j]; + const u8 *d = deltas->partition[i * 4 + j]; + + p[0] = update_prob(d[0], p[0]); + p[1] = update_prob(d[1], p[1]); + p[2] = update_prob(d[2], p[2]); + } +} + +static inline int update_mv_prob(int delta, int prob) +{ + if (!delta) + return prob; + + return delta; +} + +/* Counterpart to 6.3.16 mv_probs() */ +static void update_mv_probs(struct v4l2_vp9_frame_context *probs, + const struct v4l2_ctrl_vp9_compressed_hdr *deltas, + const struct v4l2_ctrl_vp9_frame *dec_params) +{ + u8 *p = probs->mv.joint; + const u8 *d = deltas->mv.joint; + unsigned int i, j; + + p[0] = update_mv_prob(d[0], p[0]); + p[1] = update_mv_prob(d[1], p[1]); + p[2] = update_mv_prob(d[2], p[2]); + + for (i = 0; i < ARRAY_SIZE(probs->mv.sign); i++) { + p = probs->mv.sign; + d = deltas->mv.sign; + p[i] = update_mv_prob(d[i], p[i]); + + p = probs->mv.classes[i]; + d = deltas->mv.classes[i]; + for (j = 0; j < ARRAY_SIZE(probs->mv.classes[0]); j++) + p[j] = update_mv_prob(d[j], p[j]); + + p = probs->mv.class0_bit; + d = deltas->mv.class0_bit; + p[i] = update_mv_prob(d[i], p[i]); + + p = probs->mv.bits[i]; + d = deltas->mv.bits[i]; + for (j = 0; j < ARRAY_SIZE(probs->mv.bits[0]); j++) + p[j] = update_mv_prob(d[j], p[j]); + + for (j = 0; j < ARRAY_SIZE(probs->mv.class0_fr[0]); j++) { + p = probs->mv.class0_fr[i][j]; + d = deltas->mv.class0_fr[i][j]; + + p[0] = update_mv_prob(d[0], p[0]); + p[1] = update_mv_prob(d[1], p[1]); + p[2] = update_mv_prob(d[2], p[2]); + } + + p = probs->mv.fr[i]; + d = deltas->mv.fr[i]; + for (j = 0; j < ARRAY_SIZE(probs->mv.fr[i]); j++) + p[j] = update_mv_prob(d[j], p[j]); + + if (dec_params->flags & V4L2_VP9_FRAME_FLAG_ALLOW_HIGH_PREC_MV) { + p = probs->mv.class0_hp; + d = deltas->mv.class0_hp; + p[i] = update_mv_prob(d[i], p[i]); + + p = probs->mv.hp; + d = deltas->mv.hp; + p[i] = update_mv_prob(d[i], p[i]); + } + } +} + +/* Counterpart to 6.3 compressed_header(), but parsing has been done in userspace. */ +void v4l2_vp9_fw_update_probs(struct v4l2_vp9_frame_context *probs, + const struct v4l2_ctrl_vp9_compressed_hdr *deltas, + const struct v4l2_ctrl_vp9_frame *dec_params) +{ + if (deltas->tx_mode == V4L2_VP9_TX_MODE_SELECT) + update_tx_probs(probs, deltas); + + update_coef_probs(probs, deltas, dec_params); + + update_skip_probs(probs, deltas); + + if (dec_params->flags & V4L2_VP9_FRAME_FLAG_KEY_FRAME || + dec_params->flags & V4L2_VP9_FRAME_FLAG_INTRA_ONLY) + return; + + update_inter_mode_probs(probs, deltas); + + if (dec_params->interpolation_filter == V4L2_VP9_INTERP_FILTER_SWITCHABLE) + update_interp_filter_probs(probs, deltas); + + update_is_inter_probs(probs, deltas); + + update_frame_reference_mode_probs(dec_params->reference_mode, probs, deltas); + + update_y_mode_probs(probs, deltas); + + update_partition_probs(probs, deltas); + + update_mv_probs(probs, deltas, dec_params); +} +EXPORT_SYMBOL_GPL(v4l2_vp9_fw_update_probs); + +u8 v4l2_vp9_reset_frame_ctx(const struct v4l2_ctrl_vp9_frame *dec_params, + struct v4l2_vp9_frame_context *frame_context) +{ + int i; + + u8 fctx_idx = dec_params->frame_context_idx; + + if (dec_params->flags & V4L2_VP9_FRAME_FLAG_KEY_FRAME || + dec_params->flags & V4L2_VP9_FRAME_FLAG_INTRA_ONLY || + dec_params->flags & V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT) { + /* + * setup_past_independence() + * We do nothing here. Instead of storing default probs in some intermediate + * location and then copying from that location to appropriate contexts + * in save_probs() below, we skip that step and save default probs directly + * to appropriate contexts. + */ + if (dec_params->flags & V4L2_VP9_FRAME_FLAG_KEY_FRAME || + dec_params->flags & V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT || + dec_params->reset_frame_context == V4L2_VP9_RESET_FRAME_CTX_ALL) + for (i = 0; i < 4; ++i) + /* save_probs(i) */ + memcpy(&frame_context[i], &v4l2_vp9_default_probs, + sizeof(v4l2_vp9_default_probs)); + else if (dec_params->reset_frame_context == V4L2_VP9_RESET_FRAME_CTX_SPEC) + /* save_probs(fctx_idx) */ + memcpy(&frame_context[fctx_idx], &v4l2_vp9_default_probs, + sizeof(v4l2_vp9_default_probs)); + fctx_idx = 0; + } + + return fctx_idx; +} +EXPORT_SYMBOL_GPL(v4l2_vp9_reset_frame_ctx); + +/* 8.4.1 Merge prob process */ +static u8 merge_prob(u8 pre_prob, u32 ct0, u32 ct1, u16 count_sat, u32 max_update_factor) +{ + u32 den, prob, count, factor; + + den = ct0 + ct1; + if (!den) { + /* + * prob = 128, count = 0, update_factor = 0 + * Round2's argument: pre_prob * 256 + * (pre_prob * 256 + 128) >> 8 == pre_prob + */ + return pre_prob; + } + + prob = clamp(((ct0 << 8) + (den >> 1)) / den, (u32)1, (u32)255); + count = min_t(u32, den, count_sat); + factor = fastdiv(max_update_factor * count, count_sat); + + /* + * Round2(pre_prob * (256 - factor) + prob * factor, 8) + * Round2(pre_prob * 256 + (prob - pre_prob) * factor, 8) + * (pre_prob * 256 >> 8) + (((prob - pre_prob) * factor + 128) >> 8) + */ + return pre_prob + (((prob - pre_prob) * factor + 128) >> 8); +} + +static inline u8 noncoef_merge_prob(u8 pre_prob, u32 ct0, u32 ct1) +{ + return merge_prob(pre_prob, ct0, ct1, 20, 128); +} + +/* 8.4.2 Merge probs process */ +/* + * merge_probs() is a recursive function in the spec. We avoid recursion in the kernel. + * That said, the "tree" parameter of merge_probs() controls how deep the recursion goes. + * It turns out that in all cases the recursive calls boil down to a short-ish series + * of merge_prob() invocations (note no "s"). + * + * Variant A + * --------- + * merge_probs(small_token_tree, 2): + * merge_prob(p[1], c[0], c[1] + c[2]) + * merge_prob(p[2], c[1], c[2]) + * + * Variant B + * --------- + * merge_probs(binary_tree, 0) or + * merge_probs(tx_size_8_tree, 0): + * merge_prob(p[0], c[0], c[1]) + * + * Variant C + * --------- + * merge_probs(inter_mode_tree, 0): + * merge_prob(p[0], c[2], c[1] + c[0] + c[3]) + * merge_prob(p[1], c[0], c[1] + c[3]) + * merge_prob(p[2], c[1], c[3]) + * + * Variant D + * --------- + * merge_probs(intra_mode_tree, 0): + * merge_prob(p[0], c[0], c[1] + ... + c[9]) + * merge_prob(p[1], c[9], c[1] + ... + c[8]) + * merge_prob(p[2], c[1], c[2] + ... + c[8]) + * merge_prob(p[3], c[2] + c[4] + c[5], c[3] + c[8] + c[6] + c[7]) + * merge_prob(p[4], c[2], c[4] + c[5]) + * merge_prob(p[5], c[4], c[5]) + * merge_prob(p[6], c[3], c[8] + c[6] + c[7]) + * merge_prob(p[7], c[8], c[6] + c[7]) + * merge_prob(p[8], c[6], c[7]) + * + * Variant E + * --------- + * merge_probs(partition_tree, 0) or + * merge_probs(tx_size_32_tree, 0) or + * merge_probs(mv_joint_tree, 0) or + * merge_probs(mv_fr_tree, 0): + * merge_prob(p[0], c[0], c[1] + c[2] + c[3]) + * merge_prob(p[1], c[1], c[2] + c[3]) + * merge_prob(p[2], c[2], c[3]) + * + * Variant F + * --------- + * merge_probs(interp_filter_tree, 0) or + * merge_probs(tx_size_16_tree, 0): + * merge_prob(p[0], c[0], c[1] + c[2]) + * merge_prob(p[1], c[1], c[2]) + * + * Variant G + * --------- + * merge_probs(mv_class_tree, 0): + * merge_prob(p[0], c[0], c[1] + ... + c[10]) + * merge_prob(p[1], c[1], c[2] + ... + c[10]) + * merge_prob(p[2], c[2] + c[3], c[4] + ... + c[10]) + * merge_prob(p[3], c[2], c[3]) + * merge_prob(p[4], c[4] + c[5], c[6] + ... + c[10]) + * merge_prob(p[5], c[4], c[5]) + * merge_prob(p[6], c[6], c[7] + ... + c[10]) + * merge_prob(p[7], c[7] + c[8], c[9] + c[10]) + * merge_prob(p[8], c[7], c[8]) + * merge_prob(p[9], c[9], [10]) + */ + +static inline void merge_probs_variant_a(u8 *p, const u32 *c, u16 count_sat, u32 update_factor) +{ + p[1] = merge_prob(p[1], c[0], c[1] + c[2], count_sat, update_factor); + p[2] = merge_prob(p[2], c[1], c[2], count_sat, update_factor); +} + +static inline void merge_probs_variant_b(u8 *p, const u32 *c, u16 count_sat, u32 update_factor) +{ + p[0] = merge_prob(p[0], c[0], c[1], count_sat, update_factor); +} + +static inline void merge_probs_variant_c(u8 *p, const u32 *c) +{ + p[0] = noncoef_merge_prob(p[0], c[2], c[1] + c[0] + c[3]); + p[1] = noncoef_merge_prob(p[1], c[0], c[1] + c[3]); + p[2] = noncoef_merge_prob(p[2], c[1], c[3]); +} + +static void merge_probs_variant_d(u8 *p, const u32 *c) +{ + u32 sum = 0, s2; + + sum = c[1] + c[2] + c[3] + c[4] + c[5] + c[6] + c[7] + c[8] + c[9]; + + p[0] = noncoef_merge_prob(p[0], c[0], sum); + sum -= c[9]; + p[1] = noncoef_merge_prob(p[1], c[9], sum); + sum -= c[1]; + p[2] = noncoef_merge_prob(p[2], c[1], sum); + s2 = c[2] + c[4] + c[5]; + sum -= s2; + p[3] = noncoef_merge_prob(p[3], s2, sum); + s2 -= c[2]; + p[4] = noncoef_merge_prob(p[4], c[2], s2); + p[5] = noncoef_merge_prob(p[5], c[4], c[5]); + sum -= c[3]; + p[6] = noncoef_merge_prob(p[6], c[3], sum); + sum -= c[8]; + p[7] = noncoef_merge_prob(p[7], c[8], sum); + p[8] = noncoef_merge_prob(p[8], c[6], c[7]); +} + +static inline void merge_probs_variant_e(u8 *p, const u32 *c) +{ + p[0] = noncoef_merge_prob(p[0], c[0], c[1] + c[2] + c[3]); + p[1] = noncoef_merge_prob(p[1], c[1], c[2] + c[3]); + p[2] = noncoef_merge_prob(p[2], c[2], c[3]); +} + +static inline void merge_probs_variant_f(u8 *p, const u32 *c) +{ + p[0] = noncoef_merge_prob(p[0], c[0], c[1] + c[2]); + p[1] = noncoef_merge_prob(p[1], c[1], c[2]); +} + +static void merge_probs_variant_g(u8 *p, const u32 *c) +{ + u32 sum; + + sum = c[1] + c[2] + c[3] + c[4] + c[5] + c[6] + c[7] + c[8] + c[9] + c[10]; + p[0] = noncoef_merge_prob(p[0], c[0], sum); + sum -= c[1]; + p[1] = noncoef_merge_prob(p[1], c[1], sum); + sum -= c[2] + c[3]; + p[2] = noncoef_merge_prob(p[2], c[2] + c[3], sum); + p[3] = noncoef_merge_prob(p[3], c[2], c[3]); + sum -= c[4] + c[5]; + p[4] = noncoef_merge_prob(p[4], c[4] + c[5], sum); + p[5] = noncoef_merge_prob(p[5], c[4], c[5]); + sum -= c[6]; + p[6] = noncoef_merge_prob(p[6], c[6], sum); + p[7] = noncoef_merge_prob(p[7], c[7] + c[8], c[9] + c[10]); + p[8] = noncoef_merge_prob(p[8], c[7], c[8]); + p[9] = noncoef_merge_prob(p[9], c[9], c[10]); +} + +/* 8.4.3 Coefficient probability adaptation process */ +static inline void adapt_probs_variant_a_coef(u8 *p, const u32 *c, u32 update_factor) +{ + merge_probs_variant_a(p, c, 24, update_factor); +} + +static inline void adapt_probs_variant_b_coef(u8 *p, const u32 *c, u32 update_factor) +{ + merge_probs_variant_b(p, c, 24, update_factor); +} + +static void _adapt_coeff(unsigned int i, unsigned int j, unsigned int k, + struct v4l2_vp9_frame_context *probs, + const struct v4l2_vp9_frame_symbol_counts *counts, + u32 uf) +{ + s32 l, m; + + for (l = 0; l < ARRAY_SIZE(probs->coef[0][0][0]); l++) { + for (m = 0; m < BAND_6(l); m++) { + u8 *p = probs->coef[i][j][k][l][m]; + const u32 counts_more_coefs[2] = { + *counts->eob[i][j][k][l][m][1], + *counts->eob[i][j][k][l][m][0] - *counts->eob[i][j][k][l][m][1], + }; + + adapt_probs_variant_a_coef(p, *counts->coeff[i][j][k][l][m], uf); + adapt_probs_variant_b_coef(p, counts_more_coefs, uf); + } + } +} + +static void _adapt_coef_probs(struct v4l2_vp9_frame_context *probs, + const struct v4l2_vp9_frame_symbol_counts *counts, + unsigned int uf) +{ + unsigned int i, j, k; + + for (i = 0; i < ARRAY_SIZE(probs->coef); i++) + for (j = 0; j < ARRAY_SIZE(probs->coef[0]); j++) + for (k = 0; k < ARRAY_SIZE(probs->coef[0][0]); k++) + _adapt_coeff(i, j, k, probs, counts, uf); +} + +void v4l2_vp9_adapt_coef_probs(struct v4l2_vp9_frame_context *probs, + struct v4l2_vp9_frame_symbol_counts *counts, + bool use_128, + bool frame_is_intra) +{ + if (frame_is_intra) { + _adapt_coef_probs(probs, counts, 112); + } else { + if (use_128) + _adapt_coef_probs(probs, counts, 128); + else + _adapt_coef_probs(probs, counts, 112); + } +} +EXPORT_SYMBOL_GPL(v4l2_vp9_adapt_coef_probs); + +/* 8.4.4 Non coefficient probability adaptation process, adapt_probs() */ +static inline void adapt_probs_variant_b(u8 *p, const u32 *c) +{ + merge_probs_variant_b(p, c, 20, 128); +} + +static inline void adapt_probs_variant_c(u8 *p, const u32 *c) +{ + merge_probs_variant_c(p, c); +} + +static inline void adapt_probs_variant_d(u8 *p, const u32 *c) +{ + merge_probs_variant_d(p, c); +} + +static inline void adapt_probs_variant_e(u8 *p, const u32 *c) +{ + merge_probs_variant_e(p, c); +} + +static inline void adapt_probs_variant_f(u8 *p, const u32 *c) +{ + merge_probs_variant_f(p, c); +} + +static inline void adapt_probs_variant_g(u8 *p, const u32 *c) +{ + merge_probs_variant_g(p, c); +} + +/* 8.4.4 Non coefficient probability adaptation process, adapt_prob() */ +static inline u8 adapt_prob(u8 prob, const u32 counts[2]) +{ + return noncoef_merge_prob(prob, counts[0], counts[1]); +} + +/* 8.4.4 Non coefficient probability adaptation process */ +void v4l2_vp9_adapt_noncoef_probs(struct v4l2_vp9_frame_context *probs, + struct v4l2_vp9_frame_symbol_counts *counts, + u8 reference_mode, u8 interpolation_filter, u8 tx_mode, + u32 flags) +{ + unsigned int i, j; + + for (i = 0; i < ARRAY_SIZE(probs->is_inter); i++) + probs->is_inter[i] = adapt_prob(probs->is_inter[i], (*counts->intra_inter)[i]); + + for (i = 0; i < ARRAY_SIZE(probs->comp_mode); i++) + probs->comp_mode[i] = adapt_prob(probs->comp_mode[i], (*counts->comp)[i]); + + for (i = 0; i < ARRAY_SIZE(probs->comp_ref); i++) + probs->comp_ref[i] = adapt_prob(probs->comp_ref[i], (*counts->comp_ref)[i]); + + if (reference_mode != V4L2_VP9_REFERENCE_MODE_COMPOUND_REFERENCE) + for (i = 0; i < ARRAY_SIZE(probs->single_ref); i++) + for (j = 0; j < ARRAY_SIZE(probs->single_ref[0]); j++) + probs->single_ref[i][j] = adapt_prob(probs->single_ref[i][j], + (*counts->single_ref)[i][j]); + + for (i = 0; i < ARRAY_SIZE(probs->inter_mode); i++) + adapt_probs_variant_c(probs->inter_mode[i], (*counts->mv_mode)[i]); + + for (i = 0; i < ARRAY_SIZE(probs->y_mode); i++) + adapt_probs_variant_d(probs->y_mode[i], (*counts->y_mode)[i]); + + for (i = 0; i < ARRAY_SIZE(probs->uv_mode); i++) + adapt_probs_variant_d(probs->uv_mode[i], (*counts->uv_mode)[i]); + + for (i = 0; i < ARRAY_SIZE(probs->partition); i++) + adapt_probs_variant_e(probs->partition[i], (*counts->partition)[i]); + + for (i = 0; i < ARRAY_SIZE(probs->skip); i++) + probs->skip[i] = adapt_prob(probs->skip[i], (*counts->skip)[i]); + + if (interpolation_filter == V4L2_VP9_INTERP_FILTER_SWITCHABLE) + for (i = 0; i < ARRAY_SIZE(probs->interp_filter); i++) + adapt_probs_variant_f(probs->interp_filter[i], (*counts->filter)[i]); + + if (tx_mode == V4L2_VP9_TX_MODE_SELECT) + for (i = 0; i < ARRAY_SIZE(probs->tx8); i++) { + adapt_probs_variant_b(probs->tx8[i], (*counts->tx8p)[i]); + adapt_probs_variant_f(probs->tx16[i], (*counts->tx16p)[i]); + adapt_probs_variant_e(probs->tx32[i], (*counts->tx32p)[i]); + } + + adapt_probs_variant_e(probs->mv.joint, *counts->mv_joint); + + for (i = 0; i < ARRAY_SIZE(probs->mv.sign); i++) { + probs->mv.sign[i] = adapt_prob(probs->mv.sign[i], (*counts->sign)[i]); + + adapt_probs_variant_g(probs->mv.classes[i], (*counts->classes)[i]); + + probs->mv.class0_bit[i] = adapt_prob(probs->mv.class0_bit[i], (*counts->class0)[i]); + + for (j = 0; j < ARRAY_SIZE(probs->mv.bits[0]); j++) + probs->mv.bits[i][j] = adapt_prob(probs->mv.bits[i][j], + (*counts->bits)[i][j]); + + for (j = 0; j < ARRAY_SIZE(probs->mv.class0_fr[0]); j++) + adapt_probs_variant_e(probs->mv.class0_fr[i][j], + (*counts->class0_fp)[i][j]); + + adapt_probs_variant_e(probs->mv.fr[i], (*counts->fp)[i]); + + if (!(flags & V4L2_VP9_FRAME_FLAG_ALLOW_HIGH_PREC_MV)) + continue; + + probs->mv.class0_hp[i] = adapt_prob(probs->mv.class0_hp[i], + (*counts->class0_hp)[i]); + + probs->mv.hp[i] = adapt_prob(probs->mv.hp[i], (*counts->hp)[i]); + } +} +EXPORT_SYMBOL_GPL(v4l2_vp9_adapt_noncoef_probs); + +bool +v4l2_vp9_seg_feat_enabled(const u8 *feature_enabled, + unsigned int feature, + unsigned int segid) +{ + u8 mask = V4L2_VP9_SEGMENT_FEATURE_ENABLED(feature); + + return !!(feature_enabled[segid] & mask); +} +EXPORT_SYMBOL_GPL(v4l2_vp9_seg_feat_enabled); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("V4L2 VP9 Helpers"); +MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@collabora.com>"); |