diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-10 01:45:54 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-10 01:45:54 +0300 |
commit | 96a6de1a541c86e9e67b9c310c14db4099bd1cbc (patch) | |
tree | e77eb0e998e996f53dd0709611bd8cdd8776ee70 /drivers/media | |
parent | 36011ddc78395b59a8a418c37f20bcc18828f1ef (diff) | |
parent | 15d90a6ae98e6d2c68497b44a491cb9efbb98ab1 (diff) | |
download | linux-96a6de1a541c86e9e67b9c310c14db4099bd1cbc.tar.xz |
Merge tag 'media/v5.1-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
- remove sensor drivers that got converted from soc_camera
- remaining soc_camera drivers got moved to staging
- some documentation cleanups and improvements
- the imx staging driver now supports imx7
- the ov9640, mt9m001 and mt9m111 got converted from soc_camera
- the vim2m driver now does what a m2m convert driver expects to do
- epoll() fixes on media subsystems
- several drivers fixes, typos, cleanups and improvements
* tag 'media/v5.1-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (346 commits)
media: dvb/earth-pt1: fix wrong initialization for demod blocks
media: vim2m: Address some coding style issues
media: vim2m: don't use BUG()
media: vim2m: speedup passthrough copy
media: vim2m: add an horizontal scaler
media: vim2m: don't accept YUYV anymore as output format
media: vim2m: add vertical linear scaler
media: vim2m: better handle cap/out buffers with different sizes
media: vim2m: use different framesizes for bayer formats
media: vim2m: add support for VIDIOC_ENUM_FRAMESIZES
media: vim2m: ensure that width is multiple of two
media: vim2m: improve debug messages
media: vim2m: add bayer capture formats
media: a few more typos at staging, pci, platform, radio and usb
media: Documentation: fix several typos
media: staging: fix several typos
media: include: fix several typos
media: common: fix several typos
media: v4l2-core: fix several typos
media: usb: fix several typos
...
Diffstat (limited to 'drivers/media')
373 files changed, 5937 insertions, 15616 deletions
diff --git a/drivers/media/cec/cec-api.c b/drivers/media/cec/cec-api.c index 391b6fd483e1..156a0d76ab2a 100644 --- a/drivers/media/cec/cec-api.c +++ b/drivers/media/cec/cec-api.c @@ -38,6 +38,7 @@ static __poll_t cec_poll(struct file *filp, struct cec_adapter *adap = fh->adap; __poll_t res = 0; + poll_wait(filp, &fh->wait, poll); if (!cec_is_registered(adap)) return EPOLLERR | EPOLLHUP; mutex_lock(&adap->lock); @@ -48,7 +49,6 @@ static __poll_t cec_poll(struct file *filp, res |= EPOLLIN | EPOLLRDNORM; if (fh->total_queued_events) res |= EPOLLPRI; - poll_wait(filp, &fh->wait, poll); mutex_unlock(&adap->lock); return res; } diff --git a/drivers/media/common/saa7146/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c index c790ae264464..be4355a4c126 100644 --- a/drivers/media/common/saa7146/saa7146_fops.c +++ b/drivers/media/common/saa7146/saa7146_fops.c @@ -105,7 +105,7 @@ void saa7146_buffer_finish(struct saa7146_dev *dev, } q->curr->vb.state = state; - v4l2_get_timestamp(&q->curr->vb.ts); + q->curr->vb.ts = ktime_get_ns(); wake_up(&q->curr->vb.done); q->curr = NULL; diff --git a/drivers/media/common/saa7146/saa7146_i2c.c b/drivers/media/common/saa7146/saa7146_i2c.c index 3feddc52c446..df9ebe2a168c 100644 --- a/drivers/media/common/saa7146/saa7146_i2c.c +++ b/drivers/media/common/saa7146/saa7146_i2c.c @@ -54,10 +54,7 @@ static int saa7146_i2c_msg_prepare(const struct i2c_msg *m, int num, __le32 *op) /* loop through all messages */ for(i = 0; i < num; i++) { - /* insert the address of the i2c-slave. - note: we get 7 bit i2c-addresses, - so we have to perform a translation */ - addr = (m[i].addr*2) + ( (0 != (m[i].flags & I2C_M_RD)) ? 1 : 0); + addr = i2c_8bit_addr_from_msg(&m[i]); h1 = op_count/3; h2 = op_count%3; op[h1] |= cpu_to_le32( (u8)addr << ((3-h2)*8)); op[h1] |= cpu_to_le32(SAA7146_I2C_START << ((3-h2)*2)); diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c index f90aa8109663..a0f0b5eef0bd 100644 --- a/drivers/media/common/saa7146/saa7146_video.c +++ b/drivers/media/common/saa7146/saa7146_video.c @@ -796,7 +796,7 @@ static int vidioc_s_fmt_vid_overlay(struct file *file, void *__fh, struct v4l2_f return -EFAULT; } - /* vv->ov.fh is used to indicate that we have valid overlay informations, too */ + /* vv->ov.fh is used to indicate that we have valid overlay information, too */ vv->ov.fh = fh; /* check if our current overlay is active */ diff --git a/drivers/media/common/siano/sms-cards.c b/drivers/media/common/siano/sms-cards.c index af6b2268db61..e238c9bc17d3 100644 --- a/drivers/media/common/siano/sms-cards.c +++ b/drivers/media/common/siano/sms-cards.c @@ -311,7 +311,7 @@ int sms_board_led_feedback(struct smscore_device_t *coredev, int led) int board_id = smscore_get_board_id(coredev); struct sms_board *board = sms_get_board(board_id); - /* dont touch GPIO if LEDs are already set */ + /* don't touch GPIO if LEDs are already set */ if (smscore_led_state(coredev, -1) == led) return 0; diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index eb58853008c9..476fa7a8b152 100644 --- a/drivers/media/common/siano/smscoreapi.h +++ b/drivers/media/common/siano/smscoreapi.h @@ -750,7 +750,7 @@ struct sms_stats { u32 num_of_corrected_mpe_tlbs;/* Number of MPE tables which were corrected by MPE RS decoding */ /* Common params */ - u32 ber_error_count; /* Number of errornous SYNC bits. */ + u32 ber_error_count; /* Number of erroneous SYNC bits. */ u32 ber_bit_count; /* Total number of SYNC bits. */ /* Interface information */ diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c index d9a590ae7545..07e0629af8ed 100644 --- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c +++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c @@ -246,6 +246,10 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_YUV555: case V4L2_PIX_FMT_YUV565: case V4L2_PIX_FMT_YUV32: + case V4L2_PIX_FMT_AYUV32: + case V4L2_PIX_FMT_XYUV32: + case V4L2_PIX_FMT_VUYA32: + case V4L2_PIX_FMT_VUYX32: tpg->color_enc = TGP_COLOR_ENC_YCBCR; break; case V4L2_PIX_FMT_YUV420M: @@ -372,6 +376,10 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_ARGB32: case V4L2_PIX_FMT_ABGR32: case V4L2_PIX_FMT_YUV32: + case V4L2_PIX_FMT_AYUV32: + case V4L2_PIX_FMT_XYUV32: + case V4L2_PIX_FMT_VUYA32: + case V4L2_PIX_FMT_VUYX32: case V4L2_PIX_FMT_HSV32: tpg->twopixelsize[0] = 2 * 4; break; @@ -1267,10 +1275,12 @@ static void gen_twopix(struct tpg_data *tpg, case V4L2_PIX_FMT_RGB32: case V4L2_PIX_FMT_XRGB32: case V4L2_PIX_FMT_HSV32: + case V4L2_PIX_FMT_XYUV32: alpha = 0; /* fall through */ case V4L2_PIX_FMT_YUV32: case V4L2_PIX_FMT_ARGB32: + case V4L2_PIX_FMT_AYUV32: buf[0][offset] = alpha; buf[0][offset + 1] = r_y_h; buf[0][offset + 2] = g_u_s; @@ -1278,9 +1288,11 @@ static void gen_twopix(struct tpg_data *tpg, break; case V4L2_PIX_FMT_BGR32: case V4L2_PIX_FMT_XBGR32: + case V4L2_PIX_FMT_VUYX32: alpha = 0; /* fall through */ case V4L2_PIX_FMT_ABGR32: + case V4L2_PIX_FMT_VUYA32: buf[0][offset] = b_v; buf[0][offset + 1] = g_u_s; buf[0][offset + 2] = r_y_h; diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index 70e8c3366f9c..15b6b9c0a2e4 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -499,9 +499,9 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) pr_info(" buf_init: %u buf_cleanup: %u buf_prepare: %u buf_finish: %u\n", vb->cnt_buf_init, vb->cnt_buf_cleanup, vb->cnt_buf_prepare, vb->cnt_buf_finish); - pr_info(" buf_queue: %u buf_done: %u buf_request_complete: %u\n", - vb->cnt_buf_queue, vb->cnt_buf_done, - vb->cnt_buf_request_complete); + pr_info(" buf_out_validate: %u buf_queue: %u buf_done: %u buf_request_complete: %u\n", + vb->cnt_buf_out_validate, vb->cnt_buf_queue, + vb->cnt_buf_done, vb->cnt_buf_request_complete); pr_info(" alloc: %u put: %u prepare: %u finish: %u mmap: %u\n", vb->cnt_mem_alloc, vb->cnt_mem_put, vb->cnt_mem_prepare, vb->cnt_mem_finish, @@ -934,7 +934,7 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) /* sync buffers */ for (plane = 0; plane < vb->num_planes; ++plane) call_void_memop(vb, finish, vb->planes[plane].mem_priv); - vb->synced = false; + vb->synced = 0; } spin_lock_irqsave(&q->done_lock, flags); @@ -1041,6 +1041,7 @@ static int __prepare_userptr(struct vb2_buffer *vb) if (vb->planes[plane].mem_priv) { if (!reacquired) { reacquired = true; + vb->copied_timestamp = 0; call_void_vb_qop(vb, buf_cleanup, vb); } call_void_memop(vb, put_userptr, vb->planes[plane].mem_priv); @@ -1165,6 +1166,7 @@ static int __prepare_dmabuf(struct vb2_buffer *vb) if (!reacquired) { reacquired = true; + vb->copied_timestamp = 0; call_void_vb_qop(vb, buf_cleanup, vb); } @@ -1196,6 +1198,9 @@ static int __prepare_dmabuf(struct vb2_buffer *vb) * userspace knows sooner rather than later if the dma-buf map fails. */ for (plane = 0; plane < vb->num_planes; ++plane) { + if (vb->planes[plane].dbuf_mapped) + continue; + ret = call_memop(vb, map_dmabuf, vb->planes[plane].mem_priv); if (ret) { dprintk(1, "failed to map dmabuf for plane %d\n", @@ -1274,6 +1279,14 @@ static int __buf_prepare(struct vb2_buffer *vb) return 0; WARN_ON(vb->synced); + if (q->is_output) { + ret = call_vb_qop(vb, buf_out_validate, vb); + if (ret) { + dprintk(1, "buffer validation failed\n"); + return ret; + } + } + vb->state = VB2_BUF_STATE_PREPARING; switch (q->memory) { @@ -1302,8 +1315,8 @@ static int __buf_prepare(struct vb2_buffer *vb) for (plane = 0; plane < vb->num_planes; ++plane) call_void_memop(vb, prepare, vb->planes[plane].mem_priv); - vb->synced = true; - vb->prepared = true; + vb->synced = 1; + vb->prepared = 1; vb->state = orig_state; return 0; @@ -1520,6 +1533,14 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb, return -EINVAL; } + if (q->is_output && !vb->prepared) { + ret = call_vb_qop(vb, buf_out_validate, vb); + if (ret) { + dprintk(1, "buffer validation failed\n"); + return ret; + } + } + media_request_object_init(&vb->req_obj); /* Make sure the request is in a safe state for updating. */ @@ -1750,7 +1771,6 @@ EXPORT_SYMBOL_GPL(vb2_wait_for_all_buffers); static void __vb2_dqbuf(struct vb2_buffer *vb) { struct vb2_queue *q = vb->vb2_queue; - unsigned int i; /* nothing to do if the buffer is already dequeued */ if (vb->state == VB2_BUF_STATE_DEQUEUED) @@ -1758,14 +1778,6 @@ static void __vb2_dqbuf(struct vb2_buffer *vb) vb->state = VB2_BUF_STATE_DEQUEUED; - /* unmap DMABUF buffer */ - if (q->memory == VB2_MEMORY_DMABUF) - for (i = 0; i < vb->num_planes; ++i) { - if (!vb->planes[i].dbuf_mapped) - continue; - call_void_memop(vb, unmap_dmabuf, vb->planes[i].mem_priv); - vb->planes[i].dbuf_mapped = 0; - } call_void_bufop(q, init_buffer, vb); } @@ -1792,7 +1804,7 @@ int vb2_core_dqbuf(struct vb2_queue *q, unsigned int *pindex, void *pb, } call_void_vb_qop(vb, buf_finish, vb); - vb->prepared = false; + vb->prepared = 0; if (pindex) *pindex = vb->index; @@ -1916,12 +1928,12 @@ static void __vb2_queue_cancel(struct vb2_queue *q) for (plane = 0; plane < vb->num_planes; ++plane) call_void_memop(vb, finish, vb->planes[plane].mem_priv); - vb->synced = false; + vb->synced = 0; } if (vb->prepared) { call_void_vb_qop(vb, buf_finish, vb); - vb->prepared = false; + vb->prepared = 0; } __vb2_dqbuf(vb); @@ -1932,6 +1944,7 @@ static void __vb2_queue_cancel(struct vb2_queue *q) if (vb->request) media_request_put(vb->request); vb->request = NULL; + vb->copied_timestamp = 0; } } @@ -2278,6 +2291,8 @@ __poll_t vb2_core_poll(struct vb2_queue *q, struct file *file, if (q->is_output && !(req_events & (EPOLLOUT | EPOLLWRNORM))) return 0; + poll_wait(file, &q->done_wq, wait); + /* * Start file I/O emulator only if streaming API has not been used yet. */ @@ -2329,8 +2344,6 @@ __poll_t vb2_core_poll(struct vb2_queue *q, struct file *file, */ if (q->last_buffer_dequeued) return EPOLLIN | EPOLLRDNORM; - - poll_wait(file, &q->done_wq, wait); } /* diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c b/drivers/media/common/videobuf2/videobuf2-dma-sg.c index 015e737095cd..270c3162fdcb 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c @@ -3,7 +3,7 @@ * * Copyright (C) 2010 Samsung Electronics * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.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 @@ -67,7 +67,7 @@ static int vb2_dma_sg_alloc_compacted(struct vb2_dma_sg_buf *buf, int i; order = get_order(size); - /* Dont over allocate*/ + /* Don't over allocate*/ if ((PAGE_SIZE << order) > size) order--; diff --git a/drivers/media/common/videobuf2/videobuf2-memops.c b/drivers/media/common/videobuf2/videobuf2-memops.c index 89e51989332b..c4a85be48ac2 100644 --- a/drivers/media/common/videobuf2/videobuf2-memops.c +++ b/drivers/media/common/videobuf2/videobuf2-memops.c @@ -121,7 +121,7 @@ static void vb2_common_vm_close(struct vm_area_struct *vma) } /* - * vb2_common_vm_ops - common vm_ops used for tracking refcount of mmaped + * vb2_common_vm_ops - common vm_ops used for tracking refcount of mmapped * video buffers */ const struct vm_operations_struct vb2_common_vm_ops = { diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index 3a0ca2f9854f..d09dee20e421 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -143,7 +143,7 @@ static void __copy_timestamp(struct vb2_buffer *vb, const void *pb) * and the timecode field and flag if needed. */ if (q->copy_timestamp) - vb->timestamp = timeval_to_ns(&b->timestamp); + vb->timestamp = v4l2_timeval_to_ns(&b->timestamp); vbuf->flags |= b->flags & V4L2_BUF_FLAG_TIMECODE; if (b->flags & V4L2_BUF_FLAG_TIMECODE) vbuf->timecode = b->timecode; @@ -409,6 +409,15 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md */ if (WARN_ON(!q->ops->buf_request_complete)) return -EINVAL; + /* + * Make sure this op is implemented by the driver for the output queue. + * It's easy to forget this callback, but is it important to correctly + * validate the 'field' value at QBUF time. + */ + if (WARN_ON((q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT || + q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) && + !q->ops->buf_out_validate)) + return -EINVAL; if (vb->state != VB2_BUF_STATE_DEQUEUED) { dprintk(1, "%s: buffer is not in dequeued state\n", opname); @@ -567,7 +576,7 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, struct vb2_plane *planes) struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); unsigned int plane; - if (!vb->vb2_queue->is_output || !vb->vb2_queue->copy_timestamp) + if (!vb->vb2_queue->copy_timestamp) vb->timestamp = 0; for (plane = 0; plane < vb->num_planes; ++plane) { @@ -589,6 +598,19 @@ static const struct vb2_buf_ops v4l2_buf_ops = { .copy_timestamp = __copy_timestamp, }; +int vb2_find_timestamp(const struct vb2_queue *q, u64 timestamp, + unsigned int start_idx) +{ + unsigned int i; + + for (i = start_idx; i < q->num_buffers; i++) + if (q->bufs[i]->copied_timestamp && + q->bufs[i]->timestamp == timestamp) + return i; + return -1; +} +EXPORT_SYMBOL_GPL(vb2_find_timestamp); + /* * vb2_querybuf() - query video buffer information * @q: videobuf queue @@ -846,16 +868,14 @@ EXPORT_SYMBOL_GPL(vb2_queue_release); __poll_t vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait) { struct video_device *vfd = video_devdata(file); - __poll_t req_events = poll_requested_events(wait); __poll_t res = 0; if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) { struct v4l2_fh *fh = file->private_data; + poll_wait(file, &fh->wait, wait); if (v4l2_event_pending(fh)) res = EPOLLPRI; - else if (req_events & EPOLLPRI) - poll_wait(file, &fh->wait, wait); } return res | vb2_core_poll(q, file, wait); diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index 1544e8cef564..f14a872d1268 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -1195,13 +1195,13 @@ static __poll_t dvb_demux_poll(struct file *file, poll_table *wait) struct dmxdev_filter *dmxdevfilter = file->private_data; __poll_t mask = 0; + poll_wait(file, &dmxdevfilter->buffer.queue, wait); + if ((!dmxdevfilter) || dmxdevfilter->dev->exit) return EPOLLERR; if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx)) return dvb_vb2_poll(&dmxdevfilter->vb2_ctx, file, wait); - poll_wait(file, &dmxdevfilter->buffer.queue, wait); - if (dmxdevfilter->state != DMXDEV_STATE_GO && dmxdevfilter->state != DMXDEV_STATE_DONE && dmxdevfilter->state != DMXDEV_STATE_TIMEDOUT) @@ -1346,13 +1346,13 @@ static __poll_t dvb_dvr_poll(struct file *file, poll_table *wait) dprintk("%s\n", __func__); + poll_wait(file, &dmxdev->dvr_buffer.queue, wait); + if (dmxdev->exit) return EPOLLERR; if (dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx)) return dvb_vb2_poll(&dmxdev->dvr_vb2_ctx, file, wait); - poll_wait(file, &dmxdev->dvr_buffer.queue, wait); - if (((file->f_flags & O_ACCMODE) == O_RDONLY) || dmxdev->may_do_mmap) { if (dmxdev->dvr_buffer.error) diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c index 4d371cea0d5d..ebf1e3b03819 100644 --- a/drivers/media/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb-core/dvb_ca_en50221.c @@ -1797,6 +1797,8 @@ static __poll_t dvb_ca_en50221_io_poll(struct file *file, poll_table *wait) dprintk("%s\n", __func__); + poll_wait(file, &ca->wait_queue, wait); + if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) mask |= EPOLLIN; @@ -1804,9 +1806,6 @@ static __poll_t dvb_ca_en50221_io_poll(struct file *file, poll_table *wait) if (mask) return mask; - /* wait for something to happen */ - poll_wait(file, &ca->wait_queue, wait); - if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) mask |= EPOLLIN; diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 27a1d4a98d73..fbdb4ecc7c50 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -1596,7 +1596,7 @@ static bool is_dvbv3_delsys(u32 delsys) * * Provides emulation for delivery systems that are compatible with the old * DVBv3 call. Among its usages, it provices support for ISDB-T, and allows - * using a DVB-S2 only frontend just like it were a DVB-S, if the frontent + * using a DVB-S2 only frontend just like it were a DVB-S, if the frontend * parameters are compatible with DVB-S spec. */ static int emulate_delivery_system(struct dvb_frontend *fe, u32 delsys) diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c index b7171bf094fb..4a5834a1c3b7 100644 --- a/drivers/media/dvb-core/dvbdev.c +++ b/drivers/media/dvb-core/dvbdev.c @@ -898,7 +898,7 @@ EXPORT_SYMBOL(dvb_unregister_adapter); /* if the miracle happens and "generic_usercopy()" is included into the kernel, then this can vanish. please don't make the mistake and - define this as video_usercopy(). this will introduce a dependecy + define this as video_usercopy(). this will introduce a dependency to the v4l "videodev.o" module, which is unnecessary for some cards (ie. the budget dvb-cards don't need the v4l module...) */ int dvb_usercopy(struct file *file, diff --git a/drivers/media/dvb-frontends/cxd2841er.c b/drivers/media/dvb-frontends/cxd2841er.c index c98093ed3dd7..8acf0b91b437 100644 --- a/drivers/media/dvb-frontends/cxd2841er.c +++ b/drivers/media/dvb-frontends/cxd2841er.c @@ -2947,7 +2947,7 @@ static int cxd2841er_sleep_tc_to_active_t(struct cxd2841er_priv *priv, ((priv->flags & CXD2841ER_ASCOT) ? 0x01 : 0x00), 0x01); /* Set SLV-T Bank : 0x18 */ cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0x18); - /* Pre-RS BER moniter setting */ + /* Pre-RS BER monitor setting */ cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x36, 0x40, 0x07); /* FEC Auto Recovery setting */ cxd2841er_set_reg_bits(priv, I2C_SLVT, 0x30, 0x01, 0x01); diff --git a/drivers/media/dvb-frontends/dib0090.c b/drivers/media/dvb-frontends/dib0090.c index 4813a88eb9f7..18c41cfef8d6 100644 --- a/drivers/media/dvb-frontends/dib0090.c +++ b/drivers/media/dvb-frontends/dib0090.c @@ -2459,7 +2459,7 @@ static int dib0090_tune(struct dvb_frontend *fe) state->current_standard = state->fe->dtv_property_cache.delivery_system; ret = 20; - state->calibrate = CAPTRIM_CAL; /* captrim serach now */ + state->calibrate = CAPTRIM_CAL; /* captrim search now */ } else if (*tune_state == CT_TUNER_STEP_0) { /* Warning : because of captrim cal, if you change this step, change it also in _cal.c file because it is the step following captrim cal state machine */ diff --git a/drivers/media/dvb-frontends/dib7000m.c b/drivers/media/dvb-frontends/dib7000m.c index b79358d09de6..389db9077ad5 100644 --- a/drivers/media/dvb-frontends/dib7000m.c +++ b/drivers/media/dvb-frontends/dib7000m.c @@ -369,7 +369,7 @@ static int dib7000m_sad_calib(struct dib7000m_state *state) { /* internal */ -// dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth +// dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writing in set_bandwidth dib7000m_write_word(state, 929, (0 << 1) | (0 << 0)); dib7000m_write_word(state, 930, 776); // 0.625*3.3 / 4096 @@ -928,7 +928,7 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dtv_fronte } state->div_sync_wait = (value * 3) / 2 + 32; // add 50% SFN margin + compensate for one DVSY-fifo TODO - /* deactive the possibility of diversity reception if extended interleave - not for 7000MC */ + /* deactivate the possibility of diversity reception if extended interleave - not for 7000MC */ /* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */ if (1 == 1 || state->revision > 0x4000) state->div_force_off = 0; diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c index 2818e8def1b3..f8040f6def62 100644 --- a/drivers/media/dvb-frontends/dib7000p.c +++ b/drivers/media/dvb-frontends/dib7000p.c @@ -94,7 +94,7 @@ enum dib7000p_power_mode { DIB7000P_POWER_INTERFACE_ONLY, }; -/* dib7090 specific fonctions */ +/* dib7090 specific functions */ static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode); static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff); static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode); @@ -319,7 +319,7 @@ static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_ad dib7000p_write_word(state, 1925, reg | (1 << 4) | (1 << 2)); /* en_slowAdc = 1 & reset_sladc = 1 */ - reg = dib7000p_read_word(state, 1925); /* read acces to make it works... strange ... */ + reg = dib7000p_read_word(state, 1925); /* read access to make it works... strange ... */ msleep(200); dib7000p_write_word(state, 1925, reg & ~(1 << 4)); /* en_slowAdc = 1 & reset_sladc = 0 */ @@ -1101,7 +1101,7 @@ static void dib7000p_set_channel(struct dib7000p_state *state, else state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay; - /* deactive the possibility of diversity reception if extended interleaver */ + /* deactivate the possibility of diversity reception if extended interleaver */ state->div_force_off = !1 && ch->transmission_mode != TRANSMISSION_MODE_8K; dib7000p_set_diversity_in(&state->demod, state->div_state); @@ -2378,7 +2378,7 @@ static int dib7090_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[] } } - if (apb_address != 0) /* R/W acces via APB */ + if (apb_address != 0) /* R/W access via APB */ return dib7090p_rw_on_apb(i2c_adap, msg, num, apb_address); else /* R/W access via SERPAR */ return w7090p_tuner_rw_serpar(i2c_adap, msg, num); diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c index 3c3f8cb14845..85c429cce23e 100644 --- a/drivers/media/dvb-frontends/dib8000.c +++ b/drivers/media/dvb-frontends/dib8000.c @@ -564,7 +564,7 @@ static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_s dib8000_write_word(state, 1925, reg | (1<<4) | (1<<2)); - /* read acces to make it works... strange ... */ + /* read access to make it works... strange ... */ reg = dib8000_read_word(state, 1925); msleep(20); /* en_slowAdc = 1 & reset_sladc = 0 */ @@ -1091,7 +1091,7 @@ static int dib8000_reset(struct dvb_frontend *fe) if ((state->revision != 0x8090) && (dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0)) - dprintk("OUTPUT_MODE could not be resetted.\n"); + dprintk("OUTPUT_MODE could not be reset.\n"); state->current_agc = NULL; @@ -1867,7 +1867,7 @@ static int dib8096p_tuner_xfer(struct i2c_adapter *i2c_adap, } } - if (apb_address != 0) /* R/W acces via APB */ + if (apb_address != 0) /* R/W access via APB */ return dib8096p_rw_on_apb(i2c_adap, msg, num, apb_address); else /* R/W access via SERPAR */ return dib8096p_tuner_rw_serpar(i2c_adap, msg, num); @@ -3082,7 +3082,7 @@ static int dib8000_tune(struct dvb_frontend *fe) state->autosearch_state = AS_DONE; *tune_state = CT_DEMOD_STOP; /* else we are done here */ break; - case 2: /* Succes */ + case 2: /* Success */ state->status = FE_STATUS_FFT_SUCCESS; /* signal to the upper layer, that there was a channel found and the parameters can be read */ *tune_state = CT_DEMOD_STEP_3; if (state->autosearch_state == AS_SEARCHING_GUARD) @@ -3193,10 +3193,10 @@ static int dib8000_tune(struct dvb_frontend *fe) case CT_DEMOD_STEP_6: /* (36) if there is an input (diversity) */ if ((state->fe[1] != NULL) && (state->output_mode != OUTMODE_DIVERSITY)) { - /* if there is a diversity fe in input and this fe is has not already failled : wait here until this this fe has succedeed or failled */ + /* if there is a diversity fe in input and this fe is has not already failed : wait here until this this fe has succedeed or failed */ if (dib8000_get_status(state->fe[1]) <= FE_STATUS_STD_SUCCESS) /* Something is locked on the input fe */ *tune_state = CT_DEMOD_STEP_8; /* go for mpeg */ - else if (dib8000_get_status(state->fe[1]) >= FE_STATUS_TUNE_TIME_TOO_SHORT) { /* fe in input failled also, break the current one */ + else if (dib8000_get_status(state->fe[1]) >= FE_STATUS_TUNE_TIME_TOO_SHORT) { /* fe in input failed also, break the current one */ *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */ dib8000_viterbi_state(state, 1); /* start viterbi chandec */ dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2); diff --git a/drivers/media/dvb-frontends/dib9000.c b/drivers/media/dvb-frontends/dib9000.c index 0183fb1346ef..1875da07c150 100644 --- a/drivers/media/dvb-frontends/dib9000.c +++ b/drivers/media/dvb-frontends/dib9000.c @@ -1020,7 +1020,7 @@ static int dib9000_risc_apb_access_read(struct dib9000_state *state, u32 address if (address >= 1024 || !state->platform.risc.fw_is_running) return -EINVAL; - /* dprintk( "APB access thru rd fw %d %x\n", address, attribute); */ + /* dprintk( "APB access through rd fw %d %x\n", address, attribute); */ mb[0] = (u16) address; mb[1] = len / 2; @@ -1050,7 +1050,7 @@ static int dib9000_risc_apb_access_write(struct dib9000_state *state, u32 addres if (len > 18) return -EINVAL; - /* dprintk( "APB access thru wr fw %d %x\n", address, attribute); */ + /* dprintk( "APB access through wr fw %d %x\n", address, attribute); */ mb[0] = (u16)address; for (i = 0; i + 1 < len; i += 2) diff --git a/drivers/media/dvb-frontends/drx39xyj/drx_dap_fasi.h b/drivers/media/dvb-frontends/drx39xyj/drx_dap_fasi.h index 23ae72468025..739dc5590fa4 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drx_dap_fasi.h +++ b/drivers/media/dvb-frontends/drx39xyj/drx_dap_fasi.h @@ -67,7 +67,7 @@ * (2 bytes). The DAP can operate in 3 modes: * (1) only short * (2) only long -* (3) both long and short but short preferred and long only when necesarry +* (3) both long and short but short preferred and long only when necessary * * These modes must be selected compile time via compile switches. * Compile switch settings for the different modes: @@ -112,14 +112,14 @@ * + single master mode means no use of repeated starts * + multi master mode means use of repeated starts * Default is single master. -* Default can be overriden by setting the compile switch DRXDAP_SINGLE_MASTER. +* Default can be overridden by setting the compile switch DRXDAP_SINGLE_MASTER. * * Slave: * Single/multi master selected via the flags in the FASI protocol. * + single master means remember memory address between i2c packets * + multimaster means flush memory address between i2c packets * Default is single master, DAP FASI changes multi-master setting silently -* into single master setting. This cannot be overrriden. +* into single master setting. This cannot be overridden. * */ /* set default */ @@ -139,7 +139,7 @@ * In single master mode, data can be written by sending the register address * first, then two or four bytes of data in the next packet. * Because the device address plus a register address equals five bytes, -* the mimimum chunk size must be five. +* the minimum chunk size must be five. * If ten-bit I2C device addresses are used, the minimum chunk size must be six, * because the I2C device address will then occupy two bytes when writing. * diff --git a/drivers/media/dvb-frontends/drx39xyj/drx_driver.h b/drivers/media/dvb-frontends/drx39xyj/drx_driver.h index 1ec20eecc433..15f7e58c5a30 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drx_driver.h +++ b/drivers/media/dvb-frontends/drx39xyj/drx_driver.h @@ -94,7 +94,7 @@ int drxbsp_i2c_term(void); * \param r_count The number of bytes to read * \param r_data The array to read the data from * \return int Return status. -* \retval 0 Succes. +* \retval 0 Success. * \retval -EIO Failure. * \retval -EINVAL Parameter 'wcount' is not zero but parameter * 'wdata' contains NULL. @@ -986,7 +986,7 @@ struct drx_filter_info { * \struct struct drx_channel * \brief The set of parameters describing a single channel. * * Used by DRX_CTRL_SET_CHANNEL and DRX_CTRL_GET_CHANNEL. -* Only certain fields need to be used for a specfic standard. +* Only certain fields need to be used for a specific standard. * */ struct drx_channel { @@ -1606,7 +1606,7 @@ struct drx_version_list { DRX_AUD_I2S_MATRIX_B_MONO, /*< B sound only, stereo or mono */ DRX_AUD_I2S_MATRIX_STEREO, - /*< A+B sound, transparant */ + /*< A+B sound, transparent */ DRX_AUD_I2S_MATRIX_MONO /*< A+B mixed to mono sum, (L+R)/2 */}; /* @@ -1870,7 +1870,7 @@ struct drx_reg_dump { /*< current power management mode */ /* Tuner */ - u8 tuner_port_nr; /*< nr of I2C port to wich tuner is */ + u8 tuner_port_nr; /*< nr of I2C port to which tuner is */ s32 tuner_min_freq_rf; /*< minimum RF input frequency, in kHz */ s32 tuner_max_freq_rf; diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index 551b7d65fa66..a6876fa48753 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -380,10 +380,10 @@ DEFINES */ /*****************************************************************************/ -/* Audio block 0x103 is write only. To avoid shadowing in driver accessing */ -/* RAM adresses directly. This must be READ ONLY to avoid problems. */ -/* Writing to the interface adresses is more than only writing the RAM */ -/* locations */ +/* Audio block 0x103 is write only. To avoid shadowing in driver accessing */ +/* RAM addresses directly. This must be READ ONLY to avoid problems. */ +/* Writing to the interface addresses are more than only writing the RAM */ +/* locations */ /*****************************************************************************/ /* * \brief RAM location of MODUS registers @@ -656,8 +656,8 @@ static struct drxj_data drxj_data_g = { false, /* flag: true=bypass */ ATV_TOP_VID_PEAK__PRE, /* shadow of ATV_TOP_VID_PEAK__A */ ATV_TOP_NOISE_TH__PRE, /* shadow of ATV_TOP_NOISE_TH__A */ - true, /* flag CVBS ouput enable */ - false, /* flag SIF ouput enable */ + true, /* flag CVBS output enable */ + false, /* flag SIF output enable */ DRXJ_SIF_ATTENUATION_0DB, /* current SIF att setting */ { /* qam_rf_agc_cfg */ DRX_STANDARD_ITU_B, /* standard */ @@ -832,7 +832,7 @@ static struct drx_common_attr drxj_default_comm_attr_g = { false, /* If true mirror frequency spectrum */ { /* MPEG output configuration */ - true, /* If true, enable MPEG ouput */ + true, /* If true, enable MPEG output */ false, /* If true, insert RS byte */ false, /* If true, parallel out otherwise serial */ false, /* If true, invert DATA signals */ @@ -848,7 +848,7 @@ static struct drx_common_attr drxj_default_comm_attr_g = { DRX_MPEG_STR_WIDTH_1 /* MPEG Start width in clock cycles */ }, /* Initilisations below can be omitted, they require no user input and - are initialy 0, NULL or false. The compiler will initialize them to these + are initially 0, NULL or false. The compiler will initialize them to these values when omitted. */ false, /* is_opened */ @@ -869,7 +869,7 @@ static struct drx_common_attr drxj_default_comm_attr_g = { DRX_POWER_UP, /* Tuner */ - 1, /* nr of I2C port to wich tuner is */ + 1, /* nr of I2C port to which tuner is */ 0L, /* minimum RF input frequency, in kHz */ 0L, /* maximum RF input frequency, in kHz */ false, /* Rf Agc Polarity */ @@ -1656,7 +1656,7 @@ static int drxdap_fasi_write_block(struct i2c_device_addr *dev_addr, sequense will be visible: (1) write address {i2c addr, 4 bytes chip address} (2) write data {i2c addr, 4 bytes data } (3) write address (4) write data etc... - Address must be rewriten because HI is reset after data transport and + Address must be rewritten because HI is reset after data transport and expects an address. */ todo = (block_size < datasize ? block_size : datasize); @@ -1820,7 +1820,7 @@ static int drxdap_fasi_write_reg32(struct i2c_device_addr *dev_addr, * \param wdata Data to write * \param rdata Buffer for data to read * \return int -* \retval 0 Succes +* \retval 0 Success * \retval -EIO Timeout, I2C error, illegal bank * * 16 bits register read modify write access using short addressing format only. @@ -1897,7 +1897,7 @@ static int drxj_dap_read_modify_write_reg16(struct i2c_device_addr *dev_addr, * \param addr * \param data * \return int -* \retval 0 Succes +* \retval 0 Success * \retval -EIO Timeout, I2C error, illegal bank * * 16 bits register read access via audio token ring interface. @@ -2004,7 +2004,7 @@ static int drxj_dap_read_reg16(struct i2c_device_addr *dev_addr, * \param addr * \param data * \return int -* \retval 0 Succes +* \retval 0 Success * \retval -EIO Timeout, I2C error, illegal bank * * 16 bits register write access via audio token ring interface. @@ -2094,7 +2094,7 @@ static int drxj_dap_write_reg16(struct i2c_device_addr *dev_addr, * \param datasize size of data buffer in bytes * \param data pointer to data buffer * \return int -* \retval 0 Succes +* \retval 0 Success * \retval -EIO Timeout, I2C error, illegal bank * */ @@ -2338,7 +2338,7 @@ hi_command(struct i2c_device_addr *dev_addr, const struct drxj_hi_cmd *cmd, u16 if ((cmd->cmd) == SIO_HI_RA_RAM_CMD_RESET) msleep(1); - /* Detect power down to ommit reading result */ + /* Detect power down to omit reading result */ powerdown_cmd = (bool) ((cmd->cmd == SIO_HI_RA_RAM_CMD_CONFIG) && (((cmd-> param5) & SIO_HI_RA_RAM_PAR_5_CFG_SLEEP__M) @@ -2754,7 +2754,7 @@ ctrl_set_cfg_mpeg_output(struct drx_demod_instance *demod, struct drx_cfg_mpeg_o common_attr = (struct drx_common_attr *) demod->my_common_attr; if (cfg_data->enable_mpeg_output == true) { - /* quick and dirty patch to set MPEG incase current std is not + /* quick and dirty patch to set MPEG in case current std is not producing MPEG */ switch (ext_attr->standard) { case DRX_STANDARD_8VSB: @@ -2894,7 +2894,7 @@ ctrl_set_cfg_mpeg_output(struct drx_demod_instance *demod, struct drx_cfg_mpeg_o break; default: break; - } /* swtich (standard) */ + } /* switch (standard) */ /* Check insertion of the Reed-Solomon parity bytes */ rc = drxj_dap_read_reg16(dev_addr, FEC_OC_MODE__A, &fec_oc_reg_mode, 0); @@ -4127,7 +4127,7 @@ rw_error: * \param datasize size of data buffer in bytes * \param data pointer to data buffer * \return int -* \retval 0 Succes +* \retval 0 Success * \retval -EIO Timeout, I2C error, illegal bank * */ @@ -8989,7 +8989,7 @@ qam64auto(struct drx_demod_instance *demod, ((jiffies_to_msecs(jiffies) - start_time) < (DRXJ_QAM_MAX_WAITTIME + timeout_ofs)) ); - /* Returning control to apllication ... */ + /* Returning control to application ... */ return 0; rw_error: @@ -9309,7 +9309,7 @@ get_qamrs_err_count(struct i2c_device_addr *dev_addr, return -EINVAL; /* all reported errors are received in the */ - /* most recently finished measurment period */ + /* most recently finished measurement period */ /* no of pre RS bit errors */ rc = drxj_dap_read_reg16(dev_addr, FEC_RS_NR_BIT_ERRORS__A, &nr_bit_errors, 0); if (rc != 0) { @@ -9689,7 +9689,7 @@ rw_error: (3) SIF AGC (used to amplify the output signal in case input to low) The SIF AGC is now coupled to the RF/IF AGCs. - The SIF AGC is needed for both SIF ouput and the internal SIF signal to + The SIF AGC is needed for both SIF output and the internal SIF signal to the AUD block. RF and IF AGCs DACs are part of AFE, Video and SIF AGC DACs are part of @@ -9702,11 +9702,11 @@ rw_error: later on because of the schedule) Several HW/SCU "settings" can be used for ATV. The standard selection - will reset most of these settings. To avoid that the end user apllication + will reset most of these settings. To avoid that the end user application has to perform these settings each time the ATV or FM standards is selected the driver will shadow these settings. This enables the end user to perform the settings only once after a drx_open(). The driver must - write the shadow settings to HW/SCU incase: + write the shadow settings to HW/SCU in case: ( setstandard FM/ATV) || ( settings have changed && FM/ATV standard is active) The shadow settings will be stored in the device specific data container. @@ -9908,7 +9908,7 @@ rw_error: #define IMPULSE_COSINE_ALPHA_0_5 { 2, 0, -2, -2, 2, 5, 2, -10, -20, -14, 20, 74, 125, 145} /*sqrt raised-cosine filter with alpha=0.5 */ #define IMPULSE_COSINE_ALPHA_RO_0_5 { 0, 0, 1, 2, 3, 0, -7, -15, -16, 0, 34, 77, 114, 128} /*full raised-cosine filter with alpha=0.5 (receiver only) */ -/* Coefficients for the nyquist fitler (total: 27 taps) */ +/* Coefficients for the nyquist filter (total: 27 taps) */ #define NYQFILTERLEN 27 static int ctrl_set_oob(struct drx_demod_instance *demod, struct drxoob *oob_param) diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.h b/drivers/media/dvb-frontends/drx39xyj/drxj.h index d3ee1c23bb2f..d62412f71c88 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.h +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.h @@ -49,7 +49,7 @@ INCLUDES #if ((DRXDAP_SINGLE_MASTER == 0) && (DRXDAPFASI_LONG_ADDR_ALLOWED == 0)) #error "Multi master mode and short addressing only is an illegal combination" *; /* Generate a fatal compiler error to make sure it stops here, - this is necesarry because not all compilers stop after a #error. */ + this is necessary because not all compilers stop after a #error. */ #endif /*------------------------------------------------------------------------- @@ -203,7 +203,7 @@ struct drxj_agc_status { * /struct drxjrs_errors * Available failure information in DRXJ_FEC_RS. * -* Container for errors that are received in the most recently finished measurment period +* Container for errors that are received in the most recently finished measurement period * */ struct drxjrs_errors { @@ -405,7 +405,7 @@ struct drxj_cfg_atv_output { * */ struct drxj_data { - /* device capabilties (determined during drx_open()) */ + /* device capabilities (determined during drx_open()) */ bool has_lna; /*< true if LNA (aka PGA) present */ bool has_oob; /*< true if OOB supported */ bool has_ntsc; /*< true if NTSC supported */ @@ -455,7 +455,7 @@ struct drxj_cfg_atv_output { /* IQM fs frequecy shift and inversion */ u32 iqm_fs_rate_ofs; /*< frequency shifter setting after setchannel */ - bool pos_image; /*< Ture: positive image */ + bool pos_image; /*< True: positive image */ /* IQM RC frequecy shift */ u32 iqm_rc_rate_ofs; /*< frequency shifter setting after setchannel */ @@ -468,8 +468,8 @@ struct drxj_cfg_atv_output { bool phase_correction_bypass;/*< flag: true=bypass */ s16 atv_top_vid_peak; /*< shadow of ATV_TOP_VID_PEAK__A */ u16 atv_top_noise_th; /*< shadow of ATV_TOP_NOISE_TH__A */ - bool enable_cvbs_output; /*< flag CVBS ouput enable */ - bool enable_sif_output; /*< flag SIF ouput enable */ + bool enable_cvbs_output; /*< flag CVBS output enable */ + bool enable_sif_output; /*< flag SIF output enable */ enum drxjsif_attenuation sif_attenuation; /*< current SIF att setting */ /* Agc configuration for QAM and VSB */ diff --git a/drivers/media/dvb-frontends/drxd_firm.c b/drivers/media/dvb-frontends/drxd_firm.c index 4e1d8905e06a..412871d6636b 100644 --- a/drivers/media/dvb-frontends/drxd_firm.c +++ b/drivers/media/dvb-frontends/drxd_firm.c @@ -890,7 +890,7 @@ u8 DRXD_StartDiversityEnd[] = { /* End demod, combining RF in and diversity in, MPEG TS out */ WR16(B_FE_CF_REG_IMP_VAL__A, 0x0), /* disable impulse noise cruncher */ WR16(B_FE_AD_REG_INVEXT__A, 0x0), /* clock inversion (for sohard board) */ - WR16(B_CP_REG_BR_STR_DEL__A, 10), /* apperently no mb delay matching is best */ + WR16(B_CP_REG_BR_STR_DEL__A, 10), /* apparently no mb delay matching is best */ WR16(B_EQ_REG_RC_SEL_CAR__A, B_EQ_REG_RC_SEL_CAR_DIV_ON | /* org = 0x81 combining enabled */ B_EQ_REG_RC_SEL_CAR_MEAS_A_CC | diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c index 684d428efb0d..0a5b15bee1d7 100644 --- a/drivers/media/dvb-frontends/drxd_hard.c +++ b/drivers/media/dvb-frontends/drxd_hard.c @@ -1144,6 +1144,8 @@ static int EnableAndResetMB(struct drxd_state *state) static int InitCC(struct drxd_state *state) { + int status = 0; + if (state->osc_clock_freq == 0 || state->osc_clock_freq > 20000 || (state->osc_clock_freq % 4000) != 0) { @@ -1151,14 +1153,17 @@ static int InitCC(struct drxd_state *state) return -1; } - Write16(state, CC_REG_OSC_MODE__A, CC_REG_OSC_MODE_M20, 0); - Write16(state, CC_REG_PLL_MODE__A, CC_REG_PLL_MODE_BYPASS_PLL | - CC_REG_PLL_MODE_PUMP_CUR_12, 0); - Write16(state, CC_REG_REF_DIVIDE__A, state->osc_clock_freq / 4000, 0); - Write16(state, CC_REG_PWD_MODE__A, CC_REG_PWD_MODE_DOWN_PLL, 0); - Write16(state, CC_REG_UPDATE__A, CC_REG_UPDATE_KEY, 0); + status |= Write16(state, CC_REG_OSC_MODE__A, CC_REG_OSC_MODE_M20, 0); + status |= Write16(state, CC_REG_PLL_MODE__A, + CC_REG_PLL_MODE_BYPASS_PLL | + CC_REG_PLL_MODE_PUMP_CUR_12, 0); + status |= Write16(state, CC_REG_REF_DIVIDE__A, + state->osc_clock_freq / 4000, 0); + status |= Write16(state, CC_REG_PWD_MODE__A, CC_REG_PWD_MODE_DOWN_PLL, + 0); + status |= Write16(state, CC_REG_UPDATE__A, CC_REG_UPDATE_KEY, 0); - return 0; + return status; } static int ResetECOD(struct drxd_state *state) @@ -1312,7 +1317,10 @@ static int SC_SendCommand(struct drxd_state *state, u16 cmd) int status = 0, ret; u16 errCode; - Write16(state, SC_RA_RAM_CMD__A, cmd, 0); + status = Write16(state, SC_RA_RAM_CMD__A, cmd, 0); + if (status < 0) + return status; + SC_WaitForReady(state); ret = Read16(state, SC_RA_RAM_CMD_ADDR__A, &errCode, 0); @@ -1339,9 +1347,9 @@ static int SC_ProcStartCommand(struct drxd_state *state, break; } SC_WaitForReady(state); - Write16(state, SC_RA_RAM_CMD_ADDR__A, subCmd, 0); - Write16(state, SC_RA_RAM_PARAM1__A, param1, 0); - Write16(state, SC_RA_RAM_PARAM0__A, param0, 0); + status |= Write16(state, SC_RA_RAM_CMD_ADDR__A, subCmd, 0); + status |= Write16(state, SC_RA_RAM_PARAM1__A, param1, 0); + status |= Write16(state, SC_RA_RAM_PARAM0__A, param0, 0); SC_SendCommand(state, SC_RA_RAM_CMD_PROC_START); } while (0); diff --git a/drivers/media/dvb-frontends/drxk.h b/drivers/media/dvb-frontends/drxk.h index 76466f7ec3a0..ee06e89187e4 100644 --- a/drivers/media/dvb-frontends/drxk.h +++ b/drivers/media/dvb-frontends/drxk.h @@ -24,7 +24,7 @@ * @microcode_name: Name of the firmware file with the microcode * @qam_demod_parameter_count: The number of parameters used for the command * to set the demodulator parameters. All - * firmwares are using the 2-parameter commmand. + * firmwares are using the 2-parameter command. * An exception is the ``drxk_a3.mc`` firmware, * which uses the 4-parameter command. * A value of 0 (default) or lower indicates that diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c index 8ea1e45be710..86652a4ef9ce 100644 --- a/drivers/media/dvb-frontends/drxk_hard.c +++ b/drivers/media/dvb-frontends/drxk_hard.c @@ -723,7 +723,7 @@ static int init_state(struct drxk_state *state) state->m_drxk_state = DRXK_UNINITIALIZED; /* MPEG output configuration */ - state->m_enable_mpeg_output = true; /* If TRUE; enable MPEG ouput */ + state->m_enable_mpeg_output = true; /* If TRUE; enable MPEG output */ state->m_insert_rs_byte = false; /* If TRUE; insert RS byte */ state->m_invert_data = false; /* If TRUE; invert DATA signals */ state->m_invert_err = false; /* If TRUE; invert ERR signal */ @@ -3870,7 +3870,7 @@ static int set_dvbt(struct drxk_state *state, u16 intermediate_freqk_hz, goto error; } #else - /* Set Priorty high */ + /* Set Priority high */ transmission_params |= OFDM_SC_RA_RAM_OP_PARAM_PRIO_HI; status = write16(state, OFDM_EC_SB_PRIOR__A, OFDM_EC_SB_PRIOR_HI); if (status < 0) @@ -3901,7 +3901,7 @@ static int set_dvbt(struct drxk_state *state, u16 intermediate_freqk_hz, } /* - * SAW filter selection: normaly not necesarry, but if wanted + * SAW filter selection: normally not necessary, but if wanted * the application can select a SAW filter via the driver by * using UIOs */ @@ -5423,7 +5423,7 @@ static int qam_demodulator_command(struct drxk_state *state, set_param_parameters[3] |= (QAM_MIRROR_AUTO_ON); /* Env parameters */ - /* check for LOCKRANGE Extented */ + /* check for LOCKRANGE Extended */ /* set_param_parameters[3] |= QAM_LOCKRANGE_NORMAL; */ status = scu_command(state, diff --git a/drivers/media/dvb-frontends/ds3000.c b/drivers/media/dvb-frontends/ds3000.c index 46a55146cb07..2b422d3ac5fa 100644 --- a/drivers/media/dvb-frontends/ds3000.c +++ b/drivers/media/dvb-frontends/ds3000.c @@ -914,7 +914,7 @@ static int ds3000_set_frontend(struct dvb_frontend *fe) /* ds3000 global reset */ ds3000_writereg(state, 0x07, 0x80); ds3000_writereg(state, 0x07, 0x00); - /* ds3000 build-in uC reset */ + /* ds3000 built-in uC reset */ ds3000_writereg(state, 0xb2, 0x01); /* ds3000 software reset */ ds3000_writereg(state, 0x00, 0x01); @@ -1023,7 +1023,7 @@ static int ds3000_set_frontend(struct dvb_frontend *fe) /* ds3000 out of software reset */ ds3000_writereg(state, 0x00, 0x00); - /* start ds3000 build-in uC */ + /* start ds3000 built-in uC */ ds3000_writereg(state, 0xb2, 0x00); if (fe->ops.tuner_ops.get_frequency) { diff --git a/drivers/media/dvb-frontends/isl6421.c b/drivers/media/dvb-frontends/isl6421.c index ae8ec59b665c..7de11d5062c2 100644 --- a/drivers/media/dvb-frontends/isl6421.c +++ b/drivers/media/dvb-frontends/isl6421.c @@ -98,7 +98,7 @@ static int isl6421_set_voltage(struct dvb_frontend *fe, if (ret != 2) return -EIO; - /* Store off status now incase future commands fail */ + /* Store off status now in case future commands fail */ isl6421->is_off = is_off; /* On overflow, the device will try again after 900 ms (typically) */ diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c index cee9c83e48de..99c6289ae585 100644 --- a/drivers/media/dvb-frontends/lgdt3306a.c +++ b/drivers/media/dvb-frontends/lgdt3306a.c @@ -1685,7 +1685,10 @@ static int lgdt3306a_read_signal_strength(struct dvb_frontend *fe, case QAM_256: case QAM_AUTO: /* need to know actual modulation to set proper SNR baseline */ - lgdt3306a_read_reg(state, 0x00a6, &val); + ret = lgdt3306a_read_reg(state, 0x00a6, &val); + if (lg_chkerr(ret)) + goto fail; + if(val & 0x04) ref_snr = 2800; /* QAM-256 28dB */ else diff --git a/drivers/media/dvb-frontends/lgdt330x.c b/drivers/media/dvb-frontends/lgdt330x.c index 96807e134886..8abb1a510a81 100644 --- a/drivers/media/dvb-frontends/lgdt330x.c +++ b/drivers/media/dvb-frontends/lgdt330x.c @@ -783,7 +783,7 @@ static int lgdt3303_read_status(struct dvb_frontend *fe, if ((buf[0] & 0x02) == 0x00) *status |= FE_HAS_SYNC; - if ((buf[0] & 0xfd) == 0x01) + if ((buf[0] & 0x01) == 0x01) *status |= FE_HAS_VITERBI | FE_HAS_LOCK; break; default: diff --git a/drivers/media/dvb-frontends/m88rs2000.c b/drivers/media/dvb-frontends/m88rs2000.c index d5bc85501f9e..13888732951c 100644 --- a/drivers/media/dvb-frontends/m88rs2000.c +++ b/drivers/media/dvb-frontends/m88rs2000.c @@ -701,7 +701,7 @@ static int m88rs2000_set_frontend(struct dvb_frontend *fe) if (status & FE_HAS_LOCK) { state->fec_inner = m88rs2000_get_fec(state); - /* Uknown suspect SNR level */ + /* Unknown suspect SNR level */ reg = m88rs2000_readreg(state, 0x65); } diff --git a/drivers/media/dvb-frontends/mt312.c b/drivers/media/dvb-frontends/mt312.c index 03e74a729168..bfbb879469f2 100644 --- a/drivers/media/dvb-frontends/mt312.c +++ b/drivers/media/dvb-frontends/mt312.c @@ -645,7 +645,9 @@ static int mt312_set_frontend(struct dvb_frontend *fe) if (ret < 0) return ret; - mt312_reset(state, 0); + ret = mt312_reset(state, 0); + if (ret < 0) + return ret; return 0; } diff --git a/drivers/media/dvb-frontends/nxt200x.c b/drivers/media/dvb-frontends/nxt200x.c index 0961e686ff68..0ef72d6c6f8b 100644 --- a/drivers/media/dvb-frontends/nxt200x.c +++ b/drivers/media/dvb-frontends/nxt200x.c @@ -153,7 +153,7 @@ static int nxt200x_writereg_multibyte (struct nxt200x_state* state, u8 reg, u8* u8 attr, len2, buf; dprintk("%s\n", __func__); - /* set mutli register register */ + /* set multi register register */ nxt200x_writebytes(state, 0x35, ®, 1); /* send the actual data */ @@ -214,7 +214,7 @@ static int nxt200x_readreg_multibyte (struct nxt200x_state* state, u8 reg, u8* d u8 buf, len2, attr; dprintk("%s\n", __func__); - /* set mutli register register */ + /* set multi register register */ nxt200x_writebytes(state, 0x35, ®, 1); switch (state->demod_chip) { diff --git a/drivers/media/dvb-frontends/or51211.c b/drivers/media/dvb-frontends/or51211.c index a39bbd8ff1f0..7343da11a1d8 100644 --- a/drivers/media/dvb-frontends/or51211.c +++ b/drivers/media/dvb-frontends/or51211.c @@ -59,7 +59,7 @@ struct or51211_state { /* Demodulator private data */ u8 initialized:1; - u32 snr; /* Result of last SNR claculation */ + u32 snr; /* Result of last SNR calculation */ /* Tuner private data */ u32 current_frequency; diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c index d6673f4fb47b..57fb05bb7e96 100644 --- a/drivers/media/dvb-frontends/rtl2832_sdr.c +++ b/drivers/media/dvb-frontends/rtl2832_sdr.c @@ -471,7 +471,7 @@ static int rtl2832_sdr_buf_prepare(struct vb2_buffer *vb) { struct rtl2832_sdr_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - /* Don't allow queing new buffers after device disconnection */ + /* Don't allow queueing new buffers after device disconnection */ if (!dev->udev) return -ENODEV; diff --git a/drivers/media/dvb-frontends/s5h1409.c b/drivers/media/dvb-frontends/s5h1409.c index ceeb0c3551ce..a2907d035fe2 100644 --- a/drivers/media/dvb-frontends/s5h1409.c +++ b/drivers/media/dvb-frontends/s5h1409.c @@ -490,7 +490,7 @@ static void s5h1409_set_qam_amhum_mode(struct dvb_frontend *fe) if (state->qam_state == QAM_STATE_QAM_OPTIMIZED_L3) { /* We've already reached the maximum optimization level, so - dont bother banging on the status registers */ + don't bother banging on the status registers */ return; } diff --git a/drivers/media/dvb-frontends/sp8870.c b/drivers/media/dvb-frontends/sp8870.c index 8d31cf3f4f07..270a3c559e08 100644 --- a/drivers/media/dvb-frontends/sp8870.c +++ b/drivers/media/dvb-frontends/sp8870.c @@ -293,7 +293,9 @@ static int sp8870_set_frontend_parameters(struct dvb_frontend *fe) sp8870_writereg(state, 0xc05, reg0xc05); // read status reg in order to clear pending irqs - sp8870_readreg(state, 0x200); + err = sp8870_readreg(state, 0x200); + if (err) + return err; // system controller start sp8870_microcontroller_start(state); diff --git a/drivers/media/dvb-frontends/stb0899_algo.c b/drivers/media/dvb-frontends/stb0899_algo.c index bd2defde7a77..b5debb61bca5 100644 --- a/drivers/media/dvb-frontends/stb0899_algo.c +++ b/drivers/media/dvb-frontends/stb0899_algo.c @@ -835,8 +835,8 @@ static u32 stb0899_dvbs2_calc_dev(struct stb0899_state *state) dec_ratio = (internal->master_clk * 2) / (5 * internal->srate); dec_ratio = (dec_ratio == 0) ? 1 : dec_ratio; - master_clk = internal->master_clk / 1000; /* for integer Caculation*/ - srate = internal->srate / 1000; /* for integer Caculation*/ + master_clk = internal->master_clk / 1000; /* for integer Calculation*/ + srate = internal->srate / 1000; /* for integer Calculation*/ correction = (512 * master_clk) / (2 * dec_ratio * srate); return correction; @@ -864,7 +864,7 @@ static void stb0899_dvbs2_set_srate(struct stb0899_state *state) win_sel = dec_rate - 4; decim = (1 << dec_rate); - /* (FSamp/Fsymbol *100) for integer Caculation */ + /* (FSamp/Fsymbol *100) for integer Calculation */ f_sym = internal->master_clk / ((decim * internal->srate) / 1000); if (f_sym <= 2250) /* don't band limit signal going into btr block*/ diff --git a/drivers/media/dvb-frontends/stv0367_defs.h b/drivers/media/dvb-frontends/stv0367_defs.h index 277d2971ed3f..4afe8248a667 100644 --- a/drivers/media/dvb-frontends/stv0367_defs.h +++ b/drivers/media/dvb-frontends/stv0367_defs.h @@ -1096,7 +1096,7 @@ static const struct st_register def0367dd_ofdm[] = { }; static const struct st_register def0367dd_qam[] = { - {R367CAB_CTRL_1, 0x06}, /* Orginal 0x04 */ + {R367CAB_CTRL_1, 0x06}, /* Original 0x04 */ {R367CAB_CTRL_2, 0x03}, {R367CAB_IT_STATUS1, 0x2b}, {R367CAB_IT_STATUS2, 0x08}, diff --git a/drivers/media/dvb-frontends/stv0900_core.c b/drivers/media/dvb-frontends/stv0900_core.c index 254618a06140..fa1a0fb577ad 100644 --- a/drivers/media/dvb-frontends/stv0900_core.c +++ b/drivers/media/dvb-frontends/stv0900_core.c @@ -744,12 +744,12 @@ static int stv0900_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks) if (stv0900_get_standard(fe, demod) == STV0900_DVBS2_STANDARD) { /* DVB-S2 delineator errors count */ - /* retreiving number for errnous headers */ + /* retrieving number for errnous headers */ err_val1 = stv0900_read_reg(intp, BBFCRCKO1); err_val0 = stv0900_read_reg(intp, BBFCRCKO0); header_err_val = (err_val1 << 8) | err_val0; - /* retreiving number for errnous packets */ + /* retrieving number for errnous packets */ err_val1 = stv0900_read_reg(intp, UPCRCKO1); err_val0 = stv0900_read_reg(intp, UPCRCKO0); *ucblocks = (err_val1 << 8) | err_val0; diff --git a/drivers/media/dvb-frontends/stv0910.c b/drivers/media/dvb-frontends/stv0910.c index fc2440d8af36..68d7c7b41071 100644 --- a/drivers/media/dvb-frontends/stv0910.c +++ b/drivers/media/dvb-frontends/stv0910.c @@ -1238,7 +1238,7 @@ static int gate_ctrl(struct dvb_frontend *fe, int enable) * mutex_lock note: Concurrent I2C gate bus accesses must be * prevented (STV0910 = dual demod on a single IC with a single I2C * gate/bus, and two tuners attached), similar to most (if not all) - * other I2C host interfaces/busses. + * other I2C host interfaces/buses. * * enable=1 (open I2C gate) will grab the lock * enable=0 (close I2C gate) releases the lock @@ -1500,7 +1500,7 @@ static int read_status(struct dvb_frontend *fe, enum fe_status *status) RSTV0910_P2_FBERCPT4 + state->regoff, 0x00); /* * Reset the packet Error counter2 (and Set it to - * infinit error count mode) + * infinite error count mode) */ write_reg(state, RSTV0910_P2_ERRCTRL2 + state->regoff, 0xc1); diff --git a/drivers/media/dvb-frontends/stv6110.c b/drivers/media/dvb-frontends/stv6110.c index 7db9a5bceccc..e54708eb4fb0 100644 --- a/drivers/media/dvb-frontends/stv6110.c +++ b/drivers/media/dvb-frontends/stv6110.c @@ -202,7 +202,7 @@ static int stv6110_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth) i++; } - /* RCCLKOFF = 1 calibration done, desactivate the calibration Clock */ + /* RCCLKOFF = 1 calibration done, deactivate the calibration Clock */ priv->regs[RSTV6110_CTRL3] |= (1 << 6); stv6110_write_regs(fe, &priv->regs[RSTV6110_CTRL3], RSTV6110_CTRL3, 1); return 0; diff --git a/drivers/media/dvb-frontends/tda1004x.h b/drivers/media/dvb-frontends/tda1004x.h index efd7659dace9..26f504a830e3 100644 --- a/drivers/media/dvb-frontends/tda1004x.h +++ b/drivers/media/dvb-frontends/tda1004x.h @@ -33,7 +33,7 @@ enum tda10046_xtal { enum tda10046_agc { TDA10046_AGC_DEFAULT, /* original configuration */ - TDA10046_AGC_IFO_AUTO_NEG, /* IF AGC only, automatic, negtive */ + TDA10046_AGC_IFO_AUTO_NEG, /* IF AGC only, automatic, negative */ TDA10046_AGC_IFO_AUTO_POS, /* IF AGC only, automatic, positive */ TDA10046_AGC_TDA827X, /* IF AGC only, special setup for tda827x */ }; diff --git a/drivers/media/dvb-frontends/tda10086.c b/drivers/media/dvb-frontends/tda10086.c index 8323e4e53d66..85dddfce8ef4 100644 --- a/drivers/media/dvb-frontends/tda10086.c +++ b/drivers/media/dvb-frontends/tda10086.c @@ -437,7 +437,7 @@ static int tda10086_set_frontend(struct dvb_frontend *fe) fe->ops.i2c_gate_ctrl(fe, 0); } - /* calcluate the frequency offset (in *Hz* not kHz) */ + /* calculate the frequency offset (in *Hz* not kHz) */ freqoff = fe_params->frequency - freq; freqoff = ((1<<16) * freqoff) / (SACLK/1000); tda10086_write_byte(state, 0x3d, 0x80 | ((freqoff >> 8) & 0x7f)); diff --git a/drivers/media/dvb-frontends/tda18271c2dd.c b/drivers/media/dvb-frontends/tda18271c2dd.c index eeb2318c102f..e064e2b22d9d 100644 --- a/drivers/media/dvb-frontends/tda18271c2dd.c +++ b/drivers/media/dvb-frontends/tda18271c2dd.c @@ -105,7 +105,7 @@ struct tda_state { s32 m_RF_B2[7]; u32 m_RF3[7]; - u8 m_TMValue_RFCal; /* Calibration temperatur */ + u8 m_TMValue_RFCal; /* Calibration temperature */ bool m_bFMInput; /* true to use Pin 8 for FM Radio */ @@ -400,7 +400,7 @@ static int CalibrateRF(struct tda_state *state, break; /* Switching off LT (as datasheet says) causes calibration on C1 to fail */ - /* (Readout of Cprog is allways 255) */ + /* (Readout of Cprog is always 255) */ if (state->m_Regs[ID] != 0x83) /* C1: ID == 83, C2: ID == 84 */ state->m_Regs[EP3] |= 0x40; /* SM_LT = 1 */ @@ -644,7 +644,7 @@ static int PowerScan(struct tda_state *state, if (status < 0) break; CID_Gain = Regs[EB10] & 0x3F; - state->m_Regs[ID] = Regs[ID]; /* Chip version, (needed for C1 workarround in CalibrateRF) */ + state->m_Regs[ID] = Regs[ID]; /* Chip version, (needed for C1 workaround in CalibrateRF) */ *pRF_Out = RF_in; diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 4c936e129500..6d32f8dcf83b 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -820,6 +820,25 @@ config VIDEO_OV7740 This is a Video4Linux2 sensor driver for the OmniVision OV7740 VGA camera sensor. +config VIDEO_OV8856 + tristate "OmniVision OV8856 sensor support" + depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on MEDIA_CAMERA_SUPPORT + select V4L2_FWNODE + help + This is a Video4Linux2 sensor driver for the OmniVision + OV8856 camera sensor. + + To compile this driver as a module, choose M here: the + module will be called ov8856. + +config VIDEO_OV9640 + tristate "OmniVision OV9640 sensor support" + depends on I2C && VIDEO_V4L2 + help + This is a Video4Linux2 sensor driver for the OmniVision + OV9640 camera sensor. + config VIDEO_OV9650 tristate "OmniVision OV9650/OV9652 sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API @@ -848,6 +867,14 @@ config VIDEO_VS6624 To compile this driver as a module, choose M here: the module will be called vs6624. +config VIDEO_MT9M001 + tristate "mt9m001 support" + depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on MEDIA_CAMERA_SUPPORT + help + This driver supports MT9M001 cameras from Micron, monochrome + and colour models. + config VIDEO_MT9M032 tristate "MT9M032 camera sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API @@ -1100,18 +1127,11 @@ config VIDEO_I2C Enable the I2C transport video support which supports the following: * Panasonic AMG88xx Grid-Eye Sensors + * Melexis MLX90640 Thermal Cameras To compile this driver as a module, choose M here: the module will be called video-i2c endmenu -menu "Sensors used on soc_camera driver" - -if SOC_CAMERA - source "drivers/media/i2c/soc_camera/Kconfig" -endif - -endmenu - endif diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 65fae7732de0..a64fca82e0c4 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -6,7 +6,6 @@ obj-$(CONFIG_VIDEO_SMIAPP) += smiapp/ obj-$(CONFIG_VIDEO_ET8EK8) += et8ek8/ obj-$(CONFIG_VIDEO_CX25840) += cx25840/ obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/ -obj-y += soc_camera/ obj-$(CONFIG_VIDEO_APTINA_PLL) += aptina-pll.o obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o @@ -78,8 +77,11 @@ obj-$(CONFIG_VIDEO_OV7640) += ov7640.o obj-$(CONFIG_VIDEO_OV7670) += ov7670.o obj-$(CONFIG_VIDEO_OV772X) += ov772x.o obj-$(CONFIG_VIDEO_OV7740) += ov7740.o +obj-$(CONFIG_VIDEO_OV8856) += ov8856.o +obj-$(CONFIG_VIDEO_OV9640) += ov9640.o obj-$(CONFIG_VIDEO_OV9650) += ov9650.o obj-$(CONFIG_VIDEO_OV13858) += ov13858.o +obj-$(CONFIG_VIDEO_MT9M001) += mt9m001.o obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o obj-$(CONFIG_VIDEO_MT9M111) += mt9m111.o obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o diff --git a/drivers/media/i2c/adv7175.c b/drivers/media/i2c/adv7175.c index e31e8d909bb9..419b98117133 100644 --- a/drivers/media/i2c/adv7175.c +++ b/drivers/media/i2c/adv7175.c @@ -219,7 +219,7 @@ static int adv7175_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) * SECAM->PAL (typically it does not work * due to genlock: when decoder is in SECAM * and encoder in in PAL the subcarrier can - * not be syncronized with horizontal + * not be synchronized with horizontal * quency) */ adv7175_write_block(sd, init_pal, sizeof(init_pal)); if (encoder->input == 0) diff --git a/drivers/media/i2c/adv748x/adv748x-afe.c b/drivers/media/i2c/adv748x/adv748x-afe.c index 71714634efb0..dbbb1e4d6363 100644 --- a/drivers/media/i2c/adv748x/adv748x-afe.c +++ b/drivers/media/i2c/adv748x/adv748x-afe.c @@ -282,7 +282,7 @@ static int adv748x_afe_s_stream(struct v4l2_subdev *sd, int enable) goto unlock; } - ret = adv748x_tx_power(&state->txb, enable); + ret = adv748x_tx_power(afe->tx, enable); if (ret) goto unlock; diff --git a/drivers/media/i2c/adv748x/adv748x-core.c b/drivers/media/i2c/adv748x/adv748x-core.c index 6854d898fdd1..f57cd77a32fa 100644 --- a/drivers/media/i2c/adv748x/adv748x-core.c +++ b/drivers/media/i2c/adv748x/adv748x-core.c @@ -23,6 +23,7 @@ #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-dv-timings.h> +#include <media/v4l2-fwnode.h> #include <media/v4l2-ioctl.h> #include "adv748x.h" @@ -124,6 +125,16 @@ int adv748x_write(struct adv748x_state *state, u8 page, u8 reg, u8 value) return regmap_write(state->regmap[page], reg, value); } +static int adv748x_write_check(struct adv748x_state *state, u8 page, u8 reg, + u8 value, int *error) +{ + if (*error) + return *error; + + *error = adv748x_write(state, page, reg, value); + return *error; +} + /* adv748x_write_block(): Write raw data with a maximum of I2C_SMBUS_BLOCK_MAX * size to one or more registers. * @@ -207,20 +218,13 @@ static int adv748x_write_regs(struct adv748x_state *state, { int ret; - while (regs->page != ADV748X_PAGE_EOR) { - if (regs->page == ADV748X_PAGE_WAIT) { - msleep(regs->value); - } else { - ret = adv748x_write(state, regs->page, regs->reg, - regs->value); - if (ret < 0) { - adv_err(state, - "Error regs page: 0x%02x reg: 0x%02x\n", - regs->page, regs->reg); - return ret; - } + for (; regs->page != ADV748X_PAGE_EOR; regs++) { + ret = adv748x_write(state, regs->page, regs->reg, regs->value); + if (ret < 0) { + adv_err(state, "Error regs page: 0x%02x reg: 0x%02x\n", + regs->page, regs->reg); + return ret; } - regs++; } return 0; @@ -230,68 +234,77 @@ static int adv748x_write_regs(struct adv748x_state *state, * TXA and TXB */ -static const struct adv748x_reg_value adv748x_power_up_txa_4lane[] = { +static int adv748x_power_up_tx(struct adv748x_csi2 *tx) +{ + struct adv748x_state *state = tx->state; + u8 page = is_txa(tx) ? ADV748X_PAGE_TXA : ADV748X_PAGE_TXB; + int ret = 0; - {ADV748X_PAGE_TXA, 0x00, 0x84}, /* Enable 4-lane MIPI */ - {ADV748X_PAGE_TXA, 0x00, 0xa4}, /* Set Auto DPHY Timing */ + /* Enable n-lane MIPI */ + adv748x_write_check(state, page, 0x00, 0x80 | tx->num_lanes, &ret); - {ADV748X_PAGE_TXA, 0x31, 0x82}, /* ADI Required Write */ - {ADV748X_PAGE_TXA, 0x1e, 0x40}, /* ADI Required Write */ - {ADV748X_PAGE_TXA, 0xda, 0x01}, /* i2c_mipi_pll_en - 1'b1 */ - {ADV748X_PAGE_WAIT, 0x00, 0x02},/* delay 2 */ - {ADV748X_PAGE_TXA, 0x00, 0x24 },/* Power-up CSI-TX */ - {ADV748X_PAGE_WAIT, 0x00, 0x01},/* delay 1 */ - {ADV748X_PAGE_TXA, 0xc1, 0x2b}, /* ADI Required Write */ - {ADV748X_PAGE_WAIT, 0x00, 0x01},/* delay 1 */ - {ADV748X_PAGE_TXA, 0x31, 0x80}, /* ADI Required Write */ + /* Set Auto DPHY Timing */ + adv748x_write_check(state, page, 0x00, 0xa0 | tx->num_lanes, &ret); - {ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */ -}; + /* ADI Required Write */ + if (tx->src == &state->hdmi.sd) { + adv748x_write_check(state, page, 0xdb, 0x10, &ret); + adv748x_write_check(state, page, 0xd6, 0x07, &ret); + } else { + adv748x_write_check(state, page, 0xd2, 0x40, &ret); + } -static const struct adv748x_reg_value adv748x_power_down_txa_4lane[] = { + adv748x_write_check(state, page, 0xc4, 0x0a, &ret); + adv748x_write_check(state, page, 0x71, 0x33, &ret); + adv748x_write_check(state, page, 0x72, 0x11, &ret); - {ADV748X_PAGE_TXA, 0x31, 0x82}, /* ADI Required Write */ - {ADV748X_PAGE_TXA, 0x1e, 0x00}, /* ADI Required Write */ - {ADV748X_PAGE_TXA, 0x00, 0x84}, /* Enable 4-lane MIPI */ - {ADV748X_PAGE_TXA, 0xda, 0x01}, /* i2c_mipi_pll_en - 1'b1 */ - {ADV748X_PAGE_TXA, 0xc1, 0x3b}, /* ADI Required Write */ + /* i2c_dphy_pwdn - 1'b0 */ + adv748x_write_check(state, page, 0xf0, 0x00, &ret); - {ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */ -}; + /* ADI Required Writes*/ + adv748x_write_check(state, page, 0x31, 0x82, &ret); + adv748x_write_check(state, page, 0x1e, 0x40, &ret); -static const struct adv748x_reg_value adv748x_power_up_txb_1lane[] = { + /* i2c_mipi_pll_en - 1'b1 */ + adv748x_write_check(state, page, 0xda, 0x01, &ret); + usleep_range(2000, 2500); - {ADV748X_PAGE_TXB, 0x00, 0x81}, /* Enable 1-lane MIPI */ - {ADV748X_PAGE_TXB, 0x00, 0xa1}, /* Set Auto DPHY Timing */ + /* Power-up CSI-TX */ + adv748x_write_check(state, page, 0x00, 0x20 | tx->num_lanes, &ret); + usleep_range(1000, 1500); - {ADV748X_PAGE_TXB, 0x31, 0x82}, /* ADI Required Write */ - {ADV748X_PAGE_TXB, 0x1e, 0x40}, /* ADI Required Write */ - {ADV748X_PAGE_TXB, 0xda, 0x01}, /* i2c_mipi_pll_en - 1'b1 */ - {ADV748X_PAGE_WAIT, 0x00, 0x02},/* delay 2 */ - {ADV748X_PAGE_TXB, 0x00, 0x21 },/* Power-up CSI-TX */ - {ADV748X_PAGE_WAIT, 0x00, 0x01},/* delay 1 */ - {ADV748X_PAGE_TXB, 0xc1, 0x2b}, /* ADI Required Write */ - {ADV748X_PAGE_WAIT, 0x00, 0x01},/* delay 1 */ - {ADV748X_PAGE_TXB, 0x31, 0x80}, /* ADI Required Write */ + /* ADI Required Writes */ + adv748x_write_check(state, page, 0xc1, 0x2b, &ret); + usleep_range(1000, 1500); + adv748x_write_check(state, page, 0x31, 0x80, &ret); - {ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */ -}; + return ret; +} -static const struct adv748x_reg_value adv748x_power_down_txb_1lane[] = { +static int adv748x_power_down_tx(struct adv748x_csi2 *tx) +{ + struct adv748x_state *state = tx->state; + u8 page = is_txa(tx) ? ADV748X_PAGE_TXA : ADV748X_PAGE_TXB; + int ret = 0; - {ADV748X_PAGE_TXB, 0x31, 0x82}, /* ADI Required Write */ - {ADV748X_PAGE_TXB, 0x1e, 0x00}, /* ADI Required Write */ - {ADV748X_PAGE_TXB, 0x00, 0x81}, /* Enable 1-lane MIPI */ - {ADV748X_PAGE_TXB, 0xda, 0x01}, /* i2c_mipi_pll_en - 1'b1 */ - {ADV748X_PAGE_TXB, 0xc1, 0x3b}, /* ADI Required Write */ + /* ADI Required Writes */ + adv748x_write_check(state, page, 0x31, 0x82, &ret); + adv748x_write_check(state, page, 0x1e, 0x00, &ret); - {ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */ -}; + /* Enable n-lane MIPI */ + adv748x_write_check(state, page, 0x00, 0x80 | tx->num_lanes, &ret); + + /* i2c_mipi_pll_en - 1'b1 */ + adv748x_write_check(state, page, 0xda, 0x01, &ret); + + /* ADI Required Write */ + adv748x_write_check(state, page, 0xc1, 0x3b, &ret); + + return ret; +} int adv748x_tx_power(struct adv748x_csi2 *tx, bool on) { - struct adv748x_state *state = tx->state; - const struct adv748x_reg_value *reglist; int val; if (!is_tx_enabled(tx)) @@ -309,19 +322,57 @@ int adv748x_tx_power(struct adv748x_csi2 *tx, bool on) WARN_ONCE((on && val & ADV748X_CSI_FS_AS_LS_UNKNOWN), "Enabling with unknown bit set"); - if (on) - reglist = is_txa(tx) ? adv748x_power_up_txa_4lane : - adv748x_power_up_txb_1lane; - else - reglist = is_txa(tx) ? adv748x_power_down_txa_4lane : - adv748x_power_down_txb_1lane; - - return adv748x_write_regs(state, reglist); + return on ? adv748x_power_up_tx(tx) : adv748x_power_down_tx(tx); } /* ----------------------------------------------------------------------------- * Media Operations */ +static int adv748x_link_setup(struct media_entity *entity, + const struct media_pad *local, + const struct media_pad *remote, u32 flags) +{ + struct v4l2_subdev *rsd = media_entity_to_v4l2_subdev(remote->entity); + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); + struct adv748x_state *state = v4l2_get_subdevdata(sd); + struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd); + bool enable = flags & MEDIA_LNK_FL_ENABLED; + u8 io10_mask = ADV748X_IO_10_CSI1_EN | + ADV748X_IO_10_CSI4_EN | + ADV748X_IO_10_CSI4_IN_SEL_AFE; + u8 io10 = 0; + + /* Refuse to enable multiple links to the same TX at the same time. */ + if (enable && tx->src) + return -EINVAL; + + /* Set or clear the source (HDMI or AFE) and the current TX. */ + if (rsd == &state->afe.sd) + state->afe.tx = enable ? tx : NULL; + else + state->hdmi.tx = enable ? tx : NULL; + + tx->src = enable ? rsd : NULL; + + if (state->afe.tx) { + /* AFE Requires TXA enabled, even when output to TXB */ + io10 |= ADV748X_IO_10_CSI4_EN; + if (is_txa(tx)) + io10 |= ADV748X_IO_10_CSI4_IN_SEL_AFE; + else + io10 |= ADV748X_IO_10_CSI1_EN; + } + + if (state->hdmi.tx) + io10 |= ADV748X_IO_10_CSI4_EN; + + return io_clrset(state, ADV748X_IO_10, io10_mask, io10); +} + +static const struct media_entity_operations adv748x_tx_media_ops = { + .link_setup = adv748x_link_setup, + .link_validate = v4l2_subdev_link_validate, +}; static const struct media_entity_operations adv748x_media_ops = { .link_validate = v4l2_subdev_link_validate, @@ -331,18 +382,8 @@ static const struct media_entity_operations adv748x_media_ops = { * HW setup */ -static const struct adv748x_reg_value adv748x_sw_reset[] = { - - {ADV748X_PAGE_IO, 0xff, 0xff}, /* SW reset */ - {ADV748X_PAGE_WAIT, 0x00, 0x05},/* delay 5 */ - {ADV748X_PAGE_IO, 0x01, 0x76}, /* ADI Required Write */ - {ADV748X_PAGE_IO, 0xf2, 0x01}, /* Enable I2C Read Auto-Increment */ - {ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */ -}; - -/* Supported Formats For Script Below */ -/* - 01-29 HDMI to MIPI TxA CSI 4-Lane - RGB888: */ -static const struct adv748x_reg_value adv748x_init_txa_4lane[] = { +/* Initialize CP Core with RGB888 format. */ +static const struct adv748x_reg_value adv748x_init_hdmi[] = { /* Disable chip powerdown & Enable HDMI Rx block */ {ADV748X_PAGE_IO, 0x00, 0x40}, @@ -383,32 +424,11 @@ static const struct adv748x_reg_value adv748x_init_txa_4lane[] = { {ADV748X_PAGE_IO, 0x0c, 0xe0}, /* Enable LLC_DLL & Double LLC Timing */ {ADV748X_PAGE_IO, 0x0e, 0xdd}, /* LLC/PIX/SPI PINS TRISTATED AUD */ - {ADV748X_PAGE_TXA, 0x00, 0x84}, /* Enable 4-lane MIPI */ - {ADV748X_PAGE_TXA, 0x00, 0xa4}, /* Set Auto DPHY Timing */ - {ADV748X_PAGE_TXA, 0xdb, 0x10}, /* ADI Required Write */ - {ADV748X_PAGE_TXA, 0xd6, 0x07}, /* ADI Required Write */ - {ADV748X_PAGE_TXA, 0xc4, 0x0a}, /* ADI Required Write */ - {ADV748X_PAGE_TXA, 0x71, 0x33}, /* ADI Required Write */ - {ADV748X_PAGE_TXA, 0x72, 0x11}, /* ADI Required Write */ - {ADV748X_PAGE_TXA, 0xf0, 0x00}, /* i2c_dphy_pwdn - 1'b0 */ - - {ADV748X_PAGE_TXA, 0x31, 0x82}, /* ADI Required Write */ - {ADV748X_PAGE_TXA, 0x1e, 0x40}, /* ADI Required Write */ - {ADV748X_PAGE_TXA, 0xda, 0x01}, /* i2c_mipi_pll_en - 1'b1 */ - {ADV748X_PAGE_WAIT, 0x00, 0x02},/* delay 2 */ - {ADV748X_PAGE_TXA, 0x00, 0x24 },/* Power-up CSI-TX */ - {ADV748X_PAGE_WAIT, 0x00, 0x01},/* delay 1 */ - {ADV748X_PAGE_TXA, 0xc1, 0x2b}, /* ADI Required Write */ - {ADV748X_PAGE_WAIT, 0x00, 0x01},/* delay 1 */ - {ADV748X_PAGE_TXA, 0x31, 0x80}, /* ADI Required Write */ - {ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */ }; -/* 02-01 Analog CVBS to MIPI TX-B CSI 1-Lane - */ -/* Autodetect CVBS Single Ended In Ain 1 - MIPI Out */ -static const struct adv748x_reg_value adv748x_init_txb_1lane[] = { - +/* Initialize AFE core with YUV8 format. */ +static const struct adv748x_reg_value adv748x_init_afe[] = { {ADV748X_PAGE_IO, 0x00, 0x30}, /* Disable chip powerdown Rx */ {ADV748X_PAGE_IO, 0xf2, 0x01}, /* Enable I2C Read Auto-Increment */ @@ -435,33 +455,36 @@ static const struct adv748x_reg_value adv748x_init_txb_1lane[] = { {ADV748X_PAGE_SDP, 0x31, 0x12}, /* ADI Required Write */ {ADV748X_PAGE_SDP, 0xe6, 0x4f}, /* V bit end pos manually in NTSC */ - {ADV748X_PAGE_TXB, 0x00, 0x81}, /* Enable 1-lane MIPI */ - {ADV748X_PAGE_TXB, 0x00, 0xa1}, /* Set Auto DPHY Timing */ - {ADV748X_PAGE_TXB, 0xd2, 0x40}, /* ADI Required Write */ - {ADV748X_PAGE_TXB, 0xc4, 0x0a}, /* ADI Required Write */ - {ADV748X_PAGE_TXB, 0x71, 0x33}, /* ADI Required Write */ - {ADV748X_PAGE_TXB, 0x72, 0x11}, /* ADI Required Write */ - {ADV748X_PAGE_TXB, 0xf0, 0x00}, /* i2c_dphy_pwdn - 1'b0 */ - {ADV748X_PAGE_TXB, 0x31, 0x82}, /* ADI Required Write */ - {ADV748X_PAGE_TXB, 0x1e, 0x40}, /* ADI Required Write */ - {ADV748X_PAGE_TXB, 0xda, 0x01}, /* i2c_mipi_pll_en - 1'b1 */ - - {ADV748X_PAGE_WAIT, 0x00, 0x02},/* delay 2 */ - {ADV748X_PAGE_TXB, 0x00, 0x21 },/* Power-up CSI-TX */ - {ADV748X_PAGE_WAIT, 0x00, 0x01},/* delay 1 */ - {ADV748X_PAGE_TXB, 0xc1, 0x2b}, /* ADI Required Write */ - {ADV748X_PAGE_WAIT, 0x00, 0x01},/* delay 1 */ - {ADV748X_PAGE_TXB, 0x31, 0x80}, /* ADI Required Write */ - {ADV748X_PAGE_EOR, 0xff, 0xff} /* End of register table */ }; +static int adv748x_sw_reset(struct adv748x_state *state) +{ + int ret; + + ret = io_write(state, ADV748X_IO_REG_FF, ADV748X_IO_REG_FF_MAIN_RESET); + if (ret) + return ret; + + usleep_range(5000, 6000); + + /* Disable CEC Wakeup from power-down mode */ + ret = io_clrset(state, ADV748X_IO_REG_01, ADV748X_IO_REG_01_PWRDN_MASK, + ADV748X_IO_REG_01_PWRDNB); + if (ret) + return ret; + + /* Enable I2C Read Auto-Increment for consecutive reads */ + return io_write(state, ADV748X_IO_REG_F2, + ADV748X_IO_REG_F2_READ_AUTO_INC); +} + static int adv748x_reset(struct adv748x_state *state) { int ret; u8 regval = 0; - ret = adv748x_write_regs(state, adv748x_sw_reset); + ret = adv748x_sw_reset(state); if (ret < 0) return ret; @@ -469,18 +492,19 @@ static int adv748x_reset(struct adv748x_state *state) if (ret < 0) return ret; - /* Init and power down TXA */ - ret = adv748x_write_regs(state, adv748x_init_txa_4lane); + /* Initialize CP and AFE cores. */ + ret = adv748x_write_regs(state, adv748x_init_hdmi); if (ret) return ret; - adv748x_tx_power(&state->txa, 0); - - /* Init and power down TXB */ - ret = adv748x_write_regs(state, adv748x_init_txb_1lane); + ret = adv748x_write_regs(state, adv748x_init_afe); if (ret) return ret; + /* Reset TXA and TXB */ + adv748x_tx_power(&state->txa, 1); + adv748x_tx_power(&state->txa, 0); + adv748x_tx_power(&state->txb, 1); adv748x_tx_power(&state->txb, 0); /* Disable chip powerdown & Enable HDMI Rx block */ @@ -542,7 +566,51 @@ void adv748x_subdev_init(struct v4l2_subdev *sd, struct adv748x_state *state, state->client->addr, ident); sd->entity.function = function; - sd->entity.ops = &adv748x_media_ops; + sd->entity.ops = is_tx(adv748x_sd_to_csi2(sd)) ? + &adv748x_tx_media_ops : &adv748x_media_ops; +} + +static int adv748x_parse_csi2_lanes(struct adv748x_state *state, + unsigned int port, + struct device_node *ep) +{ + struct v4l2_fwnode_endpoint vep; + unsigned int num_lanes; + int ret; + + if (port != ADV748X_PORT_TXA && port != ADV748X_PORT_TXB) + return 0; + + vep.bus_type = V4L2_MBUS_CSI2_DPHY; + ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &vep); + if (ret) + return ret; + + num_lanes = vep.bus.mipi_csi2.num_data_lanes; + + if (vep.base.port == ADV748X_PORT_TXA) { + if (num_lanes != 1 && num_lanes != 2 && num_lanes != 4) { + adv_err(state, "TXA: Invalid number (%u) of lanes\n", + num_lanes); + return -EINVAL; + } + + state->txa.num_lanes = num_lanes; + adv_dbg(state, "TXA: using %u lanes\n", state->txa.num_lanes); + } + + if (vep.base.port == ADV748X_PORT_TXB) { + if (num_lanes != 1) { + adv_err(state, "TXB: Invalid number (%u) of lanes\n", + num_lanes); + return -EINVAL; + } + + state->txb.num_lanes = num_lanes; + adv_dbg(state, "TXB: using %u lanes\n", state->txb.num_lanes); + } + + return 0; } static int adv748x_parse_dt(struct adv748x_state *state) @@ -551,6 +619,7 @@ static int adv748x_parse_dt(struct adv748x_state *state) struct of_endpoint ep; bool out_found = false; bool in_found = false; + int ret; for_each_endpoint_of_node(state->dev->of_node, ep_np) { of_graph_parse_endpoint(ep_np, &ep); @@ -581,6 +650,11 @@ static int adv748x_parse_dt(struct adv748x_state *state) in_found = true; else out_found = true; + + /* Store number of CSI-2 lanes used for TXA and TXB. */ + ret = adv748x_parse_csi2_lanes(state, ep.port, ep_np); + if (ret) + return ret; } return in_found && out_found ? 0 : -ENODEV; @@ -604,7 +678,7 @@ static int adv748x_probe(struct i2c_client *client, if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -EIO; - state = kzalloc(sizeof(struct adv748x_state), GFP_KERNEL); + state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL); if (!state) return -ENOMEM; @@ -702,7 +776,6 @@ err_cleanup_dt: adv748x_dt_cleanup(state); err_free_mutex: mutex_destroy(&state->mutex); - kfree(state); return ret; } @@ -721,8 +794,6 @@ static int adv748x_remove(struct i2c_client *client) adv748x_dt_cleanup(state); mutex_destroy(&state->mutex); - kfree(state); - return 0; } diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c index 6ce21542ed48..2091cda50935 100644 --- a/drivers/media/i2c/adv748x/adv748x-csi2.c +++ b/drivers/media/i2c/adv748x/adv748x-csi2.c @@ -27,6 +27,7 @@ static int adv748x_csi2_set_virtual_channel(struct adv748x_csi2 *tx, * @v4l2_dev: Video registration device * @src: Source subdevice to establish link * @src_pad: Pad number of source to link to this @tx + * @enable: Link enabled flag * * Ensure that the subdevice is registered against the v4l2_device, and link the * source pad to the sink pad of the CSI2 bus entity. @@ -34,26 +35,27 @@ static int adv748x_csi2_set_virtual_channel(struct adv748x_csi2 *tx, static int adv748x_csi2_register_link(struct adv748x_csi2 *tx, struct v4l2_device *v4l2_dev, struct v4l2_subdev *src, - unsigned int src_pad) + unsigned int src_pad, + bool enable) { - int enabled = MEDIA_LNK_FL_ENABLED; int ret; - /* - * Dynamic linking of the AFE is not supported. - * Register the links as immutable. - */ - enabled |= MEDIA_LNK_FL_IMMUTABLE; - if (!src->v4l2_dev) { ret = v4l2_device_register_subdev(v4l2_dev, src); if (ret) return ret; } - return media_create_pad_link(&src->entity, src_pad, - &tx->sd.entity, ADV748X_CSI2_SINK, - enabled); + ret = media_create_pad_link(&src->entity, src_pad, + &tx->sd.entity, ADV748X_CSI2_SINK, + enable ? MEDIA_LNK_FL_ENABLED : 0); + if (ret) + return ret; + + if (enable) + tx->src = src; + + return 0; } /* ----------------------------------------------------------------------------- @@ -68,24 +70,42 @@ static int adv748x_csi2_registered(struct v4l2_subdev *sd) { struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd); struct adv748x_state *state = tx->state; + int ret; adv_dbg(state, "Registered %s (%s)", is_txa(tx) ? "TXA":"TXB", sd->name); /* - * The adv748x hardware allows the AFE to route through the TXA, however - * this is not currently supported in this driver. + * Link TXA to AFE and HDMI, and TXB to AFE only as TXB cannot output + * HDMI. * - * Link HDMI->TXA, and AFE->TXB directly. + * The HDMI->TXA link is enabled by default, as is the AFE->TXB one. */ - if (is_txa(tx) && is_hdmi_enabled(state)) - return adv748x_csi2_register_link(tx, sd->v4l2_dev, - &state->hdmi.sd, - ADV748X_HDMI_SOURCE); - if (!is_txa(tx) && is_afe_enabled(state)) - return adv748x_csi2_register_link(tx, sd->v4l2_dev, - &state->afe.sd, - ADV748X_AFE_SOURCE); + if (is_afe_enabled(state)) { + ret = adv748x_csi2_register_link(tx, sd->v4l2_dev, + &state->afe.sd, + ADV748X_AFE_SOURCE, + is_txb(tx)); + if (ret) + return ret; + + /* TXB can output AFE signals only. */ + if (is_txb(tx)) + state->afe.tx = tx; + } + + /* Register link to HDMI for TXA only. */ + if (is_txb(tx) || !is_hdmi_enabled(state)) + return 0; + + ret = adv748x_csi2_register_link(tx, sd->v4l2_dev, &state->hdmi.sd, + ADV748X_HDMI_SOURCE, true); + if (ret) + return ret; + + /* The default HDMI output is TXA. */ + state->hdmi.tx = tx; + return 0; } diff --git a/drivers/media/i2c/adv748x/adv748x-hdmi.c b/drivers/media/i2c/adv748x/adv748x-hdmi.c index 35d027941482..c557f8fdf11a 100644 --- a/drivers/media/i2c/adv748x/adv748x-hdmi.c +++ b/drivers/media/i2c/adv748x/adv748x-hdmi.c @@ -358,7 +358,7 @@ static int adv748x_hdmi_s_stream(struct v4l2_subdev *sd, int enable) mutex_lock(&state->mutex); - ret = adv748x_tx_power(&state->txa, enable); + ret = adv748x_tx_power(hdmi->tx, enable); if (ret) goto done; diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h index 39c2fdc3b416..5042f9e94aee 100644 --- a/drivers/media/i2c/adv748x/adv748x.h +++ b/drivers/media/i2c/adv748x/adv748x.h @@ -39,7 +39,6 @@ enum adv748x_page { ADV748X_PAGE_MAX, /* Fake pages for register sequences */ - ADV748X_PAGE_WAIT, /* Wait x msec */ ADV748X_PAGE_EOR, /* End Mark */ }; @@ -79,17 +78,23 @@ struct adv748x_csi2 { struct v4l2_mbus_framefmt format; unsigned int page; unsigned int port; + unsigned int num_lanes; struct media_pad pads[ADV748X_CSI2_NR_PADS]; struct v4l2_ctrl_handler ctrl_hdl; struct v4l2_ctrl *pixel_rate; + struct v4l2_subdev *src; struct v4l2_subdev sd; }; #define notifier_to_csi2(n) container_of(n, struct adv748x_csi2, notifier) #define adv748x_sd_to_csi2(sd) container_of(sd, struct adv748x_csi2, sd) + #define is_tx_enabled(_tx) ((_tx)->state->endpoints[(_tx)->port] != NULL) #define is_txa(_tx) ((_tx) == &(_tx)->state->txa) +#define is_txb(_tx) ((_tx) == &(_tx)->state->txb) +#define is_tx(_tx) (is_txa(_tx) || is_txb(_tx)) + #define is_afe_enabled(_state) \ ((_state)->endpoints[ADV748X_PORT_AIN0] != NULL || \ (_state)->endpoints[ADV748X_PORT_AIN1] != NULL || \ @@ -116,6 +121,8 @@ struct adv748x_hdmi { struct v4l2_dv_timings timings; struct v4l2_fract aspect_ratio; + struct adv748x_csi2 *tx; + struct { u8 edid[512]; u32 present; @@ -146,6 +153,8 @@ struct adv748x_afe { struct v4l2_subdev sd; struct v4l2_mbus_framefmt format; + struct adv748x_csi2 *tx; + bool streaming; v4l2_std_id curr_norm; unsigned int input; @@ -201,6 +210,11 @@ struct adv748x_state { #define ADV748X_IO_PD 0x00 /* power down controls */ #define ADV748X_IO_PD_RX_EN BIT(6) +#define ADV748X_IO_REG_01 0x01 /* pwrdn{2}b, prog_xtal_freq */ +#define ADV748X_IO_REG_01_PWRDN_MASK (BIT(7) | BIT(6)) +#define ADV748X_IO_REG_01_PWRDN2B BIT(7) /* CEC Wakeup Support */ +#define ADV748X_IO_REG_01_PWRDNB BIT(6) /* CEC Wakeup Support */ + #define ADV748X_IO_REG_04 0x04 #define ADV748X_IO_REG_04_FORCE_FR BIT(0) /* Force CP free-run */ @@ -214,12 +228,24 @@ struct adv748x_state { #define ADV748X_IO_10_CSI4_EN BIT(7) #define ADV748X_IO_10_CSI1_EN BIT(6) #define ADV748X_IO_10_PIX_OUT_EN BIT(5) +#define ADV748X_IO_10_CSI4_IN_SEL_AFE BIT(3) #define ADV748X_IO_CHIP_REV_ID_1 0xdf #define ADV748X_IO_CHIP_REV_ID_2 0xe0 +#define ADV748X_IO_REG_F2 0xf2 +#define ADV748X_IO_REG_F2_READ_AUTO_INC BIT(0) + +/* For PAGE slave address offsets */ #define ADV748X_IO_SLAVE_ADDR_BASE 0xf2 +/* + * The ADV748x_Recommended_Settings_PrA_2014-08-20.pdf details both 0x80 and + * 0xff as examples for performing a software reset. + */ +#define ADV748X_IO_REG_FF 0xff +#define ADV748X_IO_REG_FF_MAIN_RESET 0xff + /* HDMI RX Map */ #define ADV748X_HDMI_LW1 0x07 /* line width_1 */ #define ADV748X_HDMI_LW1_VERT_FILTER BIT(7) diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 989259488e3d..11ab2df02dc7 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -3102,11 +3102,11 @@ static int adv7842_ddr_ram_test(struct v4l2_subdev *sd) io_write(sd, 0x00, 0x01); /* Program SDP 4x1 */ io_write(sd, 0x01, 0x00); /* Program SDP mode */ - afe_write(sd, 0x80, 0x92); /* SDP Recommeneded Write */ - afe_write(sd, 0x9B, 0x01); /* SDP Recommeneded Write ADV7844ES1 */ - afe_write(sd, 0x9C, 0x60); /* SDP Recommeneded Write ADV7844ES1 */ - afe_write(sd, 0x9E, 0x02); /* SDP Recommeneded Write ADV7844ES1 */ - afe_write(sd, 0xA0, 0x0B); /* SDP Recommeneded Write ADV7844ES1 */ + afe_write(sd, 0x80, 0x92); /* SDP Recommended Write */ + afe_write(sd, 0x9B, 0x01); /* SDP Recommended Write ADV7844ES1 */ + afe_write(sd, 0x9C, 0x60); /* SDP Recommended Write ADV7844ES1 */ + afe_write(sd, 0x9E, 0x02); /* SDP Recommended Write ADV7844ES1 */ + afe_write(sd, 0xA0, 0x0B); /* SDP Recommended Write ADV7844ES1 */ afe_write(sd, 0xC3, 0x02); /* Memory BIST Initialisation */ io_write(sd, 0x0C, 0x40); /* Power up ADV7844 */ io_write(sd, 0x15, 0xBA); /* Enable outputs */ diff --git a/drivers/media/i2c/bt819.c b/drivers/media/i2c/bt819.c index 472e37637c8d..e6d3fe7790bc 100644 --- a/drivers/media/i2c/bt819.c +++ b/drivers/media/i2c/bt819.c @@ -164,12 +164,12 @@ static int bt819_init(struct v4l2_subdev *sd) 0x0e, 0xb4, /* 0x0e Chroma Gain (V) msb */ 0x0f, 0x00, /* 0x0f Hue control */ 0x12, 0x04, /* 0x12 Output Format */ - 0x13, 0x20, /* 0x13 Vertial Scaling msb 0x00 + 0x13, 0x20, /* 0x13 Vertical Scaling msb 0x00 chroma comb OFF, line drop scaling, interlace scaling BUG? Why does turning the chroma comb on fuck up color? Bug in the bt819 stepping on my board? */ - 0x14, 0x00, /* 0x14 Vertial Scaling lsb */ + 0x14, 0x00, /* 0x14 Vertical Scaling lsb */ 0x16, 0x07, /* 0x16 Video Timing Polarity ACTIVE=active low FIELD: high=odd, diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index b168bf3635b6..8b0b8b5aa531 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -5216,8 +5216,9 @@ static int cx25840_probe(struct i2c_client *client, * those extra inputs. So, let's add it only when needed. */ state->pads[CX25840_PAD_INPUT].flags = MEDIA_PAD_FL_SINK; + state->pads[CX25840_PAD_INPUT].sig_type = PAD_SIGNAL_ANALOG; state->pads[CX25840_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE; - state->pads[CX25840_PAD_VBI_OUT].flags = MEDIA_PAD_FL_SOURCE; + state->pads[CX25840_PAD_VID_OUT].sig_type = PAD_SIGNAL_DV; sd->entity.function = MEDIA_ENT_F_ATV_DECODER; ret = media_entity_pads_init(&sd->entity, ARRAY_SIZE(state->pads), diff --git a/drivers/media/i2c/cx25840/cx25840-core.h b/drivers/media/i2c/cx25840/cx25840-core.h index c323b1af1f83..e3ff1d7ec770 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.h +++ b/drivers/media/i2c/cx25840/cx25840-core.h @@ -40,7 +40,6 @@ enum cx25840_model { enum cx25840_media_pads { CX25840_PAD_INPUT, CX25840_PAD_VID_OUT, - CX25840_PAD_VBI_OUT, CX25840_NUM_PADS }; @@ -67,7 +66,7 @@ enum cx25840_media_pads { * @is_initialized: whether we have already loaded firmware into the chip * and initialized it * @vbi_regs_offset: offset of vbi regs - * @fw_wait: wait queue to wake an initalization function up when + * @fw_wait: wait queue to wake an initialization function up when * firmware loading (on a separate workqueue) finishes * @fw_work: a work that actually loads the firmware on a separate * workqueue diff --git a/drivers/media/i2c/cx25840/cx25840-ir.c b/drivers/media/i2c/cx25840/cx25840-ir.c index 69cdc09981af..a266118cd7ca 100644 --- a/drivers/media/i2c/cx25840/cx25840-ir.c +++ b/drivers/media/i2c/cx25840/cx25840-ir.c @@ -549,7 +549,7 @@ int cx25840_ir_irq_handler(struct v4l2_subdev *sd, u32 status, bool *handled) ror = stats & STATS_ROR; /* Rx FIFO Over Run */ tse = irqen & IRQEN_TSE; /* Tx FIFO Service Request IRQ Enable */ - rse = irqen & IRQEN_RSE; /* Rx FIFO Service Reuqest IRQ Enable */ + rse = irqen & IRQEN_RSE; /* Rx FIFO Service Request IRQ Enable */ rte = irqen & IRQEN_RTE; /* Rx Pulse Width Timer Time Out IRQ Enable */ roe = irqen & IRQEN_ROE; /* Rx FIFO Over Run IRQ Enable */ @@ -638,7 +638,7 @@ int cx25840_ir_irq_handler(struct v4l2_subdev *sd, u32 status, bool *handled) events |= V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED; } if (v) { - /* Clear STATS_ROR & STATS_RTO as needed by reseting hardware */ + /* Clear STATS_ROR & STATS_RTO as needed by resetting hardware */ cx25840_write4(c, CX25840_IR_CNTRL_REG, cntrl & ~v); cx25840_write4(c, CX25840_IR_CNTRL_REG, cntrl); *handled = true; diff --git a/drivers/media/i2c/dw9714.c b/drivers/media/i2c/dw9714.c index 26d83693a681..3f0b082f863f 100644 --- a/drivers/media/i2c/dw9714.c +++ b/drivers/media/i2c/dw9714.c @@ -267,7 +267,7 @@ static struct i2c_driver dw9714_i2c_driver = { module_i2c_driver(dw9714_i2c_driver); MODULE_AUTHOR("Tianshu Qiu <tian.shu.qiu@intel.com>"); -MODULE_AUTHOR("Jian Xu Zheng <jian.xu.zheng@intel.com>"); +MODULE_AUTHOR("Jian Xu Zheng"); MODULE_AUTHOR("Yuning Pu <yuning.pu@intel.com>"); MODULE_AUTHOR("Jouni Ukkonen <jouni.ukkonen@intel.com>"); MODULE_AUTHOR("Tommi Franttila <tommi.franttila@intel.com>"); diff --git a/drivers/media/i2c/et8ek8/et8ek8_mode.c b/drivers/media/i2c/et8ek8/et8ek8_mode.c index a79882a83885..f503303cb8bc 100644 --- a/drivers/media/i2c/et8ek8/et8ek8_mode.c +++ b/drivers/media/i2c/et8ek8/et8ek8_mode.c @@ -79,7 +79,7 @@ static struct et8ek8_reglist mode1_poweron_mode2_16vga_2592x1968_12_07fps = { { ET8EK8_REG_8BIT, 0x1258, 0x00 }, /* From parallel out to serial out */ { ET8EK8_REG_8BIT, 0x125D, 0x88 }, - /* From w/ embeded data to w/o embeded data */ + /* From w/ embedded data to w/o embedded data */ { ET8EK8_REG_8BIT, 0x125E, 0xC0 }, /* CCP2 out is from STOP to ACTIVE */ { ET8EK8_REG_8BIT, 0x1263, 0x98 }, diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c index ec3d1b855f62..9857e151db46 100644 --- a/drivers/media/i2c/imx214.c +++ b/drivers/media/i2c/imx214.c @@ -377,7 +377,7 @@ static const struct reg_8 mode_table_common[] = { /* Moire reduction */ {0x6957, 0x01}, - /* image enhancment */ + /* image enhancement */ {0x6987, 0x17}, {0x698A, 0x03}, {0x698B, 0x03}, diff --git a/drivers/media/i2c/imx274.c b/drivers/media/i2c/imx274.c index 5fac7fd32634..f3ff1af209f9 100644 --- a/drivers/media/i2c/imx274.c +++ b/drivers/media/i2c/imx274.c @@ -207,8 +207,8 @@ static const char * const tp_qmenu[] = { "Vertical Stripe (555h / 000h)", "Vertical Stripe (000h / FFFh)", "Vertical Stripe (FFFh / 000h)", - "Horizontal Color Bars", "Vertical Color Bars", + "Horizontal Color Bars", }; /* @@ -405,12 +405,12 @@ static const struct reg_8 imx274_start_2[] = { */ static const struct reg_8 imx274_start_3[] = { {0x30F4, 0x00}, - {0x3018, 0xA2}, /* XHS VHS OUTUPT */ + {0x3018, 0xA2}, /* XHS VHS OUTPUT */ {IMX274_TABLE_END, 0x00} }; /* - * imx274 register configuration for stoping stream + * imx274 register configuration for stopping stream */ static const struct reg_8 imx274_stop[] = { {IMX274_STANDBY_REG, 0x01}, @@ -617,24 +617,6 @@ static int imx274_write_table(struct stimx274 *priv, const struct reg_8 table[]) return 0; } -static inline int imx274_read_reg(struct stimx274 *priv, u16 addr, u8 *val) -{ - unsigned int uint_val; - int err; - - err = regmap_read(priv->regmap, addr, &uint_val); - if (err) - dev_err(&priv->client->dev, - "%s : i2c read failed, addr = %x\n", __func__, addr); - else - dev_dbg(&priv->client->dev, - "%s : addr 0x%x, val=0x%x\n", __func__, - addr, uint_val); - - *val = uint_val; - return err; -} - static inline int imx274_write_reg(struct stimx274 *priv, u16 addr, u8 val) { int err; diff --git a/drivers/media/i2c/lm3560.c b/drivers/media/i2c/lm3560.c index f122f03bd6b7..70c3294c21d3 100644 --- a/drivers/media/i2c/lm3560.c +++ b/drivers/media/i2c/lm3560.c @@ -55,7 +55,7 @@ enum led_enable { * @regmap: reg. map for i2c * @lock: muxtex for serial access. * @led_mode: V4L2 LED mode - * @ctrls_led: V4L2 contols + * @ctrls_led: V4L2 controls * @subdev_led: V4L2 subdev */ struct lm3560_flash { diff --git a/drivers/media/i2c/lm3646.c b/drivers/media/i2c/lm3646.c index 12ef2653987b..73fbe3c37fc9 100644 --- a/drivers/media/i2c/lm3646.c +++ b/drivers/media/i2c/lm3646.c @@ -62,7 +62,7 @@ enum led_mode { * @regmap: reg. map for i2c * @lock: muxtex for serial access. * @led_mode: V4L2 LED mode - * @ctrls_led: V4L2 contols + * @ctrls_led: V4L2 controls * @subdev_led: V4L2 subdev * @mode_reg : mode register value */ diff --git a/drivers/media/i2c/m5mols/m5mols.h b/drivers/media/i2c/m5mols/m5mols.h index 90a6c520f115..aef5b4f8904e 100644 --- a/drivers/media/i2c/m5mols/m5mols.h +++ b/drivers/media/i2c/m5mols/m5mols.h @@ -253,7 +253,7 @@ struct m5mols_info { * * The I2C read operation of the M-5MOLS requires 2 messages. The first * message sends the information about the command, command category, and total - * message size. The second message is used to retrieve the data specifed in + * message size. The second message is used to retrieve the data specified in * the first message * * 1st message 2nd message diff --git a/drivers/media/i2c/m5mols/m5mols_core.c b/drivers/media/i2c/m5mols/m5mols_core.c index b8b2bf4cbfb2..454a336be336 100644 --- a/drivers/media/i2c/m5mols/m5mols_core.c +++ b/drivers/media/i2c/m5mols/m5mols_core.c @@ -291,7 +291,7 @@ int m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val) * @reg: the I2C_REG() address of an 8-bit status register to check * @value: expected status register value * @mask: bit mask for the read status register value - * @timeout: timeout in miliseconds, or -1 for default timeout + * @timeout: timeout in milliseconds, or -1 for default timeout * * The @reg register value is ORed with @mask before comparing with @value. * diff --git a/drivers/media/i2c/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c index c63be01059b2..522fb1d561e7 100644 --- a/drivers/media/i2c/msp3400-driver.c +++ b/drivers/media/i2c/msp3400-driver.c @@ -11,7 +11,7 @@ * * FM-Mono * should work. The stereo modes are backward compatible to FM-mono, - * therefore FM-Mono should be allways available. + * therefore FM-Mono should be always available. * * FM-Stereo (B/G, used in germany) * should work, with autodetect diff --git a/drivers/media/i2c/soc_camera/soc_mt9m001.c b/drivers/media/i2c/mt9m001.c index a1a85ff838c5..4b23fde937b3 100644 --- a/drivers/media/i2c/soc_camera/soc_mt9m001.c +++ b/drivers/media/i2c/mt9m001.c @@ -1,29 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Driver for MT9M001 CMOS Image Sensor from Micron * * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ -#include <linux/videodev2.h> -#include <linux/slab.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/log2.h> #include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/slab.h> +#include <linux/videodev2.h> -#include <media/soc_camera.h> -#include <media/drv-intf/soc_mediabus.h> -#include <media/v4l2-clk.h> -#include <media/v4l2-subdev.h> #include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-event.h> +#include <media/v4l2-subdev.h> /* * mt9m001 i2c address 0x5d - * The platform has to define struct i2c_board_info objects and link to them - * from struct soc_camera_host_desc */ /* mt9m001 selected register addresses */ @@ -50,6 +48,8 @@ #define MT9M001_MIN_HEIGHT 32 #define MT9M001_COLUMN_SKIP 20 #define MT9M001_ROW_SKIP 12 +#define MT9M001_DEFAULT_HBLANK 9 +#define MT9M001_DEFAULT_VBLANK 25 /* MT9M001 has only one fixed colorspace per pixelcode */ struct mt9m001_datafmt { @@ -93,13 +93,18 @@ struct mt9m001 { struct v4l2_ctrl *autoexposure; struct v4l2_ctrl *exposure; }; + bool streaming; + struct mutex mutex; struct v4l2_rect rect; /* Sensor window */ - struct v4l2_clk *clk; + struct clk *clk; + struct gpio_desc *standby_gpio; + struct gpio_desc *reset_gpio; const struct mt9m001_datafmt *fmt; const struct mt9m001_datafmt *fmts; int num_fmts; unsigned int total_h; unsigned short y_skip_top; /* Lines to skip at the top */ + struct media_pad pad; }; static struct mt9m001 *to_mt9m001(const struct i2c_client *client) @@ -140,35 +145,111 @@ static int reg_clear(struct i2c_client *client, const u8 reg, return reg_write(client, reg, ret & ~data); } +struct mt9m001_reg { + u8 reg; + u16 data; +}; + +static int multi_reg_write(struct i2c_client *client, + const struct mt9m001_reg *regs, int num) +{ + int i; + + for (i = 0; i < num; i++) { + int ret = reg_write(client, regs[i].reg, regs[i].data); + + if (ret) + return ret; + } + + return 0; +} + static int mt9m001_init(struct i2c_client *client) { - int ret; + const struct mt9m001_reg init_regs[] = { + /* + * Issue a soft reset. This returns all registers to their + * default values. + */ + { MT9M001_RESET, 1 }, + { MT9M001_RESET, 0 }, + /* Disable chip, synchronous option update */ + { MT9M001_OUTPUT_CONTROL, 0 } + }; dev_dbg(&client->dev, "%s\n", __func__); - /* - * We don't know, whether platform provides reset, issue a soft reset - * too. This returns all registers to their default values. - */ - ret = reg_write(client, MT9M001_RESET, 1); - if (!ret) - ret = reg_write(client, MT9M001_RESET, 0); + return multi_reg_write(client, init_regs, ARRAY_SIZE(init_regs)); +} - /* Disable chip, synchronous option update */ - if (!ret) - ret = reg_write(client, MT9M001_OUTPUT_CONTROL, 0); +static int mt9m001_apply_selection(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9m001 *mt9m001 = to_mt9m001(client); + const struct mt9m001_reg regs[] = { + /* Blanking and start values - default... */ + { MT9M001_HORIZONTAL_BLANKING, MT9M001_DEFAULT_HBLANK }, + { MT9M001_VERTICAL_BLANKING, MT9M001_DEFAULT_VBLANK }, + /* + * The caller provides a supported format, as verified per + * call to .set_fmt(FORMAT_TRY). + */ + { MT9M001_COLUMN_START, mt9m001->rect.left }, + { MT9M001_ROW_START, mt9m001->rect.top }, + { MT9M001_WINDOW_WIDTH, mt9m001->rect.width - 1 }, + { MT9M001_WINDOW_HEIGHT, + mt9m001->rect.height + mt9m001->y_skip_top - 1 }, + }; - return ret; + return multi_reg_write(client, regs, ARRAY_SIZE(regs)); } static int mt9m001_s_stream(struct v4l2_subdev *sd, int enable) { struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9m001 *mt9m001 = to_mt9m001(client); + int ret = 0; + + mutex_lock(&mt9m001->mutex); + + if (mt9m001->streaming == enable) + goto done; + + if (enable) { + ret = pm_runtime_get_sync(&client->dev); + if (ret < 0) + goto put_unlock; + + ret = mt9m001_apply_selection(sd); + if (ret) + goto put_unlock; + + ret = __v4l2_ctrl_handler_setup(&mt9m001->hdl); + if (ret) + goto put_unlock; + + /* Switch to master "normal" mode */ + ret = reg_write(client, MT9M001_OUTPUT_CONTROL, 2); + if (ret < 0) + goto put_unlock; + } else { + /* Switch to master stop sensor readout */ + reg_write(client, MT9M001_OUTPUT_CONTROL, 0); + pm_runtime_put(&client->dev); + } + + mt9m001->streaming = enable; +done: + mutex_unlock(&mt9m001->mutex); - /* Switch to master "normal" mode or stop sensor readout */ - if (reg_write(client, MT9M001_OUTPUT_CONTROL, enable ? 2 : 0) < 0) - return -EIO; return 0; + +put_unlock: + pm_runtime_put(&client->dev); + mutex_unlock(&mt9m001->mutex); + + return ret; } static int mt9m001_set_selection(struct v4l2_subdev *sd, @@ -178,8 +259,6 @@ static int mt9m001_set_selection(struct v4l2_subdev *sd, struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9m001 *mt9m001 = to_mt9m001(client); struct v4l2_rect rect = sel->r; - const u16 hblank = 9, vblank = 25; - int ret; if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || sel->target != V4L2_SEL_TGT_CROP) @@ -196,39 +275,22 @@ static int mt9m001_set_selection(struct v4l2_subdev *sd, rect.width = ALIGN(rect.width, 2); rect.left = ALIGN(rect.left, 2); - soc_camera_limit_side(&rect.left, &rect.width, - MT9M001_COLUMN_SKIP, MT9M001_MIN_WIDTH, MT9M001_MAX_WIDTH); + rect.width = clamp_t(u32, rect.width, MT9M001_MIN_WIDTH, + MT9M001_MAX_WIDTH); + rect.left = clamp_t(u32, rect.left, MT9M001_COLUMN_SKIP, + MT9M001_COLUMN_SKIP + MT9M001_MAX_WIDTH - rect.width); - soc_camera_limit_side(&rect.top, &rect.height, - MT9M001_ROW_SKIP, MT9M001_MIN_HEIGHT, MT9M001_MAX_HEIGHT); + rect.height = clamp_t(u32, rect.height, MT9M001_MIN_HEIGHT, + MT9M001_MAX_HEIGHT); + rect.top = clamp_t(u32, rect.top, MT9M001_ROW_SKIP, + MT9M001_ROW_SKIP + MT9M001_MAX_HEIGHT - rect.height); - mt9m001->total_h = rect.height + mt9m001->y_skip_top + vblank; + mt9m001->total_h = rect.height + mt9m001->y_skip_top + + MT9M001_DEFAULT_VBLANK; - /* Blanking and start values - default... */ - ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank); - if (!ret) - ret = reg_write(client, MT9M001_VERTICAL_BLANKING, vblank); + mt9m001->rect = rect; - /* - * The caller provides a supported format, as verified per - * call to .set_fmt(FORMAT_TRY). - */ - if (!ret) - ret = reg_write(client, MT9M001_COLUMN_START, rect.left); - if (!ret) - ret = reg_write(client, MT9M001_ROW_START, rect.top); - if (!ret) - ret = reg_write(client, MT9M001_WINDOW_WIDTH, rect.width - 1); - if (!ret) - ret = reg_write(client, MT9M001_WINDOW_HEIGHT, - rect.height + mt9m001->y_skip_top - 1); - if (!ret && v4l2_ctrl_g_ctrl(mt9m001->autoexposure) == V4L2_EXPOSURE_AUTO) - ret = reg_write(client, MT9M001_SHUTTER_WIDTH, mt9m001->total_h); - - if (!ret) - mt9m001->rect = rect; - - return ret; + return 0; } static int mt9m001_get_selection(struct v4l2_subdev *sd, @@ -267,11 +329,20 @@ static int mt9m001_get_fmt(struct v4l2_subdev *sd, if (format->pad) return -EINVAL; + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + mf = v4l2_subdev_get_try_format(sd, cfg, 0); + format->format = *mf; + return 0; + } + mf->width = mt9m001->rect.width; mf->height = mt9m001->rect.height; mf->code = mt9m001->fmt->code; mf->colorspace = mt9m001->fmt->colorspace; mf->field = V4L2_FIELD_NONE; + mf->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + mf->quantization = V4L2_QUANTIZATION_DEFAULT; + mf->xfer_func = V4L2_XFER_FUNC_DEFAULT; return 0; } @@ -332,6 +403,10 @@ static int mt9m001_set_fmt(struct v4l2_subdev *sd, } mf->colorspace = fmt->colorspace; + mf->field = V4L2_FIELD_NONE; + mf->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + mf->quantization = V4L2_QUANTIZATION_DEFAULT; + mf->xfer_func = V4L2_XFER_FUNC_DEFAULT; if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) return mt9m001_s_fmt(sd, fmt, mf); @@ -372,13 +447,40 @@ static int mt9m001_s_register(struct v4l2_subdev *sd, } #endif -static int mt9m001_s_power(struct v4l2_subdev *sd, int on) +static int mt9m001_power_on(struct device *dev) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); + struct i2c_client *client = to_i2c_client(dev); struct mt9m001 *mt9m001 = to_mt9m001(client); + int ret; + + ret = clk_prepare_enable(mt9m001->clk); + if (ret) + return ret; + + if (mt9m001->standby_gpio) { + gpiod_set_value_cansleep(mt9m001->standby_gpio, 0); + usleep_range(1000, 2000); + } + + if (mt9m001->reset_gpio) { + gpiod_set_value_cansleep(mt9m001->reset_gpio, 1); + usleep_range(1000, 2000); + gpiod_set_value_cansleep(mt9m001->reset_gpio, 0); + usleep_range(1000, 2000); + } - return soc_camera_set_power(&client->dev, ssdd, mt9m001->clk, on); + return 0; +} + +static int mt9m001_power_off(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct mt9m001 *mt9m001 = to_mt9m001(client); + + gpiod_set_value_cansleep(mt9m001->standby_gpio, 1); + clk_disable_unprepare(mt9m001->clk); + + return 0; } static int mt9m001_g_volatile_ctrl(struct v4l2_ctrl *ctrl) @@ -406,16 +508,18 @@ static int mt9m001_s_ctrl(struct v4l2_ctrl *ctrl) struct i2c_client *client = v4l2_get_subdevdata(sd); struct v4l2_ctrl *exp = mt9m001->exposure; int data; + int ret; + + if (!pm_runtime_get_if_in_use(&client->dev)) + return 0; switch (ctrl->id) { case V4L2_CID_VFLIP: if (ctrl->val) - data = reg_set(client, MT9M001_READ_OPTIONS2, 0x8000); + ret = reg_set(client, MT9M001_READ_OPTIONS2, 0x8000); else - data = reg_clear(client, MT9M001_READ_OPTIONS2, 0x8000); - if (data < 0) - return -EIO; - return 0; + ret = reg_clear(client, MT9M001_READ_OPTIONS2, 0x8000); + break; case V4L2_CID_GAIN: /* See Datasheet Table 7, Gain settings. */ @@ -425,9 +529,7 @@ static int mt9m001_s_ctrl(struct v4l2_ctrl *ctrl) data = ((ctrl->val - (s32)ctrl->minimum) * 8 + range / 2) / range; dev_dbg(&client->dev, "Setting gain %d\n", data); - data = reg_write(client, MT9M001_GLOBAL_GAIN, data); - if (data < 0) - return -EIO; + ret = reg_write(client, MT9M001_GLOBAL_GAIN, data); } else { /* Pack it into 1.125..15 variable step, register values 9..67 */ /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */ @@ -444,11 +546,9 @@ static int mt9m001_s_ctrl(struct v4l2_ctrl *ctrl) dev_dbg(&client->dev, "Setting gain from %d to %d\n", reg_read(client, MT9M001_GLOBAL_GAIN), data); - data = reg_write(client, MT9M001_GLOBAL_GAIN, data); - if (data < 0) - return -EIO; + ret = reg_write(client, MT9M001_GLOBAL_GAIN, data); } - return 0; + break; case V4L2_CID_EXPOSURE_AUTO: if (ctrl->val == V4L2_EXPOSURE_MANUAL) { @@ -459,37 +559,34 @@ static int mt9m001_s_ctrl(struct v4l2_ctrl *ctrl) dev_dbg(&client->dev, "Setting shutter width from %d to %lu\n", reg_read(client, MT9M001_SHUTTER_WIDTH), shutter); - if (reg_write(client, MT9M001_SHUTTER_WIDTH, shutter) < 0) - return -EIO; + ret = reg_write(client, MT9M001_SHUTTER_WIDTH, shutter); } else { - const u16 vblank = 25; - mt9m001->total_h = mt9m001->rect.height + - mt9m001->y_skip_top + vblank; - if (reg_write(client, MT9M001_SHUTTER_WIDTH, mt9m001->total_h) < 0) - return -EIO; + mt9m001->y_skip_top + MT9M001_DEFAULT_VBLANK; + ret = reg_write(client, MT9M001_SHUTTER_WIDTH, + mt9m001->total_h); } - return 0; + break; + default: + ret = -EINVAL; + break; } - return -EINVAL; + + pm_runtime_put(&client->dev); + + return ret; } /* * Interface active, can use i2c. If it fails, it can indeed mean, that * this wasn't our capture interface, so, we wait for the right one */ -static int mt9m001_video_probe(struct soc_camera_subdev_desc *ssdd, - struct i2c_client *client) +static int mt9m001_video_probe(struct i2c_client *client) { struct mt9m001 *mt9m001 = to_mt9m001(client); s32 data; - unsigned long flags; int ret; - ret = mt9m001_s_power(&mt9m001->subdev, 1); - if (ret < 0) - return ret; - /* Enable the chip */ data = reg_write(client, MT9M001_CHIP_ENABLE, 1); dev_dbg(&client->dev, "write: %d\n", data); @@ -502,9 +599,11 @@ static int mt9m001_video_probe(struct soc_camera_subdev_desc *ssdd, case 0x8411: case 0x8421: mt9m001->fmts = mt9m001_colour_fmts; + mt9m001->num_fmts = ARRAY_SIZE(mt9m001_colour_fmts); break; case 0x8431: mt9m001->fmts = mt9m001_monochrome_fmts; + mt9m001->num_fmts = ARRAY_SIZE(mt9m001_monochrome_fmts); break; default: dev_err(&client->dev, @@ -513,26 +612,6 @@ static int mt9m001_video_probe(struct soc_camera_subdev_desc *ssdd, goto done; } - mt9m001->num_fmts = 0; - - /* - * This is a 10bit sensor, so by default we only allow 10bit. - * The platform may support different bus widths due to - * different routing of the data lines. - */ - if (ssdd->query_bus_param) - flags = ssdd->query_bus_param(ssdd); - else - flags = SOCAM_DATAWIDTH_10; - - if (flags & SOCAM_DATAWIDTH_10) - mt9m001->num_fmts++; - else - mt9m001->fmts++; - - if (flags & SOCAM_DATAWIDTH_8) - mt9m001->num_fmts++; - mt9m001->fmt = &mt9m001->fmts[0]; dev_info(&client->dev, "Detected a MT9M001 chip ID %x (%s)\n", data, @@ -548,16 +627,9 @@ static int mt9m001_video_probe(struct soc_camera_subdev_desc *ssdd, ret = v4l2_ctrl_handler_setup(&mt9m001->hdl); done: - mt9m001_s_power(&mt9m001->subdev, 0); return ret; } -static void mt9m001_video_remove(struct soc_camera_subdev_desc *ssdd) -{ - if (ssdd->free_bus) - ssdd->free_bus(ssdd); -} - static int mt9m001_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -574,13 +646,35 @@ static const struct v4l2_ctrl_ops mt9m001_ctrl_ops = { }; static const struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = { + .log_status = v4l2_ctrl_subdev_log_status, + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = mt9m001_g_register, .s_register = mt9m001_s_register, #endif - .s_power = mt9m001_s_power, }; +static int mt9m001_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9m001 *mt9m001 = to_mt9m001(client); + struct v4l2_mbus_framefmt *try_fmt = + v4l2_subdev_get_try_format(sd, cfg, 0); + + try_fmt->width = MT9M001_MAX_WIDTH; + try_fmt->height = MT9M001_MAX_HEIGHT; + try_fmt->code = mt9m001->fmts[0].code; + try_fmt->colorspace = mt9m001->fmts[0].colorspace; + try_fmt->field = V4L2_FIELD_NONE; + try_fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + try_fmt->quantization = V4L2_QUANTIZATION_DEFAULT; + try_fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT; + + return 0; +} + static int mt9m001_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) @@ -598,41 +692,18 @@ static int mt9m001_enum_mbus_code(struct v4l2_subdev *sd, static int mt9m001_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - /* MT9M001 has all capture_format parameters fixed */ cfg->flags = V4L2_MBUS_PCLK_SAMPLE_FALLING | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH | V4L2_MBUS_MASTER; cfg->type = V4L2_MBUS_PARALLEL; - cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); return 0; } -static int mt9m001_s_mbus_config(struct v4l2_subdev *sd, - const struct v4l2_mbus_config *cfg) -{ - const struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - struct mt9m001 *mt9m001 = to_mt9m001(client); - unsigned int bps = soc_mbus_get_fmtdesc(mt9m001->fmt->code)->bits_per_sample; - - if (ssdd->set_bus_param) - return ssdd->set_bus_param(ssdd, 1 << (bps - 1)); - - /* - * Without board specific bus width settings we only support the - * sensors native bus width - */ - return bps == 10 ? 0 : -EINVAL; -} - static const struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = { .s_stream = mt9m001_s_stream, .g_mbus_config = mt9m001_g_mbus_config, - .s_mbus_config = mt9m001_s_mbus_config, }; static const struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = { @@ -640,6 +711,7 @@ static const struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = { }; static const struct v4l2_subdev_pad_ops mt9m001_subdev_pad_ops = { + .init_cfg = mt9m001_init_cfg, .enum_mbus_code = mt9m001_enum_mbus_code, .get_selection = mt9m001_get_selection, .set_selection = mt9m001_set_selection, @@ -659,25 +731,35 @@ static int mt9m001_probe(struct i2c_client *client, { struct mt9m001 *mt9m001; struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); int ret; - if (!ssdd) { - dev_err(&client->dev, "MT9M001 driver needs platform data\n"); - return -EINVAL; - } - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { dev_warn(&adapter->dev, "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); return -EIO; } - mt9m001 = devm_kzalloc(&client->dev, sizeof(struct mt9m001), GFP_KERNEL); + mt9m001 = devm_kzalloc(&client->dev, sizeof(*mt9m001), GFP_KERNEL); if (!mt9m001) return -ENOMEM; + mt9m001->clk = devm_clk_get(&client->dev, NULL); + if (IS_ERR(mt9m001->clk)) + return PTR_ERR(mt9m001->clk); + + mt9m001->standby_gpio = devm_gpiod_get_optional(&client->dev, "standby", + GPIOD_OUT_LOW); + if (IS_ERR(mt9m001->standby_gpio)) + return PTR_ERR(mt9m001->standby_gpio); + + mt9m001->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(mt9m001->reset_gpio)) + return PTR_ERR(mt9m001->reset_gpio); + v4l2_i2c_subdev_init(&mt9m001->subdev, client, &mt9m001_subdev_ops); + mt9m001->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | + V4L2_SUBDEV_FL_HAS_EVENTS; v4l2_ctrl_handler_init(&mt9m001->hdl, 4); v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0); @@ -699,6 +781,9 @@ static int mt9m001_probe(struct i2c_client *client, v4l2_ctrl_auto_cluster(2, &mt9m001->autoexposure, V4L2_EXPOSURE_MANUAL, true); + mutex_init(&mt9m001->mutex); + mt9m001->hdl.lock = &mt9m001->mutex; + /* Second stage probe - when a capture adapter is there */ mt9m001->y_skip_top = 0; mt9m001->rect.left = MT9M001_COLUMN_SKIP; @@ -706,18 +791,41 @@ static int mt9m001_probe(struct i2c_client *client, mt9m001->rect.width = MT9M001_MAX_WIDTH; mt9m001->rect.height = MT9M001_MAX_HEIGHT; - mt9m001->clk = v4l2_clk_get(&client->dev, "mclk"); - if (IS_ERR(mt9m001->clk)) { - ret = PTR_ERR(mt9m001->clk); - goto eclkget; - } + ret = mt9m001_power_on(&client->dev); + if (ret) + goto error_hdl_free; - ret = mt9m001_video_probe(ssdd, client); - if (ret) { - v4l2_clk_put(mt9m001->clk); -eclkget: - v4l2_ctrl_handler_free(&mt9m001->hdl); - } + pm_runtime_set_active(&client->dev); + pm_runtime_enable(&client->dev); + + ret = mt9m001_video_probe(client); + if (ret) + goto error_power_off; + + mt9m001->pad.flags = MEDIA_PAD_FL_SOURCE; + mt9m001->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = media_entity_pads_init(&mt9m001->subdev.entity, 1, &mt9m001->pad); + if (ret) + goto error_power_off; + + ret = v4l2_async_register_subdev(&mt9m001->subdev); + if (ret) + goto error_entity_cleanup; + + pm_runtime_idle(&client->dev); + + return 0; + +error_entity_cleanup: + media_entity_cleanup(&mt9m001->subdev.entity); +error_power_off: + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); + mt9m001_power_off(&client->dev); + +error_hdl_free: + v4l2_ctrl_handler_free(&mt9m001->hdl); + mutex_destroy(&mt9m001->mutex); return ret; } @@ -725,12 +833,19 @@ eclkget: static int mt9m001_remove(struct i2c_client *client) { struct mt9m001 *mt9m001 = to_mt9m001(client); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - v4l2_clk_put(mt9m001->clk); - v4l2_device_unregister_subdev(&mt9m001->subdev); + pm_runtime_get_sync(&client->dev); + + v4l2_async_unregister_subdev(&mt9m001->subdev); + media_entity_cleanup(&mt9m001->subdev.entity); + + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); + pm_runtime_put_noidle(&client->dev); + mt9m001_power_off(&client->dev); + v4l2_ctrl_handler_free(&mt9m001->hdl); - mt9m001_video_remove(ssdd); + mutex_destroy(&mt9m001->mutex); return 0; } @@ -741,9 +856,21 @@ static const struct i2c_device_id mt9m001_id[] = { }; MODULE_DEVICE_TABLE(i2c, mt9m001_id); +static const struct dev_pm_ops mt9m001_pm_ops = { + SET_RUNTIME_PM_OPS(mt9m001_power_off, mt9m001_power_on, NULL) +}; + +static const struct of_device_id mt9m001_of_match[] = { + { .compatible = "onnn,mt9m001", }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, mt9m001_of_match); + static struct i2c_driver mt9m001_i2c_driver = { .driver = { .name = "mt9m001", + .pm = &mt9m001_pm_ops, + .of_match_table = mt9m001_of_match, }, .probe = mt9m001_probe, .remove = mt9m001_remove, @@ -754,4 +881,4 @@ module_i2c_driver(mt9m001_i2c_driver); MODULE_DESCRIPTION("Micron MT9M001 Camera driver"); MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c index d639b9bcf64a..5168bb5880c4 100644 --- a/drivers/media/i2c/mt9m111.c +++ b/drivers/media/i2c/mt9m111.c @@ -528,11 +528,24 @@ static int mt9m111_get_fmt(struct v4l2_subdev *sd, if (format->pad) return -EINVAL; + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + mf = v4l2_subdev_get_try_format(sd, cfg, format->pad); + format->format = *mf; + return 0; +#else + return -ENOTTY; +#endif + } + mf->width = mt9m111->width; mf->height = mt9m111->height; mf->code = mt9m111->fmt->code; mf->colorspace = mt9m111->fmt->colorspace; mf->field = V4L2_FIELD_NONE; + mf->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + mf->quantization = V4L2_QUANTIZATION_DEFAULT; + mf->xfer_func = V4L2_XFER_FUNC_DEFAULT; return 0; } @@ -660,6 +673,10 @@ static int mt9m111_set_fmt(struct v4l2_subdev *sd, mf->code = fmt->code; mf->colorspace = fmt->colorspace; + mf->field = V4L2_FIELD_NONE; + mf->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + mf->quantization = V4L2_QUANTIZATION_DEFAULT; + mf->xfer_func = V4L2_XFER_FUNC_DEFAULT; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { cfg->try_fmt = *mf; @@ -1089,6 +1106,25 @@ static int mt9m111_s_stream(struct v4l2_subdev *sd, int enable) return 0; } +static int mt9m111_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg) +{ +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + struct v4l2_mbus_framefmt *format = + v4l2_subdev_get_try_format(sd, cfg, 0); + + format->width = MT9M111_MAX_WIDTH; + format->height = MT9M111_MAX_HEIGHT; + format->code = mt9m111_colour_fmts[0].code; + format->colorspace = mt9m111_colour_fmts[0].colorspace; + format->field = V4L2_FIELD_NONE; + format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + format->quantization = V4L2_QUANTIZATION_DEFAULT; + format->xfer_func = V4L2_XFER_FUNC_DEFAULT; +#endif + return 0; +} + static int mt9m111_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { @@ -1114,6 +1150,7 @@ static const struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { }; static const struct v4l2_subdev_pad_ops mt9m111_subdev_pad_ops = { + .init_cfg = mt9m111_init_cfg, .enum_mbus_code = mt9m111_enum_mbus_code, .get_selection = mt9m111_get_selection, .set_selection = mt9m111_set_selection, @@ -1273,6 +1310,8 @@ static int mt9m111_probe(struct i2c_client *client, mt9m111->rect.top = MT9M111_MIN_DARK_ROWS; mt9m111->rect.width = MT9M111_MAX_WIDTH; mt9m111->rect.height = MT9M111_MAX_HEIGHT; + mt9m111->width = mt9m111->rect.width; + mt9m111->height = mt9m111->rect.height; mt9m111->fmt = &mt9m111_colour_fmts[0]; mt9m111->lastpage = -1; mutex_init(&mt9m111->power_lock); diff --git a/drivers/media/i2c/mt9t112.c b/drivers/media/i2c/mt9t112.c index ef353a244e33..ae3c336eadf5 100644 --- a/drivers/media/i2c/mt9t112.c +++ b/drivers/media/i2c/mt9t112.c @@ -541,7 +541,7 @@ static int mt9t112_init_setting(const struct i2c_client *client) mt9t112_mcu_write(ret, client, VAR(18, 109), 0x0AF0); /* - * Flicker Dectection registers. + * Flicker Detection registers. * This section should be replaced whenever new timing file is * generated. All the following registers need to be replaced. * Following registers are generated from Register Wizard but user can diff --git a/drivers/media/i2c/ov2640.c b/drivers/media/i2c/ov2640.c index 5d2d6735cc78..83031cfc7914 100644 --- a/drivers/media/i2c/ov2640.c +++ b/drivers/media/i2c/ov2640.c @@ -842,9 +842,6 @@ static int ov2640_set_params(struct i2c_client *client, u8 val; int ret; - if (!win) - return -EINVAL; - switch (code) { case MEDIA_BUS_FMT_RGB565_2X8_BE: dev_dbg(&client->dev, "%s: Selected cfmt RGB565 BE", __func__); @@ -929,9 +926,14 @@ static int ov2640_get_fmt(struct v4l2_subdev *sd, if (format->pad) return -EINVAL; - if (!priv->win) { - priv->win = ov2640_select_win(SVGA_WIDTH, SVGA_HEIGHT); - priv->cfmt_code = MEDIA_BUS_FMT_UYVY8_2X8; + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + mf = v4l2_subdev_get_try_format(sd, cfg, 0); + format->format = *mf; + return 0; +#else + return -ENOTTY; +#endif } mf->width = priv->win->width; @@ -939,6 +941,9 @@ static int ov2640_get_fmt(struct v4l2_subdev *sd, mf->code = priv->cfmt_code; mf->colorspace = V4L2_COLORSPACE_SRGB; mf->field = V4L2_FIELD_NONE; + mf->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + mf->quantization = V4L2_QUANTIZATION_DEFAULT; + mf->xfer_func = V4L2_XFER_FUNC_DEFAULT; return 0; } @@ -965,6 +970,9 @@ static int ov2640_set_fmt(struct v4l2_subdev *sd, mf->field = V4L2_FIELD_NONE; mf->colorspace = V4L2_COLORSPACE_SRGB; + mf->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + mf->quantization = V4L2_QUANTIZATION_DEFAULT; + mf->xfer_func = V4L2_XFER_FUNC_DEFAULT; switch (mf->code) { case MEDIA_BUS_FMT_RGB565_2X8_BE: @@ -999,6 +1007,27 @@ out: return ret; } +static int ov2640_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg) +{ +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + struct v4l2_mbus_framefmt *try_fmt = + v4l2_subdev_get_try_format(sd, cfg, 0); + const struct ov2640_win_size *win = + ov2640_select_win(SVGA_WIDTH, SVGA_HEIGHT); + + try_fmt->width = win->width; + try_fmt->height = win->height; + try_fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; + try_fmt->colorspace = V4L2_COLORSPACE_SRGB; + try_fmt->field = V4L2_FIELD_NONE; + try_fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + try_fmt->quantization = V4L2_QUANTIZATION_DEFAULT; + try_fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT; +#endif + return 0; +} + static int ov2640_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) @@ -1108,6 +1137,7 @@ static const struct v4l2_subdev_core_ops ov2640_subdev_core_ops = { }; static const struct v4l2_subdev_pad_ops ov2640_subdev_pad_ops = { + .init_cfg = ov2640_init_cfg, .enum_mbus_code = ov2640_enum_mbus_code, .get_selection = ov2640_get_selection, .get_fmt = ov2640_get_fmt, @@ -1193,6 +1223,9 @@ static int ov2640_probe(struct i2c_client *client, if (ret) goto err_clk; + priv->win = ov2640_select_win(SVGA_WIDTH, SVGA_HEIGHT); + priv->cfmt_code = MEDIA_BUS_FMT_UYVY8_2X8; + v4l2_i2c_subdev_init(&priv->subdev, client, &ov2640_subdev_ops); priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index bef3f3aae0ed..82d4ce93312c 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -83,6 +83,9 @@ #define OV5640_REG_SIGMADELTA_CTRL0C 0x3c0c #define OV5640_REG_FRAME_CTRL01 0x4202 #define OV5640_REG_FORMAT_CONTROL00 0x4300 +#define OV5640_REG_VFIFO_HSIZE 0x4602 +#define OV5640_REG_VFIFO_VSIZE 0x4604 +#define OV5640_REG_JPG_MODE_SELECT 0x4713 #define OV5640_REG_POLARITY_CTRL00 0x4740 #define OV5640_REG_MIPI_CTRL00 0x4800 #define OV5640_REG_DEBUG_MODE 0x4814 @@ -115,6 +118,15 @@ enum ov5640_frame_rate { OV5640_NUM_FRAMERATES, }; +enum ov5640_format_mux { + OV5640_FMT_MUX_YUV422 = 0, + OV5640_FMT_MUX_RGB, + OV5640_FMT_MUX_DITHER, + OV5640_FMT_MUX_RAW_DPC, + OV5640_FMT_MUX_SNR_RAW, + OV5640_FMT_MUX_RAW_CIP, +}; + struct ov5640_pixfmt { u32 code; u32 colorspace; @@ -126,6 +138,10 @@ static const struct ov5640_pixfmt ov5640_formats[] = { { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_SRGB, }, { MEDIA_BUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB, }, { MEDIA_BUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB, }, + { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB, }, + { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_COLORSPACE_SRGB, }, + { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_COLORSPACE_SRGB, }, + { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_COLORSPACE_SRGB, }, }; /* @@ -288,7 +304,7 @@ static const struct reg_value ov5640_init_setting_30fps_VGA[] = { {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0}, {0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0}, - {0x501f, 0x00, 0, 0}, {0x4713, 0x03, 0, 0}, {0x4407, 0x04, 0, 0}, + {0x501f, 0x00, 0, 0}, {0x4407, 0x04, 0, 0}, {0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, {0x4837, 0x0a, 0, 0}, {0x3824, 0x02, 0, 0}, {0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0}, @@ -357,7 +373,7 @@ static const struct reg_value ov5640_setting_VGA_640_480[] = { {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, - {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, }; @@ -376,7 +392,7 @@ static const struct reg_value ov5640_setting_XGA_1024_768[] = { {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, - {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, }; @@ -395,7 +411,7 @@ static const struct reg_value ov5640_setting_QVGA_320_240[] = { {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, - {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, }; @@ -414,7 +430,7 @@ static const struct reg_value ov5640_setting_QCIF_176_144[] = { {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, - {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, }; @@ -433,7 +449,7 @@ static const struct reg_value ov5640_setting_NTSC_720_480[] = { {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, - {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, }; @@ -452,7 +468,7 @@ static const struct reg_value ov5640_setting_PAL_720_576[] = { {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, - {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, }; @@ -471,7 +487,7 @@ static const struct reg_value ov5640_setting_720P_1280_720[] = { {0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0}, {0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0}, - {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, }; @@ -491,7 +507,7 @@ static const struct reg_value ov5640_setting_1080P_1920_1080[] = { {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, - {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0}, @@ -503,7 +519,7 @@ static const struct reg_value ov5640_setting_1080P_1920_1080[] = { {0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0}, - {0x3a15, 0x60, 0, 0}, {0x4713, 0x02, 0, 0}, {0x4407, 0x04, 0, 0}, + {0x3a15, 0x60, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0}, {0x4005, 0x1a, 0, 0}, {0x3008, 0x02, 0, 0}, }; @@ -522,7 +538,7 @@ static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = { {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, - {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70}, }; @@ -705,7 +721,7 @@ static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg, /* * After trying the various combinations, reading various - * documentations spreaded around the net, and from the various + * documentations spread around the net, and from the various * feedback, the clock tree is probably as follows: * * +--------------+ @@ -1030,12 +1046,42 @@ static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor, unsigned long rate) (ilog2(pclk_div) << 4)); } +/* set JPEG framing sizes */ +static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor, + const struct ov5640_mode_info *mode) +{ + int ret; + + /* + * compression mode 3 timing + * + * Data is transmitted with programmable width (VFIFO_HSIZE). + * No padding done. Last line may have less data. Varying + * number of lines per frame, depending on amount of data. + */ + ret = ov5640_mod_reg(sensor, OV5640_REG_JPG_MODE_SELECT, 0x7, 0x3); + if (ret < 0) + return ret; + + ret = ov5640_write_reg16(sensor, OV5640_REG_VFIFO_HSIZE, mode->hact); + if (ret < 0) + return ret; + + return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->vact); +} + /* download ov5640 settings to sensor through i2c */ static int ov5640_set_timings(struct ov5640_dev *sensor, const struct ov5640_mode_info *mode) { int ret; + if (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) { + ret = ov5640_set_jpeg_timings(sensor, mode); + if (ret < 0) + return ret; + } + ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->hact); if (ret < 0) return ret; @@ -1893,7 +1939,7 @@ static void ov5640_reset(struct ov5640_dev *sensor) usleep_range(1000, 2000); gpiod_set_value_cansleep(sensor->reset_gpio, 0); - usleep_range(5000, 10000); + usleep_range(20000, 25000); } static int ov5640_set_power_on(struct ov5640_dev *sensor) @@ -2059,7 +2105,7 @@ static int ov5640_try_frame_interval(struct ov5640_dev *sensor, u32 width, u32 height) { const struct ov5640_mode_info *mode; - enum ov5640_frame_rate rate = OV5640_30_FPS; + enum ov5640_frame_rate rate = OV5640_15_FPS; int minfps, maxfps, best_fps, fps; int i; @@ -2200,46 +2246,67 @@ static int ov5640_set_framefmt(struct ov5640_dev *sensor, struct v4l2_mbus_framefmt *format) { int ret = 0; - bool is_rgb = false; bool is_jpeg = false; - u8 val; + u8 fmt, mux; switch (format->code) { case MEDIA_BUS_FMT_UYVY8_2X8: /* YUV422, UYVY */ - val = 0x3f; + fmt = 0x3f; + mux = OV5640_FMT_MUX_YUV422; break; case MEDIA_BUS_FMT_YUYV8_2X8: /* YUV422, YUYV */ - val = 0x30; + fmt = 0x30; + mux = OV5640_FMT_MUX_YUV422; break; case MEDIA_BUS_FMT_RGB565_2X8_LE: /* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */ - val = 0x6F; - is_rgb = true; + fmt = 0x6F; + mux = OV5640_FMT_MUX_RGB; break; case MEDIA_BUS_FMT_RGB565_2X8_BE: /* RGB565 {r[4:0],g[5:3]},{g[2:0],b[4:0]} */ - val = 0x61; - is_rgb = true; + fmt = 0x61; + mux = OV5640_FMT_MUX_RGB; break; case MEDIA_BUS_FMT_JPEG_1X8: /* YUV422, YUYV */ - val = 0x30; + fmt = 0x30; + mux = OV5640_FMT_MUX_YUV422; is_jpeg = true; break; + case MEDIA_BUS_FMT_SBGGR8_1X8: + /* Raw, BGBG... / GRGR... */ + fmt = 0x00; + mux = OV5640_FMT_MUX_RAW_DPC; + break; + case MEDIA_BUS_FMT_SGBRG8_1X8: + /* Raw bayer, GBGB... / RGRG... */ + fmt = 0x01; + mux = OV5640_FMT_MUX_RAW_DPC; + break; + case MEDIA_BUS_FMT_SGRBG8_1X8: + /* Raw bayer, GRGR... / BGBG... */ + fmt = 0x02; + mux = OV5640_FMT_MUX_RAW_DPC; + break; + case MEDIA_BUS_FMT_SRGGB8_1X8: + /* Raw bayer, RGRG... / GBGB... */ + fmt = 0x03; + mux = OV5640_FMT_MUX_RAW_DPC; + break; default: return -EINVAL; } /* FORMAT CONTROL00: YUV and RGB formatting */ - ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00, val); + ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00, fmt); if (ret) return ret; /* FORMAT MUX CONTROL: ISP YUV or RGB */ - ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, - is_rgb ? 0x01 : 0x00); + ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, mux); if (ret) return ret; @@ -2407,10 +2474,41 @@ static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, bool auto_gain) return ret; } +static const char * const test_pattern_menu[] = { + "Disabled", + "Color bars", + "Color bars w/ rolling bar", + "Color squares", + "Color squares w/ rolling bar", +}; + +#define OV5640_TEST_ENABLE BIT(7) +#define OV5640_TEST_ROLLING BIT(6) /* rolling horizontal bar */ +#define OV5640_TEST_TRANSPARENT BIT(5) +#define OV5640_TEST_SQUARE_BW BIT(4) /* black & white squares */ +#define OV5640_TEST_BAR_STANDARD (0 << 2) +#define OV5640_TEST_BAR_VERT_CHANGE_1 (1 << 2) +#define OV5640_TEST_BAR_HOR_CHANGE (2 << 2) +#define OV5640_TEST_BAR_VERT_CHANGE_2 (3 << 2) +#define OV5640_TEST_BAR (0 << 0) +#define OV5640_TEST_RANDOM (1 << 0) +#define OV5640_TEST_SQUARE (2 << 0) +#define OV5640_TEST_BLACK (3 << 0) + +static const u8 test_pattern_val[] = { + 0, + OV5640_TEST_ENABLE | OV5640_TEST_BAR_VERT_CHANGE_1 | + OV5640_TEST_BAR, + OV5640_TEST_ENABLE | OV5640_TEST_ROLLING | + OV5640_TEST_BAR_VERT_CHANGE_1 | OV5640_TEST_BAR, + OV5640_TEST_ENABLE | OV5640_TEST_SQUARE, + OV5640_TEST_ENABLE | OV5640_TEST_ROLLING | OV5640_TEST_SQUARE, +}; + static int ov5640_set_ctrl_test_pattern(struct ov5640_dev *sensor, int value) { - return ov5640_mod_reg(sensor, OV5640_REG_PRE_ISP_TEST_SET1, - 0xa4, value ? 0xa4 : 0); + return ov5640_write_reg(sensor, OV5640_REG_PRE_ISP_TEST_SET1, + test_pattern_val[value]); } static int ov5640_set_ctrl_light_freq(struct ov5640_dev *sensor, int value) @@ -2551,11 +2649,6 @@ static const struct v4l2_ctrl_ops ov5640_ctrl_ops = { .s_ctrl = ov5640_s_ctrl, }; -static const char * const test_pattern_menu[] = { - "Disabled", - "Color bars", -}; - static int ov5640_init_controls(struct ov5640_dev *sensor) { const struct v4l2_ctrl_ops *ops = &ov5640_ctrl_ops; diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c index 5d1b218bb7f0..c33fd584cb44 100644 --- a/drivers/media/i2c/ov6650.c +++ b/drivers/media/i2c/ov6650.c @@ -15,7 +15,7 @@ * Copyright (C) 2008 Magnus Damm * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> * - * Hardware specific bits initialy based on former work by Matt Callow + * Hardware specific bits initially based on former work by Matt Callow * drivers/media/video/omap/sensor_ov6650.c * Copyright (C) 2006 Matt Callow * @@ -759,7 +759,7 @@ static int ov6650_s_frame_interval(struct v4l2_subdev *sd, /* * Keep result to be used as tpf limit - * for subseqent clock divider calculations + * for subsequent clock divider calculations */ priv->tpf.numerator = div; priv->tpf.denominator = FRAME_RATE_MAX; diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index a70a6ff7b36e..a7d26b294eb5 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -160,10 +160,10 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)"); #define REG_GFIX 0x69 /* Fix gain control */ #define REG_DBLV 0x6b /* PLL control an debugging */ -#define DBLV_BYPASS 0x00 /* Bypass PLL */ -#define DBLV_X4 0x01 /* clock x4 */ -#define DBLV_X6 0x10 /* clock x6 */ -#define DBLV_X8 0x11 /* clock x8 */ +#define DBLV_BYPASS 0x0a /* Bypass PLL */ +#define DBLV_X4 0x4a /* clock x4 */ +#define DBLV_X6 0x8a /* clock x6 */ +#define DBLV_X8 0xca /* clock x8 */ #define REG_SCALING_XSC 0x70 /* Test pattern and horizontal scale factor */ #define TEST_PATTTERN_0 0x80 @@ -241,7 +241,9 @@ struct ov7670_info { }; struct v4l2_mbus_framefmt format; struct ov7670_format_struct *fmt; /* Current format */ + struct ov7670_win_size *wsize; struct clk *clk; + int on; struct gpio_desc *resetb_gpio; struct gpio_desc *pwdn_gpio; unsigned int mbus_config; /* Media bus configuration flags */ @@ -810,13 +812,25 @@ static void ov7675_get_framerate(struct v4l2_subdev *sd, (4 * clkrc); } +static int ov7675_apply_framerate(struct v4l2_subdev *sd) +{ + struct ov7670_info *info = to_state(sd); + int ret; + + ret = ov7670_write(sd, REG_CLKRC, info->clkrc); + if (ret < 0) + return ret; + + return ov7670_write(sd, REG_DBLV, + info->pll_bypass ? DBLV_BYPASS : DBLV_X4); +} + static int ov7675_set_framerate(struct v4l2_subdev *sd, struct v4l2_fract *tpf) { struct ov7670_info *info = to_state(sd); u32 clkrc; int pll_factor; - int ret; /* * The formula is fps = 5/4*pixclk for YUV/RGB and @@ -825,19 +839,10 @@ static int ov7675_set_framerate(struct v4l2_subdev *sd, * pixclk = clock_speed / (clkrc + 1) * PLLfactor * */ - if (info->pll_bypass) { - pll_factor = 1; - ret = ov7670_write(sd, REG_DBLV, DBLV_BYPASS); - } else { - pll_factor = PLL_FACTOR; - ret = ov7670_write(sd, REG_DBLV, DBLV_X4); - } - if (ret < 0) - return ret; - if (tpf->numerator == 0 || tpf->denominator == 0) { clkrc = 0; } else { + pll_factor = info->pll_bypass ? 1 : PLL_FACTOR; clkrc = (5 * pll_factor * info->clock_speed * tpf->numerator) / (4 * tpf->denominator); if (info->fmt->mbus_code == MEDIA_BUS_FMT_SBGGR8_1X8) @@ -859,11 +864,7 @@ static int ov7675_set_framerate(struct v4l2_subdev *sd, /* Recalculate frame rate */ ov7675_get_framerate(sd, tpf); - ret = ov7670_write(sd, REG_CLKRC, info->clkrc); - if (ret < 0) - return ret; - - return ov7670_write(sd, REG_DBLV, DBLV_X4); + return ov7675_apply_framerate(sd); } static void ov7670_get_framerate_legacy(struct v4l2_subdev *sd, @@ -1004,48 +1005,20 @@ static int ov7670_try_fmt_internal(struct v4l2_subdev *sd, return 0; } -/* - * Set a format. - */ -static int ov7670_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) +static int ov7670_apply_fmt(struct v4l2_subdev *sd) { - struct ov7670_format_struct *ovfmt; - struct ov7670_win_size *wsize; struct ov7670_info *info = to_state(sd); -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API - struct v4l2_mbus_framefmt *mbus_fmt; -#endif + struct ov7670_win_size *wsize = info->wsize; unsigned char com7, com10 = 0; int ret; - if (format->pad) - return -EINVAL; - - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - ret = ov7670_try_fmt_internal(sd, &format->format, NULL, NULL); - if (ret) - return ret; -#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API - mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); - *mbus_fmt = format->format; - return 0; -#else - return -ENOTTY; -#endif - } - - ret = ov7670_try_fmt_internal(sd, &format->format, &ovfmt, &wsize); - if (ret) - return ret; /* * COM7 is a pain in the ass, it doesn't like to be read then * quickly written afterward. But we have everything we need * to set it absolutely here, as long as the format-specific * register sets list it first. */ - com7 = ovfmt->regs[0].value; + com7 = info->fmt->regs[0].value; com7 |= wsize->com7_bit; ret = ov7670_write(sd, REG_COM7, com7); if (ret) @@ -1067,7 +1040,7 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd, /* * Now write the rest of the array. Also store start/stops */ - ret = ov7670_write_array(sd, ovfmt->regs + 1); + ret = ov7670_write_array(sd, info->fmt->regs + 1); if (ret) return ret; @@ -1082,8 +1055,6 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd, return ret; } - info->fmt = ovfmt; - /* * If we're running RGB565, we must rewrite clkrc after setting * the other parameters or the image looks poor. If we're *not* @@ -1101,6 +1072,46 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd, return 0; } +/* + * Set a format. + */ +static int ov7670_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct ov7670_info *info = to_state(sd); +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + struct v4l2_mbus_framefmt *mbus_fmt; +#endif + int ret; + + if (format->pad) + return -EINVAL; + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + ret = ov7670_try_fmt_internal(sd, &format->format, NULL, NULL); + if (ret) + return ret; +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); + *mbus_fmt = format->format; + return 0; +#else + return -ENOTTY; +#endif + } + + ret = ov7670_try_fmt_internal(sd, &format->format, &info->fmt, &info->wsize); + if (ret) + return ret; + + ret = ov7670_apply_fmt(sd); + if (ret) + return ret; + + return 0; +} + static int ov7670_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) @@ -1607,17 +1618,57 @@ static int ov7670_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_regis } #endif -static int ov7670_s_power(struct v4l2_subdev *sd, int on) +static void ov7670_power_on(struct v4l2_subdev *sd) { struct ov7670_info *info = to_state(sd); + if (info->on) + return; + + clk_prepare_enable(info->clk); + if (info->pwdn_gpio) - gpiod_set_value(info->pwdn_gpio, !on); - if (on && info->resetb_gpio) { + gpiod_set_value(info->pwdn_gpio, 0); + if (info->resetb_gpio) { gpiod_set_value(info->resetb_gpio, 1); usleep_range(500, 1000); gpiod_set_value(info->resetb_gpio, 0); + } + if (info->pwdn_gpio || info->resetb_gpio || info->clk) usleep_range(3000, 5000); + + info->on = true; +} + +static void ov7670_power_off(struct v4l2_subdev *sd) +{ + struct ov7670_info *info = to_state(sd); + + if (!info->on) + return; + + clk_disable_unprepare(info->clk); + + if (info->pwdn_gpio) + gpiod_set_value(info->pwdn_gpio, 1); + + info->on = false; +} + +static int ov7670_s_power(struct v4l2_subdev *sd, int on) +{ + struct ov7670_info *info = to_state(sd); + + if (info->on == on) + return 0; + + if (on) { + ov7670_power_on (sd); + ov7670_apply_fmt(sd); + ov7675_apply_framerate(sd); + v4l2_ctrl_handler_setup(&info->hdl); + } else { + ov7670_power_off (sd); } return 0; @@ -1652,6 +1703,7 @@ static int ov7670_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) static const struct v4l2_subdev_core_ops ov7670_core_ops = { .reset = ov7670_reset, .init = ov7670_init, + .s_power = ov7670_s_power, .log_status = v4l2_ctrl_subdev_log_status, .subscribe_event = v4l2_ctrl_subdev_subscribe_event, .unsubscribe_event = v4l2_event_subdev_unsubscribe, @@ -1801,11 +1853,7 @@ static int ov7670_probe(struct i2c_client *client, if (config->clock_speed) info->clock_speed = config->clock_speed; - /* - * It should be allowed for ov7670 too when it is migrated to - * the new frame rate formula. - */ - if (config->pll_bypass && id->driver_data != MODEL_OV7670) + if (config->pll_bypass) info->pll_bypass = true; if (config->pclk_hb_disable) @@ -1820,24 +1868,21 @@ static int ov7670_probe(struct i2c_client *client, else return ret; } - if (info->clk) { - ret = clk_prepare_enable(info->clk); - if (ret) - return ret; + ret = ov7670_init_gpio(client, info); + if (ret) + return ret; + + ov7670_power_on(sd); + + if (info->clk) { info->clock_speed = clk_get_rate(info->clk) / 1000000; if (info->clock_speed < 10 || info->clock_speed > 48) { ret = -EINVAL; - goto clk_disable; + goto power_off; } } - ret = ov7670_init_gpio(client, info); - if (ret) - goto clk_disable; - - ov7670_s_power(sd, 1); - /* Make sure it's an ov7670 */ ret = ov7670_detect(sd); if (ret) { @@ -1851,6 +1896,7 @@ static int ov7670_probe(struct i2c_client *client, info->devtype = &ov7670_devdata[id->driver_data]; info->fmt = &ov7670_formats[0]; + info->wsize = &info->devtype->win_sizes[0]; ov7670_get_default_format(sd, &info->format); @@ -1916,6 +1962,7 @@ static int ov7670_probe(struct i2c_client *client, if (ret < 0) goto entity_cleanup; + ov7670_power_off(sd); return 0; entity_cleanup: @@ -1923,13 +1970,10 @@ entity_cleanup: hdl_free: v4l2_ctrl_handler_free(&info->hdl); power_off: - ov7670_s_power(sd, 0); -clk_disable: - clk_disable_unprepare(info->clk); + ov7670_power_off(sd); return ret; } - static int ov7670_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); @@ -1937,9 +1981,8 @@ static int ov7670_remove(struct i2c_client *client) v4l2_async_unregister_subdev(sd); v4l2_ctrl_handler_free(&info->hdl); - clk_disable_unprepare(info->clk); media_entity_cleanup(&info->sd.entity); - ov7670_s_power(sd, 0); + ov7670_power_off(sd); return 0; } diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c index 177688afd9a6..dfece91ce96b 100644 --- a/drivers/media/i2c/ov7740.c +++ b/drivers/media/i2c/ov7740.c @@ -20,7 +20,7 @@ #define REG_BGAIN 0x01 /* blue gain */ #define REG_RGAIN 0x02 /* red gain */ #define REG_GGAIN 0x03 /* green gain */ -#define REG_REG04 0x04 /* analog setting, dont change*/ +#define REG_REG04 0x04 /* analog setting, don't change*/ #define REG_BAVG 0x05 /* b channel average */ #define REG_GAVG 0x06 /* g channel average */ #define REG_RAVG 0x07 /* r channel average */ @@ -1101,6 +1101,9 @@ static int ov7740_probe(struct i2c_client *client, if (ret) return ret; + pm_runtime_set_active(&client->dev); + pm_runtime_enable(&client->dev); + ret = ov7740_detect(ov7740); if (ret) goto error_detect; @@ -1123,8 +1126,6 @@ static int ov7740_probe(struct i2c_client *client, if (ret) goto error_async_register; - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); pm_runtime_idle(&client->dev); return 0; @@ -1134,6 +1135,8 @@ error_async_register: error_init_controls: ov7740_free_controls(ov7740); error_detect: + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); ov7740_set_power(ov7740, 0); media_entity_cleanup(&ov7740->subdev.entity); diff --git a/drivers/media/i2c/ov8856.c b/drivers/media/i2c/ov8856.c new file mode 100644 index 000000000000..dbf1095b9440 --- /dev/null +++ b/drivers/media/i2c/ov8856.c @@ -0,0 +1,1268 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2019 Intel Corporation. + +#include <asm/unaligned.h> +#include <linux/acpi.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> + +#define OV8856_REG_VALUE_08BIT 1 +#define OV8856_REG_VALUE_16BIT 2 +#define OV8856_REG_VALUE_24BIT 3 + +#define OV8856_LINK_FREQ_360MHZ 360000000ULL +#define OV8856_LINK_FREQ_180MHZ 180000000ULL +#define OV8856_SCLK 144000000ULL +#define OV8856_MCLK 19200000 +#define OV8856_DATA_LANES 4 +#define OV8856_RGB_DEPTH 10 + +#define OV8856_REG_CHIP_ID 0x300a +#define OV8856_CHIP_ID 0x00885a + +#define OV8856_REG_MODE_SELECT 0x0100 +#define OV8856_MODE_STANDBY 0x00 +#define OV8856_MODE_STREAMING 0x01 + +/* vertical-timings from sensor */ +#define OV8856_REG_VTS 0x380e +#define OV8856_VTS_MAX 0x7fff + +/* horizontal-timings from sensor */ +#define OV8856_REG_HTS 0x380c + +/* Exposure controls from sensor */ +#define OV8856_REG_EXPOSURE 0x3500 +#define OV8856_EXPOSURE_MIN 6 +#define OV8856_EXPOSURE_MAX_MARGIN 6 +#define OV8856_EXPOSURE_STEP 1 + +/* Analog gain controls from sensor */ +#define OV8856_REG_ANALOG_GAIN 0x3508 +#define OV8856_ANAL_GAIN_MIN 128 +#define OV8856_ANAL_GAIN_MAX 2047 +#define OV8856_ANAL_GAIN_STEP 1 + +/* Digital gain controls from sensor */ +#define OV8856_REG_MWB_R_GAIN 0x5019 +#define OV8856_REG_MWB_G_GAIN 0x501b +#define OV8856_REG_MWB_B_GAIN 0x501d +#define OV8856_DGTL_GAIN_MIN 0 +#define OV8856_DGTL_GAIN_MAX 4095 +#define OV8856_DGTL_GAIN_STEP 1 +#define OV8856_DGTL_GAIN_DEFAULT 1024 + +/* Test Pattern Control */ +#define OV8856_REG_TEST_PATTERN 0x5e00 +#define OV8856_TEST_PATTERN_ENABLE BIT(7) +#define OV8856_TEST_PATTERN_BAR_SHIFT 2 + +#define to_ov8856(_sd) container_of(_sd, struct ov8856, sd) + +enum { + OV8856_LINK_FREQ_720MBPS, + OV8856_LINK_FREQ_360MBPS, +}; + +struct ov8856_reg { + u16 address; + u8 val; +}; + +struct ov8856_reg_list { + u32 num_of_regs; + const struct ov8856_reg *regs; +}; + +struct ov8856_link_freq_config { + const struct ov8856_reg_list reg_list; +}; + +struct ov8856_mode { + /* Frame width in pixels */ + u32 width; + + /* Frame height in pixels */ + u32 height; + + /* Horizontal timining size */ + u32 hts; + + /* Default vertical timining size */ + u32 vts_def; + + /* Min vertical timining size */ + u32 vts_min; + + /* Link frequency needed for this resolution */ + u32 link_freq_index; + + /* Sensor register settings for this resolution */ + const struct ov8856_reg_list reg_list; +}; + +static const struct ov8856_reg mipi_data_rate_720mbps[] = { + {0x0103, 0x01}, + {0x0100, 0x00}, + {0x0302, 0x4b}, + {0x0303, 0x01}, + {0x030b, 0x02}, + {0x030d, 0x4b}, + {0x031e, 0x0c}, +}; + +static const struct ov8856_reg mipi_data_rate_360mbps[] = { + {0x0103, 0x01}, + {0x0100, 0x00}, + {0x0302, 0x4b}, + {0x0303, 0x03}, + {0x030b, 0x02}, + {0x030d, 0x4b}, + {0x031e, 0x0c}, +}; + +static const struct ov8856_reg mode_3280x2464_regs[] = { + {0x3000, 0x20}, + {0x3003, 0x08}, + {0x300e, 0x20}, + {0x3010, 0x00}, + {0x3015, 0x84}, + {0x3018, 0x72}, + {0x3021, 0x23}, + {0x3033, 0x24}, + {0x3500, 0x00}, + {0x3501, 0x9a}, + {0x3502, 0x20}, + {0x3503, 0x08}, + {0x3505, 0x83}, + {0x3508, 0x01}, + {0x3509, 0x80}, + {0x350c, 0x00}, + {0x350d, 0x80}, + {0x350e, 0x04}, + {0x350f, 0x00}, + {0x3510, 0x00}, + {0x3511, 0x02}, + {0x3512, 0x00}, + {0x3600, 0x72}, + {0x3601, 0x40}, + {0x3602, 0x30}, + {0x3610, 0xc5}, + {0x3611, 0x58}, + {0x3612, 0x5c}, + {0x3613, 0xca}, + {0x3614, 0x20}, + {0x3628, 0xff}, + {0x3629, 0xff}, + {0x362a, 0xff}, + {0x3633, 0x10}, + {0x3634, 0x10}, + {0x3635, 0x10}, + {0x3636, 0x10}, + {0x3663, 0x08}, + {0x3669, 0x34}, + {0x366e, 0x10}, + {0x3706, 0x86}, + {0x370b, 0x7e}, + {0x3714, 0x23}, + {0x3730, 0x12}, + {0x3733, 0x10}, + {0x3764, 0x00}, + {0x3765, 0x00}, + {0x3769, 0x62}, + {0x376a, 0x2a}, + {0x376b, 0x30}, + {0x3780, 0x00}, + {0x3781, 0x24}, + {0x3782, 0x00}, + {0x3783, 0x23}, + {0x3798, 0x2f}, + {0x37a1, 0x60}, + {0x37a8, 0x6a}, + {0x37ab, 0x3f}, + {0x37c2, 0x04}, + {0x37c3, 0xf1}, + {0x37c9, 0x80}, + {0x37cb, 0x16}, + {0x37cc, 0x16}, + {0x37cd, 0x16}, + {0x37ce, 0x16}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x00}, + {0x3803, 0x07}, + {0x3804, 0x0c}, + {0x3805, 0xdf}, + {0x3806, 0x09}, + {0x3807, 0xa6}, + {0x3808, 0x0c}, + {0x3809, 0xd0}, + {0x380a, 0x09}, + {0x380b, 0xa0}, + {0x380c, 0x07}, + {0x380d, 0x88}, + {0x380e, 0x09}, + {0x380f, 0xb8}, + {0x3810, 0x00}, + {0x3811, 0x00}, + {0x3812, 0x00}, + {0x3813, 0x00}, + {0x3814, 0x01}, + {0x3815, 0x01}, + {0x3816, 0x00}, + {0x3817, 0x00}, + {0x3818, 0x00}, + {0x3819, 0x10}, + {0x3820, 0x80}, + {0x3821, 0x46}, + {0x382a, 0x01}, + {0x382b, 0x01}, + {0x3830, 0x06}, + {0x3836, 0x02}, + {0x3862, 0x04}, + {0x3863, 0x08}, + {0x3cc0, 0x33}, + {0x3d85, 0x17}, + {0x3d8c, 0x73}, + {0x3d8d, 0xde}, + {0x4001, 0xe0}, + {0x4003, 0x40}, + {0x4008, 0x00}, + {0x4009, 0x0b}, + {0x400a, 0x00}, + {0x400b, 0x84}, + {0x400f, 0x80}, + {0x4010, 0xf0}, + {0x4011, 0xff}, + {0x4012, 0x02}, + {0x4013, 0x01}, + {0x4014, 0x01}, + {0x4015, 0x01}, + {0x4042, 0x00}, + {0x4043, 0x80}, + {0x4044, 0x00}, + {0x4045, 0x80}, + {0x4046, 0x00}, + {0x4047, 0x80}, + {0x4048, 0x00}, + {0x4049, 0x80}, + {0x4041, 0x03}, + {0x404c, 0x20}, + {0x404d, 0x00}, + {0x404e, 0x20}, + {0x4203, 0x80}, + {0x4307, 0x30}, + {0x4317, 0x00}, + {0x4503, 0x08}, + {0x4601, 0x80}, + {0x4800, 0x44}, + {0x4816, 0x53}, + {0x481b, 0x58}, + {0x481f, 0x27}, + {0x4837, 0x16}, + {0x483c, 0x0f}, + {0x484b, 0x05}, + {0x5000, 0x57}, + {0x5001, 0x0a}, + {0x5004, 0x04}, + {0x502e, 0x03}, + {0x5030, 0x41}, + {0x5780, 0x14}, + {0x5781, 0x0f}, + {0x5782, 0x44}, + {0x5783, 0x02}, + {0x5784, 0x01}, + {0x5785, 0x01}, + {0x5786, 0x00}, + {0x5787, 0x04}, + {0x5788, 0x02}, + {0x5789, 0x0f}, + {0x578a, 0xfd}, + {0x578b, 0xf5}, + {0x578c, 0xf5}, + {0x578d, 0x03}, + {0x578e, 0x08}, + {0x578f, 0x0c}, + {0x5790, 0x08}, + {0x5791, 0x04}, + {0x5792, 0x00}, + {0x5793, 0x52}, + {0x5794, 0xa3}, + {0x5795, 0x02}, + {0x5796, 0x20}, + {0x5797, 0x20}, + {0x5798, 0xd5}, + {0x5799, 0xd5}, + {0x579a, 0x00}, + {0x579b, 0x50}, + {0x579c, 0x00}, + {0x579d, 0x2c}, + {0x579e, 0x0c}, + {0x579f, 0x40}, + {0x57a0, 0x09}, + {0x57a1, 0x40}, + {0x59f8, 0x3d}, + {0x5a08, 0x02}, + {0x5b00, 0x02}, + {0x5b01, 0x10}, + {0x5b02, 0x03}, + {0x5b03, 0xcf}, + {0x5b05, 0x6c}, + {0x5e00, 0x00} +}; + +static const struct ov8856_reg mode_1640x1232_regs[] = { + {0x3000, 0x20}, + {0x3003, 0x08}, + {0x300e, 0x20}, + {0x3010, 0x00}, + {0x3015, 0x84}, + {0x3018, 0x72}, + {0x3021, 0x23}, + {0x3033, 0x24}, + {0x3500, 0x00}, + {0x3501, 0x4c}, + {0x3502, 0xe0}, + {0x3503, 0x08}, + {0x3505, 0x83}, + {0x3508, 0x01}, + {0x3509, 0x80}, + {0x350c, 0x00}, + {0x350d, 0x80}, + {0x350e, 0x04}, + {0x350f, 0x00}, + {0x3510, 0x00}, + {0x3511, 0x02}, + {0x3512, 0x00}, + {0x3600, 0x72}, + {0x3601, 0x40}, + {0x3602, 0x30}, + {0x3610, 0xc5}, + {0x3611, 0x58}, + {0x3612, 0x5c}, + {0x3613, 0xca}, + {0x3614, 0x20}, + {0x3628, 0xff}, + {0x3629, 0xff}, + {0x362a, 0xff}, + {0x3633, 0x10}, + {0x3634, 0x10}, + {0x3635, 0x10}, + {0x3636, 0x10}, + {0x3663, 0x08}, + {0x3669, 0x34}, + {0x366e, 0x08}, + {0x3706, 0x86}, + {0x370b, 0x7e}, + {0x3714, 0x27}, + {0x3730, 0x12}, + {0x3733, 0x10}, + {0x3764, 0x00}, + {0x3765, 0x00}, + {0x3769, 0x62}, + {0x376a, 0x2a}, + {0x376b, 0x30}, + {0x3780, 0x00}, + {0x3781, 0x24}, + {0x3782, 0x00}, + {0x3783, 0x23}, + {0x3798, 0x2f}, + {0x37a1, 0x60}, + {0x37a8, 0x6a}, + {0x37ab, 0x3f}, + {0x37c2, 0x14}, + {0x37c3, 0xf1}, + {0x37c9, 0x80}, + {0x37cb, 0x16}, + {0x37cc, 0x16}, + {0x37cd, 0x16}, + {0x37ce, 0x16}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x00}, + {0x3803, 0x07}, + {0x3804, 0x0c}, + {0x3805, 0xdf}, + {0x3806, 0x09}, + {0x3807, 0xa6}, + {0x3808, 0x06}, + {0x3809, 0x68}, + {0x380a, 0x04}, + {0x380b, 0xd0}, + {0x380c, 0x0e}, + {0x380d, 0xec}, + {0x380e, 0x04}, + {0x380f, 0xe8}, + {0x3810, 0x00}, + {0x3811, 0x00}, + {0x3812, 0x00}, + {0x3813, 0x00}, + {0x3814, 0x03}, + {0x3815, 0x01}, + {0x3816, 0x00}, + {0x3817, 0x00}, + {0x3818, 0x00}, + {0x3819, 0x10}, + {0x3820, 0x90}, + {0x3821, 0x67}, + {0x382a, 0x03}, + {0x382b, 0x01}, + {0x3830, 0x06}, + {0x3836, 0x02}, + {0x3862, 0x04}, + {0x3863, 0x08}, + {0x3cc0, 0x33}, + {0x3d85, 0x17}, + {0x3d8c, 0x73}, + {0x3d8d, 0xde}, + {0x4001, 0xe0}, + {0x4003, 0x40}, + {0x4008, 0x00}, + {0x4009, 0x05}, + {0x400a, 0x00}, + {0x400b, 0x84}, + {0x400f, 0x80}, + {0x4010, 0xf0}, + {0x4011, 0xff}, + {0x4012, 0x02}, + {0x4013, 0x01}, + {0x4014, 0x01}, + {0x4015, 0x01}, + {0x4042, 0x00}, + {0x4043, 0x80}, + {0x4044, 0x00}, + {0x4045, 0x80}, + {0x4046, 0x00}, + {0x4047, 0x80}, + {0x4048, 0x00}, + {0x4049, 0x80}, + {0x4041, 0x03}, + {0x404c, 0x20}, + {0x404d, 0x00}, + {0x404e, 0x20}, + {0x4203, 0x80}, + {0x4307, 0x30}, + {0x4317, 0x00}, + {0x4503, 0x08}, + {0x4601, 0x80}, + {0x4800, 0x44}, + {0x4816, 0x53}, + {0x481b, 0x58}, + {0x481f, 0x27}, + {0x4837, 0x16}, + {0x483c, 0x0f}, + {0x484b, 0x05}, + {0x5000, 0x57}, + {0x5001, 0x0a}, + {0x5004, 0x04}, + {0x502e, 0x03}, + {0x5030, 0x41}, + {0x5780, 0x14}, + {0x5781, 0x0f}, + {0x5782, 0x44}, + {0x5783, 0x02}, + {0x5784, 0x01}, + {0x5785, 0x01}, + {0x5786, 0x00}, + {0x5787, 0x04}, + {0x5788, 0x02}, + {0x5789, 0x0f}, + {0x578a, 0xfd}, + {0x578b, 0xf5}, + {0x578c, 0xf5}, + {0x578d, 0x03}, + {0x578e, 0x08}, + {0x578f, 0x0c}, + {0x5790, 0x08}, + {0x5791, 0x04}, + {0x5792, 0x00}, + {0x5793, 0x52}, + {0x5794, 0xa3}, + {0x5795, 0x00}, + {0x5796, 0x10}, + {0x5797, 0x10}, + {0x5798, 0x73}, + {0x5799, 0x73}, + {0x579a, 0x00}, + {0x579b, 0x28}, + {0x579c, 0x00}, + {0x579d, 0x16}, + {0x579e, 0x06}, + {0x579f, 0x20}, + {0x57a0, 0x04}, + {0x57a1, 0xa0}, + {0x59f8, 0x3d}, + {0x5a08, 0x02}, + {0x5b00, 0x02}, + {0x5b01, 0x10}, + {0x5b02, 0x03}, + {0x5b03, 0xcf}, + {0x5b05, 0x6c}, + {0x5e00, 0x00} +}; + +static const char * const ov8856_test_pattern_menu[] = { + "Disabled", + "Standard Color Bar", + "Top-Bottom Darker Color Bar", + "Right-Left Darker Color Bar", + "Bottom-Top Darker Color Bar" +}; + +static const s64 link_freq_menu_items[] = { + OV8856_LINK_FREQ_360MHZ, + OV8856_LINK_FREQ_180MHZ +}; + +static const struct ov8856_link_freq_config link_freq_configs[] = { + [OV8856_LINK_FREQ_720MBPS] = { + .reg_list = { + .num_of_regs = ARRAY_SIZE(mipi_data_rate_720mbps), + .regs = mipi_data_rate_720mbps, + } + }, + [OV8856_LINK_FREQ_360MBPS] = { + .reg_list = { + .num_of_regs = ARRAY_SIZE(mipi_data_rate_360mbps), + .regs = mipi_data_rate_360mbps, + } + } +}; + +static const struct ov8856_mode supported_modes[] = { + { + .width = 3280, + .height = 2464, + .hts = 1928, + .vts_def = 2488, + .vts_min = 2488, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_3280x2464_regs), + .regs = mode_3280x2464_regs, + }, + .link_freq_index = OV8856_LINK_FREQ_720MBPS, + }, + { + .width = 1640, + .height = 1232, + .hts = 3820, + .vts_def = 1256, + .vts_min = 1256, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_1640x1232_regs), + .regs = mode_1640x1232_regs, + }, + .link_freq_index = OV8856_LINK_FREQ_360MBPS, + } +}; + +struct ov8856 { + struct v4l2_subdev sd; + struct media_pad pad; + struct v4l2_ctrl_handler ctrl_handler; + + /* V4L2 Controls */ + struct v4l2_ctrl *link_freq; + struct v4l2_ctrl *pixel_rate; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *exposure; + + /* Current mode */ + const struct ov8856_mode *cur_mode; + + /* To serialize asynchronus callbacks */ + struct mutex mutex; + + /* Streaming on/off */ + bool streaming; +}; + +static u64 to_pixel_rate(u32 f_index) +{ + u64 pixel_rate = link_freq_menu_items[f_index] * 2 * OV8856_DATA_LANES; + + do_div(pixel_rate, OV8856_RGB_DEPTH); + + return pixel_rate; +} + +static u64 to_pixels_per_line(u32 hts, u32 f_index) +{ + u64 ppl = hts * to_pixel_rate(f_index); + + do_div(ppl, OV8856_SCLK); + + return ppl; +} + +static int ov8856_read_reg(struct ov8856 *ov8856, u16 reg, u16 len, u32 *val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov8856->sd); + struct i2c_msg msgs[2]; + u8 addr_buf[2]; + u8 data_buf[4] = {0}; + int ret; + + if (len > 4) + return -EINVAL; + + put_unaligned_be16(reg, addr_buf); + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = sizeof(addr_buf); + msgs[0].buf = addr_buf; + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = len; + msgs[1].buf = &data_buf[4 - len]; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) + return -EIO; + + *val = get_unaligned_be32(data_buf); + + return 0; +} + +static int ov8856_write_reg(struct ov8856 *ov8856, u16 reg, u16 len, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov8856->sd); + u8 buf[6]; + + if (len > 4) + return -EINVAL; + + put_unaligned_be16(reg, buf); + put_unaligned_be32(val << 8 * (4 - len), buf + 2); + if (i2c_master_send(client, buf, len + 2) != len + 2) + return -EIO; + + return 0; +} + +static int ov8856_write_reg_list(struct ov8856 *ov8856, + const struct ov8856_reg_list *r_list) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov8856->sd); + unsigned int i; + int ret; + + for (i = 0; i < r_list->num_of_regs; i++) { + ret = ov8856_write_reg(ov8856, r_list->regs[i].address, 1, + r_list->regs[i].val); + if (ret) { + dev_err_ratelimited(&client->dev, + "failed to write reg 0x%4.4x. error = %d", + r_list->regs[i].address, ret); + return ret; + } + } + + return 0; +} + +static int ov8856_update_digital_gain(struct ov8856 *ov8856, u32 d_gain) +{ + int ret; + + ret = ov8856_write_reg(ov8856, OV8856_REG_MWB_R_GAIN, + OV8856_REG_VALUE_16BIT, d_gain); + if (ret) + return ret; + + ret = ov8856_write_reg(ov8856, OV8856_REG_MWB_G_GAIN, + OV8856_REG_VALUE_16BIT, d_gain); + if (ret) + return ret; + + return ov8856_write_reg(ov8856, OV8856_REG_MWB_B_GAIN, + OV8856_REG_VALUE_16BIT, d_gain); +} + +static int ov8856_test_pattern(struct ov8856 *ov8856, u32 pattern) +{ + if (pattern) + pattern = (pattern - 1) << OV8856_TEST_PATTERN_BAR_SHIFT | + OV8856_TEST_PATTERN_ENABLE; + + return ov8856_write_reg(ov8856, OV8856_REG_TEST_PATTERN, + OV8856_REG_VALUE_08BIT, pattern); +} + +static int ov8856_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov8856 *ov8856 = container_of(ctrl->handler, + struct ov8856, ctrl_handler); + struct i2c_client *client = v4l2_get_subdevdata(&ov8856->sd); + s64 exposure_max; + int ret = 0; + + /* Propagate change of current control to all related controls */ + if (ctrl->id == V4L2_CID_VBLANK) { + /* Update max exposure while meeting expected vblanking */ + exposure_max = ov8856->cur_mode->height + ctrl->val - + OV8856_EXPOSURE_MAX_MARGIN; + __v4l2_ctrl_modify_range(ov8856->exposure, + ov8856->exposure->minimum, + exposure_max, ov8856->exposure->step, + exposure_max); + } + + /* V4L2 controls values will be applied only when power is already up */ + if (!pm_runtime_get_if_in_use(&client->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_ANALOGUE_GAIN: + ret = ov8856_write_reg(ov8856, OV8856_REG_ANALOG_GAIN, + OV8856_REG_VALUE_16BIT, ctrl->val); + break; + + case V4L2_CID_DIGITAL_GAIN: + ret = ov8856_update_digital_gain(ov8856, ctrl->val); + break; + + case V4L2_CID_EXPOSURE: + /* 4 least significant bits of expsoure are fractional part */ + ret = ov8856_write_reg(ov8856, OV8856_REG_EXPOSURE, + OV8856_REG_VALUE_24BIT, ctrl->val << 4); + break; + + case V4L2_CID_VBLANK: + ret = ov8856_write_reg(ov8856, OV8856_REG_VTS, + OV8856_REG_VALUE_16BIT, + ov8856->cur_mode->height + ctrl->val); + break; + + case V4L2_CID_TEST_PATTERN: + ret = ov8856_test_pattern(ov8856, ctrl->val); + break; + + default: + ret = -EINVAL; + break; + } + + pm_runtime_put(&client->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops ov8856_ctrl_ops = { + .s_ctrl = ov8856_set_ctrl, +}; + +static int ov8856_init_controls(struct ov8856 *ov8856) +{ + struct v4l2_ctrl_handler *ctrl_hdlr; + s64 exposure_max, h_blank; + int ret; + + ctrl_hdlr = &ov8856->ctrl_handler; + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8); + if (ret) + return ret; + + ctrl_hdlr->lock = &ov8856->mutex; + ov8856->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &ov8856_ctrl_ops, + V4L2_CID_LINK_FREQ, + ARRAY_SIZE(link_freq_menu_items) - 1, + 0, link_freq_menu_items); + if (ov8856->link_freq) + ov8856->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + ov8856->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov8856_ctrl_ops, + V4L2_CID_PIXEL_RATE, 0, + to_pixel_rate(OV8856_LINK_FREQ_720MBPS), + 1, + to_pixel_rate(OV8856_LINK_FREQ_720MBPS)); + ov8856->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov8856_ctrl_ops, + V4L2_CID_VBLANK, + ov8856->cur_mode->vts_min - ov8856->cur_mode->height, + OV8856_VTS_MAX - ov8856->cur_mode->height, 1, + ov8856->cur_mode->vts_def - ov8856->cur_mode->height); + h_blank = to_pixels_per_line(ov8856->cur_mode->hts, + ov8856->cur_mode->link_freq_index) - ov8856->cur_mode->width; + ov8856->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov8856_ctrl_ops, + V4L2_CID_HBLANK, h_blank, h_blank, 1, + h_blank); + if (ov8856->hblank) + ov8856->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + v4l2_ctrl_new_std(ctrl_hdlr, &ov8856_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, + OV8856_ANAL_GAIN_MIN, OV8856_ANAL_GAIN_MAX, + OV8856_ANAL_GAIN_STEP, OV8856_ANAL_GAIN_MIN); + v4l2_ctrl_new_std(ctrl_hdlr, &ov8856_ctrl_ops, V4L2_CID_DIGITAL_GAIN, + OV8856_DGTL_GAIN_MIN, OV8856_DGTL_GAIN_MAX, + OV8856_DGTL_GAIN_STEP, OV8856_DGTL_GAIN_DEFAULT); + exposure_max = ov8856->cur_mode->vts_def - OV8856_EXPOSURE_MAX_MARGIN; + ov8856->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov8856_ctrl_ops, + V4L2_CID_EXPOSURE, + OV8856_EXPOSURE_MIN, exposure_max, + OV8856_EXPOSURE_STEP, + exposure_max); + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &ov8856_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov8856_test_pattern_menu) - 1, + 0, 0, ov8856_test_pattern_menu); + if (ctrl_hdlr->error) + return ctrl_hdlr->error; + + ov8856->sd.ctrl_handler = ctrl_hdlr; + + return 0; +} + +static void ov8856_update_pad_format(const struct ov8856_mode *mode, + struct v4l2_mbus_framefmt *fmt) +{ + fmt->width = mode->width; + fmt->height = mode->height; + fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; + fmt->field = V4L2_FIELD_NONE; +} + +static int ov8856_start_streaming(struct ov8856 *ov8856) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov8856->sd); + const struct ov8856_reg_list *reg_list; + int link_freq_index, ret; + + link_freq_index = ov8856->cur_mode->link_freq_index; + reg_list = &link_freq_configs[link_freq_index].reg_list; + ret = ov8856_write_reg_list(ov8856, reg_list); + if (ret) { + dev_err(&client->dev, "failed to set plls"); + return ret; + } + + reg_list = &ov8856->cur_mode->reg_list; + ret = ov8856_write_reg_list(ov8856, reg_list); + if (ret) { + dev_err(&client->dev, "failed to set mode"); + return ret; + } + + ret = __v4l2_ctrl_handler_setup(ov8856->sd.ctrl_handler); + if (ret) + return ret; + + ret = ov8856_write_reg(ov8856, OV8856_REG_MODE_SELECT, + OV8856_REG_VALUE_08BIT, OV8856_MODE_STREAMING); + if (ret) { + dev_err(&client->dev, "failed to set stream"); + return ret; + } + + return 0; +} + +static void ov8856_stop_streaming(struct ov8856 *ov8856) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov8856->sd); + + if (ov8856_write_reg(ov8856, OV8856_REG_MODE_SELECT, + OV8856_REG_VALUE_08BIT, OV8856_MODE_STANDBY)) + dev_err(&client->dev, "failed to set stream"); +} + +static int ov8856_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct ov8856 *ov8856 = to_ov8856(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + if (ov8856->streaming == enable) + return 0; + + mutex_lock(&ov8856->mutex); + if (enable) { + ret = pm_runtime_get_sync(&client->dev); + if (ret < 0) { + pm_runtime_put_noidle(&client->dev); + mutex_unlock(&ov8856->mutex); + return ret; + } + + ret = ov8856_start_streaming(ov8856); + if (ret) { + enable = 0; + ov8856_stop_streaming(ov8856); + pm_runtime_put(&client->dev); + } + } else { + ov8856_stop_streaming(ov8856); + pm_runtime_put(&client->dev); + } + + ov8856->streaming = enable; + mutex_unlock(&ov8856->mutex); + + return ret; +} + +static int __maybe_unused ov8856_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov8856 *ov8856 = to_ov8856(sd); + + mutex_lock(&ov8856->mutex); + if (ov8856->streaming) + ov8856_stop_streaming(ov8856); + + mutex_unlock(&ov8856->mutex); + + return 0; +} + +static int __maybe_unused ov8856_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov8856 *ov8856 = to_ov8856(sd); + int ret; + + mutex_lock(&ov8856->mutex); + if (ov8856->streaming) { + ret = ov8856_start_streaming(ov8856); + if (ret) { + ov8856->streaming = false; + ov8856_stop_streaming(ov8856); + mutex_unlock(&ov8856->mutex); + return ret; + } + } + + mutex_unlock(&ov8856->mutex); + + return 0; +} + +static int ov8856_set_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct ov8856 *ov8856 = to_ov8856(sd); + const struct ov8856_mode *mode; + s32 vblank_def, h_blank; + + mode = v4l2_find_nearest_size(supported_modes, + ARRAY_SIZE(supported_modes), width, + height, fmt->format.width, + fmt->format.height); + + mutex_lock(&ov8856->mutex); + ov8856_update_pad_format(mode, &fmt->format); + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format; + } else { + ov8856->cur_mode = mode; + __v4l2_ctrl_s_ctrl(ov8856->link_freq, mode->link_freq_index); + __v4l2_ctrl_s_ctrl_int64(ov8856->pixel_rate, + to_pixel_rate(mode->link_freq_index)); + + /* Update limits and set FPS to default */ + vblank_def = mode->vts_def - mode->height; + __v4l2_ctrl_modify_range(ov8856->vblank, + mode->vts_min - mode->height, + OV8856_VTS_MAX - mode->height, 1, + vblank_def); + __v4l2_ctrl_s_ctrl(ov8856->vblank, vblank_def); + h_blank = to_pixels_per_line(mode->hts, mode->link_freq_index) - + mode->width; + __v4l2_ctrl_modify_range(ov8856->hblank, h_blank, h_blank, 1, + h_blank); + } + + mutex_unlock(&ov8856->mutex); + + return 0; +} + +static int ov8856_get_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct ov8856 *ov8856 = to_ov8856(sd); + + mutex_lock(&ov8856->mutex); + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) + fmt->format = *v4l2_subdev_get_try_format(&ov8856->sd, cfg, + fmt->pad); + else + ov8856_update_pad_format(ov8856->cur_mode, &fmt->format); + + mutex_unlock(&ov8856->mutex); + + return 0; +} + +static int ov8856_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + /* Only one bayer order GRBG is supported */ + if (code->index > 0) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_SGRBG10_1X10; + + return 0; +} + +static int ov8856_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (fse->index >= ARRAY_SIZE(supported_modes)) + return -EINVAL; + + if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10) + return -EINVAL; + + fse->min_width = supported_modes[fse->index].width; + fse->max_width = fse->min_width; + fse->min_height = supported_modes[fse->index].height; + fse->max_height = fse->min_height; + + return 0; +} + +static int ov8856_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct ov8856 *ov8856 = to_ov8856(sd); + + mutex_lock(&ov8856->mutex); + ov8856_update_pad_format(&supported_modes[0], + v4l2_subdev_get_try_format(sd, fh->pad, 0)); + mutex_unlock(&ov8856->mutex); + + return 0; +} + +static const struct v4l2_subdev_video_ops ov8856_video_ops = { + .s_stream = ov8856_set_stream, +}; + +static const struct v4l2_subdev_pad_ops ov8856_pad_ops = { + .set_fmt = ov8856_set_format, + .get_fmt = ov8856_get_format, + .enum_mbus_code = ov8856_enum_mbus_code, + .enum_frame_size = ov8856_enum_frame_size, +}; + +static const struct v4l2_subdev_ops ov8856_subdev_ops = { + .video = &ov8856_video_ops, + .pad = &ov8856_pad_ops, +}; + +static const struct media_entity_operations ov8856_subdev_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +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; + } + + return 0; +} + +static int ov8856_check_hwcfg(struct device *dev) +{ + struct fwnode_handle *ep; + struct fwnode_handle *fwnode = dev_fwnode(dev); + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY + }; + u32 mclk; + int ret; + unsigned int i, j; + + if (!fwnode) + return -ENXIO; + + fwnode_property_read_u32(fwnode, "clock-frequency", &mclk); + if (mclk != OV8856_MCLK) { + dev_err(dev, "external clock %d is not supported", mclk); + return -EINVAL; + } + + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!ep) + return -ENXIO; + + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + fwnode_handle_put(ep); + if (ret) + return ret; + + if (bus_cfg.bus.mipi_csi2.num_data_lanes != OV8856_DATA_LANES) { + dev_err(dev, "number of CSI2 data lanes %d is not supported", + bus_cfg.bus.mipi_csi2.num_data_lanes); + ret = -EINVAL; + goto check_hwcfg_error; + } + + if (!bus_cfg.nr_of_link_frequencies) { + dev_err(dev, "no link frequencies defined"); + ret = -EINVAL; + goto check_hwcfg_error; + } + + for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) { + for (j = 0; j < bus_cfg.nr_of_link_frequencies; j++) { + if (link_freq_menu_items[i] == + bus_cfg.link_frequencies[j]) + break; + } + + if (j == bus_cfg.nr_of_link_frequencies) { + dev_err(dev, "no link frequency %lld supported", + link_freq_menu_items[i]); + ret = -EINVAL; + goto check_hwcfg_error; + } + } + +check_hwcfg_error: + v4l2_fwnode_endpoint_free(&bus_cfg); + + return ret; +} + +static int ov8856_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov8856 *ov8856 = to_ov8856(sd); + + v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(sd->ctrl_handler); + pm_runtime_disable(&client->dev); + mutex_destroy(&ov8856->mutex); + + return 0; +} + +static int ov8856_probe(struct i2c_client *client) +{ + struct ov8856 *ov8856; + int ret; + + ret = ov8856_check_hwcfg(&client->dev); + if (ret) { + dev_err(&client->dev, "failed to check HW configuration: %d", + ret); + return ret; + } + + ov8856 = devm_kzalloc(&client->dev, sizeof(*ov8856), GFP_KERNEL); + if (!ov8856) + return -ENOMEM; + + v4l2_i2c_subdev_init(&ov8856->sd, client, &ov8856_subdev_ops); + ret = ov8856_identify_module(ov8856); + if (ret) { + dev_err(&client->dev, "failed to find sensor: %d", ret); + return ret; + } + + mutex_init(&ov8856->mutex); + ov8856->cur_mode = &supported_modes[0]; + ret = ov8856_init_controls(ov8856); + if (ret) { + dev_err(&client->dev, "failed to init controls: %d", ret); + goto probe_error_v4l2_ctrl_handler_free; + } + + ov8856->sd.internal_ops = &ov8856_internal_ops; + ov8856->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + ov8856->sd.entity.ops = &ov8856_subdev_entity_ops; + ov8856->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + ov8856->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&ov8856->sd.entity, 1, &ov8856->pad); + if (ret) { + dev_err(&client->dev, "failed to init entity pads: %d", ret); + goto probe_error_v4l2_ctrl_handler_free; + } + + ret = v4l2_async_register_subdev_sensor_common(&ov8856->sd); + if (ret < 0) { + dev_err(&client->dev, "failed to register V4L2 subdev: %d", + ret); + 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); + pm_runtime_enable(&client->dev); + pm_runtime_idle(&client->dev); + + return 0; + +probe_error_media_entity_cleanup: + media_entity_cleanup(&ov8856->sd.entity); + +probe_error_v4l2_ctrl_handler_free: + v4l2_ctrl_handler_free(ov8856->sd.ctrl_handler); + mutex_destroy(&ov8856->mutex); + + return ret; +} + +static const struct dev_pm_ops ov8856_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(ov8856_suspend, ov8856_resume) +}; + +#ifdef CONFIG_ACPI +static const struct acpi_device_id ov8856_acpi_ids[] = { + {"OVTI8856"}, + {} +}; + +MODULE_DEVICE_TABLE(acpi, ov8856_acpi_ids); +#endif + +static struct i2c_driver ov8856_i2c_driver = { + .driver = { + .name = "ov8856", + .pm = &ov8856_pm_ops, + .acpi_match_table = ACPI_PTR(ov8856_acpi_ids), + }, + .probe_new = ov8856_probe, + .remove = ov8856_remove, +}; + +module_i2c_driver(ov8856_i2c_driver); + +MODULE_AUTHOR("Ben Kao <ben.kao@intel.com>"); +MODULE_DESCRIPTION("OmniVision OV8856 sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/soc_camera/soc_ov9640.c b/drivers/media/i2c/ov9640.c index eb91b8240083..d6831f28378b 100644 --- a/drivers/media/i2c/soc_camera/soc_ov9640.c +++ b/drivers/media/i2c/ov9640.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * OmniVision OV96xx Camera Driver * @@ -9,14 +10,11 @@ * Kuninori Morimoto <morimoto.kuninori@renesas.com> * * Based on ov7670 and soc_camera_platform driver, + * transition from soc_camera to pxa_camera based on mt9m111 * * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net> * Copyright (C) 2008 Magnus Damm * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include <linux/init.h> @@ -27,10 +25,14 @@ #include <linux/v4l2-mediabus.h> #include <linux/videodev2.h> -#include <media/soc_camera.h> +#include <media/v4l2-async.h> #include <media/v4l2-clk.h> #include <media/v4l2-common.h> #include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-event.h> + +#include <linux/gpio/consumer.h> #include "ov9640.h" @@ -159,7 +161,7 @@ static const struct ov9640_reg ov9640_regs_rgb[] = { { OV9640_MTXS, 0x65 }, }; -static u32 ov9640_codes[] = { +static const u32 ov9640_codes[] = { MEDIA_BUS_FMT_UYVY8_2X8, MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, MEDIA_BUS_FMT_RGB565_2X8_LE, @@ -269,21 +271,23 @@ static int ov9640_s_stream(struct v4l2_subdev *sd, int enable) /* Set status of additional camera capabilities */ static int ov9640_s_ctrl(struct v4l2_ctrl *ctrl) { - struct ov9640_priv *priv = container_of(ctrl->handler, struct ov9640_priv, hdl); + struct ov9640_priv *priv = container_of(ctrl->handler, + struct ov9640_priv, hdl); struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev); switch (ctrl->id) { case V4L2_CID_VFLIP: if (ctrl->val) return ov9640_reg_rmw(client, OV9640_MVFP, - OV9640_MVFP_V, 0); + OV9640_MVFP_V, 0); return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_V); case V4L2_CID_HFLIP: if (ctrl->val) return ov9640_reg_rmw(client, OV9640_MVFP, - OV9640_MVFP_H, 0); + OV9640_MVFP_H, 0); return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_H); } + return -EINVAL; } @@ -323,20 +327,33 @@ static int ov9640_set_register(struct v4l2_subdev *sd, static int ov9640_s_power(struct v4l2_subdev *sd, int on) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); struct ov9640_priv *priv = to_ov9640_sensor(sd); + int ret = 0; + + if (on) { + gpiod_set_value(priv->gpio_power, 1); + usleep_range(1000, 2000); + ret = v4l2_clk_enable(priv->clk); + usleep_range(1000, 2000); + gpiod_set_value(priv->gpio_reset, 0); + } else { + gpiod_set_value(priv->gpio_reset, 1); + usleep_range(1000, 2000); + v4l2_clk_disable(priv->clk); + usleep_range(1000, 2000); + gpiod_set_value(priv->gpio_power, 0); + } - return soc_camera_set_power(&client->dev, ssdd, priv->clk, on); + return ret; } /* select nearest higher resolution for capture */ static void ov9640_res_roundup(u32 *width, u32 *height) { - int i; + unsigned int i; enum { QQCIF, QQVGA, QCIF, QVGA, CIF, VGA, SXGA }; - static const int res_x[] = { 88, 160, 176, 320, 352, 640, 1280 }; - static const int res_y[] = { 72, 120, 144, 240, 288, 480, 960 }; + static const u32 res_x[] = { 88, 160, 176, 320, 352, 640, 1280 }; + static const u32 res_y[] = { 72, 120, 144, 240, 288, 480, 960 }; for (i = 0; i < ARRAY_SIZE(res_x); i++) { if (res_x[i] >= *width && res_y[i] >= *height) { @@ -379,8 +396,9 @@ static int ov9640_write_regs(struct i2c_client *client, u32 width, u32 code, struct ov9640_reg_alt *alts) { const struct ov9640_reg *ov9640_regs, *matrix_regs; - int ov9640_regs_len, matrix_regs_len; - int i, ret; + unsigned int ov9640_regs_len, matrix_regs_len; + unsigned int i; + int ret; u8 val; /* select register configuration for given resolution */ @@ -454,7 +472,7 @@ static int ov9640_write_regs(struct i2c_client *client, u32 width, /* write color matrix configuration into the module */ for (i = 0; i < matrix_regs_len; i++) { ret = ov9640_reg_write(client, matrix_regs[i].reg, - matrix_regs[i].val); + matrix_regs[i].val); if (ret) return ret; } @@ -465,17 +483,18 @@ static int ov9640_write_regs(struct i2c_client *client, u32 width, /* program default register values */ static int ov9640_prog_dflt(struct i2c_client *client) { - int i, ret; + unsigned int i; + int ret; for (i = 0; i < ARRAY_SIZE(ov9640_regs_dflt); i++) { ret = ov9640_reg_write(client, ov9640_regs_dflt[i].reg, - ov9640_regs_dflt[i].val); + ov9640_regs_dflt[i].val); if (ret) return ret; } /* wait for the changes to actually happen, 140ms are not enough yet */ - mdelay(150); + msleep(150); return 0; } @@ -529,6 +548,7 @@ static int ov9640_set_fmt(struct v4l2_subdev *sd, return ov9640_s_fmt(sd, mf); cfg->try_fmt = *mf; + return 0; } @@ -540,6 +560,7 @@ static int ov9640_enum_mbus_code(struct v4l2_subdev *sd, return -EINVAL; code->code = ov9640_codes[code->index]; + return 0; } @@ -630,14 +651,10 @@ static const struct v4l2_subdev_core_ops ov9640_core_ops = { static int ov9640_g_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH; cfg->type = V4L2_MBUS_PARALLEL; - cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); return 0; } @@ -666,41 +683,62 @@ static int ov9640_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct ov9640_priv *priv; - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); int ret; - if (!ssdd) { - dev_err(&client->dev, "Missing platform_data for driver\n"); - return -EINVAL; - } - priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; + priv->gpio_power = devm_gpiod_get(&client->dev, "Camera power", + GPIOD_OUT_LOW); + if (IS_ERR_OR_NULL(priv->gpio_power)) { + ret = PTR_ERR(priv->gpio_power); + return ret; + } + + priv->gpio_reset = devm_gpiod_get(&client->dev, "Camera reset", + GPIOD_OUT_HIGH); + if (IS_ERR_OR_NULL(priv->gpio_reset)) { + ret = PTR_ERR(priv->gpio_reset); + return ret; + } + v4l2_i2c_subdev_init(&priv->subdev, client, &ov9640_subdev_ops); v4l2_ctrl_handler_init(&priv->hdl, 2); v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops, - V4L2_CID_VFLIP, 0, 1, 1, 0); + V4L2_CID_VFLIP, 0, 1, 1, 0); v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops, - V4L2_CID_HFLIP, 0, 1, 1, 0); + V4L2_CID_HFLIP, 0, 1, 1, 0); + + if (priv->hdl.error) { + ret = priv->hdl.error; + goto ectrlinit; + } + priv->subdev.ctrl_handler = &priv->hdl; - if (priv->hdl.error) - return priv->hdl.error; priv->clk = v4l2_clk_get(&client->dev, "mclk"); if (IS_ERR(priv->clk)) { ret = PTR_ERR(priv->clk); - goto eclkget; + goto ectrlinit; } ret = ov9640_video_probe(client); - if (ret) { - v4l2_clk_put(priv->clk); -eclkget: - v4l2_ctrl_handler_free(&priv->hdl); - } + if (ret) + goto eprobe; + + priv->subdev.dev = &client->dev; + ret = v4l2_async_register_subdev(&priv->subdev); + if (ret) + goto eprobe; + + return 0; + +eprobe: + v4l2_clk_put(priv->clk); +ectrlinit: + v4l2_ctrl_handler_free(&priv->hdl); return ret; } @@ -711,8 +749,9 @@ static int ov9640_remove(struct i2c_client *client) struct ov9640_priv *priv = to_ov9640_sensor(sd); v4l2_clk_put(priv->clk); - v4l2_device_unregister_subdev(&priv->subdev); + v4l2_async_unregister_subdev(&priv->subdev); v4l2_ctrl_handler_free(&priv->hdl); + return 0; } diff --git a/drivers/media/i2c/soc_camera/ov9640.h b/drivers/media/i2c/ov9640.h index 65d13ff17536..a8ed6992c1a8 100644 --- a/drivers/media/i2c/soc_camera/ov9640.h +++ b/drivers/media/i2c/ov9640.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * OmniVision OV96xx Camera Header File * * Copyright (C) 2009 Marek Vasut <marek.vasut@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __DRIVERS_MEDIA_VIDEO_OV9640_H__ @@ -200,6 +197,8 @@ struct ov9640_priv { struct v4l2_subdev subdev; struct v4l2_ctrl_handler hdl; struct v4l2_clk *clk; + struct gpio_desc *gpio_power; + struct gpio_desc *gpio_reset; int model; int revision; diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c index f0587c0c0a72..eefd57ec2a73 100644 --- a/drivers/media/i2c/ov9650.c +++ b/drivers/media/i2c/ov9650.c @@ -45,8 +45,8 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)"); * OV9650/OV9652 register definitions */ #define REG_GAIN 0x00 /* Gain control, AGC[7:0] */ -#define REG_BLUE 0x01 /* AWB - Blue chanel gain */ -#define REG_RED 0x02 /* AWB - Red chanel gain */ +#define REG_BLUE 0x01 /* AWB - Blue channel gain */ +#define REG_RED 0x02 /* AWB - Red channel gain */ #define REG_VREF 0x03 /* [7:6] - AGC[9:8], [5:3]/[2:0] */ #define VREF_GAIN_MASK 0xc0 /* - VREF end/start low 3 bits */ #define REG_COM1 0x04 diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c index c461847ddae8..b52fe250f75f 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c @@ -1431,7 +1431,7 @@ err: for (++i; i < S5C73M3_MAX_SUPPLIES; i++) { int r = regulator_enable(state->supplies[i].consumer); if (r < 0) - v4l2_err(&state->oif_sd, "Failed to reenable %s: %d\n", + v4l2_err(&state->oif_sd, "Failed to re-enable %s: %d\n", state->supplies[i].supply, r); } diff --git a/drivers/media/i2c/s5k4ecgx.c b/drivers/media/i2c/s5k4ecgx.c index 79aa2740edc4..79c1894c2c83 100644 --- a/drivers/media/i2c/s5k4ecgx.c +++ b/drivers/media/i2c/s5k4ecgx.c @@ -263,8 +263,6 @@ static int s5k4ecgx_read(struct i2c_client *client, u32 addr, u16 *val) ret = s5k4ecgx_i2c_write(client, REG_CMDRD_ADDRL, low); if (!ret) ret = s5k4ecgx_i2c_read(client, REG_CMDBUF0_ADDR, val); - if (!ret) - dev_err(&client->dev, "Failed to execute read command\n"); return ret; } diff --git a/drivers/media/i2c/s5k6aa.c b/drivers/media/i2c/s5k6aa.c index ab26f549d716..f8630c4c2ef0 100644 --- a/drivers/media/i2c/s5k6aa.c +++ b/drivers/media/i2c/s5k6aa.c @@ -729,7 +729,7 @@ static int s5k6aa_new_config_sync(struct i2c_client *client, int timeout, * @s5k6aa: pointer to &struct s5k6aa describing the device * @preset: s5kaa preset to be applied * - * Configure output resolution and color fromat, pixel clock + * Configure output resolution and color format, pixel clock * frequency range, device frame rate type and frame period range. */ static int s5k6aa_set_prev_config(struct s5k6aa *s5k6aa, diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c index 6bc278aa31fc..88dc6baac639 100644 --- a/drivers/media/i2c/saa7115.c +++ b/drivers/media/i2c/saa7115.c @@ -1766,7 +1766,7 @@ static int saa711x_detect_chip(struct i2c_client *client, * exists. However, tests on a device labeled as: * "GM7113C 1145" returned "10" on all 16 chip * version (reg 0x00) reads. So, we need to also - * accept at least verion 0. For now, let's just + * accept at least version 0. For now, let's just * assume that a device that returns "0000" for * the lower nibble is a gm7113c. */ diff --git a/drivers/media/i2c/saa717x.c b/drivers/media/i2c/saa717x.c index 668c39cc29e8..86b8b65ea683 100644 --- a/drivers/media/i2c/saa717x.c +++ b/drivers/media/i2c/saa717x.c @@ -844,7 +844,7 @@ static void set_h_prescale(struct v4l2_subdev *sd, if (i == count) return; - /* horizonal prescaling */ + /* horizontal prescaling */ saa717x_write(sd, 0x60 + task_shift, vals[i].xpsc); /* accumulation length */ saa717x_write(sd, 0x61 + task_shift, vals[i].xacl); diff --git a/drivers/media/i2c/soc_camera/Kconfig b/drivers/media/i2c/soc_camera/Kconfig deleted file mode 100644 index 7c2aabc8a3f6..000000000000 --- a/drivers/media/i2c/soc_camera/Kconfig +++ /dev/null @@ -1,66 +0,0 @@ -comment "soc_camera sensor drivers" - -config SOC_CAMERA_MT9M001 - tristate "mt9m001 support" - depends on SOC_CAMERA && I2C - help - This driver supports MT9M001 cameras from Micron, monochrome - and colour models. - -config SOC_CAMERA_MT9M111 - tristate "legacy soc_camera mt9m111, mt9m112 and mt9m131 support" - depends on SOC_CAMERA && I2C - select VIDEO_MT9M111 - help - This driver supports MT9M111, MT9M112 and MT9M131 cameras from - Micron/Aptina. - This is the legacy configuration which shouldn't be used anymore, - while VIDEO_MT9M111 should be used instead. - -config SOC_CAMERA_MT9T112 - tristate "mt9t112 support" - depends on SOC_CAMERA && I2C - help - This driver supports MT9T112 cameras from Aptina. - -config SOC_CAMERA_MT9V022 - tristate "mt9v022 and mt9v024 support" - depends on SOC_CAMERA && I2C - help - This driver supports MT9V022 cameras from Micron - -config SOC_CAMERA_OV5642 - tristate "ov5642 camera support" - depends on SOC_CAMERA && I2C - help - This is a V4L2 camera driver for the OmniVision OV5642 sensor - -config SOC_CAMERA_OV772X - tristate "ov772x camera support" - depends on SOC_CAMERA && I2C - help - This is a ov772x camera driver - -config SOC_CAMERA_OV9640 - tristate "ov9640 camera support" - depends on SOC_CAMERA && I2C - help - This is a ov9640 camera driver - -config SOC_CAMERA_OV9740 - tristate "ov9740 camera support" - depends on SOC_CAMERA && I2C - help - This is a ov9740 camera driver - -config SOC_CAMERA_RJ54N1 - tristate "rj54n1cb0c support" - depends on SOC_CAMERA && I2C - help - This is a rj54n1cb0c video driver - -config SOC_CAMERA_TW9910 - tristate "tw9910 support" - depends on SOC_CAMERA && I2C - help - This is a tw9910 video driver diff --git a/drivers/media/i2c/soc_camera/Makefile b/drivers/media/i2c/soc_camera/Makefile deleted file mode 100644 index 09ae483b96ef..000000000000 --- a/drivers/media/i2c/soc_camera/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_SOC_CAMERA_MT9M001) += soc_mt9m001.o -obj-$(CONFIG_SOC_CAMERA_MT9T112) += soc_mt9t112.o -obj-$(CONFIG_SOC_CAMERA_MT9V022) += soc_mt9v022.o -obj-$(CONFIG_SOC_CAMERA_OV5642) += soc_ov5642.o -obj-$(CONFIG_SOC_CAMERA_OV772X) += soc_ov772x.o -obj-$(CONFIG_SOC_CAMERA_OV9640) += soc_ov9640.o -obj-$(CONFIG_SOC_CAMERA_OV9740) += soc_ov9740.o -obj-$(CONFIG_SOC_CAMERA_RJ54N1) += soc_rj54n1cb0c.o -obj-$(CONFIG_SOC_CAMERA_TW9910) += soc_tw9910.o diff --git a/drivers/media/i2c/soc_camera/soc_mt9t112.c b/drivers/media/i2c/soc_camera/soc_mt9t112.c deleted file mode 100644 index ea1ff270bc2d..000000000000 --- a/drivers/media/i2c/soc_camera/soc_mt9t112.c +++ /dev/null @@ -1,1157 +0,0 @@ -/* - * mt9t112 Camera Driver - * - * Copyright (C) 2009 Renesas Solutions Corp. - * Kuninori Morimoto <morimoto.kuninori@renesas.com> - * - * Based on ov772x driver, mt9m111 driver, - * - * Copyright (C) 2008 Kuninori Morimoto <morimoto.kuninori@renesas.com> - * Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@free.fr> - * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net> - * Copyright (C) 2008 Magnus Damm - * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/delay.h> -#include <linux/i2c.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/v4l2-mediabus.h> -#include <linux/videodev2.h> - -#include <media/i2c/mt9t112.h> -#include <media/soc_camera.h> -#include <media/v4l2-clk.h> -#include <media/v4l2-common.h> -#include <media/v4l2-image-sizes.h> - -/* you can check PLL/clock info */ -/* #define EXT_CLOCK 24000000 */ - -/************************************************************************ - macro -************************************************************************/ -/* - * frame size - */ -#define MAX_WIDTH 2048 -#define MAX_HEIGHT 1536 - -/* - * macro of read/write - */ -#define ECHECKER(ret, x) \ - do { \ - (ret) = (x); \ - if ((ret) < 0) \ - return (ret); \ - } while (0) - -#define mt9t112_reg_write(ret, client, a, b) \ - ECHECKER(ret, __mt9t112_reg_write(client, a, b)) -#define mt9t112_mcu_write(ret, client, a, b) \ - ECHECKER(ret, __mt9t112_mcu_write(client, a, b)) - -#define mt9t112_reg_mask_set(ret, client, a, b, c) \ - ECHECKER(ret, __mt9t112_reg_mask_set(client, a, b, c)) -#define mt9t112_mcu_mask_set(ret, client, a, b, c) \ - ECHECKER(ret, __mt9t112_mcu_mask_set(client, a, b, c)) - -#define mt9t112_reg_read(ret, client, a) \ - ECHECKER(ret, __mt9t112_reg_read(client, a)) - -/* - * Logical address - */ -#define _VAR(id, offset, base) (base | (id & 0x1f) << 10 | (offset & 0x3ff)) -#define VAR(id, offset) _VAR(id, offset, 0x0000) -#define VAR8(id, offset) _VAR(id, offset, 0x8000) - -/************************************************************************ - struct -************************************************************************/ -struct mt9t112_format { - u32 code; - enum v4l2_colorspace colorspace; - u16 fmt; - u16 order; -}; - -struct mt9t112_priv { - struct v4l2_subdev subdev; - struct mt9t112_platform_data *info; - struct i2c_client *client; - struct v4l2_rect frame; - struct v4l2_clk *clk; - const struct mt9t112_format *format; - int num_formats; - u32 flags; -/* for flags */ -#define INIT_DONE (1 << 0) -#define PCLK_RISING (1 << 1) -}; - -/************************************************************************ - supported format -************************************************************************/ - -static const struct mt9t112_format mt9t112_cfmts[] = { - { - .code = MEDIA_BUS_FMT_UYVY8_2X8, - .colorspace = V4L2_COLORSPACE_SRGB, - .fmt = 1, - .order = 0, - }, { - .code = MEDIA_BUS_FMT_VYUY8_2X8, - .colorspace = V4L2_COLORSPACE_SRGB, - .fmt = 1, - .order = 1, - }, { - .code = MEDIA_BUS_FMT_YUYV8_2X8, - .colorspace = V4L2_COLORSPACE_SRGB, - .fmt = 1, - .order = 2, - }, { - .code = MEDIA_BUS_FMT_YVYU8_2X8, - .colorspace = V4L2_COLORSPACE_SRGB, - .fmt = 1, - .order = 3, - }, { - .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, - .colorspace = V4L2_COLORSPACE_SRGB, - .fmt = 8, - .order = 2, - }, { - .code = MEDIA_BUS_FMT_RGB565_2X8_LE, - .colorspace = V4L2_COLORSPACE_SRGB, - .fmt = 4, - .order = 2, - }, -}; - -/************************************************************************ - general function -************************************************************************/ -static struct mt9t112_priv *to_mt9t112(const struct i2c_client *client) -{ - return container_of(i2c_get_clientdata(client), - struct mt9t112_priv, - subdev); -} - -static int __mt9t112_reg_read(const struct i2c_client *client, u16 command) -{ - struct i2c_msg msg[2]; - u8 buf[2]; - int ret; - - command = swab16(command); - - msg[0].addr = client->addr; - msg[0].flags = 0; - msg[0].len = 2; - msg[0].buf = (u8 *)&command; - - msg[1].addr = client->addr; - msg[1].flags = I2C_M_RD; - msg[1].len = 2; - msg[1].buf = buf; - - /* - * if return value of this function is < 0, - * it mean error. - * else, under 16bit is valid data. - */ - ret = i2c_transfer(client->adapter, msg, 2); - if (ret < 0) - return ret; - - memcpy(&ret, buf, 2); - return swab16(ret); -} - -static int __mt9t112_reg_write(const struct i2c_client *client, - u16 command, u16 data) -{ - struct i2c_msg msg; - u8 buf[4]; - int ret; - - command = swab16(command); - data = swab16(data); - - memcpy(buf + 0, &command, 2); - memcpy(buf + 2, &data, 2); - - msg.addr = client->addr; - msg.flags = 0; - msg.len = 4; - msg.buf = buf; - - /* - * i2c_transfer return message length, - * but this function should return 0 if correct case - */ - ret = i2c_transfer(client->adapter, &msg, 1); - if (ret >= 0) - ret = 0; - - return ret; -} - -static int __mt9t112_reg_mask_set(const struct i2c_client *client, - u16 command, - u16 mask, - u16 set) -{ - int val = __mt9t112_reg_read(client, command); - if (val < 0) - return val; - - val &= ~mask; - val |= set & mask; - - return __mt9t112_reg_write(client, command, val); -} - -/* mcu access */ -static int __mt9t112_mcu_read(const struct i2c_client *client, u16 command) -{ - int ret; - - ret = __mt9t112_reg_write(client, 0x098E, command); - if (ret < 0) - return ret; - - return __mt9t112_reg_read(client, 0x0990); -} - -static int __mt9t112_mcu_write(const struct i2c_client *client, - u16 command, u16 data) -{ - int ret; - - ret = __mt9t112_reg_write(client, 0x098E, command); - if (ret < 0) - return ret; - - return __mt9t112_reg_write(client, 0x0990, data); -} - -static int __mt9t112_mcu_mask_set(const struct i2c_client *client, - u16 command, - u16 mask, - u16 set) -{ - int val = __mt9t112_mcu_read(client, command); - if (val < 0) - return val; - - val &= ~mask; - val |= set & mask; - - return __mt9t112_mcu_write(client, command, val); -} - -static int mt9t112_reset(const struct i2c_client *client) -{ - int ret; - - mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0001); - msleep(1); - mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0000); - - return ret; -} - -#ifndef EXT_CLOCK -#define CLOCK_INFO(a, b) -#else -#define CLOCK_INFO(a, b) mt9t112_clock_info(a, b) -static int mt9t112_clock_info(const struct i2c_client *client, u32 ext) -{ - int m, n, p1, p2, p3, p4, p5, p6, p7; - u32 vco, clk; - char *enable; - - ext /= 1000; /* kbyte order */ - - mt9t112_reg_read(n, client, 0x0012); - p1 = n & 0x000f; - n = n >> 4; - p2 = n & 0x000f; - n = n >> 4; - p3 = n & 0x000f; - - mt9t112_reg_read(n, client, 0x002a); - p4 = n & 0x000f; - n = n >> 4; - p5 = n & 0x000f; - n = n >> 4; - p6 = n & 0x000f; - - mt9t112_reg_read(n, client, 0x002c); - p7 = n & 0x000f; - - mt9t112_reg_read(n, client, 0x0010); - m = n & 0x00ff; - n = (n >> 8) & 0x003f; - - enable = ((6000 > ext) || (54000 < ext)) ? "X" : ""; - dev_dbg(&client->dev, "EXTCLK : %10u K %s\n", ext, enable); - - vco = 2 * m * ext / (n+1); - enable = ((384000 > vco) || (768000 < vco)) ? "X" : ""; - dev_dbg(&client->dev, "VCO : %10u K %s\n", vco, enable); - - clk = vco / (p1+1) / (p2+1); - enable = (96000 < clk) ? "X" : ""; - dev_dbg(&client->dev, "PIXCLK : %10u K %s\n", clk, enable); - - clk = vco / (p3+1); - enable = (768000 < clk) ? "X" : ""; - dev_dbg(&client->dev, "MIPICLK : %10u K %s\n", clk, enable); - - clk = vco / (p6+1); - enable = (96000 < clk) ? "X" : ""; - dev_dbg(&client->dev, "MCU CLK : %10u K %s\n", clk, enable); - - clk = vco / (p5+1); - enable = (54000 < clk) ? "X" : ""; - dev_dbg(&client->dev, "SOC CLK : %10u K %s\n", clk, enable); - - clk = vco / (p4+1); - enable = (70000 < clk) ? "X" : ""; - dev_dbg(&client->dev, "Sensor CLK : %10u K %s\n", clk, enable); - - clk = vco / (p7+1); - dev_dbg(&client->dev, "External sensor : %10u K\n", clk); - - clk = ext / (n+1); - enable = ((2000 > clk) || (24000 < clk)) ? "X" : ""; - dev_dbg(&client->dev, "PFD : %10u K %s\n", clk, enable); - - return 0; -} -#endif - -static void mt9t112_frame_check(u32 *width, u32 *height, u32 *left, u32 *top) -{ - soc_camera_limit_side(left, width, 0, 0, MAX_WIDTH); - soc_camera_limit_side(top, height, 0, 0, MAX_HEIGHT); -} - -static int mt9t112_set_a_frame_size(const struct i2c_client *client, - u16 width, - u16 height) -{ - int ret; - u16 wstart = (MAX_WIDTH - width) / 2; - u16 hstart = (MAX_HEIGHT - height) / 2; - - /* (Context A) Image Width/Height */ - mt9t112_mcu_write(ret, client, VAR(26, 0), width); - mt9t112_mcu_write(ret, client, VAR(26, 2), height); - - /* (Context A) Output Width/Height */ - mt9t112_mcu_write(ret, client, VAR(18, 43), 8 + width); - mt9t112_mcu_write(ret, client, VAR(18, 45), 8 + height); - - /* (Context A) Start Row/Column */ - mt9t112_mcu_write(ret, client, VAR(18, 2), 4 + hstart); - mt9t112_mcu_write(ret, client, VAR(18, 4), 4 + wstart); - - /* (Context A) End Row/Column */ - mt9t112_mcu_write(ret, client, VAR(18, 6), 11 + height + hstart); - mt9t112_mcu_write(ret, client, VAR(18, 8), 11 + width + wstart); - - mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06); - - return ret; -} - -static int mt9t112_set_pll_dividers(const struct i2c_client *client, - u8 m, u8 n, - u8 p1, u8 p2, u8 p3, - u8 p4, u8 p5, u8 p6, - u8 p7) -{ - int ret; - u16 val; - - /* N/M */ - val = (n << 8) | - (m << 0); - mt9t112_reg_mask_set(ret, client, 0x0010, 0x3fff, val); - - /* P1/P2/P3 */ - val = ((p3 & 0x0F) << 8) | - ((p2 & 0x0F) << 4) | - ((p1 & 0x0F) << 0); - mt9t112_reg_mask_set(ret, client, 0x0012, 0x0fff, val); - - /* P4/P5/P6 */ - val = (0x7 << 12) | - ((p6 & 0x0F) << 8) | - ((p5 & 0x0F) << 4) | - ((p4 & 0x0F) << 0); - mt9t112_reg_mask_set(ret, client, 0x002A, 0x7fff, val); - - /* P7 */ - val = (0x1 << 12) | - ((p7 & 0x0F) << 0); - mt9t112_reg_mask_set(ret, client, 0x002C, 0x100f, val); - - return ret; -} - -static int mt9t112_init_pll(const struct i2c_client *client) -{ - struct mt9t112_priv *priv = to_mt9t112(client); - int data, i, ret; - - mt9t112_reg_mask_set(ret, client, 0x0014, 0x003, 0x0001); - - /* PLL control: BYPASS PLL = 8517 */ - mt9t112_reg_write(ret, client, 0x0014, 0x2145); - - /* Replace these registers when new timing parameters are generated */ - mt9t112_set_pll_dividers(client, - priv->info->divider.m, - priv->info->divider.n, - priv->info->divider.p1, - priv->info->divider.p2, - priv->info->divider.p3, - priv->info->divider.p4, - priv->info->divider.p5, - priv->info->divider.p6, - priv->info->divider.p7); - - /* - * TEST_BYPASS on - * PLL_ENABLE on - * SEL_LOCK_DET on - * TEST_BYPASS off - */ - mt9t112_reg_write(ret, client, 0x0014, 0x2525); - mt9t112_reg_write(ret, client, 0x0014, 0x2527); - mt9t112_reg_write(ret, client, 0x0014, 0x3427); - mt9t112_reg_write(ret, client, 0x0014, 0x3027); - - mdelay(10); - - /* - * PLL_BYPASS off - * Reference clock count - * I2C Master Clock Divider - */ - mt9t112_reg_write(ret, client, 0x0014, 0x3046); - mt9t112_reg_write(ret, client, 0x0016, 0x0400); /* JPEG initialization workaround */ - mt9t112_reg_write(ret, client, 0x0022, 0x0190); - mt9t112_reg_write(ret, client, 0x3B84, 0x0212); - - /* External sensor clock is PLL bypass */ - mt9t112_reg_write(ret, client, 0x002E, 0x0500); - - mt9t112_reg_mask_set(ret, client, 0x0018, 0x0002, 0x0002); - mt9t112_reg_mask_set(ret, client, 0x3B82, 0x0004, 0x0004); - - /* MCU disabled */ - mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0x0004); - - /* out of standby */ - mt9t112_reg_mask_set(ret, client, 0x0018, 0x0001, 0); - - mdelay(50); - - /* - * Standby Workaround - * Disable Secondary I2C Pads - */ - mt9t112_reg_write(ret, client, 0x0614, 0x0001); - mdelay(1); - mt9t112_reg_write(ret, client, 0x0614, 0x0001); - mdelay(1); - mt9t112_reg_write(ret, client, 0x0614, 0x0001); - mdelay(1); - mt9t112_reg_write(ret, client, 0x0614, 0x0001); - mdelay(1); - mt9t112_reg_write(ret, client, 0x0614, 0x0001); - mdelay(1); - mt9t112_reg_write(ret, client, 0x0614, 0x0001); - mdelay(1); - - /* poll to verify out of standby. Must Poll this bit */ - for (i = 0; i < 100; i++) { - mt9t112_reg_read(data, client, 0x0018); - if (!(0x4000 & data)) - break; - - mdelay(10); - } - - return ret; -} - -static int mt9t112_init_setting(const struct i2c_client *client) -{ - - int ret; - - /* Adaptive Output Clock (A) */ - mt9t112_mcu_mask_set(ret, client, VAR(26, 160), 0x0040, 0x0000); - - /* Read Mode (A) */ - mt9t112_mcu_write(ret, client, VAR(18, 12), 0x0024); - - /* Fine Correction (A) */ - mt9t112_mcu_write(ret, client, VAR(18, 15), 0x00CC); - - /* Fine IT Min (A) */ - mt9t112_mcu_write(ret, client, VAR(18, 17), 0x01f1); - - /* Fine IT Max Margin (A) */ - mt9t112_mcu_write(ret, client, VAR(18, 19), 0x00fF); - - /* Base Frame Lines (A) */ - mt9t112_mcu_write(ret, client, VAR(18, 29), 0x032D); - - /* Min Line Length (A) */ - mt9t112_mcu_write(ret, client, VAR(18, 31), 0x073a); - - /* Line Length (A) */ - mt9t112_mcu_write(ret, client, VAR(18, 37), 0x07d0); - - /* Adaptive Output Clock (B) */ - mt9t112_mcu_mask_set(ret, client, VAR(27, 160), 0x0040, 0x0000); - - /* Row Start (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 74), 0x004); - - /* Column Start (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 76), 0x004); - - /* Row End (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 78), 0x60B); - - /* Column End (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 80), 0x80B); - - /* Fine Correction (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 87), 0x008C); - - /* Fine IT Min (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 89), 0x01F1); - - /* Fine IT Max Margin (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 91), 0x00FF); - - /* Base Frame Lines (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 101), 0x0668); - - /* Min Line Length (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 103), 0x0AF0); - - /* Line Length (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 109), 0x0AF0); - - /* - * Flicker Dectection registers - * This section should be replaced whenever new Timing file is generated - * All the following registers need to be replaced - * Following registers are generated from Register Wizard but user can - * modify them. For detail see auto flicker detection tuning - */ - - /* FD_FDPERIOD_SELECT */ - mt9t112_mcu_write(ret, client, VAR8(8, 5), 0x01); - - /* PRI_B_CONFIG_FD_ALGO_RUN */ - mt9t112_mcu_write(ret, client, VAR(27, 17), 0x0003); - - /* PRI_A_CONFIG_FD_ALGO_RUN */ - mt9t112_mcu_write(ret, client, VAR(26, 17), 0x0003); - - /* - * AFD range detection tuning registers - */ - - /* search_f1_50 */ - mt9t112_mcu_write(ret, client, VAR8(18, 165), 0x25); - - /* search_f2_50 */ - mt9t112_mcu_write(ret, client, VAR8(18, 166), 0x28); - - /* search_f1_60 */ - mt9t112_mcu_write(ret, client, VAR8(18, 167), 0x2C); - - /* search_f2_60 */ - mt9t112_mcu_write(ret, client, VAR8(18, 168), 0x2F); - - /* period_50Hz (A) */ - mt9t112_mcu_write(ret, client, VAR8(18, 68), 0xBA); - - /* secret register by aptina */ - /* period_50Hz (A MSB) */ - mt9t112_mcu_write(ret, client, VAR8(18, 303), 0x00); - - /* period_60Hz (A) */ - mt9t112_mcu_write(ret, client, VAR8(18, 69), 0x9B); - - /* secret register by aptina */ - /* period_60Hz (A MSB) */ - mt9t112_mcu_write(ret, client, VAR8(18, 301), 0x00); - - /* period_50Hz (B) */ - mt9t112_mcu_write(ret, client, VAR8(18, 140), 0x82); - - /* secret register by aptina */ - /* period_50Hz (B) MSB */ - mt9t112_mcu_write(ret, client, VAR8(18, 304), 0x00); - - /* period_60Hz (B) */ - mt9t112_mcu_write(ret, client, VAR8(18, 141), 0x6D); - - /* secret register by aptina */ - /* period_60Hz (B) MSB */ - mt9t112_mcu_write(ret, client, VAR8(18, 302), 0x00); - - /* FD Mode */ - mt9t112_mcu_write(ret, client, VAR8(8, 2), 0x10); - - /* Stat_min */ - mt9t112_mcu_write(ret, client, VAR8(8, 9), 0x02); - - /* Stat_max */ - mt9t112_mcu_write(ret, client, VAR8(8, 10), 0x03); - - /* Min_amplitude */ - mt9t112_mcu_write(ret, client, VAR8(8, 12), 0x0A); - - /* RX FIFO Watermark (A) */ - mt9t112_mcu_write(ret, client, VAR(18, 70), 0x0014); - - /* RX FIFO Watermark (B) */ - mt9t112_mcu_write(ret, client, VAR(18, 142), 0x0014); - - /* MCLK: 16MHz - * PCLK: 73MHz - * CorePixCLK: 36.5 MHz - */ - mt9t112_mcu_write(ret, client, VAR8(18, 0x0044), 133); - mt9t112_mcu_write(ret, client, VAR8(18, 0x0045), 110); - mt9t112_mcu_write(ret, client, VAR8(18, 0x008c), 130); - mt9t112_mcu_write(ret, client, VAR8(18, 0x008d), 108); - - mt9t112_mcu_write(ret, client, VAR8(18, 0x00A5), 27); - mt9t112_mcu_write(ret, client, VAR8(18, 0x00a6), 30); - mt9t112_mcu_write(ret, client, VAR8(18, 0x00a7), 32); - mt9t112_mcu_write(ret, client, VAR8(18, 0x00a8), 35); - - return ret; -} - -static int mt9t112_auto_focus_setting(const struct i2c_client *client) -{ - int ret; - - mt9t112_mcu_write(ret, client, VAR(12, 13), 0x000F); - mt9t112_mcu_write(ret, client, VAR(12, 23), 0x0F0F); - mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06); - - mt9t112_reg_write(ret, client, 0x0614, 0x0000); - - mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x05); - mt9t112_mcu_write(ret, client, VAR8(12, 2), 0x02); - mt9t112_mcu_write(ret, client, VAR(12, 3), 0x0002); - mt9t112_mcu_write(ret, client, VAR(17, 3), 0x8001); - mt9t112_mcu_write(ret, client, VAR(17, 11), 0x0025); - mt9t112_mcu_write(ret, client, VAR(17, 13), 0x0193); - mt9t112_mcu_write(ret, client, VAR8(17, 33), 0x18); - mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x05); - - return ret; -} - -static int mt9t112_auto_focus_trigger(const struct i2c_client *client) -{ - int ret; - - mt9t112_mcu_write(ret, client, VAR8(12, 25), 0x01); - - return ret; -} - -static int mt9t112_init_camera(const struct i2c_client *client) -{ - int ret; - - ECHECKER(ret, mt9t112_reset(client)); - - ECHECKER(ret, mt9t112_init_pll(client)); - - ECHECKER(ret, mt9t112_init_setting(client)); - - ECHECKER(ret, mt9t112_auto_focus_setting(client)); - - mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0); - - /* Analog setting B */ - mt9t112_reg_write(ret, client, 0x3084, 0x2409); - mt9t112_reg_write(ret, client, 0x3092, 0x0A49); - mt9t112_reg_write(ret, client, 0x3094, 0x4949); - mt9t112_reg_write(ret, client, 0x3096, 0x4950); - - /* - * Disable adaptive clock - * PRI_A_CONFIG_JPEG_OB_TX_CONTROL_VAR - * PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR - */ - mt9t112_mcu_write(ret, client, VAR(26, 160), 0x0A2E); - mt9t112_mcu_write(ret, client, VAR(27, 160), 0x0A2E); - - /* Configure STatus in Status_before_length Format and enable header */ - /* PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR */ - mt9t112_mcu_write(ret, client, VAR(27, 144), 0x0CB4); - - /* Enable JPEG in context B */ - /* PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR */ - mt9t112_mcu_write(ret, client, VAR8(27, 142), 0x01); - - /* Disable Dac_TXLO */ - mt9t112_reg_write(ret, client, 0x316C, 0x350F); - - /* Set max slew rates */ - mt9t112_reg_write(ret, client, 0x1E, 0x777); - - return ret; -} - -/************************************************************************ - v4l2_subdev_core_ops -************************************************************************/ - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int mt9t112_g_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - reg->size = 2; - mt9t112_reg_read(ret, client, reg->reg); - - reg->val = (__u64)ret; - - return 0; -} - -static int mt9t112_s_register(struct v4l2_subdev *sd, - const struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - mt9t112_reg_write(ret, client, reg->reg, reg->val); - - return ret; -} -#endif - -static int mt9t112_s_power(struct v4l2_subdev *sd, int on) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - struct mt9t112_priv *priv = to_mt9t112(client); - - return soc_camera_set_power(&client->dev, ssdd, priv->clk, on); -} - -static const struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = { -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = mt9t112_g_register, - .s_register = mt9t112_s_register, -#endif - .s_power = mt9t112_s_power, -}; - - -/************************************************************************ - v4l2_subdev_video_ops -************************************************************************/ -static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t112_priv *priv = to_mt9t112(client); - int ret = 0; - - if (!enable) { - /* FIXME - * - * If user selected large output size, - * and used it long time, - * mt9t112 camera will be very warm. - * - * But current driver can not stop mt9t112 camera. - * So, set small size here to solve this problem. - */ - mt9t112_set_a_frame_size(client, VGA_WIDTH, VGA_HEIGHT); - return ret; - } - - if (!(priv->flags & INIT_DONE)) { - u16 param = PCLK_RISING & priv->flags ? 0x0001 : 0x0000; - - ECHECKER(ret, mt9t112_init_camera(client)); - - /* Invert PCLK (Data sampled on falling edge of pixclk) */ - mt9t112_reg_write(ret, client, 0x3C20, param); - - mdelay(5); - - priv->flags |= INIT_DONE; - } - - mt9t112_mcu_write(ret, client, VAR(26, 7), priv->format->fmt); - mt9t112_mcu_write(ret, client, VAR(26, 9), priv->format->order); - mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06); - - mt9t112_set_a_frame_size(client, - priv->frame.width, - priv->frame.height); - - ECHECKER(ret, mt9t112_auto_focus_trigger(client)); - - dev_dbg(&client->dev, "format : %d\n", priv->format->code); - dev_dbg(&client->dev, "size : %d x %d\n", - priv->frame.width, - priv->frame.height); - - CLOCK_INFO(client, EXT_CLOCK); - - return ret; -} - -static int mt9t112_set_params(struct mt9t112_priv *priv, - const struct v4l2_rect *rect, - u32 code) -{ - int i; - - /* - * get color format - */ - for (i = 0; i < priv->num_formats; i++) - if (mt9t112_cfmts[i].code == code) - break; - - if (i == priv->num_formats) - return -EINVAL; - - priv->frame = *rect; - - /* - * frame size check - */ - mt9t112_frame_check(&priv->frame.width, &priv->frame.height, - &priv->frame.left, &priv->frame.top); - - priv->format = mt9t112_cfmts + i; - - return 0; -} - -static int mt9t112_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t112_priv *priv = to_mt9t112(client); - - if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - switch (sel->target) { - case V4L2_SEL_TGT_CROP_BOUNDS: - sel->r.left = 0; - sel->r.top = 0; - sel->r.width = MAX_WIDTH; - sel->r.height = MAX_HEIGHT; - return 0; - case V4L2_SEL_TGT_CROP: - sel->r = priv->frame; - return 0; - default: - return -EINVAL; - } -} - -static int mt9t112_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t112_priv *priv = to_mt9t112(client); - const struct v4l2_rect *rect = &sel->r; - - if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || - sel->target != V4L2_SEL_TGT_CROP) - return -EINVAL; - - return mt9t112_set_params(priv, rect, priv->format->code); -} - -static int mt9t112_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *mf = &format->format; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t112_priv *priv = to_mt9t112(client); - - if (format->pad) - return -EINVAL; - - mf->width = priv->frame.width; - mf->height = priv->frame.height; - mf->colorspace = priv->format->colorspace; - mf->code = priv->format->code; - mf->field = V4L2_FIELD_NONE; - - return 0; -} - -static int mt9t112_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t112_priv *priv = to_mt9t112(client); - struct v4l2_rect rect = { - .width = mf->width, - .height = mf->height, - .left = priv->frame.left, - .top = priv->frame.top, - }; - int ret; - - ret = mt9t112_set_params(priv, &rect, mf->code); - - if (!ret) - mf->colorspace = priv->format->colorspace; - - return ret; -} - -static int mt9t112_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *mf = &format->format; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t112_priv *priv = to_mt9t112(client); - unsigned int top, left; - int i; - - if (format->pad) - return -EINVAL; - - for (i = 0; i < priv->num_formats; i++) - if (mt9t112_cfmts[i].code == mf->code) - break; - - if (i == priv->num_formats) { - mf->code = MEDIA_BUS_FMT_UYVY8_2X8; - mf->colorspace = V4L2_COLORSPACE_JPEG; - } else { - mf->colorspace = mt9t112_cfmts[i].colorspace; - } - - mt9t112_frame_check(&mf->width, &mf->height, &left, &top); - - mf->field = V4L2_FIELD_NONE; - - if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) - return mt9t112_s_fmt(sd, mf); - cfg->try_fmt = *mf; - return 0; -} - -static int mt9t112_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9t112_priv *priv = to_mt9t112(client); - - if (code->pad || code->index >= priv->num_formats) - return -EINVAL; - - code->code = mt9t112_cfmts[code->index].code; - - return 0; -} - -static int mt9t112_g_mbus_config(struct v4l2_subdev *sd, - struct v4l2_mbus_config *cfg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - - cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH | - V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH | - V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING; - cfg->type = V4L2_MBUS_PARALLEL; - cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); - - return 0; -} - -static int mt9t112_s_mbus_config(struct v4l2_subdev *sd, - const struct v4l2_mbus_config *cfg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - struct mt9t112_priv *priv = to_mt9t112(client); - - if (soc_camera_apply_board_flags(ssdd, cfg) & V4L2_MBUS_PCLK_SAMPLE_RISING) - priv->flags |= PCLK_RISING; - - return 0; -} - -static const struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = { - .s_stream = mt9t112_s_stream, - .g_mbus_config = mt9t112_g_mbus_config, - .s_mbus_config = mt9t112_s_mbus_config, -}; - -static const struct v4l2_subdev_pad_ops mt9t112_subdev_pad_ops = { - .enum_mbus_code = mt9t112_enum_mbus_code, - .get_selection = mt9t112_get_selection, - .set_selection = mt9t112_set_selection, - .get_fmt = mt9t112_get_fmt, - .set_fmt = mt9t112_set_fmt, -}; - -/************************************************************************ - i2c driver -************************************************************************/ -static const struct v4l2_subdev_ops mt9t112_subdev_ops = { - .core = &mt9t112_subdev_core_ops, - .video = &mt9t112_subdev_video_ops, - .pad = &mt9t112_subdev_pad_ops, -}; - -static int mt9t112_camera_probe(struct i2c_client *client) -{ - struct mt9t112_priv *priv = to_mt9t112(client); - const char *devname; - int chipid; - int ret; - - ret = mt9t112_s_power(&priv->subdev, 1); - if (ret < 0) - return ret; - - /* - * check and show chip ID - */ - mt9t112_reg_read(chipid, client, 0x0000); - - switch (chipid) { - case 0x2680: - devname = "mt9t111"; - priv->num_formats = 1; - break; - case 0x2682: - devname = "mt9t112"; - priv->num_formats = ARRAY_SIZE(mt9t112_cfmts); - break; - default: - dev_err(&client->dev, "Product ID error %04x\n", chipid); - ret = -ENODEV; - goto done; - } - - dev_info(&client->dev, "%s chip ID %04x\n", devname, chipid); - -done: - mt9t112_s_power(&priv->subdev, 0); - return ret; -} - -static int mt9t112_probe(struct i2c_client *client, - const struct i2c_device_id *did) -{ - struct mt9t112_priv *priv; - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - struct v4l2_rect rect = { - .width = VGA_WIDTH, - .height = VGA_HEIGHT, - .left = (MAX_WIDTH - VGA_WIDTH) / 2, - .top = (MAX_HEIGHT - VGA_HEIGHT) / 2, - }; - int ret; - - if (!ssdd || !ssdd->drv_priv) { - dev_err(&client->dev, "mt9t112: missing platform data!\n"); - return -EINVAL; - } - - priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->info = ssdd->drv_priv; - - v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops); - - priv->clk = v4l2_clk_get(&client->dev, "mclk"); - if (IS_ERR(priv->clk)) - return PTR_ERR(priv->clk); - - ret = mt9t112_camera_probe(client); - - /* Cannot fail: using the default supported pixel code */ - if (!ret) - mt9t112_set_params(priv, &rect, MEDIA_BUS_FMT_UYVY8_2X8); - else - v4l2_clk_put(priv->clk); - - return ret; -} - -static int mt9t112_remove(struct i2c_client *client) -{ - struct mt9t112_priv *priv = to_mt9t112(client); - - v4l2_clk_put(priv->clk); - return 0; -} - -static const struct i2c_device_id mt9t112_id[] = { - { "mt9t112", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, mt9t112_id); - -static struct i2c_driver mt9t112_i2c_driver = { - .driver = { - .name = "mt9t112", - }, - .probe = mt9t112_probe, - .remove = mt9t112_remove, - .id_table = mt9t112_id, -}; - -module_i2c_driver(mt9t112_i2c_driver); - -MODULE_DESCRIPTION("SoC Camera driver for mt9t112"); -MODULE_AUTHOR("Kuninori Morimoto"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/soc_camera/soc_mt9v022.c b/drivers/media/i2c/soc_camera/soc_mt9v022.c deleted file mode 100644 index 6d922b17ea94..000000000000 --- a/drivers/media/i2c/soc_camera/soc_mt9v022.c +++ /dev/null @@ -1,1012 +0,0 @@ -/* - * Driver for MT9V022 CMOS Image Sensor from Micron - * - * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/videodev2.h> -#include <linux/slab.h> -#include <linux/i2c.h> -#include <linux/delay.h> -#include <linux/log2.h> -#include <linux/module.h> - -#include <media/i2c/mt9v022.h> -#include <media/soc_camera.h> -#include <media/drv-intf/soc_mediabus.h> -#include <media/v4l2-subdev.h> -#include <media/v4l2-clk.h> -#include <media/v4l2-ctrls.h> - -/* - * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c - * The platform has to define struct i2c_board_info objects and link to them - * from struct soc_camera_host_desc - */ - -static char *sensor_type; -module_param(sensor_type, charp, S_IRUGO); -MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\""); - -/* mt9v022 selected register addresses */ -#define MT9V022_CHIP_VERSION 0x00 -#define MT9V022_COLUMN_START 0x01 -#define MT9V022_ROW_START 0x02 -#define MT9V022_WINDOW_HEIGHT 0x03 -#define MT9V022_WINDOW_WIDTH 0x04 -#define MT9V022_HORIZONTAL_BLANKING 0x05 -#define MT9V022_VERTICAL_BLANKING 0x06 -#define MT9V022_CHIP_CONTROL 0x07 -#define MT9V022_SHUTTER_WIDTH1 0x08 -#define MT9V022_SHUTTER_WIDTH2 0x09 -#define MT9V022_SHUTTER_WIDTH_CTRL 0x0a -#define MT9V022_TOTAL_SHUTTER_WIDTH 0x0b -#define MT9V022_RESET 0x0c -#define MT9V022_READ_MODE 0x0d -#define MT9V022_MONITOR_MODE 0x0e -#define MT9V022_PIXEL_OPERATION_MODE 0x0f -#define MT9V022_LED_OUT_CONTROL 0x1b -#define MT9V022_ADC_MODE_CONTROL 0x1c -#define MT9V022_REG32 0x20 -#define MT9V022_ANALOG_GAIN 0x35 -#define MT9V022_BLACK_LEVEL_CALIB_CTRL 0x47 -#define MT9V022_PIXCLK_FV_LV 0x74 -#define MT9V022_DIGITAL_TEST_PATTERN 0x7f -#define MT9V022_AEC_AGC_ENABLE 0xAF -#define MT9V022_MAX_TOTAL_SHUTTER_WIDTH 0xBD - -/* mt9v024 partial list register addresses changes with respect to mt9v022 */ -#define MT9V024_PIXCLK_FV_LV 0x72 -#define MT9V024_MAX_TOTAL_SHUTTER_WIDTH 0xAD - -/* Progressive scan, master, defaults */ -#define MT9V022_CHIP_CONTROL_DEFAULT 0x188 - -#define MT9V022_MAX_WIDTH 752 -#define MT9V022_MAX_HEIGHT 480 -#define MT9V022_MIN_WIDTH 48 -#define MT9V022_MIN_HEIGHT 32 -#define MT9V022_COLUMN_SKIP 1 -#define MT9V022_ROW_SKIP 4 - -#define MT9V022_HORIZONTAL_BLANKING_MIN 43 -#define MT9V022_HORIZONTAL_BLANKING_MAX 1023 -#define MT9V022_HORIZONTAL_BLANKING_DEF 94 -#define MT9V022_VERTICAL_BLANKING_MIN 2 -#define MT9V022_VERTICAL_BLANKING_MAX 3000 -#define MT9V022_VERTICAL_BLANKING_DEF 45 - -#define is_mt9v022_rev3(id) (id == 0x1313) -#define is_mt9v024(id) (id == 0x1324) - -/* MT9V022 has only one fixed colorspace per pixelcode */ -struct mt9v022_datafmt { - u32 code; - enum v4l2_colorspace colorspace; -}; - -/* Find a data format by a pixel code in an array */ -static const struct mt9v022_datafmt *mt9v022_find_datafmt( - u32 code, const struct mt9v022_datafmt *fmt, - int n) -{ - int i; - for (i = 0; i < n; i++) - if (fmt[i].code == code) - return fmt + i; - - return NULL; -} - -static const struct mt9v022_datafmt mt9v022_colour_fmts[] = { - /* - * Order important: first natively supported, - * second supported with a GPIO extender - */ - {MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB}, - {MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB}, -}; - -static const struct mt9v022_datafmt mt9v022_monochrome_fmts[] = { - /* Order important - see above */ - {MEDIA_BUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG}, - {MEDIA_BUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG}, -}; - -/* only registers with different addresses on different mt9v02x sensors */ -struct mt9v02x_register { - u8 max_total_shutter_width; - u8 pixclk_fv_lv; -}; - -static const struct mt9v02x_register mt9v022_register = { - .max_total_shutter_width = MT9V022_MAX_TOTAL_SHUTTER_WIDTH, - .pixclk_fv_lv = MT9V022_PIXCLK_FV_LV, -}; - -static const struct mt9v02x_register mt9v024_register = { - .max_total_shutter_width = MT9V024_MAX_TOTAL_SHUTTER_WIDTH, - .pixclk_fv_lv = MT9V024_PIXCLK_FV_LV, -}; - -enum mt9v022_model { - MT9V022IX7ATM, - MT9V022IX7ATC, -}; - -struct mt9v022 { - struct v4l2_subdev subdev; - struct v4l2_ctrl_handler hdl; - struct { - /* exposure/auto-exposure cluster */ - struct v4l2_ctrl *autoexposure; - struct v4l2_ctrl *exposure; - }; - struct { - /* gain/auto-gain cluster */ - struct v4l2_ctrl *autogain; - struct v4l2_ctrl *gain; - }; - struct v4l2_ctrl *hblank; - struct v4l2_ctrl *vblank; - struct v4l2_rect rect; /* Sensor window */ - struct v4l2_clk *clk; - const struct mt9v022_datafmt *fmt; - const struct mt9v022_datafmt *fmts; - const struct mt9v02x_register *reg; - int num_fmts; - enum mt9v022_model model; - u16 chip_control; - u16 chip_version; - unsigned short y_skip_top; /* Lines to skip at the top */ -}; - -static struct mt9v022 *to_mt9v022(const struct i2c_client *client) -{ - return container_of(i2c_get_clientdata(client), struct mt9v022, subdev); -} - -static int reg_read(struct i2c_client *client, const u8 reg) -{ - return i2c_smbus_read_word_swapped(client, reg); -} - -static int reg_write(struct i2c_client *client, const u8 reg, - const u16 data) -{ - return i2c_smbus_write_word_swapped(client, reg, data); -} - -static int reg_set(struct i2c_client *client, const u8 reg, - const u16 data) -{ - int ret; - - ret = reg_read(client, reg); - if (ret < 0) - return ret; - return reg_write(client, reg, ret | data); -} - -static int reg_clear(struct i2c_client *client, const u8 reg, - const u16 data) -{ - int ret; - - ret = reg_read(client, reg); - if (ret < 0) - return ret; - return reg_write(client, reg, ret & ~data); -} - -static int mt9v022_init(struct i2c_client *client) -{ - struct mt9v022 *mt9v022 = to_mt9v022(client); - int ret; - - /* - * Almost the default mode: master, parallel, simultaneous, and an - * undocumented bit 0x200, which is present in table 7, but not in 8, - * plus snapshot mode to disable scan for now - */ - mt9v022->chip_control |= 0x10; - ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control); - if (!ret) - ret = reg_write(client, MT9V022_READ_MODE, 0x300); - - /* All defaults */ - if (!ret) - /* AEC, AGC on */ - ret = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x3); - if (!ret) - ret = reg_write(client, MT9V022_ANALOG_GAIN, 16); - if (!ret) - ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, 480); - if (!ret) - ret = reg_write(client, mt9v022->reg->max_total_shutter_width, 480); - if (!ret) - /* default - auto */ - ret = reg_clear(client, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1); - if (!ret) - ret = reg_write(client, MT9V022_DIGITAL_TEST_PATTERN, 0); - if (!ret) - return v4l2_ctrl_handler_setup(&mt9v022->hdl); - - return ret; -} - -static int mt9v022_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9v022 *mt9v022 = to_mt9v022(client); - - if (enable) { - /* Switch to master "normal" mode */ - mt9v022->chip_control &= ~0x10; - if (is_mt9v022_rev3(mt9v022->chip_version) || - is_mt9v024(mt9v022->chip_version)) { - /* - * Unset snapshot mode specific settings: clear bit 9 - * and bit 2 in reg. 0x20 when in normal mode. - */ - if (reg_clear(client, MT9V022_REG32, 0x204)) - return -EIO; - } - } else { - /* Switch to snapshot mode */ - mt9v022->chip_control |= 0x10; - if (is_mt9v022_rev3(mt9v022->chip_version) || - is_mt9v024(mt9v022->chip_version)) { - /* - * Required settings for snapshot mode: set bit 9 - * (RST enable) and bit 2 (CR enable) in reg. 0x20 - * See TechNote TN0960 or TN-09-225. - */ - if (reg_set(client, MT9V022_REG32, 0x204)) - return -EIO; - } - } - - if (reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control) < 0) - return -EIO; - return 0; -} - -static int mt9v022_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9v022 *mt9v022 = to_mt9v022(client); - struct v4l2_rect rect = sel->r; - int min_row, min_blank; - int ret; - - if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || - sel->target != V4L2_SEL_TGT_CROP) - return -EINVAL; - - /* Bayer format - even size lengths */ - if (mt9v022->fmts == mt9v022_colour_fmts) { - rect.width = ALIGN(rect.width, 2); - rect.height = ALIGN(rect.height, 2); - /* Let the user play with the starting pixel */ - } - - soc_camera_limit_side(&rect.left, &rect.width, - MT9V022_COLUMN_SKIP, MT9V022_MIN_WIDTH, MT9V022_MAX_WIDTH); - - soc_camera_limit_side(&rect.top, &rect.height, - MT9V022_ROW_SKIP, MT9V022_MIN_HEIGHT, MT9V022_MAX_HEIGHT); - - /* Like in example app. Contradicts the datasheet though */ - ret = reg_read(client, MT9V022_AEC_AGC_ENABLE); - if (ret >= 0) { - if (ret & 1) /* Autoexposure */ - ret = reg_write(client, mt9v022->reg->max_total_shutter_width, - rect.height + mt9v022->y_skip_top + 43); - /* - * If autoexposure is off, there is no need to set - * MT9V022_TOTAL_SHUTTER_WIDTH here. Autoexposure can be off - * only if the user has set exposure manually, using the - * V4L2_CID_EXPOSURE_AUTO with the value V4L2_EXPOSURE_MANUAL. - * In this case the register MT9V022_TOTAL_SHUTTER_WIDTH - * already contains the correct value. - */ - } - /* Setup frame format: defaults apart from width and height */ - if (!ret) - ret = reg_write(client, MT9V022_COLUMN_START, rect.left); - if (!ret) - ret = reg_write(client, MT9V022_ROW_START, rect.top); - /* - * mt9v022: min total row time is 660 columns, min blanking is 43 - * mt9v024: min total row time is 690 columns, min blanking is 61 - */ - if (is_mt9v024(mt9v022->chip_version)) { - min_row = 690; - min_blank = 61; - } else { - min_row = 660; - min_blank = 43; - } - if (!ret) - ret = v4l2_ctrl_s_ctrl(mt9v022->hblank, - rect.width > min_row - min_blank ? - min_blank : min_row - rect.width); - if (!ret) - ret = v4l2_ctrl_s_ctrl(mt9v022->vblank, 45); - if (!ret) - ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect.width); - if (!ret) - ret = reg_write(client, MT9V022_WINDOW_HEIGHT, - rect.height + mt9v022->y_skip_top); - - if (ret < 0) - return ret; - - dev_dbg(&client->dev, "Frame %dx%d pixel\n", rect.width, rect.height); - - mt9v022->rect = rect; - - return 0; -} - -static int mt9v022_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9v022 *mt9v022 = to_mt9v022(client); - - if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - switch (sel->target) { - case V4L2_SEL_TGT_CROP_BOUNDS: - sel->r.left = MT9V022_COLUMN_SKIP; - sel->r.top = MT9V022_ROW_SKIP; - sel->r.width = MT9V022_MAX_WIDTH; - sel->r.height = MT9V022_MAX_HEIGHT; - return 0; - case V4L2_SEL_TGT_CROP: - sel->r = mt9v022->rect; - return 0; - default: - return -EINVAL; - } -} - -static int mt9v022_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *mf = &format->format; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9v022 *mt9v022 = to_mt9v022(client); - - if (format->pad) - return -EINVAL; - - mf->width = mt9v022->rect.width; - mf->height = mt9v022->rect.height; - mf->code = mt9v022->fmt->code; - mf->colorspace = mt9v022->fmt->colorspace; - mf->field = V4L2_FIELD_NONE; - - return 0; -} - -static int mt9v022_s_fmt(struct v4l2_subdev *sd, - const struct mt9v022_datafmt *fmt, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9v022 *mt9v022 = to_mt9v022(client); - struct v4l2_subdev_selection sel = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - .target = V4L2_SEL_TGT_CROP, - .r.left = mt9v022->rect.left, - .r.top = mt9v022->rect.top, - .r.width = mf->width, - .r.height = mf->height, - }; - int ret; - - /* - * The caller provides a supported format, as verified per call to - * .set_fmt(FORMAT_TRY), datawidth is from our supported format list - */ - switch (mf->code) { - case MEDIA_BUS_FMT_Y8_1X8: - case MEDIA_BUS_FMT_Y10_1X10: - if (mt9v022->model != MT9V022IX7ATM) - return -EINVAL; - break; - case MEDIA_BUS_FMT_SBGGR8_1X8: - case MEDIA_BUS_FMT_SBGGR10_1X10: - if (mt9v022->model != MT9V022IX7ATC) - return -EINVAL; - break; - default: - return -EINVAL; - } - - /* No support for scaling on this camera, just crop. */ - ret = mt9v022_set_selection(sd, NULL, &sel); - if (!ret) { - mf->width = mt9v022->rect.width; - mf->height = mt9v022->rect.height; - mt9v022->fmt = fmt; - mf->colorspace = fmt->colorspace; - } - - return ret; -} - -static int mt9v022_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *mf = &format->format; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9v022 *mt9v022 = to_mt9v022(client); - const struct mt9v022_datafmt *fmt; - int align = mf->code == MEDIA_BUS_FMT_SBGGR8_1X8 || - mf->code == MEDIA_BUS_FMT_SBGGR10_1X10; - - if (format->pad) - return -EINVAL; - - v4l_bound_align_image(&mf->width, MT9V022_MIN_WIDTH, - MT9V022_MAX_WIDTH, align, - &mf->height, MT9V022_MIN_HEIGHT + mt9v022->y_skip_top, - MT9V022_MAX_HEIGHT + mt9v022->y_skip_top, align, 0); - - fmt = mt9v022_find_datafmt(mf->code, mt9v022->fmts, - mt9v022->num_fmts); - if (!fmt) { - fmt = mt9v022->fmt; - mf->code = fmt->code; - } - - mf->colorspace = fmt->colorspace; - - if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) - return mt9v022_s_fmt(sd, fmt, mf); - cfg->try_fmt = *mf; - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int mt9v022_g_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->reg > 0xff) - return -EINVAL; - - reg->size = 2; - reg->val = reg_read(client, reg->reg); - - if (reg->val > 0xffff) - return -EIO; - - return 0; -} - -static int mt9v022_s_register(struct v4l2_subdev *sd, - const struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->reg > 0xff) - return -EINVAL; - - if (reg_write(client, reg->reg, reg->val) < 0) - return -EIO; - - return 0; -} -#endif - -static int mt9v022_s_power(struct v4l2_subdev *sd, int on) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - struct mt9v022 *mt9v022 = to_mt9v022(client); - - return soc_camera_set_power(&client->dev, ssdd, mt9v022->clk, on); -} - -static int mt9v022_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct mt9v022 *mt9v022 = container_of(ctrl->handler, - struct mt9v022, hdl); - struct v4l2_subdev *sd = &mt9v022->subdev; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct v4l2_ctrl *gain = mt9v022->gain; - struct v4l2_ctrl *exp = mt9v022->exposure; - unsigned long range; - int data; - - switch (ctrl->id) { - case V4L2_CID_AUTOGAIN: - data = reg_read(client, MT9V022_ANALOG_GAIN); - if (data < 0) - return -EIO; - - range = gain->maximum - gain->minimum; - gain->val = ((data - 16) * range + 24) / 48 + gain->minimum; - return 0; - case V4L2_CID_EXPOSURE_AUTO: - data = reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH); - if (data < 0) - return -EIO; - - range = exp->maximum - exp->minimum; - exp->val = ((data - 1) * range + 239) / 479 + exp->minimum; - return 0; - case V4L2_CID_HBLANK: - data = reg_read(client, MT9V022_HORIZONTAL_BLANKING); - if (data < 0) - return -EIO; - ctrl->val = data; - return 0; - case V4L2_CID_VBLANK: - data = reg_read(client, MT9V022_VERTICAL_BLANKING); - if (data < 0) - return -EIO; - ctrl->val = data; - return 0; - } - return -EINVAL; -} - -static int mt9v022_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct mt9v022 *mt9v022 = container_of(ctrl->handler, - struct mt9v022, hdl); - struct v4l2_subdev *sd = &mt9v022->subdev; - struct i2c_client *client = v4l2_get_subdevdata(sd); - int data; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - if (ctrl->val) - data = reg_set(client, MT9V022_READ_MODE, 0x10); - else - data = reg_clear(client, MT9V022_READ_MODE, 0x10); - if (data < 0) - return -EIO; - return 0; - case V4L2_CID_HFLIP: - if (ctrl->val) - data = reg_set(client, MT9V022_READ_MODE, 0x20); - else - data = reg_clear(client, MT9V022_READ_MODE, 0x20); - if (data < 0) - return -EIO; - return 0; - case V4L2_CID_AUTOGAIN: - if (ctrl->val) { - if (reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) - return -EIO; - } else { - struct v4l2_ctrl *gain = mt9v022->gain; - /* mt9v022 has minimum == default */ - unsigned long range = gain->maximum - gain->minimum; - /* Valid values 16 to 64, 32 to 64 must be even. */ - unsigned long gain_val = ((gain->val - (s32)gain->minimum) * - 48 + range / 2) / range + 16; - - if (gain_val >= 32) - gain_val &= ~1; - - /* - * The user wants to set gain manually, hope, she - * knows, what she's doing... Switch AGC off. - */ - if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) - return -EIO; - - dev_dbg(&client->dev, "Setting gain from %d to %lu\n", - reg_read(client, MT9V022_ANALOG_GAIN), gain_val); - if (reg_write(client, MT9V022_ANALOG_GAIN, gain_val) < 0) - return -EIO; - } - return 0; - case V4L2_CID_EXPOSURE_AUTO: - if (ctrl->val == V4L2_EXPOSURE_AUTO) { - data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x1); - } else { - struct v4l2_ctrl *exp = mt9v022->exposure; - unsigned long range = exp->maximum - exp->minimum; - unsigned long shutter = ((exp->val - (s32)exp->minimum) * - 479 + range / 2) / range + 1; - - /* - * The user wants to set shutter width manually, hope, - * she knows, what she's doing... Switch AEC off. - */ - data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1); - if (data < 0) - return -EIO; - dev_dbg(&client->dev, "Shutter width from %d to %lu\n", - reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH), - shutter); - if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, - shutter) < 0) - return -EIO; - } - return 0; - case V4L2_CID_HBLANK: - if (reg_write(client, MT9V022_HORIZONTAL_BLANKING, - ctrl->val) < 0) - return -EIO; - return 0; - case V4L2_CID_VBLANK: - if (reg_write(client, MT9V022_VERTICAL_BLANKING, - ctrl->val) < 0) - return -EIO; - return 0; - } - return -EINVAL; -} - -/* - * Interface active, can use i2c. If it fails, it can indeed mean, that - * this wasn't our capture interface, so, we wait for the right one - */ -static int mt9v022_video_probe(struct i2c_client *client) -{ - struct mt9v022 *mt9v022 = to_mt9v022(client); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - s32 data; - int ret; - unsigned long flags; - - ret = mt9v022_s_power(&mt9v022->subdev, 1); - if (ret < 0) - return ret; - - /* Read out the chip version register */ - data = reg_read(client, MT9V022_CHIP_VERSION); - - /* must be 0x1311, 0x1313 or 0x1324 */ - if (data != 0x1311 && data != 0x1313 && data != 0x1324) { - ret = -ENODEV; - dev_info(&client->dev, "No MT9V022 found, ID register 0x%x\n", - data); - goto ei2c; - } - - mt9v022->chip_version = data; - - mt9v022->reg = is_mt9v024(data) ? &mt9v024_register : - &mt9v022_register; - - /* Soft reset */ - ret = reg_write(client, MT9V022_RESET, 1); - if (ret < 0) - goto ei2c; - /* 15 clock cycles */ - udelay(200); - if (reg_read(client, MT9V022_RESET)) { - dev_err(&client->dev, "Resetting MT9V022 failed!\n"); - if (ret > 0) - ret = -EIO; - goto ei2c; - } - - /* Set monochrome or colour sensor type */ - if (sensor_type && (!strcmp("colour", sensor_type) || - !strcmp("color", sensor_type))) { - ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11); - mt9v022->model = MT9V022IX7ATC; - mt9v022->fmts = mt9v022_colour_fmts; - } else { - ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 0x11); - mt9v022->model = MT9V022IX7ATM; - mt9v022->fmts = mt9v022_monochrome_fmts; - } - - if (ret < 0) - goto ei2c; - - mt9v022->num_fmts = 0; - - /* - * This is a 10bit sensor, so by default we only allow 10bit. - * The platform may support different bus widths due to - * different routing of the data lines. - */ - if (ssdd->query_bus_param) - flags = ssdd->query_bus_param(ssdd); - else - flags = SOCAM_DATAWIDTH_10; - - if (flags & SOCAM_DATAWIDTH_10) - mt9v022->num_fmts++; - else - mt9v022->fmts++; - - if (flags & SOCAM_DATAWIDTH_8) - mt9v022->num_fmts++; - - mt9v022->fmt = &mt9v022->fmts[0]; - - dev_info(&client->dev, "Detected a MT9V022 chip ID %x, %s sensor\n", - data, mt9v022->model == MT9V022IX7ATM ? - "monochrome" : "colour"); - - ret = mt9v022_init(client); - if (ret < 0) - dev_err(&client->dev, "Failed to initialise the camera\n"); - -ei2c: - mt9v022_s_power(&mt9v022->subdev, 0); - return ret; -} - -static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9v022 *mt9v022 = to_mt9v022(client); - - *lines = mt9v022->y_skip_top; - - return 0; -} - -static const struct v4l2_ctrl_ops mt9v022_ctrl_ops = { - .g_volatile_ctrl = mt9v022_g_volatile_ctrl, - .s_ctrl = mt9v022_s_ctrl, -}; - -static const struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = { -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = mt9v022_g_register, - .s_register = mt9v022_s_register, -#endif - .s_power = mt9v022_s_power, -}; - -static int mt9v022_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9v022 *mt9v022 = to_mt9v022(client); - - if (code->pad || code->index >= mt9v022->num_fmts) - return -EINVAL; - - code->code = mt9v022->fmts[code->index].code; - return 0; -} - -static int mt9v022_g_mbus_config(struct v4l2_subdev *sd, - struct v4l2_mbus_config *cfg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - - cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE | - V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | - V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW | - V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | - V4L2_MBUS_DATA_ACTIVE_HIGH; - cfg->type = V4L2_MBUS_PARALLEL; - cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); - - return 0; -} - -static int mt9v022_s_mbus_config(struct v4l2_subdev *sd, - const struct v4l2_mbus_config *cfg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - struct mt9v022 *mt9v022 = to_mt9v022(client); - unsigned long flags = soc_camera_apply_board_flags(ssdd, cfg); - unsigned int bps = soc_mbus_get_fmtdesc(mt9v022->fmt->code)->bits_per_sample; - int ret; - u16 pixclk = 0; - - if (ssdd->set_bus_param) { - ret = ssdd->set_bus_param(ssdd, 1 << (bps - 1)); - if (ret) - return ret; - } else if (bps != 10) { - /* - * Without board specific bus width settings we only support the - * sensors native bus width - */ - return -EINVAL; - } - - if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) - pixclk |= 0x10; - - if (!(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)) - pixclk |= 0x1; - - if (!(flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)) - pixclk |= 0x2; - - ret = reg_write(client, mt9v022->reg->pixclk_fv_lv, pixclk); - if (ret < 0) - return ret; - - if (!(flags & V4L2_MBUS_MASTER)) - mt9v022->chip_control &= ~0x8; - - ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control); - if (ret < 0) - return ret; - - dev_dbg(&client->dev, "Calculated pixclk 0x%x, chip control 0x%x\n", - pixclk, mt9v022->chip_control); - - return 0; -} - -static const struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { - .s_stream = mt9v022_s_stream, - .g_mbus_config = mt9v022_g_mbus_config, - .s_mbus_config = mt9v022_s_mbus_config, -}; - -static const struct v4l2_subdev_sensor_ops mt9v022_subdev_sensor_ops = { - .g_skip_top_lines = mt9v022_g_skip_top_lines, -}; - -static const struct v4l2_subdev_pad_ops mt9v022_subdev_pad_ops = { - .enum_mbus_code = mt9v022_enum_mbus_code, - .get_selection = mt9v022_get_selection, - .set_selection = mt9v022_set_selection, - .get_fmt = mt9v022_get_fmt, - .set_fmt = mt9v022_set_fmt, -}; - -static const struct v4l2_subdev_ops mt9v022_subdev_ops = { - .core = &mt9v022_subdev_core_ops, - .video = &mt9v022_subdev_video_ops, - .sensor = &mt9v022_subdev_sensor_ops, - .pad = &mt9v022_subdev_pad_ops, -}; - -static int mt9v022_probe(struct i2c_client *client, - const struct i2c_device_id *did) -{ - struct mt9v022 *mt9v022; - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct mt9v022_platform_data *pdata; - int ret; - - if (!ssdd) { - dev_err(&client->dev, "MT9V022 driver needs platform data\n"); - return -EINVAL; - } - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { - dev_warn(&adapter->dev, - "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); - return -EIO; - } - - mt9v022 = devm_kzalloc(&client->dev, sizeof(struct mt9v022), GFP_KERNEL); - if (!mt9v022) - return -ENOMEM; - - pdata = ssdd->drv_priv; - v4l2_i2c_subdev_init(&mt9v022->subdev, client, &mt9v022_subdev_ops); - v4l2_ctrl_handler_init(&mt9v022->hdl, 6); - v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, - V4L2_CID_VFLIP, 0, 1, 1, 0); - v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, - V4L2_CID_HFLIP, 0, 1, 1, 0); - mt9v022->autogain = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, - V4L2_CID_AUTOGAIN, 0, 1, 1, 1); - mt9v022->gain = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, - V4L2_CID_GAIN, 0, 127, 1, 64); - - /* - * Simulated autoexposure. If enabled, we calculate shutter width - * ourselves in the driver based on vertical blanking and frame width - */ - mt9v022->autoexposure = v4l2_ctrl_new_std_menu(&mt9v022->hdl, - &mt9v022_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, - V4L2_EXPOSURE_AUTO); - mt9v022->exposure = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, - V4L2_CID_EXPOSURE, 1, 255, 1, 255); - - mt9v022->hblank = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, - V4L2_CID_HBLANK, MT9V022_HORIZONTAL_BLANKING_MIN, - MT9V022_HORIZONTAL_BLANKING_MAX, 1, - MT9V022_HORIZONTAL_BLANKING_DEF); - - mt9v022->vblank = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, - V4L2_CID_VBLANK, MT9V022_VERTICAL_BLANKING_MIN, - MT9V022_VERTICAL_BLANKING_MAX, 1, - MT9V022_VERTICAL_BLANKING_DEF); - - mt9v022->subdev.ctrl_handler = &mt9v022->hdl; - if (mt9v022->hdl.error) { - int err = mt9v022->hdl.error; - - dev_err(&client->dev, "control initialisation err %d\n", err); - return err; - } - v4l2_ctrl_auto_cluster(2, &mt9v022->autoexposure, - V4L2_EXPOSURE_MANUAL, true); - v4l2_ctrl_auto_cluster(2, &mt9v022->autogain, 0, true); - - mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT; - - /* - * On some platforms the first read out line is corrupted. - * Workaround it by skipping if indicated by platform data. - */ - mt9v022->y_skip_top = pdata ? pdata->y_skip_top : 0; - mt9v022->rect.left = MT9V022_COLUMN_SKIP; - mt9v022->rect.top = MT9V022_ROW_SKIP; - mt9v022->rect.width = MT9V022_MAX_WIDTH; - mt9v022->rect.height = MT9V022_MAX_HEIGHT; - - mt9v022->clk = v4l2_clk_get(&client->dev, "mclk"); - if (IS_ERR(mt9v022->clk)) { - ret = PTR_ERR(mt9v022->clk); - goto eclkget; - } - - ret = mt9v022_video_probe(client); - if (ret) { - v4l2_clk_put(mt9v022->clk); -eclkget: - v4l2_ctrl_handler_free(&mt9v022->hdl); - } - - return ret; -} - -static int mt9v022_remove(struct i2c_client *client) -{ - struct mt9v022 *mt9v022 = to_mt9v022(client); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - - v4l2_clk_put(mt9v022->clk); - v4l2_device_unregister_subdev(&mt9v022->subdev); - if (ssdd->free_bus) - ssdd->free_bus(ssdd); - v4l2_ctrl_handler_free(&mt9v022->hdl); - - return 0; -} -static const struct i2c_device_id mt9v022_id[] = { - { "mt9v022", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, mt9v022_id); - -static struct i2c_driver mt9v022_i2c_driver = { - .driver = { - .name = "mt9v022", - }, - .probe = mt9v022_probe, - .remove = mt9v022_remove, - .id_table = mt9v022_id, -}; - -module_i2c_driver(mt9v022_i2c_driver); - -MODULE_DESCRIPTION("Micron MT9V022 Camera driver"); -MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/soc_camera/soc_ov5642.c b/drivers/media/i2c/soc_camera/soc_ov5642.c deleted file mode 100644 index 0931898c79dd..000000000000 --- a/drivers/media/i2c/soc_camera/soc_ov5642.c +++ /dev/null @@ -1,1087 +0,0 @@ -/* - * Driver for OV5642 CMOS Image Sensor from Omnivision - * - * Copyright (C) 2011, Bastian Hecht <hechtb@gmail.com> - * - * Based on Sony IMX074 Camera Driver - * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de> - * - * Based on Omnivision OV7670 Camera Driver - * Copyright (C) 2006-7 Jonathan Corbet <corbet@lwn.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/bitops.h> -#include <linux/delay.h> -#include <linux/i2c.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/videodev2.h> -#include <linux/module.h> -#include <linux/v4l2-mediabus.h> - -#include <media/soc_camera.h> -#include <media/v4l2-clk.h> -#include <media/v4l2-subdev.h> - -/* OV5642 registers */ -#define REG_CHIP_ID_HIGH 0x300a -#define REG_CHIP_ID_LOW 0x300b - -#define REG_WINDOW_START_X_HIGH 0x3800 -#define REG_WINDOW_START_X_LOW 0x3801 -#define REG_WINDOW_START_Y_HIGH 0x3802 -#define REG_WINDOW_START_Y_LOW 0x3803 -#define REG_WINDOW_WIDTH_HIGH 0x3804 -#define REG_WINDOW_WIDTH_LOW 0x3805 -#define REG_WINDOW_HEIGHT_HIGH 0x3806 -#define REG_WINDOW_HEIGHT_LOW 0x3807 -#define REG_OUT_WIDTH_HIGH 0x3808 -#define REG_OUT_WIDTH_LOW 0x3809 -#define REG_OUT_HEIGHT_HIGH 0x380a -#define REG_OUT_HEIGHT_LOW 0x380b -#define REG_OUT_TOTAL_WIDTH_HIGH 0x380c -#define REG_OUT_TOTAL_WIDTH_LOW 0x380d -#define REG_OUT_TOTAL_HEIGHT_HIGH 0x380e -#define REG_OUT_TOTAL_HEIGHT_LOW 0x380f -#define REG_OUTPUT_FORMAT 0x4300 -#define REG_ISP_CTRL_01 0x5001 -#define REG_AVG_WINDOW_END_X_HIGH 0x5682 -#define REG_AVG_WINDOW_END_X_LOW 0x5683 -#define REG_AVG_WINDOW_END_Y_HIGH 0x5686 -#define REG_AVG_WINDOW_END_Y_LOW 0x5687 - -/* active pixel array size */ -#define OV5642_SENSOR_SIZE_X 2592 -#define OV5642_SENSOR_SIZE_Y 1944 - -/* - * About OV5642 resolution, cropping and binning: - * This sensor supports it all, at least in the feature description. - * Unfortunately, no combination of appropriate registers settings could make - * the chip work the intended way. As it works with predefined register lists, - * some undocumented registers are presumably changed there to achieve their - * goals. - * This driver currently only works for resolutions up to 720 lines with a - * 1:1 scale. Hopefully these restrictions will be removed in the future. - */ -#define OV5642_MAX_WIDTH OV5642_SENSOR_SIZE_X -#define OV5642_MAX_HEIGHT 720 - -/* default sizes */ -#define OV5642_DEFAULT_WIDTH 1280 -#define OV5642_DEFAULT_HEIGHT OV5642_MAX_HEIGHT - -/* minimum extra blanking */ -#define BLANKING_EXTRA_WIDTH 500 -#define BLANKING_EXTRA_HEIGHT 20 - -/* - * the sensor's autoexposure is buggy when setting total_height low. - * It tries to expose longer than 1 frame period without taking care of it - * and this leads to weird output. So we set 1000 lines as minimum. - */ -#define BLANKING_MIN_HEIGHT 1000 - -struct regval_list { - u16 reg_num; - u8 value; -}; - -static struct regval_list ov5642_default_regs_init[] = { - { 0x3103, 0x93 }, - { 0x3008, 0x82 }, - { 0x3017, 0x7f }, - { 0x3018, 0xfc }, - { 0x3810, 0xc2 }, - { 0x3615, 0xf0 }, - { 0x3000, 0x0 }, - { 0x3001, 0x0 }, - { 0x3002, 0x0 }, - { 0x3003, 0x0 }, - { 0x3004, 0xff }, - { 0x3030, 0x2b }, - { 0x3011, 0x8 }, - { 0x3010, 0x10 }, - { 0x3604, 0x60 }, - { 0x3622, 0x60 }, - { 0x3621, 0x9 }, - { 0x3709, 0x0 }, - { 0x4000, 0x21 }, - { 0x401d, 0x22 }, - { 0x3600, 0x54 }, - { 0x3605, 0x4 }, - { 0x3606, 0x3f }, - { 0x3c01, 0x80 }, - { 0x300d, 0x22 }, - { 0x3623, 0x22 }, - { 0x5000, 0x4f }, - { 0x5020, 0x4 }, - { 0x5181, 0x79 }, - { 0x5182, 0x0 }, - { 0x5185, 0x22 }, - { 0x5197, 0x1 }, - { 0x5500, 0xa }, - { 0x5504, 0x0 }, - { 0x5505, 0x7f }, - { 0x5080, 0x8 }, - { 0x300e, 0x18 }, - { 0x4610, 0x0 }, - { 0x471d, 0x5 }, - { 0x4708, 0x6 }, - { 0x370c, 0xa0 }, - { 0x5687, 0x94 }, - { 0x501f, 0x0 }, - { 0x5000, 0x4f }, - { 0x5001, 0xcf }, - { 0x4300, 0x30 }, - { 0x4300, 0x30 }, - { 0x460b, 0x35 }, - { 0x471d, 0x0 }, - { 0x3002, 0xc }, - { 0x3002, 0x0 }, - { 0x4713, 0x3 }, - { 0x471c, 0x50 }, - { 0x4721, 0x2 }, - { 0x4402, 0x90 }, - { 0x460c, 0x22 }, - { 0x3815, 0x44 }, - { 0x3503, 0x7 }, - { 0x3501, 0x73 }, - { 0x3502, 0x80 }, - { 0x350b, 0x0 }, - { 0x3818, 0xc8 }, - { 0x3824, 0x11 }, - { 0x3a00, 0x78 }, - { 0x3a1a, 0x4 }, - { 0x3a13, 0x30 }, - { 0x3a18, 0x0 }, - { 0x3a19, 0x7c }, - { 0x3a08, 0x12 }, - { 0x3a09, 0xc0 }, - { 0x3a0a, 0xf }, - { 0x3a0b, 0xa0 }, - { 0x350c, 0x7 }, - { 0x350d, 0xd0 }, - { 0x3a0d, 0x8 }, - { 0x3a0e, 0x6 }, - { 0x3500, 0x0 }, - { 0x3501, 0x0 }, - { 0x3502, 0x0 }, - { 0x350a, 0x0 }, - { 0x350b, 0x0 }, - { 0x3503, 0x0 }, - { 0x3a0f, 0x3c }, - { 0x3a10, 0x32 }, - { 0x3a1b, 0x3c }, - { 0x3a1e, 0x32 }, - { 0x3a11, 0x80 }, - { 0x3a1f, 0x20 }, - { 0x3030, 0x2b }, - { 0x3a02, 0x0 }, - { 0x3a03, 0x7d }, - { 0x3a04, 0x0 }, - { 0x3a14, 0x0 }, - { 0x3a15, 0x7d }, - { 0x3a16, 0x0 }, - { 0x3a00, 0x78 }, - { 0x3a08, 0x9 }, - { 0x3a09, 0x60 }, - { 0x3a0a, 0x7 }, - { 0x3a0b, 0xd0 }, - { 0x3a0d, 0x10 }, - { 0x3a0e, 0xd }, - { 0x4407, 0x4 }, - { 0x5193, 0x70 }, - { 0x589b, 0x0 }, - { 0x589a, 0xc0 }, - { 0x401e, 0x20 }, - { 0x4001, 0x42 }, - { 0x401c, 0x6 }, - { 0x3825, 0xac }, - { 0x3827, 0xc }, - { 0x528a, 0x1 }, - { 0x528b, 0x4 }, - { 0x528c, 0x8 }, - { 0x528d, 0x10 }, - { 0x528e, 0x20 }, - { 0x528f, 0x28 }, - { 0x5290, 0x30 }, - { 0x5292, 0x0 }, - { 0x5293, 0x1 }, - { 0x5294, 0x0 }, - { 0x5295, 0x4 }, - { 0x5296, 0x0 }, - { 0x5297, 0x8 }, - { 0x5298, 0x0 }, - { 0x5299, 0x10 }, - { 0x529a, 0x0 }, - { 0x529b, 0x20 }, - { 0x529c, 0x0 }, - { 0x529d, 0x28 }, - { 0x529e, 0x0 }, - { 0x529f, 0x30 }, - { 0x5282, 0x0 }, - { 0x5300, 0x0 }, - { 0x5301, 0x20 }, - { 0x5302, 0x0 }, - { 0x5303, 0x7c }, - { 0x530c, 0x0 }, - { 0x530d, 0xc }, - { 0x530e, 0x20 }, - { 0x530f, 0x80 }, - { 0x5310, 0x20 }, - { 0x5311, 0x80 }, - { 0x5308, 0x20 }, - { 0x5309, 0x40 }, - { 0x5304, 0x0 }, - { 0x5305, 0x30 }, - { 0x5306, 0x0 }, - { 0x5307, 0x80 }, - { 0x5314, 0x8 }, - { 0x5315, 0x20 }, - { 0x5319, 0x30 }, - { 0x5316, 0x10 }, - { 0x5317, 0x0 }, - { 0x5318, 0x2 }, - { 0x5380, 0x1 }, - { 0x5381, 0x0 }, - { 0x5382, 0x0 }, - { 0x5383, 0x4e }, - { 0x5384, 0x0 }, - { 0x5385, 0xf }, - { 0x5386, 0x0 }, - { 0x5387, 0x0 }, - { 0x5388, 0x1 }, - { 0x5389, 0x15 }, - { 0x538a, 0x0 }, - { 0x538b, 0x31 }, - { 0x538c, 0x0 }, - { 0x538d, 0x0 }, - { 0x538e, 0x0 }, - { 0x538f, 0xf }, - { 0x5390, 0x0 }, - { 0x5391, 0xab }, - { 0x5392, 0x0 }, - { 0x5393, 0xa2 }, - { 0x5394, 0x8 }, - { 0x5480, 0x14 }, - { 0x5481, 0x21 }, - { 0x5482, 0x36 }, - { 0x5483, 0x57 }, - { 0x5484, 0x65 }, - { 0x5485, 0x71 }, - { 0x5486, 0x7d }, - { 0x5487, 0x87 }, - { 0x5488, 0x91 }, - { 0x5489, 0x9a }, - { 0x548a, 0xaa }, - { 0x548b, 0xb8 }, - { 0x548c, 0xcd }, - { 0x548d, 0xdd }, - { 0x548e, 0xea }, - { 0x548f, 0x1d }, - { 0x5490, 0x5 }, - { 0x5491, 0x0 }, - { 0x5492, 0x4 }, - { 0x5493, 0x20 }, - { 0x5494, 0x3 }, - { 0x5495, 0x60 }, - { 0x5496, 0x2 }, - { 0x5497, 0xb8 }, - { 0x5498, 0x2 }, - { 0x5499, 0x86 }, - { 0x549a, 0x2 }, - { 0x549b, 0x5b }, - { 0x549c, 0x2 }, - { 0x549d, 0x3b }, - { 0x549e, 0x2 }, - { 0x549f, 0x1c }, - { 0x54a0, 0x2 }, - { 0x54a1, 0x4 }, - { 0x54a2, 0x1 }, - { 0x54a3, 0xed }, - { 0x54a4, 0x1 }, - { 0x54a5, 0xc5 }, - { 0x54a6, 0x1 }, - { 0x54a7, 0xa5 }, - { 0x54a8, 0x1 }, - { 0x54a9, 0x6c }, - { 0x54aa, 0x1 }, - { 0x54ab, 0x41 }, - { 0x54ac, 0x1 }, - { 0x54ad, 0x20 }, - { 0x54ae, 0x0 }, - { 0x54af, 0x16 }, - { 0x54b0, 0x1 }, - { 0x54b1, 0x20 }, - { 0x54b2, 0x0 }, - { 0x54b3, 0x10 }, - { 0x54b4, 0x0 }, - { 0x54b5, 0xf0 }, - { 0x54b6, 0x0 }, - { 0x54b7, 0xdf }, - { 0x5402, 0x3f }, - { 0x5403, 0x0 }, - { 0x3406, 0x0 }, - { 0x5180, 0xff }, - { 0x5181, 0x52 }, - { 0x5182, 0x11 }, - { 0x5183, 0x14 }, - { 0x5184, 0x25 }, - { 0x5185, 0x24 }, - { 0x5186, 0x6 }, - { 0x5187, 0x8 }, - { 0x5188, 0x8 }, - { 0x5189, 0x7c }, - { 0x518a, 0x60 }, - { 0x518b, 0xb2 }, - { 0x518c, 0xb2 }, - { 0x518d, 0x44 }, - { 0x518e, 0x3d }, - { 0x518f, 0x58 }, - { 0x5190, 0x46 }, - { 0x5191, 0xf8 }, - { 0x5192, 0x4 }, - { 0x5193, 0x70 }, - { 0x5194, 0xf0 }, - { 0x5195, 0xf0 }, - { 0x5196, 0x3 }, - { 0x5197, 0x1 }, - { 0x5198, 0x4 }, - { 0x5199, 0x12 }, - { 0x519a, 0x4 }, - { 0x519b, 0x0 }, - { 0x519c, 0x6 }, - { 0x519d, 0x82 }, - { 0x519e, 0x0 }, - { 0x5025, 0x80 }, - { 0x3a0f, 0x38 }, - { 0x3a10, 0x30 }, - { 0x3a1b, 0x3a }, - { 0x3a1e, 0x2e }, - { 0x3a11, 0x60 }, - { 0x3a1f, 0x10 }, - { 0x5688, 0xa6 }, - { 0x5689, 0x6a }, - { 0x568a, 0xea }, - { 0x568b, 0xae }, - { 0x568c, 0xa6 }, - { 0x568d, 0x6a }, - { 0x568e, 0x62 }, - { 0x568f, 0x26 }, - { 0x5583, 0x40 }, - { 0x5584, 0x40 }, - { 0x5580, 0x2 }, - { 0x5000, 0xcf }, - { 0x5800, 0x27 }, - { 0x5801, 0x19 }, - { 0x5802, 0x12 }, - { 0x5803, 0xf }, - { 0x5804, 0x10 }, - { 0x5805, 0x15 }, - { 0x5806, 0x1e }, - { 0x5807, 0x2f }, - { 0x5808, 0x15 }, - { 0x5809, 0xd }, - { 0x580a, 0xa }, - { 0x580b, 0x9 }, - { 0x580c, 0xa }, - { 0x580d, 0xc }, - { 0x580e, 0x12 }, - { 0x580f, 0x19 }, - { 0x5810, 0xb }, - { 0x5811, 0x7 }, - { 0x5812, 0x4 }, - { 0x5813, 0x3 }, - { 0x5814, 0x3 }, - { 0x5815, 0x6 }, - { 0x5816, 0xa }, - { 0x5817, 0xf }, - { 0x5818, 0xa }, - { 0x5819, 0x5 }, - { 0x581a, 0x1 }, - { 0x581b, 0x0 }, - { 0x581c, 0x0 }, - { 0x581d, 0x3 }, - { 0x581e, 0x8 }, - { 0x581f, 0xc }, - { 0x5820, 0xa }, - { 0x5821, 0x5 }, - { 0x5822, 0x1 }, - { 0x5823, 0x0 }, - { 0x5824, 0x0 }, - { 0x5825, 0x3 }, - { 0x5826, 0x8 }, - { 0x5827, 0xc }, - { 0x5828, 0xe }, - { 0x5829, 0x8 }, - { 0x582a, 0x6 }, - { 0x582b, 0x4 }, - { 0x582c, 0x5 }, - { 0x582d, 0x7 }, - { 0x582e, 0xb }, - { 0x582f, 0x12 }, - { 0x5830, 0x18 }, - { 0x5831, 0x10 }, - { 0x5832, 0xc }, - { 0x5833, 0xa }, - { 0x5834, 0xb }, - { 0x5835, 0xe }, - { 0x5836, 0x15 }, - { 0x5837, 0x19 }, - { 0x5838, 0x32 }, - { 0x5839, 0x1f }, - { 0x583a, 0x18 }, - { 0x583b, 0x16 }, - { 0x583c, 0x17 }, - { 0x583d, 0x1e }, - { 0x583e, 0x26 }, - { 0x583f, 0x53 }, - { 0x5840, 0x10 }, - { 0x5841, 0xf }, - { 0x5842, 0xd }, - { 0x5843, 0xc }, - { 0x5844, 0xe }, - { 0x5845, 0x9 }, - { 0x5846, 0x11 }, - { 0x5847, 0x10 }, - { 0x5848, 0x10 }, - { 0x5849, 0x10 }, - { 0x584a, 0x10 }, - { 0x584b, 0xe }, - { 0x584c, 0x10 }, - { 0x584d, 0x10 }, - { 0x584e, 0x11 }, - { 0x584f, 0x10 }, - { 0x5850, 0xf }, - { 0x5851, 0xc }, - { 0x5852, 0xf }, - { 0x5853, 0x10 }, - { 0x5854, 0x10 }, - { 0x5855, 0xf }, - { 0x5856, 0xe }, - { 0x5857, 0xb }, - { 0x5858, 0x10 }, - { 0x5859, 0xd }, - { 0x585a, 0xd }, - { 0x585b, 0xc }, - { 0x585c, 0xc }, - { 0x585d, 0xc }, - { 0x585e, 0xb }, - { 0x585f, 0xc }, - { 0x5860, 0xc }, - { 0x5861, 0xc }, - { 0x5862, 0xd }, - { 0x5863, 0x8 }, - { 0x5864, 0x11 }, - { 0x5865, 0x18 }, - { 0x5866, 0x18 }, - { 0x5867, 0x19 }, - { 0x5868, 0x17 }, - { 0x5869, 0x19 }, - { 0x586a, 0x16 }, - { 0x586b, 0x13 }, - { 0x586c, 0x13 }, - { 0x586d, 0x12 }, - { 0x586e, 0x13 }, - { 0x586f, 0x16 }, - { 0x5870, 0x14 }, - { 0x5871, 0x12 }, - { 0x5872, 0x10 }, - { 0x5873, 0x11 }, - { 0x5874, 0x11 }, - { 0x5875, 0x16 }, - { 0x5876, 0x14 }, - { 0x5877, 0x11 }, - { 0x5878, 0x10 }, - { 0x5879, 0xf }, - { 0x587a, 0x10 }, - { 0x587b, 0x14 }, - { 0x587c, 0x13 }, - { 0x587d, 0x12 }, - { 0x587e, 0x11 }, - { 0x587f, 0x11 }, - { 0x5880, 0x12 }, - { 0x5881, 0x15 }, - { 0x5882, 0x14 }, - { 0x5883, 0x15 }, - { 0x5884, 0x15 }, - { 0x5885, 0x15 }, - { 0x5886, 0x13 }, - { 0x5887, 0x17 }, - { 0x3710, 0x10 }, - { 0x3632, 0x51 }, - { 0x3702, 0x10 }, - { 0x3703, 0xb2 }, - { 0x3704, 0x18 }, - { 0x370b, 0x40 }, - { 0x370d, 0x3 }, - { 0x3631, 0x1 }, - { 0x3632, 0x52 }, - { 0x3606, 0x24 }, - { 0x3620, 0x96 }, - { 0x5785, 0x7 }, - { 0x3a13, 0x30 }, - { 0x3600, 0x52 }, - { 0x3604, 0x48 }, - { 0x3606, 0x1b }, - { 0x370d, 0xb }, - { 0x370f, 0xc0 }, - { 0x3709, 0x1 }, - { 0x3823, 0x0 }, - { 0x5007, 0x0 }, - { 0x5009, 0x0 }, - { 0x5011, 0x0 }, - { 0x5013, 0x0 }, - { 0x519e, 0x0 }, - { 0x5086, 0x0 }, - { 0x5087, 0x0 }, - { 0x5088, 0x0 }, - { 0x5089, 0x0 }, - { 0x302b, 0x0 }, - { 0x3503, 0x7 }, - { 0x3011, 0x8 }, - { 0x350c, 0x2 }, - { 0x350d, 0xe4 }, - { 0x3621, 0xc9 }, - { 0x370a, 0x81 }, - { 0xffff, 0xff }, -}; - -static struct regval_list ov5642_default_regs_finalise[] = { - { 0x3810, 0xc2 }, - { 0x3818, 0xc9 }, - { 0x381c, 0x10 }, - { 0x381d, 0xa0 }, - { 0x381e, 0x5 }, - { 0x381f, 0xb0 }, - { 0x3820, 0x0 }, - { 0x3821, 0x0 }, - { 0x3824, 0x11 }, - { 0x3a08, 0x1b }, - { 0x3a09, 0xc0 }, - { 0x3a0a, 0x17 }, - { 0x3a0b, 0x20 }, - { 0x3a0d, 0x2 }, - { 0x3a0e, 0x1 }, - { 0x401c, 0x4 }, - { 0x5682, 0x5 }, - { 0x5683, 0x0 }, - { 0x5686, 0x2 }, - { 0x5687, 0xcc }, - { 0x5001, 0x4f }, - { 0x589b, 0x6 }, - { 0x589a, 0xc5 }, - { 0x3503, 0x0 }, - { 0x460c, 0x20 }, - { 0x460b, 0x37 }, - { 0x471c, 0xd0 }, - { 0x471d, 0x5 }, - { 0x3815, 0x1 }, - { 0x3818, 0xc1 }, - { 0x501f, 0x0 }, - { 0x5002, 0xe0 }, - { 0x4300, 0x32 }, /* UYVY */ - { 0x3002, 0x1c }, - { 0x4800, 0x14 }, - { 0x4801, 0xf }, - { 0x3007, 0x3b }, - { 0x300e, 0x4 }, - { 0x4803, 0x50 }, - { 0x3815, 0x1 }, - { 0x4713, 0x2 }, - { 0x4842, 0x1 }, - { 0x300f, 0xe }, - { 0x3003, 0x3 }, - { 0x3003, 0x1 }, - { 0xffff, 0xff }, -}; - -struct ov5642_datafmt { - u32 code; - enum v4l2_colorspace colorspace; -}; - -struct ov5642 { - struct v4l2_subdev subdev; - const struct ov5642_datafmt *fmt; - struct v4l2_rect crop_rect; - struct v4l2_clk *clk; - - /* blanking information */ - int total_width; - int total_height; -}; - -static const struct ov5642_datafmt ov5642_colour_fmts[] = { - {MEDIA_BUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG}, -}; - -static struct ov5642 *to_ov5642(const struct i2c_client *client) -{ - return container_of(i2c_get_clientdata(client), struct ov5642, subdev); -} - -/* Find a data format by a pixel code in an array */ -static const struct ov5642_datafmt - *ov5642_find_datafmt(u32 code) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(ov5642_colour_fmts); i++) - if (ov5642_colour_fmts[i].code == code) - return ov5642_colour_fmts + i; - - return NULL; -} - -static int reg_read(struct i2c_client *client, u16 reg, u8 *val) -{ - int ret; - /* We have 16-bit i2c addresses - care for endianness */ - unsigned char data[2] = { reg >> 8, reg & 0xff }; - - ret = i2c_master_send(client, data, 2); - if (ret < 2) { - dev_err(&client->dev, "%s: i2c read error, reg: %x\n", - __func__, reg); - return ret < 0 ? ret : -EIO; - } - - ret = i2c_master_recv(client, val, 1); - if (ret < 1) { - dev_err(&client->dev, "%s: i2c read error, reg: %x\n", - __func__, reg); - return ret < 0 ? ret : -EIO; - } - return 0; -} - -static int reg_write(struct i2c_client *client, u16 reg, u8 val) -{ - int ret; - unsigned char data[3] = { reg >> 8, reg & 0xff, val }; - - ret = i2c_master_send(client, data, 3); - if (ret < 3) { - dev_err(&client->dev, "%s: i2c write error, reg: %x\n", - __func__, reg); - return ret < 0 ? ret : -EIO; - } - - return 0; -} - -/* - * convenience function to write 16 bit register values that are split up - * into two consecutive high and low parts - */ -static int reg_write16(struct i2c_client *client, u16 reg, u16 val16) -{ - int ret; - - ret = reg_write(client, reg, val16 >> 8); - if (ret) - return ret; - return reg_write(client, reg + 1, val16 & 0x00ff); -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int ov5642_get_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - u8 val; - - if (reg->reg & ~0xffff) - return -EINVAL; - - reg->size = 1; - - ret = reg_read(client, reg->reg, &val); - if (!ret) - reg->val = (__u64)val; - - return ret; -} - -static int ov5642_set_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->reg & ~0xffff || reg->val & ~0xff) - return -EINVAL; - - return reg_write(client, reg->reg, reg->val); -} -#endif - -static int ov5642_write_array(struct i2c_client *client, - struct regval_list *vals) -{ - while (vals->reg_num != 0xffff || vals->value != 0xff) { - int ret = reg_write(client, vals->reg_num, vals->value); - if (ret < 0) - return ret; - vals++; - } - dev_dbg(&client->dev, "Register list loaded\n"); - return 0; -} - -static int ov5642_set_resolution(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov5642 *priv = to_ov5642(client); - int width = priv->crop_rect.width; - int height = priv->crop_rect.height; - int total_width = priv->total_width; - int total_height = priv->total_height; - int start_x = (OV5642_SENSOR_SIZE_X - width) / 2; - int start_y = (OV5642_SENSOR_SIZE_Y - height) / 2; - int ret; - - /* - * This should set the starting point for cropping. - * Doesn't work so far. - */ - ret = reg_write16(client, REG_WINDOW_START_X_HIGH, start_x); - if (!ret) - ret = reg_write16(client, REG_WINDOW_START_Y_HIGH, start_y); - if (!ret) { - priv->crop_rect.left = start_x; - priv->crop_rect.top = start_y; - } - - if (!ret) - ret = reg_write16(client, REG_WINDOW_WIDTH_HIGH, width); - if (!ret) - ret = reg_write16(client, REG_WINDOW_HEIGHT_HIGH, height); - if (ret) - return ret; - priv->crop_rect.width = width; - priv->crop_rect.height = height; - - /* Set the output window size. Only 1:1 scale is supported so far. */ - ret = reg_write16(client, REG_OUT_WIDTH_HIGH, width); - if (!ret) - ret = reg_write16(client, REG_OUT_HEIGHT_HIGH, height); - - /* Total width = output size + blanking */ - if (!ret) - ret = reg_write16(client, REG_OUT_TOTAL_WIDTH_HIGH, total_width); - if (!ret) - ret = reg_write16(client, REG_OUT_TOTAL_HEIGHT_HIGH, total_height); - - /* Sets the window for AWB calculations */ - if (!ret) - ret = reg_write16(client, REG_AVG_WINDOW_END_X_HIGH, width); - if (!ret) - ret = reg_write16(client, REG_AVG_WINDOW_END_Y_HIGH, height); - - return ret; -} - -static int ov5642_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *mf = &format->format; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov5642 *priv = to_ov5642(client); - const struct ov5642_datafmt *fmt = ov5642_find_datafmt(mf->code); - - if (format->pad) - return -EINVAL; - - mf->width = priv->crop_rect.width; - mf->height = priv->crop_rect.height; - - if (!fmt) { - if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - mf->code = ov5642_colour_fmts[0].code; - mf->colorspace = ov5642_colour_fmts[0].colorspace; - } - - mf->field = V4L2_FIELD_NONE; - - if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) - priv->fmt = fmt; - else - cfg->try_fmt = *mf; - return 0; -} - -static int ov5642_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *mf = &format->format; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov5642 *priv = to_ov5642(client); - - const struct ov5642_datafmt *fmt = priv->fmt; - - if (format->pad) - return -EINVAL; - - mf->code = fmt->code; - mf->colorspace = fmt->colorspace; - mf->width = priv->crop_rect.width; - mf->height = priv->crop_rect.height; - mf->field = V4L2_FIELD_NONE; - - return 0; -} - -static int ov5642_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (code->pad || code->index >= ARRAY_SIZE(ov5642_colour_fmts)) - return -EINVAL; - - code->code = ov5642_colour_fmts[code->index].code; - return 0; -} - -static int ov5642_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov5642 *priv = to_ov5642(client); - struct v4l2_rect rect = sel->r; - int ret; - - if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || - sel->target != V4L2_SEL_TGT_CROP) - return -EINVAL; - - v4l_bound_align_image(&rect.width, 48, OV5642_MAX_WIDTH, 1, - &rect.height, 32, OV5642_MAX_HEIGHT, 1, 0); - - priv->crop_rect.width = rect.width; - priv->crop_rect.height = rect.height; - priv->total_width = rect.width + BLANKING_EXTRA_WIDTH; - priv->total_height = max_t(int, rect.height + - BLANKING_EXTRA_HEIGHT, - BLANKING_MIN_HEIGHT); - priv->crop_rect.width = rect.width; - priv->crop_rect.height = rect.height; - - ret = ov5642_write_array(client, ov5642_default_regs_init); - if (!ret) - ret = ov5642_set_resolution(sd); - if (!ret) - ret = ov5642_write_array(client, ov5642_default_regs_finalise); - - return ret; -} - -static int ov5642_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov5642 *priv = to_ov5642(client); - - if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - switch (sel->target) { - case V4L2_SEL_TGT_CROP_BOUNDS: - sel->r.left = 0; - sel->r.top = 0; - sel->r.width = OV5642_MAX_WIDTH; - sel->r.height = OV5642_MAX_HEIGHT; - return 0; - case V4L2_SEL_TGT_CROP: - sel->r = priv->crop_rect; - return 0; - default: - return -EINVAL; - } -} - -static int ov5642_g_mbus_config(struct v4l2_subdev *sd, - struct v4l2_mbus_config *cfg) -{ - cfg->type = V4L2_MBUS_CSI2_DPHY; - cfg->flags = V4L2_MBUS_CSI2_2_LANE | V4L2_MBUS_CSI2_CHANNEL_0 | - V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; - - return 0; -} - -static int ov5642_s_power(struct v4l2_subdev *sd, int on) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - struct ov5642 *priv = to_ov5642(client); - int ret; - - if (!on) - return soc_camera_power_off(&client->dev, ssdd, priv->clk); - - ret = soc_camera_power_on(&client->dev, ssdd, priv->clk); - if (ret < 0) - return ret; - - ret = ov5642_write_array(client, ov5642_default_regs_init); - if (!ret) - ret = ov5642_set_resolution(sd); - if (!ret) - ret = ov5642_write_array(client, ov5642_default_regs_finalise); - - return ret; -} - -static const struct v4l2_subdev_video_ops ov5642_subdev_video_ops = { - .g_mbus_config = ov5642_g_mbus_config, -}; - -static const struct v4l2_subdev_pad_ops ov5642_subdev_pad_ops = { - .enum_mbus_code = ov5642_enum_mbus_code, - .get_selection = ov5642_get_selection, - .set_selection = ov5642_set_selection, - .get_fmt = ov5642_get_fmt, - .set_fmt = ov5642_set_fmt, -}; - -static const struct v4l2_subdev_core_ops ov5642_subdev_core_ops = { - .s_power = ov5642_s_power, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = ov5642_get_register, - .s_register = ov5642_set_register, -#endif -}; - -static const struct v4l2_subdev_ops ov5642_subdev_ops = { - .core = &ov5642_subdev_core_ops, - .video = &ov5642_subdev_video_ops, - .pad = &ov5642_subdev_pad_ops, -}; - -static int ov5642_video_probe(struct i2c_client *client) -{ - struct v4l2_subdev *subdev = i2c_get_clientdata(client); - int ret; - u8 id_high, id_low; - u16 id; - - ret = ov5642_s_power(subdev, 1); - if (ret < 0) - return ret; - - /* Read sensor Model ID */ - ret = reg_read(client, REG_CHIP_ID_HIGH, &id_high); - if (ret < 0) - goto done; - - id = id_high << 8; - - ret = reg_read(client, REG_CHIP_ID_LOW, &id_low); - if (ret < 0) - goto done; - - id |= id_low; - - dev_info(&client->dev, "Chip ID 0x%04x detected\n", id); - - if (id != 0x5642) { - ret = -ENODEV; - goto done; - } - - ret = 0; - -done: - ov5642_s_power(subdev, 0); - return ret; -} - -static int ov5642_probe(struct i2c_client *client, - const struct i2c_device_id *did) -{ - struct ov5642 *priv; - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - int ret; - - if (!ssdd) { - dev_err(&client->dev, "OV5642: missing platform data!\n"); - return -EINVAL; - } - - priv = devm_kzalloc(&client->dev, sizeof(struct ov5642), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - v4l2_i2c_subdev_init(&priv->subdev, client, &ov5642_subdev_ops); - - priv->fmt = &ov5642_colour_fmts[0]; - - priv->crop_rect.width = OV5642_DEFAULT_WIDTH; - priv->crop_rect.height = OV5642_DEFAULT_HEIGHT; - priv->crop_rect.left = (OV5642_MAX_WIDTH - OV5642_DEFAULT_WIDTH) / 2; - priv->crop_rect.top = (OV5642_MAX_HEIGHT - OV5642_DEFAULT_HEIGHT) / 2; - priv->total_width = OV5642_DEFAULT_WIDTH + BLANKING_EXTRA_WIDTH; - priv->total_height = BLANKING_MIN_HEIGHT; - - priv->clk = v4l2_clk_get(&client->dev, "mclk"); - if (IS_ERR(priv->clk)) - return PTR_ERR(priv->clk); - - ret = ov5642_video_probe(client); - if (ret < 0) - v4l2_clk_put(priv->clk); - - return ret; -} - -static int ov5642_remove(struct i2c_client *client) -{ - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - struct ov5642 *priv = to_ov5642(client); - - v4l2_clk_put(priv->clk); - if (ssdd->free_bus) - ssdd->free_bus(ssdd); - - return 0; -} - -static const struct i2c_device_id ov5642_id[] = { - { "ov5642", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, ov5642_id); - -#if IS_ENABLED(CONFIG_OF) -static const struct of_device_id ov5642_of_match[] = { - { .compatible = "ovti,ov5642" }, - { }, -}; -MODULE_DEVICE_TABLE(of, ov5642_of_match); -#endif - -static struct i2c_driver ov5642_i2c_driver = { - .driver = { - .name = "ov5642", - .of_match_table = of_match_ptr(ov5642_of_match), - }, - .probe = ov5642_probe, - .remove = ov5642_remove, - .id_table = ov5642_id, -}; - -module_i2c_driver(ov5642_i2c_driver); - -MODULE_DESCRIPTION("Omnivision OV5642 Camera driver"); -MODULE_AUTHOR("Bastian Hecht <hechtb@gmail.com>"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/soc_camera/soc_ov772x.c b/drivers/media/i2c/soc_camera/soc_ov772x.c deleted file mode 100644 index fafd372527b2..000000000000 --- a/drivers/media/i2c/soc_camera/soc_ov772x.c +++ /dev/null @@ -1,1123 +0,0 @@ -/* - * ov772x Camera Driver - * - * Copyright (C) 2008 Renesas Solutions Corp. - * Kuninori Morimoto <morimoto.kuninori@renesas.com> - * - * Based on ov7670 and soc_camera_platform driver, - * - * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net> - * Copyright (C) 2008 Magnus Damm - * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/i2c.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/v4l2-mediabus.h> -#include <linux/videodev2.h> - -#include <media/i2c/ov772x.h> -#include <media/soc_camera.h> -#include <media/v4l2-clk.h> -#include <media/v4l2-ctrls.h> -#include <media/v4l2-subdev.h> -#include <media/v4l2-image-sizes.h> - -/* - * register offset - */ -#define GAIN 0x00 /* AGC - Gain control gain setting */ -#define BLUE 0x01 /* AWB - Blue channel gain setting */ -#define RED 0x02 /* AWB - Red channel gain setting */ -#define GREEN 0x03 /* AWB - Green channel gain setting */ -#define COM1 0x04 /* Common control 1 */ -#define BAVG 0x05 /* U/B Average Level */ -#define GAVG 0x06 /* Y/Gb Average Level */ -#define RAVG 0x07 /* V/R Average Level */ -#define AECH 0x08 /* Exposure Value - AEC MSBs */ -#define COM2 0x09 /* Common control 2 */ -#define PID 0x0A /* Product ID Number MSB */ -#define VER 0x0B /* Product ID Number LSB */ -#define COM3 0x0C /* Common control 3 */ -#define COM4 0x0D /* Common control 4 */ -#define COM5 0x0E /* Common control 5 */ -#define COM6 0x0F /* Common control 6 */ -#define AEC 0x10 /* Exposure Value */ -#define CLKRC 0x11 /* Internal clock */ -#define COM7 0x12 /* Common control 7 */ -#define COM8 0x13 /* Common control 8 */ -#define COM9 0x14 /* Common control 9 */ -#define COM10 0x15 /* Common control 10 */ -#define REG16 0x16 /* Register 16 */ -#define HSTART 0x17 /* Horizontal sensor size */ -#define HSIZE 0x18 /* Horizontal frame (HREF column) end high 8-bit */ -#define VSTART 0x19 /* Vertical frame (row) start high 8-bit */ -#define VSIZE 0x1A /* Vertical sensor size */ -#define PSHFT 0x1B /* Data format - pixel delay select */ -#define MIDH 0x1C /* Manufacturer ID byte - high */ -#define MIDL 0x1D /* Manufacturer ID byte - low */ -#define LAEC 0x1F /* Fine AEC value */ -#define COM11 0x20 /* Common control 11 */ -#define BDBASE 0x22 /* Banding filter Minimum AEC value */ -#define DBSTEP 0x23 /* Banding filter Maximum Setp */ -#define AEW 0x24 /* AGC/AEC - Stable operating region (upper limit) */ -#define AEB 0x25 /* AGC/AEC - Stable operating region (lower limit) */ -#define VPT 0x26 /* AGC/AEC Fast mode operating region */ -#define REG28 0x28 /* Register 28 */ -#define HOUTSIZE 0x29 /* Horizontal data output size MSBs */ -#define EXHCH 0x2A /* Dummy pixel insert MSB */ -#define EXHCL 0x2B /* Dummy pixel insert LSB */ -#define VOUTSIZE 0x2C /* Vertical data output size MSBs */ -#define ADVFL 0x2D /* LSB of insert dummy lines in Vertical direction */ -#define ADVFH 0x2E /* MSG of insert dummy lines in Vertical direction */ -#define YAVE 0x2F /* Y/G Channel Average value */ -#define LUMHTH 0x30 /* Histogram AEC/AGC Luminance high level threshold */ -#define LUMLTH 0x31 /* Histogram AEC/AGC Luminance low level threshold */ -#define HREF 0x32 /* Image start and size control */ -#define DM_LNL 0x33 /* Dummy line low 8 bits */ -#define DM_LNH 0x34 /* Dummy line high 8 bits */ -#define ADOFF_B 0x35 /* AD offset compensation value for B channel */ -#define ADOFF_R 0x36 /* AD offset compensation value for R channel */ -#define ADOFF_GB 0x37 /* AD offset compensation value for Gb channel */ -#define ADOFF_GR 0x38 /* AD offset compensation value for Gr channel */ -#define OFF_B 0x39 /* Analog process B channel offset value */ -#define OFF_R 0x3A /* Analog process R channel offset value */ -#define OFF_GB 0x3B /* Analog process Gb channel offset value */ -#define OFF_GR 0x3C /* Analog process Gr channel offset value */ -#define COM12 0x3D /* Common control 12 */ -#define COM13 0x3E /* Common control 13 */ -#define COM14 0x3F /* Common control 14 */ -#define COM15 0x40 /* Common control 15*/ -#define COM16 0x41 /* Common control 16 */ -#define TGT_B 0x42 /* BLC blue channel target value */ -#define TGT_R 0x43 /* BLC red channel target value */ -#define TGT_GB 0x44 /* BLC Gb channel target value */ -#define TGT_GR 0x45 /* BLC Gr channel target value */ -/* for ov7720 */ -#define LCC0 0x46 /* Lens correction control 0 */ -#define LCC1 0x47 /* Lens correction option 1 - X coordinate */ -#define LCC2 0x48 /* Lens correction option 2 - Y coordinate */ -#define LCC3 0x49 /* Lens correction option 3 */ -#define LCC4 0x4A /* Lens correction option 4 - radius of the circular */ -#define LCC5 0x4B /* Lens correction option 5 */ -#define LCC6 0x4C /* Lens correction option 6 */ -/* for ov7725 */ -#define LC_CTR 0x46 /* Lens correction control */ -#define LC_XC 0x47 /* X coordinate of lens correction center relative */ -#define LC_YC 0x48 /* Y coordinate of lens correction center relative */ -#define LC_COEF 0x49 /* Lens correction coefficient */ -#define LC_RADI 0x4A /* Lens correction radius */ -#define LC_COEFB 0x4B /* Lens B channel compensation coefficient */ -#define LC_COEFR 0x4C /* Lens R channel compensation coefficient */ - -#define FIXGAIN 0x4D /* Analog fix gain amplifer */ -#define AREF0 0x4E /* Sensor reference control */ -#define AREF1 0x4F /* Sensor reference current control */ -#define AREF2 0x50 /* Analog reference control */ -#define AREF3 0x51 /* ADC reference control */ -#define AREF4 0x52 /* ADC reference control */ -#define AREF5 0x53 /* ADC reference control */ -#define AREF6 0x54 /* Analog reference control */ -#define AREF7 0x55 /* Analog reference control */ -#define UFIX 0x60 /* U channel fixed value output */ -#define VFIX 0x61 /* V channel fixed value output */ -#define AWBB_BLK 0x62 /* AWB option for advanced AWB */ -#define AWB_CTRL0 0x63 /* AWB control byte 0 */ -#define DSP_CTRL1 0x64 /* DSP control byte 1 */ -#define DSP_CTRL2 0x65 /* DSP control byte 2 */ -#define DSP_CTRL3 0x66 /* DSP control byte 3 */ -#define DSP_CTRL4 0x67 /* DSP control byte 4 */ -#define AWB_BIAS 0x68 /* AWB BLC level clip */ -#define AWB_CTRL1 0x69 /* AWB control 1 */ -#define AWB_CTRL2 0x6A /* AWB control 2 */ -#define AWB_CTRL3 0x6B /* AWB control 3 */ -#define AWB_CTRL4 0x6C /* AWB control 4 */ -#define AWB_CTRL5 0x6D /* AWB control 5 */ -#define AWB_CTRL6 0x6E /* AWB control 6 */ -#define AWB_CTRL7 0x6F /* AWB control 7 */ -#define AWB_CTRL8 0x70 /* AWB control 8 */ -#define AWB_CTRL9 0x71 /* AWB control 9 */ -#define AWB_CTRL10 0x72 /* AWB control 10 */ -#define AWB_CTRL11 0x73 /* AWB control 11 */ -#define AWB_CTRL12 0x74 /* AWB control 12 */ -#define AWB_CTRL13 0x75 /* AWB control 13 */ -#define AWB_CTRL14 0x76 /* AWB control 14 */ -#define AWB_CTRL15 0x77 /* AWB control 15 */ -#define AWB_CTRL16 0x78 /* AWB control 16 */ -#define AWB_CTRL17 0x79 /* AWB control 17 */ -#define AWB_CTRL18 0x7A /* AWB control 18 */ -#define AWB_CTRL19 0x7B /* AWB control 19 */ -#define AWB_CTRL20 0x7C /* AWB control 20 */ -#define AWB_CTRL21 0x7D /* AWB control 21 */ -#define GAM1 0x7E /* Gamma Curve 1st segment input end point */ -#define GAM2 0x7F /* Gamma Curve 2nd segment input end point */ -#define GAM3 0x80 /* Gamma Curve 3rd segment input end point */ -#define GAM4 0x81 /* Gamma Curve 4th segment input end point */ -#define GAM5 0x82 /* Gamma Curve 5th segment input end point */ -#define GAM6 0x83 /* Gamma Curve 6th segment input end point */ -#define GAM7 0x84 /* Gamma Curve 7th segment input end point */ -#define GAM8 0x85 /* Gamma Curve 8th segment input end point */ -#define GAM9 0x86 /* Gamma Curve 9th segment input end point */ -#define GAM10 0x87 /* Gamma Curve 10th segment input end point */ -#define GAM11 0x88 /* Gamma Curve 11th segment input end point */ -#define GAM12 0x89 /* Gamma Curve 12th segment input end point */ -#define GAM13 0x8A /* Gamma Curve 13th segment input end point */ -#define GAM14 0x8B /* Gamma Curve 14th segment input end point */ -#define GAM15 0x8C /* Gamma Curve 15th segment input end point */ -#define SLOP 0x8D /* Gamma curve highest segment slope */ -#define DNSTH 0x8E /* De-noise threshold */ -#define EDGE_STRNGT 0x8F /* Edge strength control when manual mode */ -#define EDGE_TRSHLD 0x90 /* Edge threshold control when manual mode */ -#define DNSOFF 0x91 /* Auto De-noise threshold control */ -#define EDGE_UPPER 0x92 /* Edge strength upper limit when Auto mode */ -#define EDGE_LOWER 0x93 /* Edge strength lower limit when Auto mode */ -#define MTX1 0x94 /* Matrix coefficient 1 */ -#define MTX2 0x95 /* Matrix coefficient 2 */ -#define MTX3 0x96 /* Matrix coefficient 3 */ -#define MTX4 0x97 /* Matrix coefficient 4 */ -#define MTX5 0x98 /* Matrix coefficient 5 */ -#define MTX6 0x99 /* Matrix coefficient 6 */ -#define MTX_CTRL 0x9A /* Matrix control */ -#define BRIGHT 0x9B /* Brightness control */ -#define CNTRST 0x9C /* Contrast contrast */ -#define CNTRST_CTRL 0x9D /* Contrast contrast center */ -#define UVAD_J0 0x9E /* Auto UV adjust contrast 0 */ -#define UVAD_J1 0x9F /* Auto UV adjust contrast 1 */ -#define SCAL0 0xA0 /* Scaling control 0 */ -#define SCAL1 0xA1 /* Scaling control 1 */ -#define SCAL2 0xA2 /* Scaling control 2 */ -#define FIFODLYM 0xA3 /* FIFO manual mode delay control */ -#define FIFODLYA 0xA4 /* FIFO auto mode delay control */ -#define SDE 0xA6 /* Special digital effect control */ -#define USAT 0xA7 /* U component saturation control */ -#define VSAT 0xA8 /* V component saturation control */ -/* for ov7720 */ -#define HUE0 0xA9 /* Hue control 0 */ -#define HUE1 0xAA /* Hue control 1 */ -/* for ov7725 */ -#define HUECOS 0xA9 /* Cosine value */ -#define HUESIN 0xAA /* Sine value */ - -#define SIGN 0xAB /* Sign bit for Hue and contrast */ -#define DSPAUTO 0xAC /* DSP auto function ON/OFF control */ - -/* - * register detail - */ - -/* COM2 */ -#define SOFT_SLEEP_MODE 0x10 /* Soft sleep mode */ - /* Output drive capability */ -#define OCAP_1x 0x00 /* 1x */ -#define OCAP_2x 0x01 /* 2x */ -#define OCAP_3x 0x02 /* 3x */ -#define OCAP_4x 0x03 /* 4x */ - -/* COM3 */ -#define SWAP_MASK (SWAP_RGB | SWAP_YUV | SWAP_ML) -#define IMG_MASK (VFLIP_IMG | HFLIP_IMG) - -#define VFLIP_IMG 0x80 /* Vertical flip image ON/OFF selection */ -#define HFLIP_IMG 0x40 /* Horizontal mirror image ON/OFF selection */ -#define SWAP_RGB 0x20 /* Swap B/R output sequence in RGB mode */ -#define SWAP_YUV 0x10 /* Swap Y/UV output sequence in YUV mode */ -#define SWAP_ML 0x08 /* Swap output MSB/LSB */ - /* Tri-state option for output clock */ -#define NOTRI_CLOCK 0x04 /* 0: Tri-state at this period */ - /* 1: No tri-state at this period */ - /* Tri-state option for output data */ -#define NOTRI_DATA 0x02 /* 0: Tri-state at this period */ - /* 1: No tri-state at this period */ -#define SCOLOR_TEST 0x01 /* Sensor color bar test pattern */ - -/* COM4 */ - /* PLL frequency control */ -#define PLL_BYPASS 0x00 /* 00: Bypass PLL */ -#define PLL_4x 0x40 /* 01: PLL 4x */ -#define PLL_6x 0x80 /* 10: PLL 6x */ -#define PLL_8x 0xc0 /* 11: PLL 8x */ - /* AEC evaluate window */ -#define AEC_FULL 0x00 /* 00: Full window */ -#define AEC_1p2 0x10 /* 01: 1/2 window */ -#define AEC_1p4 0x20 /* 10: 1/4 window */ -#define AEC_2p3 0x30 /* 11: Low 2/3 window */ - -/* COM5 */ -#define AFR_ON_OFF 0x80 /* Auto frame rate control ON/OFF selection */ -#define AFR_SPPED 0x40 /* Auto frame rate control speed selection */ - /* Auto frame rate max rate control */ -#define AFR_NO_RATE 0x00 /* No reduction of frame rate */ -#define AFR_1p2 0x10 /* Max reduction to 1/2 frame rate */ -#define AFR_1p4 0x20 /* Max reduction to 1/4 frame rate */ -#define AFR_1p8 0x30 /* Max reduction to 1/8 frame rate */ - /* Auto frame rate active point control */ -#define AF_2x 0x00 /* Add frame when AGC reaches 2x gain */ -#define AF_4x 0x04 /* Add frame when AGC reaches 4x gain */ -#define AF_8x 0x08 /* Add frame when AGC reaches 8x gain */ -#define AF_16x 0x0c /* Add frame when AGC reaches 16x gain */ - /* AEC max step control */ -#define AEC_NO_LIMIT 0x01 /* 0 : AEC incease step has limit */ - /* 1 : No limit to AEC increase step */ - -/* COM7 */ - /* SCCB Register Reset */ -#define SCCB_RESET 0x80 /* 0 : No change */ - /* 1 : Resets all registers to default */ - /* Resolution selection */ -#define SLCT_MASK 0x40 /* Mask of VGA or QVGA */ -#define SLCT_VGA 0x00 /* 0 : VGA */ -#define SLCT_QVGA 0x40 /* 1 : QVGA */ -#define ITU656_ON_OFF 0x20 /* ITU656 protocol ON/OFF selection */ -#define SENSOR_RAW 0x10 /* Sensor RAW */ - /* RGB output format control */ -#define FMT_MASK 0x0c /* Mask of color format */ -#define FMT_GBR422 0x00 /* 00 : GBR 4:2:2 */ -#define FMT_RGB565 0x04 /* 01 : RGB 565 */ -#define FMT_RGB555 0x08 /* 10 : RGB 555 */ -#define FMT_RGB444 0x0c /* 11 : RGB 444 */ - /* Output format control */ -#define OFMT_MASK 0x03 /* Mask of output format */ -#define OFMT_YUV 0x00 /* 00 : YUV */ -#define OFMT_P_BRAW 0x01 /* 01 : Processed Bayer RAW */ -#define OFMT_RGB 0x02 /* 10 : RGB */ -#define OFMT_BRAW 0x03 /* 11 : Bayer RAW */ - -/* COM8 */ -#define FAST_ALGO 0x80 /* Enable fast AGC/AEC algorithm */ - /* AEC Setp size limit */ -#define UNLMT_STEP 0x40 /* 0 : Step size is limited */ - /* 1 : Unlimited step size */ -#define BNDF_ON_OFF 0x20 /* Banding filter ON/OFF */ -#define AEC_BND 0x10 /* Enable AEC below banding value */ -#define AEC_ON_OFF 0x08 /* Fine AEC ON/OFF control */ -#define AGC_ON 0x04 /* AGC Enable */ -#define AWB_ON 0x02 /* AWB Enable */ -#define AEC_ON 0x01 /* AEC Enable */ - -/* COM9 */ -#define BASE_AECAGC 0x80 /* Histogram or average based AEC/AGC */ - /* Automatic gain ceiling - maximum AGC value */ -#define GAIN_2x 0x00 /* 000 : 2x */ -#define GAIN_4x 0x10 /* 001 : 4x */ -#define GAIN_8x 0x20 /* 010 : 8x */ -#define GAIN_16x 0x30 /* 011 : 16x */ -#define GAIN_32x 0x40 /* 100 : 32x */ -#define GAIN_64x 0x50 /* 101 : 64x */ -#define GAIN_128x 0x60 /* 110 : 128x */ -#define DROP_VSYNC 0x04 /* Drop VSYNC output of corrupt frame */ -#define DROP_HREF 0x02 /* Drop HREF output of corrupt frame */ - -/* COM11 */ -#define SGLF_ON_OFF 0x02 /* Single frame ON/OFF selection */ -#define SGLF_TRIG 0x01 /* Single frame transfer trigger */ - -/* HREF */ -#define HREF_VSTART_SHIFT 6 /* VSTART LSB */ -#define HREF_HSTART_SHIFT 4 /* HSTART 2 LSBs */ -#define HREF_VSIZE_SHIFT 2 /* VSIZE LSB */ -#define HREF_HSIZE_SHIFT 0 /* HSIZE 2 LSBs */ - -/* EXHCH */ -#define EXHCH_VSIZE_SHIFT 2 /* VOUTSIZE LSB */ -#define EXHCH_HSIZE_SHIFT 0 /* HOUTSIZE 2 LSBs */ - -/* DSP_CTRL1 */ -#define FIFO_ON 0x80 /* FIFO enable/disable selection */ -#define UV_ON_OFF 0x40 /* UV adjust function ON/OFF selection */ -#define YUV444_2_422 0x20 /* YUV444 to 422 UV channel option selection */ -#define CLR_MTRX_ON_OFF 0x10 /* Color matrix ON/OFF selection */ -#define INTPLT_ON_OFF 0x08 /* Interpolation ON/OFF selection */ -#define GMM_ON_OFF 0x04 /* Gamma function ON/OFF selection */ -#define AUTO_BLK_ON_OFF 0x02 /* Black defect auto correction ON/OFF */ -#define AUTO_WHT_ON_OFF 0x01 /* White define auto correction ON/OFF */ - -/* DSP_CTRL3 */ -#define UV_MASK 0x80 /* UV output sequence option */ -#define UV_ON 0x80 /* ON */ -#define UV_OFF 0x00 /* OFF */ -#define CBAR_MASK 0x20 /* DSP Color bar mask */ -#define CBAR_ON 0x20 /* ON */ -#define CBAR_OFF 0x00 /* OFF */ - -/* DSP_CTRL4 */ -#define DSP_OFMT_YUV 0x00 -#define DSP_OFMT_RGB 0x00 -#define DSP_OFMT_RAW8 0x02 -#define DSP_OFMT_RAW10 0x03 - -/* DSPAUTO (DSP Auto Function ON/OFF Control) */ -#define AWB_ACTRL 0x80 /* AWB auto threshold control */ -#define DENOISE_ACTRL 0x40 /* De-noise auto threshold control */ -#define EDGE_ACTRL 0x20 /* Edge enhancement auto strength control */ -#define UV_ACTRL 0x10 /* UV adjust auto slope control */ -#define SCAL0_ACTRL 0x08 /* Auto scaling factor control */ -#define SCAL1_2_ACTRL 0x04 /* Auto scaling factor control */ - -#define OV772X_MAX_WIDTH VGA_WIDTH -#define OV772X_MAX_HEIGHT VGA_HEIGHT - -/* - * ID - */ -#define OV7720 0x7720 -#define OV7725 0x7721 -#define VERSION(pid, ver) ((pid<<8)|(ver&0xFF)) - -/* - * struct - */ - -struct ov772x_color_format { - u32 code; - enum v4l2_colorspace colorspace; - u8 dsp3; - u8 dsp4; - u8 com3; - u8 com7; -}; - -struct ov772x_win_size { - char *name; - unsigned char com7_bit; - struct v4l2_rect rect; -}; - -struct ov772x_priv { - struct v4l2_subdev subdev; - struct v4l2_ctrl_handler hdl; - struct v4l2_clk *clk; - struct ov772x_camera_info *info; - const struct ov772x_color_format *cfmt; - const struct ov772x_win_size *win; - unsigned short flag_vflip:1; - unsigned short flag_hflip:1; - /* band_filter = COM8[5] ? 256 - BDBASE : 0 */ - unsigned short band_filter; -}; - -/* - * supported color format list - */ -static const struct ov772x_color_format ov772x_cfmts[] = { - { - .code = MEDIA_BUS_FMT_YUYV8_2X8, - .colorspace = V4L2_COLORSPACE_JPEG, - .dsp3 = 0x0, - .dsp4 = DSP_OFMT_YUV, - .com3 = SWAP_YUV, - .com7 = OFMT_YUV, - }, - { - .code = MEDIA_BUS_FMT_YVYU8_2X8, - .colorspace = V4L2_COLORSPACE_JPEG, - .dsp3 = UV_ON, - .dsp4 = DSP_OFMT_YUV, - .com3 = SWAP_YUV, - .com7 = OFMT_YUV, - }, - { - .code = MEDIA_BUS_FMT_UYVY8_2X8, - .colorspace = V4L2_COLORSPACE_JPEG, - .dsp3 = 0x0, - .dsp4 = DSP_OFMT_YUV, - .com3 = 0x0, - .com7 = OFMT_YUV, - }, - { - .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, - .colorspace = V4L2_COLORSPACE_SRGB, - .dsp3 = 0x0, - .dsp4 = DSP_OFMT_YUV, - .com3 = SWAP_RGB, - .com7 = FMT_RGB555 | OFMT_RGB, - }, - { - .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, - .colorspace = V4L2_COLORSPACE_SRGB, - .dsp3 = 0x0, - .dsp4 = DSP_OFMT_YUV, - .com3 = 0x0, - .com7 = FMT_RGB555 | OFMT_RGB, - }, - { - .code = MEDIA_BUS_FMT_RGB565_2X8_LE, - .colorspace = V4L2_COLORSPACE_SRGB, - .dsp3 = 0x0, - .dsp4 = DSP_OFMT_YUV, - .com3 = SWAP_RGB, - .com7 = FMT_RGB565 | OFMT_RGB, - }, - { - .code = MEDIA_BUS_FMT_RGB565_2X8_BE, - .colorspace = V4L2_COLORSPACE_SRGB, - .dsp3 = 0x0, - .dsp4 = DSP_OFMT_YUV, - .com3 = 0x0, - .com7 = FMT_RGB565 | OFMT_RGB, - }, - { - /* Setting DSP4 to DSP_OFMT_RAW8 still gives 10-bit output, - * regardless of the COM7 value. We can thus only support 10-bit - * Bayer until someone figures it out. - */ - .code = MEDIA_BUS_FMT_SBGGR10_1X10, - .colorspace = V4L2_COLORSPACE_SRGB, - .dsp3 = 0x0, - .dsp4 = DSP_OFMT_RAW10, - .com3 = 0x0, - .com7 = SENSOR_RAW | OFMT_BRAW, - }, -}; - - -/* - * window size list - */ - -static const struct ov772x_win_size ov772x_win_sizes[] = { - { - .name = "VGA", - .com7_bit = SLCT_VGA, - .rect = { - .left = 140, - .top = 14, - .width = VGA_WIDTH, - .height = VGA_HEIGHT, - }, - }, { - .name = "QVGA", - .com7_bit = SLCT_QVGA, - .rect = { - .left = 252, - .top = 6, - .width = QVGA_WIDTH, - .height = QVGA_HEIGHT, - }, - }, -}; - -/* - * general function - */ - -static struct ov772x_priv *to_ov772x(struct v4l2_subdev *sd) -{ - return container_of(sd, struct ov772x_priv, subdev); -} - -static inline int ov772x_read(struct i2c_client *client, u8 addr) -{ - return i2c_smbus_read_byte_data(client, addr); -} - -static inline int ov772x_write(struct i2c_client *client, u8 addr, u8 value) -{ - return i2c_smbus_write_byte_data(client, addr, value); -} - -static int ov772x_mask_set(struct i2c_client *client, u8 command, u8 mask, - u8 set) -{ - s32 val = ov772x_read(client, command); - if (val < 0) - return val; - - val &= ~mask; - val |= set & mask; - - return ov772x_write(client, command, val); -} - -static int ov772x_reset(struct i2c_client *client) -{ - int ret; - - ret = ov772x_write(client, COM7, SCCB_RESET); - if (ret < 0) - return ret; - - msleep(1); - - return ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE); -} - -/* - * soc_camera_ops function - */ - -static int ov772x_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov772x_priv *priv = to_ov772x(sd); - - if (!enable) { - ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE); - return 0; - } - - ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, 0); - - dev_dbg(&client->dev, "format %d, win %s\n", - priv->cfmt->code, priv->win->name); - - return 0; -} - -static int ov772x_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct ov772x_priv *priv = container_of(ctrl->handler, - struct ov772x_priv, hdl); - struct v4l2_subdev *sd = &priv->subdev; - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - u8 val; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - val = ctrl->val ? VFLIP_IMG : 0x00; - priv->flag_vflip = ctrl->val; - if (priv->info->flags & OV772X_FLAG_VFLIP) - val ^= VFLIP_IMG; - return ov772x_mask_set(client, COM3, VFLIP_IMG, val); - case V4L2_CID_HFLIP: - val = ctrl->val ? HFLIP_IMG : 0x00; - priv->flag_hflip = ctrl->val; - if (priv->info->flags & OV772X_FLAG_HFLIP) - val ^= HFLIP_IMG; - return ov772x_mask_set(client, COM3, HFLIP_IMG, val); - case V4L2_CID_BAND_STOP_FILTER: - if (!ctrl->val) { - /* Switch the filter off, it is on now */ - ret = ov772x_mask_set(client, BDBASE, 0xff, 0xff); - if (!ret) - ret = ov772x_mask_set(client, COM8, - BNDF_ON_OFF, 0); - } else { - /* Switch the filter on, set AEC low limit */ - val = 256 - ctrl->val; - ret = ov772x_mask_set(client, COM8, - BNDF_ON_OFF, BNDF_ON_OFF); - if (!ret) - ret = ov772x_mask_set(client, BDBASE, - 0xff, val); - } - if (!ret) - priv->band_filter = ctrl->val; - return ret; - } - - return -EINVAL; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int ov772x_g_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - reg->size = 1; - if (reg->reg > 0xff) - return -EINVAL; - - ret = ov772x_read(client, reg->reg); - if (ret < 0) - return ret; - - reg->val = (__u64)ret; - - return 0; -} - -static int ov772x_s_register(struct v4l2_subdev *sd, - const struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->reg > 0xff || - reg->val > 0xff) - return -EINVAL; - - return ov772x_write(client, reg->reg, reg->val); -} -#endif - -static int ov772x_s_power(struct v4l2_subdev *sd, int on) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - struct ov772x_priv *priv = to_ov772x(sd); - - return soc_camera_set_power(&client->dev, ssdd, priv->clk, on); -} - -static const struct ov772x_win_size *ov772x_select_win(u32 width, u32 height) -{ - const struct ov772x_win_size *win = &ov772x_win_sizes[0]; - u32 best_diff = UINT_MAX; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(ov772x_win_sizes); ++i) { - u32 diff = abs(width - ov772x_win_sizes[i].rect.width) - + abs(height - ov772x_win_sizes[i].rect.height); - if (diff < best_diff) { - best_diff = diff; - win = &ov772x_win_sizes[i]; - } - } - - return win; -} - -static void ov772x_select_params(const struct v4l2_mbus_framefmt *mf, - const struct ov772x_color_format **cfmt, - const struct ov772x_win_size **win) -{ - unsigned int i; - - /* Select a format. */ - *cfmt = &ov772x_cfmts[0]; - - for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++) { - if (mf->code == ov772x_cfmts[i].code) { - *cfmt = &ov772x_cfmts[i]; - break; - } - } - - /* Select a window size. */ - *win = ov772x_select_win(mf->width, mf->height); -} - -static int ov772x_set_params(struct ov772x_priv *priv, - const struct ov772x_color_format *cfmt, - const struct ov772x_win_size *win) -{ - struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev); - int ret; - u8 val; - - /* - * reset hardware - */ - ov772x_reset(client); - - /* - * Edge Ctrl - */ - if (priv->info->edgectrl.strength & OV772X_MANUAL_EDGE_CTRL) { - - /* - * Manual Edge Control Mode - * - * Edge auto strength bit is set by default. - * Remove it when manual mode. - */ - - ret = ov772x_mask_set(client, DSPAUTO, EDGE_ACTRL, 0x00); - if (ret < 0) - goto ov772x_set_fmt_error; - - ret = ov772x_mask_set(client, - EDGE_TRSHLD, OV772X_EDGE_THRESHOLD_MASK, - priv->info->edgectrl.threshold); - if (ret < 0) - goto ov772x_set_fmt_error; - - ret = ov772x_mask_set(client, - EDGE_STRNGT, OV772X_EDGE_STRENGTH_MASK, - priv->info->edgectrl.strength); - if (ret < 0) - goto ov772x_set_fmt_error; - - } else if (priv->info->edgectrl.upper > priv->info->edgectrl.lower) { - /* - * Auto Edge Control Mode - * - * set upper and lower limit - */ - ret = ov772x_mask_set(client, - EDGE_UPPER, OV772X_EDGE_UPPER_MASK, - priv->info->edgectrl.upper); - if (ret < 0) - goto ov772x_set_fmt_error; - - ret = ov772x_mask_set(client, - EDGE_LOWER, OV772X_EDGE_LOWER_MASK, - priv->info->edgectrl.lower); - if (ret < 0) - goto ov772x_set_fmt_error; - } - - /* Format and window size */ - ret = ov772x_write(client, HSTART, win->rect.left >> 2); - if (ret < 0) - goto ov772x_set_fmt_error; - ret = ov772x_write(client, HSIZE, win->rect.width >> 2); - if (ret < 0) - goto ov772x_set_fmt_error; - ret = ov772x_write(client, VSTART, win->rect.top >> 1); - if (ret < 0) - goto ov772x_set_fmt_error; - ret = ov772x_write(client, VSIZE, win->rect.height >> 1); - if (ret < 0) - goto ov772x_set_fmt_error; - ret = ov772x_write(client, HOUTSIZE, win->rect.width >> 2); - if (ret < 0) - goto ov772x_set_fmt_error; - ret = ov772x_write(client, VOUTSIZE, win->rect.height >> 1); - if (ret < 0) - goto ov772x_set_fmt_error; - ret = ov772x_write(client, HREF, - ((win->rect.top & 1) << HREF_VSTART_SHIFT) | - ((win->rect.left & 3) << HREF_HSTART_SHIFT) | - ((win->rect.height & 1) << HREF_VSIZE_SHIFT) | - ((win->rect.width & 3) << HREF_HSIZE_SHIFT)); - if (ret < 0) - goto ov772x_set_fmt_error; - ret = ov772x_write(client, EXHCH, - ((win->rect.height & 1) << EXHCH_VSIZE_SHIFT) | - ((win->rect.width & 3) << EXHCH_HSIZE_SHIFT)); - if (ret < 0) - goto ov772x_set_fmt_error; - - /* - * set DSP_CTRL3 - */ - val = cfmt->dsp3; - if (val) { - ret = ov772x_mask_set(client, - DSP_CTRL3, UV_MASK, val); - if (ret < 0) - goto ov772x_set_fmt_error; - } - - /* DSP_CTRL4: AEC reference point and DSP output format. */ - if (cfmt->dsp4) { - ret = ov772x_write(client, DSP_CTRL4, cfmt->dsp4); - if (ret < 0) - goto ov772x_set_fmt_error; - } - - /* - * set COM3 - */ - val = cfmt->com3; - if (priv->info->flags & OV772X_FLAG_VFLIP) - val |= VFLIP_IMG; - if (priv->info->flags & OV772X_FLAG_HFLIP) - val |= HFLIP_IMG; - if (priv->flag_vflip) - val ^= VFLIP_IMG; - if (priv->flag_hflip) - val ^= HFLIP_IMG; - - ret = ov772x_mask_set(client, - COM3, SWAP_MASK | IMG_MASK, val); - if (ret < 0) - goto ov772x_set_fmt_error; - - /* COM7: Sensor resolution and output format control. */ - ret = ov772x_write(client, COM7, win->com7_bit | cfmt->com7); - if (ret < 0) - goto ov772x_set_fmt_error; - - /* - * set COM8 - */ - if (priv->band_filter) { - ret = ov772x_mask_set(client, COM8, BNDF_ON_OFF, BNDF_ON_OFF); - if (!ret) - ret = ov772x_mask_set(client, BDBASE, - 0xff, 256 - priv->band_filter); - if (ret < 0) - goto ov772x_set_fmt_error; - } - - return ret; - -ov772x_set_fmt_error: - - ov772x_reset(client); - - return ret; -} - -static int ov772x_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - sel->r.left = 0; - sel->r.top = 0; - switch (sel->target) { - case V4L2_SEL_TGT_CROP_BOUNDS: - sel->r.width = OV772X_MAX_WIDTH; - sel->r.height = OV772X_MAX_HEIGHT; - return 0; - case V4L2_SEL_TGT_CROP: - sel->r.width = VGA_WIDTH; - sel->r.height = VGA_HEIGHT; - return 0; - default: - return -EINVAL; - } -} - -static int ov772x_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *mf = &format->format; - struct ov772x_priv *priv = to_ov772x(sd); - - if (format->pad) - return -EINVAL; - - mf->width = priv->win->rect.width; - mf->height = priv->win->rect.height; - mf->code = priv->cfmt->code; - mf->colorspace = priv->cfmt->colorspace; - mf->field = V4L2_FIELD_NONE; - - return 0; -} - -static int ov772x_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct ov772x_priv *priv = to_ov772x(sd); - struct v4l2_mbus_framefmt *mf = &format->format; - const struct ov772x_color_format *cfmt; - const struct ov772x_win_size *win; - int ret; - - if (format->pad) - return -EINVAL; - - ov772x_select_params(mf, &cfmt, &win); - - mf->code = cfmt->code; - mf->width = win->rect.width; - mf->height = win->rect.height; - mf->field = V4L2_FIELD_NONE; - mf->colorspace = cfmt->colorspace; - - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - cfg->try_fmt = *mf; - return 0; - } - - ret = ov772x_set_params(priv, cfmt, win); - if (ret < 0) - return ret; - - priv->win = win; - priv->cfmt = cfmt; - return 0; -} - -static int ov772x_video_probe(struct ov772x_priv *priv) -{ - struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev); - u8 pid, ver; - const char *devname; - int ret; - - ret = ov772x_s_power(&priv->subdev, 1); - if (ret < 0) - return ret; - - /* - * check and show product ID and manufacturer ID - */ - pid = ov772x_read(client, PID); - ver = ov772x_read(client, VER); - - switch (VERSION(pid, ver)) { - case OV7720: - devname = "ov7720"; - break; - case OV7725: - devname = "ov7725"; - break; - default: - dev_err(&client->dev, - "Product ID error %x:%x\n", pid, ver); - ret = -ENODEV; - goto done; - } - - dev_info(&client->dev, - "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", - devname, - pid, - ver, - ov772x_read(client, MIDH), - ov772x_read(client, MIDL)); - ret = v4l2_ctrl_handler_setup(&priv->hdl); - -done: - ov772x_s_power(&priv->subdev, 0); - return ret; -} - -static const struct v4l2_ctrl_ops ov772x_ctrl_ops = { - .s_ctrl = ov772x_s_ctrl, -}; - -static const struct v4l2_subdev_core_ops ov772x_subdev_core_ops = { -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = ov772x_g_register, - .s_register = ov772x_s_register, -#endif - .s_power = ov772x_s_power, -}; - -static int ov772x_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (code->pad || code->index >= ARRAY_SIZE(ov772x_cfmts)) - return -EINVAL; - - code->code = ov772x_cfmts[code->index].code; - return 0; -} - -static int ov772x_g_mbus_config(struct v4l2_subdev *sd, - struct v4l2_mbus_config *cfg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - - cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | - V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | - V4L2_MBUS_DATA_ACTIVE_HIGH; - cfg->type = V4L2_MBUS_PARALLEL; - cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); - - return 0; -} - -static const struct v4l2_subdev_video_ops ov772x_subdev_video_ops = { - .s_stream = ov772x_s_stream, - .g_mbus_config = ov772x_g_mbus_config, -}; - -static const struct v4l2_subdev_pad_ops ov772x_subdev_pad_ops = { - .enum_mbus_code = ov772x_enum_mbus_code, - .get_selection = ov772x_get_selection, - .get_fmt = ov772x_get_fmt, - .set_fmt = ov772x_set_fmt, -}; - -static const struct v4l2_subdev_ops ov772x_subdev_ops = { - .core = &ov772x_subdev_core_ops, - .video = &ov772x_subdev_video_ops, - .pad = &ov772x_subdev_pad_ops, -}; - -/* - * i2c_driver function - */ - -static int ov772x_probe(struct i2c_client *client, - const struct i2c_device_id *did) -{ - struct ov772x_priv *priv; - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - int ret; - - if (!ssdd || !ssdd->drv_priv) { - dev_err(&client->dev, "OV772X: missing platform data!\n"); - return -EINVAL; - } - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_PROTOCOL_MANGLING)) { - dev_err(&adapter->dev, - "I2C-Adapter doesn't support SMBUS_BYTE_DATA or PROTOCOL_MANGLING\n"); - return -EIO; - } - client->flags |= I2C_CLIENT_SCCB; - - priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->info = ssdd->drv_priv; - - v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops); - v4l2_ctrl_handler_init(&priv->hdl, 3); - v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops, - V4L2_CID_VFLIP, 0, 1, 1, 0); - v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops, - V4L2_CID_HFLIP, 0, 1, 1, 0); - v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops, - V4L2_CID_BAND_STOP_FILTER, 0, 256, 1, 0); - priv->subdev.ctrl_handler = &priv->hdl; - if (priv->hdl.error) - return priv->hdl.error; - - priv->clk = v4l2_clk_get(&client->dev, "mclk"); - if (IS_ERR(priv->clk)) { - ret = PTR_ERR(priv->clk); - goto eclkget; - } - - ret = ov772x_video_probe(priv); - if (ret < 0) { - v4l2_clk_put(priv->clk); -eclkget: - v4l2_ctrl_handler_free(&priv->hdl); - } else { - priv->cfmt = &ov772x_cfmts[0]; - priv->win = &ov772x_win_sizes[0]; - } - - return ret; -} - -static int ov772x_remove(struct i2c_client *client) -{ - struct ov772x_priv *priv = to_ov772x(i2c_get_clientdata(client)); - - v4l2_clk_put(priv->clk); - v4l2_device_unregister_subdev(&priv->subdev); - v4l2_ctrl_handler_free(&priv->hdl); - return 0; -} - -static const struct i2c_device_id ov772x_id[] = { - { "ov772x", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, ov772x_id); - -static struct i2c_driver ov772x_i2c_driver = { - .driver = { - .name = "ov772x", - }, - .probe = ov772x_probe, - .remove = ov772x_remove, - .id_table = ov772x_id, -}; - -module_i2c_driver(ov772x_i2c_driver); - -MODULE_DESCRIPTION("SoC Camera driver for ov772x"); -MODULE_AUTHOR("Kuninori Morimoto"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/soc_camera/soc_ov9740.c b/drivers/media/i2c/soc_camera/soc_ov9740.c deleted file mode 100644 index a07d3145d1b4..000000000000 --- a/drivers/media/i2c/soc_camera/soc_ov9740.c +++ /dev/null @@ -1,996 +0,0 @@ -/* - * OmniVision OV9740 Camera Driver - * - * Copyright (C) 2011 NVIDIA Corporation - * - * Based on ov9640 camera driver. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/i2c.h> -#include <linux/slab.h> -#include <linux/v4l2-mediabus.h> - -#include <media/soc_camera.h> -#include <media/v4l2-clk.h> -#include <media/v4l2-ctrls.h> - -#define to_ov9740(sd) container_of(sd, struct ov9740_priv, subdev) - -/* General Status Registers */ -#define OV9740_MODEL_ID_HI 0x0000 -#define OV9740_MODEL_ID_LO 0x0001 -#define OV9740_REVISION_NUMBER 0x0002 -#define OV9740_MANUFACTURER_ID 0x0003 -#define OV9740_SMIA_VERSION 0x0004 - -/* General Setup Registers */ -#define OV9740_MODE_SELECT 0x0100 -#define OV9740_IMAGE_ORT 0x0101 -#define OV9740_SOFTWARE_RESET 0x0103 -#define OV9740_GRP_PARAM_HOLD 0x0104 -#define OV9740_MSK_CORRUP_FM 0x0105 - -/* Timing Setting */ -#define OV9740_FRM_LENGTH_LN_HI 0x0340 /* VTS */ -#define OV9740_FRM_LENGTH_LN_LO 0x0341 /* VTS */ -#define OV9740_LN_LENGTH_PCK_HI 0x0342 /* HTS */ -#define OV9740_LN_LENGTH_PCK_LO 0x0343 /* HTS */ -#define OV9740_X_ADDR_START_HI 0x0344 -#define OV9740_X_ADDR_START_LO 0x0345 -#define OV9740_Y_ADDR_START_HI 0x0346 -#define OV9740_Y_ADDR_START_LO 0x0347 -#define OV9740_X_ADDR_END_HI 0x0348 -#define OV9740_X_ADDR_END_LO 0x0349 -#define OV9740_Y_ADDR_END_HI 0x034a -#define OV9740_Y_ADDR_END_LO 0x034b -#define OV9740_X_OUTPUT_SIZE_HI 0x034c -#define OV9740_X_OUTPUT_SIZE_LO 0x034d -#define OV9740_Y_OUTPUT_SIZE_HI 0x034e -#define OV9740_Y_OUTPUT_SIZE_LO 0x034f - -/* IO Control Registers */ -#define OV9740_IO_CREL00 0x3002 -#define OV9740_IO_CREL01 0x3004 -#define OV9740_IO_CREL02 0x3005 -#define OV9740_IO_OUTPUT_SEL01 0x3026 -#define OV9740_IO_OUTPUT_SEL02 0x3027 - -/* AWB Registers */ -#define OV9740_AWB_MANUAL_CTRL 0x3406 - -/* Analog Control Registers */ -#define OV9740_ANALOG_CTRL01 0x3601 -#define OV9740_ANALOG_CTRL02 0x3602 -#define OV9740_ANALOG_CTRL03 0x3603 -#define OV9740_ANALOG_CTRL04 0x3604 -#define OV9740_ANALOG_CTRL10 0x3610 -#define OV9740_ANALOG_CTRL12 0x3612 -#define OV9740_ANALOG_CTRL15 0x3615 -#define OV9740_ANALOG_CTRL20 0x3620 -#define OV9740_ANALOG_CTRL21 0x3621 -#define OV9740_ANALOG_CTRL22 0x3622 -#define OV9740_ANALOG_CTRL30 0x3630 -#define OV9740_ANALOG_CTRL31 0x3631 -#define OV9740_ANALOG_CTRL32 0x3632 -#define OV9740_ANALOG_CTRL33 0x3633 - -/* Sensor Control */ -#define OV9740_SENSOR_CTRL03 0x3703 -#define OV9740_SENSOR_CTRL04 0x3704 -#define OV9740_SENSOR_CTRL05 0x3705 -#define OV9740_SENSOR_CTRL07 0x3707 - -/* Timing Control */ -#define OV9740_TIMING_CTRL17 0x3817 -#define OV9740_TIMING_CTRL19 0x3819 -#define OV9740_TIMING_CTRL33 0x3833 -#define OV9740_TIMING_CTRL35 0x3835 - -/* Banding Filter */ -#define OV9740_AEC_MAXEXPO_60_H 0x3a02 -#define OV9740_AEC_MAXEXPO_60_L 0x3a03 -#define OV9740_AEC_B50_STEP_HI 0x3a08 -#define OV9740_AEC_B50_STEP_LO 0x3a09 -#define OV9740_AEC_B60_STEP_HI 0x3a0a -#define OV9740_AEC_B60_STEP_LO 0x3a0b -#define OV9740_AEC_CTRL0D 0x3a0d -#define OV9740_AEC_CTRL0E 0x3a0e -#define OV9740_AEC_MAXEXPO_50_H 0x3a14 -#define OV9740_AEC_MAXEXPO_50_L 0x3a15 - -/* AEC/AGC Control */ -#define OV9740_AEC_ENABLE 0x3503 -#define OV9740_GAIN_CEILING_01 0x3a18 -#define OV9740_GAIN_CEILING_02 0x3a19 -#define OV9740_AEC_HI_THRESHOLD 0x3a11 -#define OV9740_AEC_3A1A 0x3a1a -#define OV9740_AEC_CTRL1B_WPT2 0x3a1b -#define OV9740_AEC_CTRL0F_WPT 0x3a0f -#define OV9740_AEC_CTRL10_BPT 0x3a10 -#define OV9740_AEC_CTRL1E_BPT2 0x3a1e -#define OV9740_AEC_LO_THRESHOLD 0x3a1f - -/* BLC Control */ -#define OV9740_BLC_AUTO_ENABLE 0x4002 -#define OV9740_BLC_MODE 0x4005 - -/* VFIFO */ -#define OV9740_VFIFO_READ_START_HI 0x4608 -#define OV9740_VFIFO_READ_START_LO 0x4609 - -/* DVP Control */ -#define OV9740_DVP_VSYNC_CTRL02 0x4702 -#define OV9740_DVP_VSYNC_MODE 0x4704 -#define OV9740_DVP_VSYNC_CTRL06 0x4706 - -/* PLL Setting */ -#define OV9740_PLL_MODE_CTRL01 0x3104 -#define OV9740_PRE_PLL_CLK_DIV 0x0305 -#define OV9740_PLL_MULTIPLIER 0x0307 -#define OV9740_VT_SYS_CLK_DIV 0x0303 -#define OV9740_VT_PIX_CLK_DIV 0x0301 -#define OV9740_PLL_CTRL3010 0x3010 -#define OV9740_VFIFO_CTRL00 0x460e - -/* ISP Control */ -#define OV9740_ISP_CTRL00 0x5000 -#define OV9740_ISP_CTRL01 0x5001 -#define OV9740_ISP_CTRL03 0x5003 -#define OV9740_ISP_CTRL05 0x5005 -#define OV9740_ISP_CTRL12 0x5012 -#define OV9740_ISP_CTRL19 0x5019 -#define OV9740_ISP_CTRL1A 0x501a -#define OV9740_ISP_CTRL1E 0x501e -#define OV9740_ISP_CTRL1F 0x501f -#define OV9740_ISP_CTRL20 0x5020 -#define OV9740_ISP_CTRL21 0x5021 - -/* AWB */ -#define OV9740_AWB_CTRL00 0x5180 -#define OV9740_AWB_CTRL01 0x5181 -#define OV9740_AWB_CTRL02 0x5182 -#define OV9740_AWB_CTRL03 0x5183 -#define OV9740_AWB_ADV_CTRL01 0x5184 -#define OV9740_AWB_ADV_CTRL02 0x5185 -#define OV9740_AWB_ADV_CTRL03 0x5186 -#define OV9740_AWB_ADV_CTRL04 0x5187 -#define OV9740_AWB_ADV_CTRL05 0x5188 -#define OV9740_AWB_ADV_CTRL06 0x5189 -#define OV9740_AWB_ADV_CTRL07 0x518a -#define OV9740_AWB_ADV_CTRL08 0x518b -#define OV9740_AWB_ADV_CTRL09 0x518c -#define OV9740_AWB_ADV_CTRL10 0x518d -#define OV9740_AWB_ADV_CTRL11 0x518e -#define OV9740_AWB_CTRL0F 0x518f -#define OV9740_AWB_CTRL10 0x5190 -#define OV9740_AWB_CTRL11 0x5191 -#define OV9740_AWB_CTRL12 0x5192 -#define OV9740_AWB_CTRL13 0x5193 -#define OV9740_AWB_CTRL14 0x5194 - -/* MIPI Control */ -#define OV9740_MIPI_CTRL00 0x4800 -#define OV9740_MIPI_3837 0x3837 -#define OV9740_MIPI_CTRL01 0x4801 -#define OV9740_MIPI_CTRL03 0x4803 -#define OV9740_MIPI_CTRL05 0x4805 -#define OV9740_VFIFO_RD_CTRL 0x4601 -#define OV9740_MIPI_CTRL_3012 0x3012 -#define OV9740_SC_CMMM_MIPI_CTR 0x3014 - -#define OV9740_MAX_WIDTH 1280 -#define OV9740_MAX_HEIGHT 720 - -/* Misc. structures */ -struct ov9740_reg { - u16 reg; - u8 val; -}; - -struct ov9740_priv { - struct v4l2_subdev subdev; - struct v4l2_ctrl_handler hdl; - struct v4l2_clk *clk; - - u16 model; - u8 revision; - u8 manid; - u8 smiaver; - - bool flag_vflip; - bool flag_hflip; - - /* For suspend/resume. */ - struct v4l2_mbus_framefmt current_mf; - bool current_enable; -}; - -static const struct ov9740_reg ov9740_defaults[] = { - /* Software Reset */ - { OV9740_SOFTWARE_RESET, 0x01 }, - - /* Banding Filter */ - { OV9740_AEC_B50_STEP_HI, 0x00 }, - { OV9740_AEC_B50_STEP_LO, 0xe8 }, - { OV9740_AEC_CTRL0E, 0x03 }, - { OV9740_AEC_MAXEXPO_50_H, 0x15 }, - { OV9740_AEC_MAXEXPO_50_L, 0xc6 }, - { OV9740_AEC_B60_STEP_HI, 0x00 }, - { OV9740_AEC_B60_STEP_LO, 0xc0 }, - { OV9740_AEC_CTRL0D, 0x04 }, - { OV9740_AEC_MAXEXPO_60_H, 0x18 }, - { OV9740_AEC_MAXEXPO_60_L, 0x20 }, - - /* LC */ - { 0x5842, 0x02 }, { 0x5843, 0x5e }, { 0x5844, 0x04 }, { 0x5845, 0x32 }, - { 0x5846, 0x03 }, { 0x5847, 0x29 }, { 0x5848, 0x02 }, { 0x5849, 0xcc }, - - /* Un-documented OV9740 registers */ - { 0x5800, 0x29 }, { 0x5801, 0x25 }, { 0x5802, 0x20 }, { 0x5803, 0x21 }, - { 0x5804, 0x26 }, { 0x5805, 0x2e }, { 0x5806, 0x11 }, { 0x5807, 0x0c }, - { 0x5808, 0x09 }, { 0x5809, 0x0a }, { 0x580a, 0x0e }, { 0x580b, 0x16 }, - { 0x580c, 0x06 }, { 0x580d, 0x02 }, { 0x580e, 0x00 }, { 0x580f, 0x00 }, - { 0x5810, 0x04 }, { 0x5811, 0x0a }, { 0x5812, 0x05 }, { 0x5813, 0x02 }, - { 0x5814, 0x00 }, { 0x5815, 0x00 }, { 0x5816, 0x03 }, { 0x5817, 0x09 }, - { 0x5818, 0x0f }, { 0x5819, 0x0a }, { 0x581a, 0x07 }, { 0x581b, 0x08 }, - { 0x581c, 0x0b }, { 0x581d, 0x14 }, { 0x581e, 0x28 }, { 0x581f, 0x23 }, - { 0x5820, 0x1d }, { 0x5821, 0x1e }, { 0x5822, 0x24 }, { 0x5823, 0x2a }, - { 0x5824, 0x4f }, { 0x5825, 0x6f }, { 0x5826, 0x5f }, { 0x5827, 0x7f }, - { 0x5828, 0x9f }, { 0x5829, 0x5f }, { 0x582a, 0x8f }, { 0x582b, 0x9e }, - { 0x582c, 0x8f }, { 0x582d, 0x9f }, { 0x582e, 0x4f }, { 0x582f, 0x87 }, - { 0x5830, 0x86 }, { 0x5831, 0x97 }, { 0x5832, 0xae }, { 0x5833, 0x3f }, - { 0x5834, 0x8e }, { 0x5835, 0x7c }, { 0x5836, 0x7e }, { 0x5837, 0xaf }, - { 0x5838, 0x8f }, { 0x5839, 0x8f }, { 0x583a, 0x9f }, { 0x583b, 0x7f }, - { 0x583c, 0x5f }, - - /* Y Gamma */ - { 0x5480, 0x07 }, { 0x5481, 0x18 }, { 0x5482, 0x2c }, { 0x5483, 0x4e }, - { 0x5484, 0x5e }, { 0x5485, 0x6b }, { 0x5486, 0x77 }, { 0x5487, 0x82 }, - { 0x5488, 0x8c }, { 0x5489, 0x95 }, { 0x548a, 0xa4 }, { 0x548b, 0xb1 }, - { 0x548c, 0xc6 }, { 0x548d, 0xd8 }, { 0x548e, 0xe9 }, - - /* UV Gamma */ - { 0x5490, 0x0f }, { 0x5491, 0xff }, { 0x5492, 0x0d }, { 0x5493, 0x05 }, - { 0x5494, 0x07 }, { 0x5495, 0x1a }, { 0x5496, 0x04 }, { 0x5497, 0x01 }, - { 0x5498, 0x03 }, { 0x5499, 0x53 }, { 0x549a, 0x02 }, { 0x549b, 0xeb }, - { 0x549c, 0x02 }, { 0x549d, 0xa0 }, { 0x549e, 0x02 }, { 0x549f, 0x67 }, - { 0x54a0, 0x02 }, { 0x54a1, 0x3b }, { 0x54a2, 0x02 }, { 0x54a3, 0x18 }, - { 0x54a4, 0x01 }, { 0x54a5, 0xe7 }, { 0x54a6, 0x01 }, { 0x54a7, 0xc3 }, - { 0x54a8, 0x01 }, { 0x54a9, 0x94 }, { 0x54aa, 0x01 }, { 0x54ab, 0x72 }, - { 0x54ac, 0x01 }, { 0x54ad, 0x57 }, - - /* AWB */ - { OV9740_AWB_CTRL00, 0xf0 }, - { OV9740_AWB_CTRL01, 0x00 }, - { OV9740_AWB_CTRL02, 0x41 }, - { OV9740_AWB_CTRL03, 0x42 }, - { OV9740_AWB_ADV_CTRL01, 0x8a }, - { OV9740_AWB_ADV_CTRL02, 0x61 }, - { OV9740_AWB_ADV_CTRL03, 0xce }, - { OV9740_AWB_ADV_CTRL04, 0xa8 }, - { OV9740_AWB_ADV_CTRL05, 0x17 }, - { OV9740_AWB_ADV_CTRL06, 0x1f }, - { OV9740_AWB_ADV_CTRL07, 0x27 }, - { OV9740_AWB_ADV_CTRL08, 0x41 }, - { OV9740_AWB_ADV_CTRL09, 0x34 }, - { OV9740_AWB_ADV_CTRL10, 0xf0 }, - { OV9740_AWB_ADV_CTRL11, 0x10 }, - { OV9740_AWB_CTRL0F, 0xff }, - { OV9740_AWB_CTRL10, 0x00 }, - { OV9740_AWB_CTRL11, 0xff }, - { OV9740_AWB_CTRL12, 0x00 }, - { OV9740_AWB_CTRL13, 0xff }, - { OV9740_AWB_CTRL14, 0x00 }, - - /* CIP */ - { 0x530d, 0x12 }, - - /* CMX */ - { 0x5380, 0x01 }, { 0x5381, 0x00 }, { 0x5382, 0x00 }, { 0x5383, 0x17 }, - { 0x5384, 0x00 }, { 0x5385, 0x01 }, { 0x5386, 0x00 }, { 0x5387, 0x00 }, - { 0x5388, 0x00 }, { 0x5389, 0xe0 }, { 0x538a, 0x00 }, { 0x538b, 0x20 }, - { 0x538c, 0x00 }, { 0x538d, 0x00 }, { 0x538e, 0x00 }, { 0x538f, 0x16 }, - { 0x5390, 0x00 }, { 0x5391, 0x9c }, { 0x5392, 0x00 }, { 0x5393, 0xa0 }, - { 0x5394, 0x18 }, - - /* 50/60 Detection */ - { 0x3c0a, 0x9c }, { 0x3c0b, 0x3f }, - - /* Output Select */ - { OV9740_IO_OUTPUT_SEL01, 0x00 }, - { OV9740_IO_OUTPUT_SEL02, 0x00 }, - { OV9740_IO_CREL00, 0x00 }, - { OV9740_IO_CREL01, 0x00 }, - { OV9740_IO_CREL02, 0x00 }, - - /* AWB Control */ - { OV9740_AWB_MANUAL_CTRL, 0x00 }, - - /* Analog Control */ - { OV9740_ANALOG_CTRL03, 0xaa }, - { OV9740_ANALOG_CTRL32, 0x2f }, - { OV9740_ANALOG_CTRL20, 0x66 }, - { OV9740_ANALOG_CTRL21, 0xc0 }, - { OV9740_ANALOG_CTRL31, 0x52 }, - { OV9740_ANALOG_CTRL33, 0x50 }, - { OV9740_ANALOG_CTRL30, 0xca }, - { OV9740_ANALOG_CTRL04, 0x0c }, - { OV9740_ANALOG_CTRL01, 0x40 }, - { OV9740_ANALOG_CTRL02, 0x16 }, - { OV9740_ANALOG_CTRL10, 0xa1 }, - { OV9740_ANALOG_CTRL12, 0x24 }, - { OV9740_ANALOG_CTRL22, 0x9f }, - { OV9740_ANALOG_CTRL15, 0xf0 }, - - /* Sensor Control */ - { OV9740_SENSOR_CTRL03, 0x42 }, - { OV9740_SENSOR_CTRL04, 0x10 }, - { OV9740_SENSOR_CTRL05, 0x45 }, - { OV9740_SENSOR_CTRL07, 0x14 }, - - /* Timing Control */ - { OV9740_TIMING_CTRL33, 0x04 }, - { OV9740_TIMING_CTRL35, 0x02 }, - { OV9740_TIMING_CTRL19, 0x6e }, - { OV9740_TIMING_CTRL17, 0x94 }, - - /* AEC/AGC Control */ - { OV9740_AEC_ENABLE, 0x10 }, - { OV9740_GAIN_CEILING_01, 0x00 }, - { OV9740_GAIN_CEILING_02, 0x7f }, - { OV9740_AEC_HI_THRESHOLD, 0xa0 }, - { OV9740_AEC_3A1A, 0x05 }, - { OV9740_AEC_CTRL1B_WPT2, 0x50 }, - { OV9740_AEC_CTRL0F_WPT, 0x50 }, - { OV9740_AEC_CTRL10_BPT, 0x4c }, - { OV9740_AEC_CTRL1E_BPT2, 0x4c }, - { OV9740_AEC_LO_THRESHOLD, 0x26 }, - - /* BLC Control */ - { OV9740_BLC_AUTO_ENABLE, 0x45 }, - { OV9740_BLC_MODE, 0x18 }, - - /* DVP Control */ - { OV9740_DVP_VSYNC_CTRL02, 0x04 }, - { OV9740_DVP_VSYNC_MODE, 0x00 }, - { OV9740_DVP_VSYNC_CTRL06, 0x08 }, - - /* PLL Setting */ - { OV9740_PLL_MODE_CTRL01, 0x20 }, - { OV9740_PRE_PLL_CLK_DIV, 0x03 }, - { OV9740_PLL_MULTIPLIER, 0x4c }, - { OV9740_VT_SYS_CLK_DIV, 0x01 }, - { OV9740_VT_PIX_CLK_DIV, 0x08 }, - { OV9740_PLL_CTRL3010, 0x01 }, - { OV9740_VFIFO_CTRL00, 0x82 }, - - /* Timing Setting */ - /* VTS */ - { OV9740_FRM_LENGTH_LN_HI, 0x03 }, - { OV9740_FRM_LENGTH_LN_LO, 0x07 }, - /* HTS */ - { OV9740_LN_LENGTH_PCK_HI, 0x06 }, - { OV9740_LN_LENGTH_PCK_LO, 0x62 }, - - /* MIPI Control */ - { OV9740_MIPI_CTRL00, 0x44 }, /* 0x64 for discontinuous clk */ - { OV9740_MIPI_3837, 0x01 }, - { OV9740_MIPI_CTRL01, 0x0f }, - { OV9740_MIPI_CTRL03, 0x05 }, - { OV9740_MIPI_CTRL05, 0x10 }, - { OV9740_VFIFO_RD_CTRL, 0x16 }, - { OV9740_MIPI_CTRL_3012, 0x70 }, - { OV9740_SC_CMMM_MIPI_CTR, 0x01 }, - - /* YUYV order */ - { OV9740_ISP_CTRL19, 0x02 }, -}; - -static u32 ov9740_codes[] = { - MEDIA_BUS_FMT_YUYV8_2X8, -}; - -/* read a register */ -static int ov9740_reg_read(struct i2c_client *client, u16 reg, u8 *val) -{ - int ret; - struct i2c_msg msg[] = { - { - .addr = client->addr, - .flags = 0, - .len = 2, - .buf = (u8 *)®, - }, - { - .addr = client->addr, - .flags = I2C_M_RD, - .len = 1, - .buf = val, - }, - }; - - reg = swab16(reg); - - ret = i2c_transfer(client->adapter, msg, 2); - if (ret < 0) { - dev_err(&client->dev, "Failed reading register 0x%04x!\n", reg); - return ret; - } - - return 0; -} - -/* write a register */ -static int ov9740_reg_write(struct i2c_client *client, u16 reg, u8 val) -{ - struct i2c_msg msg; - struct { - u16 reg; - u8 val; - } __packed buf; - int ret; - - reg = swab16(reg); - - buf.reg = reg; - buf.val = val; - - msg.addr = client->addr; - msg.flags = 0; - msg.len = 3; - msg.buf = (u8 *)&buf; - - ret = i2c_transfer(client->adapter, &msg, 1); - if (ret < 0) { - dev_err(&client->dev, "Failed writing register 0x%04x!\n", reg); - return ret; - } - - return 0; -} - - -/* Read a register, alter its bits, write it back */ -static int ov9740_reg_rmw(struct i2c_client *client, u16 reg, u8 set, u8 unset) -{ - u8 val; - int ret; - - ret = ov9740_reg_read(client, reg, &val); - if (ret < 0) { - dev_err(&client->dev, - "[Read]-Modify-Write of register 0x%04x failed!\n", - reg); - return ret; - } - - val |= set; - val &= ~unset; - - ret = ov9740_reg_write(client, reg, val); - if (ret < 0) { - dev_err(&client->dev, - "Read-Modify-[Write] of register 0x%04x failed!\n", - reg); - return ret; - } - - return 0; -} - -static int ov9740_reg_write_array(struct i2c_client *client, - const struct ov9740_reg *regarray, - int regarraylen) -{ - int i; - int ret; - - for (i = 0; i < regarraylen; i++) { - ret = ov9740_reg_write(client, - regarray[i].reg, regarray[i].val); - if (ret < 0) - return ret; - } - - return 0; -} - -/* Start/Stop streaming from the device */ -static int ov9740_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov9740_priv *priv = to_ov9740(sd); - int ret; - - /* Program orientation register. */ - if (priv->flag_vflip) - ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0x2, 0); - else - ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0, 0x2); - if (ret < 0) - return ret; - - if (priv->flag_hflip) - ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0x1, 0); - else - ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0, 0x1); - if (ret < 0) - return ret; - - if (enable) { - dev_dbg(&client->dev, "Enabling Streaming\n"); - /* Start Streaming */ - ret = ov9740_reg_write(client, OV9740_MODE_SELECT, 0x01); - - } else { - dev_dbg(&client->dev, "Disabling Streaming\n"); - /* Software Reset */ - ret = ov9740_reg_write(client, OV9740_SOFTWARE_RESET, 0x01); - if (!ret) - /* Setting Streaming to Standby */ - ret = ov9740_reg_write(client, OV9740_MODE_SELECT, - 0x00); - } - - priv->current_enable = enable; - - return ret; -} - -/* select nearest higher resolution for capture */ -static void ov9740_res_roundup(u32 *width, u32 *height) -{ - /* Width must be a multiple of 4 pixels. */ - *width = ALIGN(*width, 4); - - /* Max resolution is 1280x720 (720p). */ - if (*width > OV9740_MAX_WIDTH) - *width = OV9740_MAX_WIDTH; - - if (*height > OV9740_MAX_HEIGHT) - *height = OV9740_MAX_HEIGHT; -} - -/* Setup registers according to resolution and color encoding */ -static int ov9740_set_res(struct i2c_client *client, u32 width, u32 height) -{ - u32 x_start; - u32 y_start; - u32 x_end; - u32 y_end; - bool scaling = false; - u32 scale_input_x; - u32 scale_input_y; - int ret; - - if ((width != OV9740_MAX_WIDTH) || (height != OV9740_MAX_HEIGHT)) - scaling = true; - - /* - * Try to use as much of the sensor area as possible when supporting - * smaller resolutions. Depending on the aspect ratio of the - * chosen resolution, we can either use the full width of the sensor, - * or the full height of the sensor (or both if the aspect ratio is - * the same as 1280x720. - */ - if ((OV9740_MAX_WIDTH * height) > (OV9740_MAX_HEIGHT * width)) { - scale_input_x = (OV9740_MAX_HEIGHT * width) / height; - scale_input_y = OV9740_MAX_HEIGHT; - } else { - scale_input_x = OV9740_MAX_WIDTH; - scale_input_y = (OV9740_MAX_WIDTH * height) / width; - } - - /* These describe the area of the sensor to use. */ - x_start = (OV9740_MAX_WIDTH - scale_input_x) / 2; - y_start = (OV9740_MAX_HEIGHT - scale_input_y) / 2; - x_end = x_start + scale_input_x - 1; - y_end = y_start + scale_input_y - 1; - - ret = ov9740_reg_write(client, OV9740_X_ADDR_START_HI, x_start >> 8); - if (ret) - goto done; - ret = ov9740_reg_write(client, OV9740_X_ADDR_START_LO, x_start & 0xff); - if (ret) - goto done; - ret = ov9740_reg_write(client, OV9740_Y_ADDR_START_HI, y_start >> 8); - if (ret) - goto done; - ret = ov9740_reg_write(client, OV9740_Y_ADDR_START_LO, y_start & 0xff); - if (ret) - goto done; - - ret = ov9740_reg_write(client, OV9740_X_ADDR_END_HI, x_end >> 8); - if (ret) - goto done; - ret = ov9740_reg_write(client, OV9740_X_ADDR_END_LO, x_end & 0xff); - if (ret) - goto done; - ret = ov9740_reg_write(client, OV9740_Y_ADDR_END_HI, y_end >> 8); - if (ret) - goto done; - ret = ov9740_reg_write(client, OV9740_Y_ADDR_END_LO, y_end & 0xff); - if (ret) - goto done; - - ret = ov9740_reg_write(client, OV9740_X_OUTPUT_SIZE_HI, width >> 8); - if (ret) - goto done; - ret = ov9740_reg_write(client, OV9740_X_OUTPUT_SIZE_LO, width & 0xff); - if (ret) - goto done; - ret = ov9740_reg_write(client, OV9740_Y_OUTPUT_SIZE_HI, height >> 8); - if (ret) - goto done; - ret = ov9740_reg_write(client, OV9740_Y_OUTPUT_SIZE_LO, height & 0xff); - if (ret) - goto done; - - ret = ov9740_reg_write(client, OV9740_ISP_CTRL1E, scale_input_x >> 8); - if (ret) - goto done; - ret = ov9740_reg_write(client, OV9740_ISP_CTRL1F, scale_input_x & 0xff); - if (ret) - goto done; - ret = ov9740_reg_write(client, OV9740_ISP_CTRL20, scale_input_y >> 8); - if (ret) - goto done; - ret = ov9740_reg_write(client, OV9740_ISP_CTRL21, scale_input_y & 0xff); - if (ret) - goto done; - - ret = ov9740_reg_write(client, OV9740_VFIFO_READ_START_HI, - (scale_input_x - width) >> 8); - if (ret) - goto done; - ret = ov9740_reg_write(client, OV9740_VFIFO_READ_START_LO, - (scale_input_x - width) & 0xff); - if (ret) - goto done; - - ret = ov9740_reg_write(client, OV9740_ISP_CTRL00, 0xff); - if (ret) - goto done; - ret = ov9740_reg_write(client, OV9740_ISP_CTRL01, 0xef | - (scaling << 4)); - if (ret) - goto done; - ret = ov9740_reg_write(client, OV9740_ISP_CTRL03, 0xff); - -done: - return ret; -} - -/* set the format we will capture in */ -static int ov9740_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov9740_priv *priv = to_ov9740(sd); - int ret; - - ret = ov9740_reg_write_array(client, ov9740_defaults, - ARRAY_SIZE(ov9740_defaults)); - if (ret < 0) - return ret; - - ret = ov9740_set_res(client, mf->width, mf->height); - if (ret < 0) - return ret; - - priv->current_mf = *mf; - return ret; -} - -static int ov9740_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *mf = &format->format; - - if (format->pad) - return -EINVAL; - - ov9740_res_roundup(&mf->width, &mf->height); - - mf->field = V4L2_FIELD_NONE; - mf->code = MEDIA_BUS_FMT_YUYV8_2X8; - mf->colorspace = V4L2_COLORSPACE_SRGB; - - if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) - return ov9740_s_fmt(sd, mf); - cfg->try_fmt = *mf; - return 0; -} - -static int ov9740_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (code->pad || code->index >= ARRAY_SIZE(ov9740_codes)) - return -EINVAL; - - code->code = ov9740_codes[code->index]; - - return 0; -} - -static int ov9740_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - switch (sel->target) { - case V4L2_SEL_TGT_CROP_BOUNDS: - case V4L2_SEL_TGT_CROP: - sel->r.left = 0; - sel->r.top = 0; - sel->r.width = OV9740_MAX_WIDTH; - sel->r.height = OV9740_MAX_HEIGHT; - return 0; - default: - return -EINVAL; - } -} - -/* Set status of additional camera capabilities */ -static int ov9740_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct ov9740_priv *priv = - container_of(ctrl->handler, struct ov9740_priv, hdl); - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - priv->flag_vflip = ctrl->val; - break; - case V4L2_CID_HFLIP: - priv->flag_hflip = ctrl->val; - break; - default: - return -EINVAL; - } - - return 0; -} - -static int ov9740_s_power(struct v4l2_subdev *sd, int on) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - struct ov9740_priv *priv = to_ov9740(sd); - int ret; - - if (on) { - ret = soc_camera_power_on(&client->dev, ssdd, priv->clk); - if (ret < 0) - return ret; - - if (priv->current_enable) { - ov9740_s_fmt(sd, &priv->current_mf); - ov9740_s_stream(sd, 1); - } - } else { - if (priv->current_enable) { - ov9740_s_stream(sd, 0); - priv->current_enable = true; - } - - soc_camera_power_off(&client->dev, ssdd, priv->clk); - } - - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int ov9740_get_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - u8 val; - - if (reg->reg & ~0xffff) - return -EINVAL; - - reg->size = 2; - - ret = ov9740_reg_read(client, reg->reg, &val); - if (ret) - return ret; - - reg->val = (__u64)val; - - return ret; -} - -static int ov9740_set_register(struct v4l2_subdev *sd, - const struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->reg & ~0xffff || reg->val & ~0xff) - return -EINVAL; - - return ov9740_reg_write(client, reg->reg, reg->val); -} -#endif - -static int ov9740_video_probe(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov9740_priv *priv = to_ov9740(sd); - u8 modelhi, modello; - int ret; - - ret = ov9740_s_power(&priv->subdev, 1); - if (ret < 0) - return ret; - - /* - * check and show product ID and manufacturer ID - */ - ret = ov9740_reg_read(client, OV9740_MODEL_ID_HI, &modelhi); - if (ret < 0) - goto done; - - ret = ov9740_reg_read(client, OV9740_MODEL_ID_LO, &modello); - if (ret < 0) - goto done; - - priv->model = (modelhi << 8) | modello; - - ret = ov9740_reg_read(client, OV9740_REVISION_NUMBER, &priv->revision); - if (ret < 0) - goto done; - - ret = ov9740_reg_read(client, OV9740_MANUFACTURER_ID, &priv->manid); - if (ret < 0) - goto done; - - ret = ov9740_reg_read(client, OV9740_SMIA_VERSION, &priv->smiaver); - if (ret < 0) - goto done; - - if (priv->model != 0x9740) { - ret = -ENODEV; - goto done; - } - - dev_info(&client->dev, "ov9740 Model ID 0x%04x, Revision 0x%02x, Manufacturer 0x%02x, SMIA Version 0x%02x\n", - priv->model, priv->revision, priv->manid, priv->smiaver); - - ret = v4l2_ctrl_handler_setup(&priv->hdl); - -done: - ov9740_s_power(&priv->subdev, 0); - return ret; -} - -/* Request bus settings on camera side */ -static int ov9740_g_mbus_config(struct v4l2_subdev *sd, - struct v4l2_mbus_config *cfg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - - cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | - V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | - V4L2_MBUS_DATA_ACTIVE_HIGH; - cfg->type = V4L2_MBUS_PARALLEL; - cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); - - return 0; -} - -static const struct v4l2_subdev_video_ops ov9740_video_ops = { - .s_stream = ov9740_s_stream, - .g_mbus_config = ov9740_g_mbus_config, -}; - -static const struct v4l2_subdev_core_ops ov9740_core_ops = { - .s_power = ov9740_s_power, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = ov9740_get_register, - .s_register = ov9740_set_register, -#endif -}; - -static const struct v4l2_subdev_pad_ops ov9740_pad_ops = { - .enum_mbus_code = ov9740_enum_mbus_code, - .get_selection = ov9740_get_selection, - .set_fmt = ov9740_set_fmt, -}; - -static const struct v4l2_subdev_ops ov9740_subdev_ops = { - .core = &ov9740_core_ops, - .video = &ov9740_video_ops, - .pad = &ov9740_pad_ops, -}; - -static const struct v4l2_ctrl_ops ov9740_ctrl_ops = { - .s_ctrl = ov9740_s_ctrl, -}; - -/* - * i2c_driver function - */ -static int ov9740_probe(struct i2c_client *client, - const struct i2c_device_id *did) -{ - struct ov9740_priv *priv; - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - int ret; - - if (!ssdd) { - dev_err(&client->dev, "Missing platform_data for driver\n"); - return -EINVAL; - } - - priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - v4l2_i2c_subdev_init(&priv->subdev, client, &ov9740_subdev_ops); - v4l2_ctrl_handler_init(&priv->hdl, 13); - v4l2_ctrl_new_std(&priv->hdl, &ov9740_ctrl_ops, - V4L2_CID_VFLIP, 0, 1, 1, 0); - v4l2_ctrl_new_std(&priv->hdl, &ov9740_ctrl_ops, - V4L2_CID_HFLIP, 0, 1, 1, 0); - priv->subdev.ctrl_handler = &priv->hdl; - if (priv->hdl.error) - return priv->hdl.error; - - priv->clk = v4l2_clk_get(&client->dev, "mclk"); - if (IS_ERR(priv->clk)) { - ret = PTR_ERR(priv->clk); - goto eclkget; - } - - ret = ov9740_video_probe(client); - if (ret < 0) { - v4l2_clk_put(priv->clk); -eclkget: - v4l2_ctrl_handler_free(&priv->hdl); - } - - return ret; -} - -static int ov9740_remove(struct i2c_client *client) -{ - struct ov9740_priv *priv = i2c_get_clientdata(client); - - v4l2_clk_put(priv->clk); - v4l2_device_unregister_subdev(&priv->subdev); - v4l2_ctrl_handler_free(&priv->hdl); - return 0; -} - -static const struct i2c_device_id ov9740_id[] = { - { "ov9740", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, ov9740_id); - -static struct i2c_driver ov9740_i2c_driver = { - .driver = { - .name = "ov9740", - }, - .probe = ov9740_probe, - .remove = ov9740_remove, - .id_table = ov9740_id, -}; - -module_i2c_driver(ov9740_i2c_driver); - -MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV9740"); -MODULE_AUTHOR("Andrew Chew <achew@nvidia.com>"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/soc_camera/soc_rj54n1cb0c.c b/drivers/media/i2c/soc_camera/soc_rj54n1cb0c.c deleted file mode 100644 index f0cb49a6167b..000000000000 --- a/drivers/media/i2c/soc_camera/soc_rj54n1cb0c.c +++ /dev/null @@ -1,1415 +0,0 @@ -/* - * Driver for RJ54N1CB0C CMOS Image Sensor from Sharp - * - * Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/delay.h> -#include <linux/i2c.h> -#include <linux/slab.h> -#include <linux/v4l2-mediabus.h> -#include <linux/videodev2.h> -#include <linux/module.h> - -#include <media/i2c/rj54n1cb0c.h> -#include <media/soc_camera.h> -#include <media/v4l2-clk.h> -#include <media/v4l2-subdev.h> -#include <media/v4l2-ctrls.h> - -#define RJ54N1_DEV_CODE 0x0400 -#define RJ54N1_DEV_CODE2 0x0401 -#define RJ54N1_OUT_SEL 0x0403 -#define RJ54N1_XY_OUTPUT_SIZE_S_H 0x0404 -#define RJ54N1_X_OUTPUT_SIZE_S_L 0x0405 -#define RJ54N1_Y_OUTPUT_SIZE_S_L 0x0406 -#define RJ54N1_XY_OUTPUT_SIZE_P_H 0x0407 -#define RJ54N1_X_OUTPUT_SIZE_P_L 0x0408 -#define RJ54N1_Y_OUTPUT_SIZE_P_L 0x0409 -#define RJ54N1_LINE_LENGTH_PCK_S_H 0x040a -#define RJ54N1_LINE_LENGTH_PCK_S_L 0x040b -#define RJ54N1_LINE_LENGTH_PCK_P_H 0x040c -#define RJ54N1_LINE_LENGTH_PCK_P_L 0x040d -#define RJ54N1_RESIZE_N 0x040e -#define RJ54N1_RESIZE_N_STEP 0x040f -#define RJ54N1_RESIZE_STEP 0x0410 -#define RJ54N1_RESIZE_HOLD_H 0x0411 -#define RJ54N1_RESIZE_HOLD_L 0x0412 -#define RJ54N1_H_OBEN_OFS 0x0413 -#define RJ54N1_V_OBEN_OFS 0x0414 -#define RJ54N1_RESIZE_CONTROL 0x0415 -#define RJ54N1_STILL_CONTROL 0x0417 -#define RJ54N1_INC_USE_SEL_H 0x0425 -#define RJ54N1_INC_USE_SEL_L 0x0426 -#define RJ54N1_MIRROR_STILL_MODE 0x0427 -#define RJ54N1_INIT_START 0x0428 -#define RJ54N1_SCALE_1_2_LEV 0x0429 -#define RJ54N1_SCALE_4_LEV 0x042a -#define RJ54N1_Y_GAIN 0x04d8 -#define RJ54N1_APT_GAIN_UP 0x04fa -#define RJ54N1_RA_SEL_UL 0x0530 -#define RJ54N1_BYTE_SWAP 0x0531 -#define RJ54N1_OUT_SIGPO 0x053b -#define RJ54N1_WB_SEL_WEIGHT_I 0x054e -#define RJ54N1_BIT8_WB 0x0569 -#define RJ54N1_HCAPS_WB 0x056a -#define RJ54N1_VCAPS_WB 0x056b -#define RJ54N1_HCAPE_WB 0x056c -#define RJ54N1_VCAPE_WB 0x056d -#define RJ54N1_EXPOSURE_CONTROL 0x058c -#define RJ54N1_FRAME_LENGTH_S_H 0x0595 -#define RJ54N1_FRAME_LENGTH_S_L 0x0596 -#define RJ54N1_FRAME_LENGTH_P_H 0x0597 -#define RJ54N1_FRAME_LENGTH_P_L 0x0598 -#define RJ54N1_PEAK_H 0x05b7 -#define RJ54N1_PEAK_50 0x05b8 -#define RJ54N1_PEAK_60 0x05b9 -#define RJ54N1_PEAK_DIFF 0x05ba -#define RJ54N1_IOC 0x05ef -#define RJ54N1_TG_BYPASS 0x0700 -#define RJ54N1_PLL_L 0x0701 -#define RJ54N1_PLL_N 0x0702 -#define RJ54N1_PLL_EN 0x0704 -#define RJ54N1_RATIO_TG 0x0706 -#define RJ54N1_RATIO_T 0x0707 -#define RJ54N1_RATIO_R 0x0708 -#define RJ54N1_RAMP_TGCLK_EN 0x0709 -#define RJ54N1_OCLK_DSP 0x0710 -#define RJ54N1_RATIO_OP 0x0711 -#define RJ54N1_RATIO_O 0x0712 -#define RJ54N1_OCLK_SEL_EN 0x0713 -#define RJ54N1_CLK_RST 0x0717 -#define RJ54N1_RESET_STANDBY 0x0718 -#define RJ54N1_FWFLG 0x07fe - -#define E_EXCLK (1 << 7) -#define SOFT_STDBY (1 << 4) -#define SEN_RSTX (1 << 2) -#define TG_RSTX (1 << 1) -#define DSP_RSTX (1 << 0) - -#define RESIZE_HOLD_SEL (1 << 2) -#define RESIZE_GO (1 << 1) - -/* - * When cropping, the camera automatically centers the cropped region, there - * doesn't seem to be a way to specify an explicit location of the rectangle. - */ -#define RJ54N1_COLUMN_SKIP 0 -#define RJ54N1_ROW_SKIP 0 -#define RJ54N1_MAX_WIDTH 1600 -#define RJ54N1_MAX_HEIGHT 1200 - -#define PLL_L 2 -#define PLL_N 0x31 - -/* I2C addresses: 0x50, 0x51, 0x60, 0x61 */ - -/* RJ54N1CB0C has only one fixed colorspace per pixelcode */ -struct rj54n1_datafmt { - u32 code; - enum v4l2_colorspace colorspace; -}; - -/* Find a data format by a pixel code in an array */ -static const struct rj54n1_datafmt *rj54n1_find_datafmt( - u32 code, const struct rj54n1_datafmt *fmt, - int n) -{ - int i; - for (i = 0; i < n; i++) - if (fmt[i].code == code) - return fmt + i; - - return NULL; -} - -static const struct rj54n1_datafmt rj54n1_colour_fmts[] = { - {MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG}, - {MEDIA_BUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG}, - {MEDIA_BUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB}, - {MEDIA_BUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB}, - {MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB}, - {MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE, V4L2_COLORSPACE_SRGB}, - {MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE, V4L2_COLORSPACE_SRGB}, - {MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE, V4L2_COLORSPACE_SRGB}, - {MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB}, -}; - -struct rj54n1_clock_div { - u8 ratio_tg; /* can be 0 or an odd number */ - u8 ratio_t; - u8 ratio_r; - u8 ratio_op; - u8 ratio_o; -}; - -struct rj54n1 { - struct v4l2_subdev subdev; - struct v4l2_ctrl_handler hdl; - struct v4l2_clk *clk; - struct rj54n1_clock_div clk_div; - const struct rj54n1_datafmt *fmt; - struct v4l2_rect rect; /* Sensor window */ - unsigned int tgclk_mhz; - bool auto_wb; - unsigned short width; /* Output window */ - unsigned short height; - unsigned short resize; /* Sensor * 1024 / resize = Output */ - unsigned short scale; - u8 bank; -}; - -struct rj54n1_reg_val { - u16 reg; - u8 val; -}; - -static const struct rj54n1_reg_val bank_4[] = { - {0x417, 0}, - {0x42c, 0}, - {0x42d, 0xf0}, - {0x42e, 0}, - {0x42f, 0x50}, - {0x430, 0xf5}, - {0x431, 0x16}, - {0x432, 0x20}, - {0x433, 0}, - {0x434, 0xc8}, - {0x43c, 8}, - {0x43e, 0x90}, - {0x445, 0x83}, - {0x4ba, 0x58}, - {0x4bb, 4}, - {0x4bc, 0x20}, - {0x4db, 4}, - {0x4fe, 2}, -}; - -static const struct rj54n1_reg_val bank_5[] = { - {0x514, 0}, - {0x516, 0}, - {0x518, 0}, - {0x51a, 0}, - {0x51d, 0xff}, - {0x56f, 0x28}, - {0x575, 0x40}, - {0x5bc, 0x48}, - {0x5c1, 6}, - {0x5e5, 0x11}, - {0x5e6, 0x43}, - {0x5e7, 0x33}, - {0x5e8, 0x21}, - {0x5e9, 0x30}, - {0x5ea, 0x0}, - {0x5eb, 0xa5}, - {0x5ec, 0xff}, - {0x5fe, 2}, -}; - -static const struct rj54n1_reg_val bank_7[] = { - {0x70a, 0}, - {0x714, 0xff}, - {0x715, 0xff}, - {0x716, 0x1f}, - {0x7FE, 2}, -}; - -static const struct rj54n1_reg_val bank_8[] = { - {0x800, 0x00}, - {0x801, 0x01}, - {0x802, 0x61}, - {0x805, 0x00}, - {0x806, 0x00}, - {0x807, 0x00}, - {0x808, 0x00}, - {0x809, 0x01}, - {0x80A, 0x61}, - {0x80B, 0x00}, - {0x80C, 0x01}, - {0x80D, 0x00}, - {0x80E, 0x00}, - {0x80F, 0x00}, - {0x810, 0x00}, - {0x811, 0x01}, - {0x812, 0x61}, - {0x813, 0x00}, - {0x814, 0x11}, - {0x815, 0x00}, - {0x816, 0x41}, - {0x817, 0x00}, - {0x818, 0x51}, - {0x819, 0x01}, - {0x81A, 0x1F}, - {0x81B, 0x00}, - {0x81C, 0x01}, - {0x81D, 0x00}, - {0x81E, 0x11}, - {0x81F, 0x00}, - {0x820, 0x41}, - {0x821, 0x00}, - {0x822, 0x51}, - {0x823, 0x00}, - {0x824, 0x00}, - {0x825, 0x00}, - {0x826, 0x47}, - {0x827, 0x01}, - {0x828, 0x4F}, - {0x829, 0x00}, - {0x82A, 0x00}, - {0x82B, 0x00}, - {0x82C, 0x30}, - {0x82D, 0x00}, - {0x82E, 0x40}, - {0x82F, 0x00}, - {0x830, 0xB3}, - {0x831, 0x00}, - {0x832, 0xE3}, - {0x833, 0x00}, - {0x834, 0x00}, - {0x835, 0x00}, - {0x836, 0x00}, - {0x837, 0x00}, - {0x838, 0x00}, - {0x839, 0x01}, - {0x83A, 0x61}, - {0x83B, 0x00}, - {0x83C, 0x01}, - {0x83D, 0x00}, - {0x83E, 0x00}, - {0x83F, 0x00}, - {0x840, 0x00}, - {0x841, 0x01}, - {0x842, 0x61}, - {0x843, 0x00}, - {0x844, 0x1D}, - {0x845, 0x00}, - {0x846, 0x00}, - {0x847, 0x00}, - {0x848, 0x00}, - {0x849, 0x01}, - {0x84A, 0x1F}, - {0x84B, 0x00}, - {0x84C, 0x05}, - {0x84D, 0x00}, - {0x84E, 0x19}, - {0x84F, 0x01}, - {0x850, 0x21}, - {0x851, 0x01}, - {0x852, 0x5D}, - {0x853, 0x00}, - {0x854, 0x00}, - {0x855, 0x00}, - {0x856, 0x19}, - {0x857, 0x01}, - {0x858, 0x21}, - {0x859, 0x00}, - {0x85A, 0x00}, - {0x85B, 0x00}, - {0x85C, 0x00}, - {0x85D, 0x00}, - {0x85E, 0x00}, - {0x85F, 0x00}, - {0x860, 0xB3}, - {0x861, 0x00}, - {0x862, 0xE3}, - {0x863, 0x00}, - {0x864, 0x00}, - {0x865, 0x00}, - {0x866, 0x00}, - {0x867, 0x00}, - {0x868, 0x00}, - {0x869, 0xE2}, - {0x86A, 0x00}, - {0x86B, 0x01}, - {0x86C, 0x06}, - {0x86D, 0x00}, - {0x86E, 0x00}, - {0x86F, 0x00}, - {0x870, 0x60}, - {0x871, 0x8C}, - {0x872, 0x10}, - {0x873, 0x00}, - {0x874, 0xE0}, - {0x875, 0x00}, - {0x876, 0x27}, - {0x877, 0x01}, - {0x878, 0x00}, - {0x879, 0x00}, - {0x87A, 0x00}, - {0x87B, 0x03}, - {0x87C, 0x00}, - {0x87D, 0x00}, - {0x87E, 0x00}, - {0x87F, 0x00}, - {0x880, 0x00}, - {0x881, 0x00}, - {0x882, 0x00}, - {0x883, 0x00}, - {0x884, 0x00}, - {0x885, 0x00}, - {0x886, 0xF8}, - {0x887, 0x00}, - {0x888, 0x03}, - {0x889, 0x00}, - {0x88A, 0x64}, - {0x88B, 0x00}, - {0x88C, 0x03}, - {0x88D, 0x00}, - {0x88E, 0xB1}, - {0x88F, 0x00}, - {0x890, 0x03}, - {0x891, 0x01}, - {0x892, 0x1D}, - {0x893, 0x00}, - {0x894, 0x03}, - {0x895, 0x01}, - {0x896, 0x4B}, - {0x897, 0x00}, - {0x898, 0xE5}, - {0x899, 0x00}, - {0x89A, 0x01}, - {0x89B, 0x00}, - {0x89C, 0x01}, - {0x89D, 0x04}, - {0x89E, 0xC8}, - {0x89F, 0x00}, - {0x8A0, 0x01}, - {0x8A1, 0x01}, - {0x8A2, 0x61}, - {0x8A3, 0x00}, - {0x8A4, 0x01}, - {0x8A5, 0x00}, - {0x8A6, 0x00}, - {0x8A7, 0x00}, - {0x8A8, 0x00}, - {0x8A9, 0x00}, - {0x8AA, 0x7F}, - {0x8AB, 0x03}, - {0x8AC, 0x00}, - {0x8AD, 0x00}, - {0x8AE, 0x00}, - {0x8AF, 0x00}, - {0x8B0, 0x00}, - {0x8B1, 0x00}, - {0x8B6, 0x00}, - {0x8B7, 0x01}, - {0x8B8, 0x00}, - {0x8B9, 0x00}, - {0x8BA, 0x02}, - {0x8BB, 0x00}, - {0x8BC, 0xFF}, - {0x8BD, 0x00}, - {0x8FE, 2}, -}; - -static const struct rj54n1_reg_val bank_10[] = { - {0x10bf, 0x69} -}; - -/* Clock dividers - these are default register values, divider = register + 1 */ -static const struct rj54n1_clock_div clk_div = { - .ratio_tg = 3 /* default: 5 */, - .ratio_t = 4 /* default: 1 */, - .ratio_r = 4 /* default: 0 */, - .ratio_op = 1 /* default: 5 */, - .ratio_o = 9 /* default: 0 */, -}; - -static struct rj54n1 *to_rj54n1(const struct i2c_client *client) -{ - return container_of(i2c_get_clientdata(client), struct rj54n1, subdev); -} - -static int reg_read(struct i2c_client *client, const u16 reg) -{ - struct rj54n1 *rj54n1 = to_rj54n1(client); - int ret; - - /* set bank */ - if (rj54n1->bank != reg >> 8) { - dev_dbg(&client->dev, "[0x%x] = 0x%x\n", 0xff, reg >> 8); - ret = i2c_smbus_write_byte_data(client, 0xff, reg >> 8); - if (ret < 0) - return ret; - rj54n1->bank = reg >> 8; - } - return i2c_smbus_read_byte_data(client, reg & 0xff); -} - -static int reg_write(struct i2c_client *client, const u16 reg, - const u8 data) -{ - struct rj54n1 *rj54n1 = to_rj54n1(client); - int ret; - - /* set bank */ - if (rj54n1->bank != reg >> 8) { - dev_dbg(&client->dev, "[0x%x] = 0x%x\n", 0xff, reg >> 8); - ret = i2c_smbus_write_byte_data(client, 0xff, reg >> 8); - if (ret < 0) - return ret; - rj54n1->bank = reg >> 8; - } - dev_dbg(&client->dev, "[0x%x] = 0x%x\n", reg & 0xff, data); - return i2c_smbus_write_byte_data(client, reg & 0xff, data); -} - -static int reg_set(struct i2c_client *client, const u16 reg, - const u8 data, const u8 mask) -{ - int ret; - - ret = reg_read(client, reg); - if (ret < 0) - return ret; - return reg_write(client, reg, (ret & ~mask) | (data & mask)); -} - -static int reg_write_multiple(struct i2c_client *client, - const struct rj54n1_reg_val *rv, const int n) -{ - int i, ret; - - for (i = 0; i < n; i++) { - ret = reg_write(client, rv->reg, rv->val); - if (ret < 0) - return ret; - rv++; - } - - return 0; -} - -static int rj54n1_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (code->pad || code->index >= ARRAY_SIZE(rj54n1_colour_fmts)) - return -EINVAL; - - code->code = rj54n1_colour_fmts[code->index].code; - return 0; -} - -static int rj54n1_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - /* Switch between preview and still shot modes */ - return reg_set(client, RJ54N1_STILL_CONTROL, (!enable) << 7, 0x80); -} - -static int rj54n1_set_rect(struct i2c_client *client, - u16 reg_x, u16 reg_y, u16 reg_xy, - u32 width, u32 height) -{ - int ret; - - ret = reg_write(client, reg_xy, - ((width >> 4) & 0x70) | - ((height >> 8) & 7)); - - if (!ret) - ret = reg_write(client, reg_x, width & 0xff); - if (!ret) - ret = reg_write(client, reg_y, height & 0xff); - - return ret; -} - -/* - * Some commands, specifically certain initialisation sequences, require - * a commit operation. - */ -static int rj54n1_commit(struct i2c_client *client) -{ - int ret = reg_write(client, RJ54N1_INIT_START, 1); - msleep(10); - if (!ret) - ret = reg_write(client, RJ54N1_INIT_START, 0); - return ret; -} - -static int rj54n1_sensor_scale(struct v4l2_subdev *sd, s32 *in_w, s32 *in_h, - s32 *out_w, s32 *out_h); - -static int rj54n1_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct rj54n1 *rj54n1 = to_rj54n1(client); - const struct v4l2_rect *rect = &sel->r; - int dummy = 0, output_w, output_h, - input_w = rect->width, input_h = rect->height; - int ret; - - if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || - sel->target != V4L2_SEL_TGT_CROP) - return -EINVAL; - - /* arbitrary minimum width and height, edges unimportant */ - soc_camera_limit_side(&dummy, &input_w, - RJ54N1_COLUMN_SKIP, 8, RJ54N1_MAX_WIDTH); - - soc_camera_limit_side(&dummy, &input_h, - RJ54N1_ROW_SKIP, 8, RJ54N1_MAX_HEIGHT); - - output_w = (input_w * 1024 + rj54n1->resize / 2) / rj54n1->resize; - output_h = (input_h * 1024 + rj54n1->resize / 2) / rj54n1->resize; - - dev_dbg(&client->dev, "Scaling for %dx%d : %u = %dx%d\n", - input_w, input_h, rj54n1->resize, output_w, output_h); - - ret = rj54n1_sensor_scale(sd, &input_w, &input_h, &output_w, &output_h); - if (ret < 0) - return ret; - - rj54n1->width = output_w; - rj54n1->height = output_h; - rj54n1->resize = ret; - rj54n1->rect.width = input_w; - rj54n1->rect.height = input_h; - - return 0; -} - -static int rj54n1_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct rj54n1 *rj54n1 = to_rj54n1(client); - - if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - switch (sel->target) { - case V4L2_SEL_TGT_CROP_BOUNDS: - sel->r.left = RJ54N1_COLUMN_SKIP; - sel->r.top = RJ54N1_ROW_SKIP; - sel->r.width = RJ54N1_MAX_WIDTH; - sel->r.height = RJ54N1_MAX_HEIGHT; - return 0; - case V4L2_SEL_TGT_CROP: - sel->r = rj54n1->rect; - return 0; - default: - return -EINVAL; - } -} - -static int rj54n1_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *mf = &format->format; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct rj54n1 *rj54n1 = to_rj54n1(client); - - if (format->pad) - return -EINVAL; - - mf->code = rj54n1->fmt->code; - mf->colorspace = rj54n1->fmt->colorspace; - mf->field = V4L2_FIELD_NONE; - mf->width = rj54n1->width; - mf->height = rj54n1->height; - - return 0; -} - -/* - * The actual geometry configuration routine. It scales the input window into - * the output one, updates the window sizes and returns an error or the resize - * coefficient on success. Note: we only use the "Fixed Scaling" on this camera. - */ -static int rj54n1_sensor_scale(struct v4l2_subdev *sd, s32 *in_w, s32 *in_h, - s32 *out_w, s32 *out_h) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct rj54n1 *rj54n1 = to_rj54n1(client); - unsigned int skip, resize, input_w = *in_w, input_h = *in_h, - output_w = *out_w, output_h = *out_h; - u16 inc_sel, wb_bit8, wb_left, wb_right, wb_top, wb_bottom; - unsigned int peak, peak_50, peak_60; - int ret; - - /* - * We have a problem with crops, where the window is larger than 512x384 - * and output window is larger than a half of the input one. In this - * case we have to either reduce the input window to equal or below - * 512x384 or the output window to equal or below 1/2 of the input. - */ - if (output_w > max(512U, input_w / 2)) { - if (2 * output_w > RJ54N1_MAX_WIDTH) { - input_w = RJ54N1_MAX_WIDTH; - output_w = RJ54N1_MAX_WIDTH / 2; - } else { - input_w = output_w * 2; - } - - dev_dbg(&client->dev, "Adjusted output width: in %u, out %u\n", - input_w, output_w); - } - - if (output_h > max(384U, input_h / 2)) { - if (2 * output_h > RJ54N1_MAX_HEIGHT) { - input_h = RJ54N1_MAX_HEIGHT; - output_h = RJ54N1_MAX_HEIGHT / 2; - } else { - input_h = output_h * 2; - } - - dev_dbg(&client->dev, "Adjusted output height: in %u, out %u\n", - input_h, output_h); - } - - /* Idea: use the read mode for snapshots, handle separate geometries */ - ret = rj54n1_set_rect(client, RJ54N1_X_OUTPUT_SIZE_S_L, - RJ54N1_Y_OUTPUT_SIZE_S_L, - RJ54N1_XY_OUTPUT_SIZE_S_H, output_w, output_h); - if (!ret) - ret = rj54n1_set_rect(client, RJ54N1_X_OUTPUT_SIZE_P_L, - RJ54N1_Y_OUTPUT_SIZE_P_L, - RJ54N1_XY_OUTPUT_SIZE_P_H, output_w, output_h); - - if (ret < 0) - return ret; - - if (output_w > input_w && output_h > input_h) { - input_w = output_w; - input_h = output_h; - - resize = 1024; - } else { - unsigned int resize_x, resize_y; - resize_x = (input_w * 1024 + output_w / 2) / output_w; - resize_y = (input_h * 1024 + output_h / 2) / output_h; - - /* We want max(resize_x, resize_y), check if it still fits */ - if (resize_x > resize_y && - (output_h * resize_x + 512) / 1024 > RJ54N1_MAX_HEIGHT) - resize = (RJ54N1_MAX_HEIGHT * 1024 + output_h / 2) / - output_h; - else if (resize_y > resize_x && - (output_w * resize_y + 512) / 1024 > RJ54N1_MAX_WIDTH) - resize = (RJ54N1_MAX_WIDTH * 1024 + output_w / 2) / - output_w; - else - resize = max(resize_x, resize_y); - - /* Prohibited value ranges */ - switch (resize) { - case 2040 ... 2047: - resize = 2039; - break; - case 4080 ... 4095: - resize = 4079; - break; - case 8160 ... 8191: - resize = 8159; - break; - case 16320 ... 16384: - resize = 16319; - } - } - - /* Set scaling */ - ret = reg_write(client, RJ54N1_RESIZE_HOLD_L, resize & 0xff); - if (!ret) - ret = reg_write(client, RJ54N1_RESIZE_HOLD_H, resize >> 8); - - if (ret < 0) - return ret; - - /* - * Configure a skipping bitmask. The sensor will select a skipping value - * among set bits automatically. This is very unclear in the datasheet - * too. I was told, in this register one enables all skipping values, - * that are required for a specific resize, and the camera selects - * automatically, which ones to use. But it is unclear how to identify, - * which cropping values are needed. Secondly, why don't we just set all - * bits and let the camera choose? Would it increase processing time and - * reduce the framerate? Using 0xfffc for INC_USE_SEL doesn't seem to - * improve the image quality or stability for larger frames (see comment - * above), but I didn't check the framerate. - */ - skip = min(resize / 1024, 15U); - - inc_sel = 1 << skip; - - if (inc_sel <= 2) - inc_sel = 0xc; - else if (resize & 1023 && skip < 15) - inc_sel |= 1 << (skip + 1); - - ret = reg_write(client, RJ54N1_INC_USE_SEL_L, inc_sel & 0xfc); - if (!ret) - ret = reg_write(client, RJ54N1_INC_USE_SEL_H, inc_sel >> 8); - - if (!rj54n1->auto_wb) { - /* Auto white balance window */ - wb_left = output_w / 16; - wb_right = (3 * output_w / 4 - 3) / 4; - wb_top = output_h / 16; - wb_bottom = (3 * output_h / 4 - 3) / 4; - wb_bit8 = ((wb_left >> 2) & 0x40) | ((wb_top >> 4) & 0x10) | - ((wb_right >> 6) & 4) | ((wb_bottom >> 8) & 1); - - if (!ret) - ret = reg_write(client, RJ54N1_BIT8_WB, wb_bit8); - if (!ret) - ret = reg_write(client, RJ54N1_HCAPS_WB, wb_left); - if (!ret) - ret = reg_write(client, RJ54N1_VCAPS_WB, wb_top); - if (!ret) - ret = reg_write(client, RJ54N1_HCAPE_WB, wb_right); - if (!ret) - ret = reg_write(client, RJ54N1_VCAPE_WB, wb_bottom); - } - - /* Antiflicker */ - peak = 12 * RJ54N1_MAX_WIDTH * (1 << 14) * resize / rj54n1->tgclk_mhz / - 10000; - peak_50 = peak / 6; - peak_60 = peak / 5; - - if (!ret) - ret = reg_write(client, RJ54N1_PEAK_H, - ((peak_50 >> 4) & 0xf0) | (peak_60 >> 8)); - if (!ret) - ret = reg_write(client, RJ54N1_PEAK_50, peak_50); - if (!ret) - ret = reg_write(client, RJ54N1_PEAK_60, peak_60); - if (!ret) - ret = reg_write(client, RJ54N1_PEAK_DIFF, peak / 150); - - /* Start resizing */ - if (!ret) - ret = reg_write(client, RJ54N1_RESIZE_CONTROL, - RESIZE_HOLD_SEL | RESIZE_GO | 1); - - if (ret < 0) - return ret; - - /* Constant taken from manufacturer's example */ - msleep(230); - - ret = reg_write(client, RJ54N1_RESIZE_CONTROL, RESIZE_HOLD_SEL | 1); - if (ret < 0) - return ret; - - *in_w = (output_w * resize + 512) / 1024; - *in_h = (output_h * resize + 512) / 1024; - *out_w = output_w; - *out_h = output_h; - - dev_dbg(&client->dev, "Scaled for %dx%d : %u = %ux%u, skip %u\n", - *in_w, *in_h, resize, output_w, output_h, skip); - - return resize; -} - -static int rj54n1_set_clock(struct i2c_client *client) -{ - struct rj54n1 *rj54n1 = to_rj54n1(client); - int ret; - - /* Enable external clock */ - ret = reg_write(client, RJ54N1_RESET_STANDBY, E_EXCLK | SOFT_STDBY); - /* Leave stand-by. Note: use this when implementing suspend / resume */ - if (!ret) - ret = reg_write(client, RJ54N1_RESET_STANDBY, E_EXCLK); - - if (!ret) - ret = reg_write(client, RJ54N1_PLL_L, PLL_L); - if (!ret) - ret = reg_write(client, RJ54N1_PLL_N, PLL_N); - - /* TGCLK dividers */ - if (!ret) - ret = reg_write(client, RJ54N1_RATIO_TG, - rj54n1->clk_div.ratio_tg); - if (!ret) - ret = reg_write(client, RJ54N1_RATIO_T, - rj54n1->clk_div.ratio_t); - if (!ret) - ret = reg_write(client, RJ54N1_RATIO_R, - rj54n1->clk_div.ratio_r); - - /* Enable TGCLK & RAMP */ - if (!ret) - ret = reg_write(client, RJ54N1_RAMP_TGCLK_EN, 3); - - /* Disable clock output */ - if (!ret) - ret = reg_write(client, RJ54N1_OCLK_DSP, 0); - - /* Set divisors */ - if (!ret) - ret = reg_write(client, RJ54N1_RATIO_OP, - rj54n1->clk_div.ratio_op); - if (!ret) - ret = reg_write(client, RJ54N1_RATIO_O, - rj54n1->clk_div.ratio_o); - - /* Enable OCLK */ - if (!ret) - ret = reg_write(client, RJ54N1_OCLK_SEL_EN, 1); - - /* Use PLL for Timing Generator, write 2 to reserved bits */ - if (!ret) - ret = reg_write(client, RJ54N1_TG_BYPASS, 2); - - /* Take sensor out of reset */ - if (!ret) - ret = reg_write(client, RJ54N1_RESET_STANDBY, - E_EXCLK | SEN_RSTX); - /* Enable PLL */ - if (!ret) - ret = reg_write(client, RJ54N1_PLL_EN, 1); - - /* Wait for PLL to stabilise */ - msleep(10); - - /* Enable clock to frequency divider */ - if (!ret) - ret = reg_write(client, RJ54N1_CLK_RST, 1); - - if (!ret) - ret = reg_read(client, RJ54N1_CLK_RST); - if (ret != 1) { - dev_err(&client->dev, - "Resetting RJ54N1CB0C clock failed: %d!\n", ret); - return -EIO; - } - - /* Start the PLL */ - ret = reg_set(client, RJ54N1_OCLK_DSP, 1, 1); - - /* Enable OCLK */ - if (!ret) - ret = reg_write(client, RJ54N1_OCLK_SEL_EN, 1); - - return ret; -} - -static int rj54n1_reg_init(struct i2c_client *client) -{ - struct rj54n1 *rj54n1 = to_rj54n1(client); - int ret = rj54n1_set_clock(client); - - if (!ret) - ret = reg_write_multiple(client, bank_7, ARRAY_SIZE(bank_7)); - if (!ret) - ret = reg_write_multiple(client, bank_10, ARRAY_SIZE(bank_10)); - - /* Set binning divisors */ - if (!ret) - ret = reg_write(client, RJ54N1_SCALE_1_2_LEV, 3 | (7 << 4)); - if (!ret) - ret = reg_write(client, RJ54N1_SCALE_4_LEV, 0xf); - - /* Switch to fixed resize mode */ - if (!ret) - ret = reg_write(client, RJ54N1_RESIZE_CONTROL, - RESIZE_HOLD_SEL | 1); - - /* Set gain */ - if (!ret) - ret = reg_write(client, RJ54N1_Y_GAIN, 0x84); - - /* - * Mirror the image back: default is upside down and left-to-right... - * Set manual preview / still shot switching - */ - if (!ret) - ret = reg_write(client, RJ54N1_MIRROR_STILL_MODE, 0x27); - - if (!ret) - ret = reg_write_multiple(client, bank_4, ARRAY_SIZE(bank_4)); - - /* Auto exposure area */ - if (!ret) - ret = reg_write(client, RJ54N1_EXPOSURE_CONTROL, 0x80); - /* Check current auto WB config */ - if (!ret) - ret = reg_read(client, RJ54N1_WB_SEL_WEIGHT_I); - if (ret >= 0) { - rj54n1->auto_wb = ret & 0x80; - ret = reg_write_multiple(client, bank_5, ARRAY_SIZE(bank_5)); - } - if (!ret) - ret = reg_write_multiple(client, bank_8, ARRAY_SIZE(bank_8)); - - if (!ret) - ret = reg_write(client, RJ54N1_RESET_STANDBY, - E_EXCLK | DSP_RSTX | SEN_RSTX); - - /* Commit init */ - if (!ret) - ret = rj54n1_commit(client); - - /* Take DSP, TG, sensor out of reset */ - if (!ret) - ret = reg_write(client, RJ54N1_RESET_STANDBY, - E_EXCLK | DSP_RSTX | TG_RSTX | SEN_RSTX); - - /* Start register update? Same register as 0x?FE in many bank_* sets */ - if (!ret) - ret = reg_write(client, RJ54N1_FWFLG, 2); - - /* Constant taken from manufacturer's example */ - msleep(700); - - return ret; -} - -static int rj54n1_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *mf = &format->format; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct rj54n1 *rj54n1 = to_rj54n1(client); - const struct rj54n1_datafmt *fmt; - int output_w, output_h, max_w, max_h, - input_w = rj54n1->rect.width, input_h = rj54n1->rect.height; - int align = mf->code == MEDIA_BUS_FMT_SBGGR10_1X10 || - mf->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE || - mf->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE || - mf->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE || - mf->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE; - int ret; - - if (format->pad) - return -EINVAL; - - dev_dbg(&client->dev, "%s: code = %d, width = %u, height = %u\n", - __func__, mf->code, mf->width, mf->height); - - fmt = rj54n1_find_datafmt(mf->code, rj54n1_colour_fmts, - ARRAY_SIZE(rj54n1_colour_fmts)); - if (!fmt) { - fmt = rj54n1->fmt; - mf->code = fmt->code; - } - - mf->field = V4L2_FIELD_NONE; - mf->colorspace = fmt->colorspace; - - v4l_bound_align_image(&mf->width, 112, RJ54N1_MAX_WIDTH, align, - &mf->height, 84, RJ54N1_MAX_HEIGHT, align, 0); - - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - cfg->try_fmt = *mf; - return 0; - } - - /* - * Verify if the sensor has just been powered on. TODO: replace this - * with proper PM, when a suitable API is available. - */ - ret = reg_read(client, RJ54N1_RESET_STANDBY); - if (ret < 0) - return ret; - - if (!(ret & E_EXCLK)) { - ret = rj54n1_reg_init(client); - if (ret < 0) - return ret; - } - - /* RA_SEL_UL is only relevant for raw modes, ignored otherwise. */ - switch (mf->code) { - case MEDIA_BUS_FMT_YUYV8_2X8: - ret = reg_write(client, RJ54N1_OUT_SEL, 0); - if (!ret) - ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8); - break; - case MEDIA_BUS_FMT_YVYU8_2X8: - ret = reg_write(client, RJ54N1_OUT_SEL, 0); - if (!ret) - ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8); - break; - case MEDIA_BUS_FMT_RGB565_2X8_LE: - ret = reg_write(client, RJ54N1_OUT_SEL, 0x11); - if (!ret) - ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8); - break; - case MEDIA_BUS_FMT_RGB565_2X8_BE: - ret = reg_write(client, RJ54N1_OUT_SEL, 0x11); - if (!ret) - ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8); - break; - case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE: - ret = reg_write(client, RJ54N1_OUT_SEL, 4); - if (!ret) - ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8); - if (!ret) - ret = reg_write(client, RJ54N1_RA_SEL_UL, 0); - break; - case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE: - ret = reg_write(client, RJ54N1_OUT_SEL, 4); - if (!ret) - ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8); - if (!ret) - ret = reg_write(client, RJ54N1_RA_SEL_UL, 8); - break; - case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE: - ret = reg_write(client, RJ54N1_OUT_SEL, 4); - if (!ret) - ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8); - if (!ret) - ret = reg_write(client, RJ54N1_RA_SEL_UL, 0); - break; - case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE: - ret = reg_write(client, RJ54N1_OUT_SEL, 4); - if (!ret) - ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8); - if (!ret) - ret = reg_write(client, RJ54N1_RA_SEL_UL, 8); - break; - case MEDIA_BUS_FMT_SBGGR10_1X10: - ret = reg_write(client, RJ54N1_OUT_SEL, 5); - break; - default: - ret = -EINVAL; - } - - /* Special case: a raw mode with 10 bits of data per clock tick */ - if (!ret) - ret = reg_set(client, RJ54N1_OCLK_SEL_EN, - (mf->code == MEDIA_BUS_FMT_SBGGR10_1X10) << 1, 2); - - if (ret < 0) - return ret; - - /* Supported scales 1:1 >= scale > 1:16 */ - max_w = mf->width * (16 * 1024 - 1) / 1024; - if (input_w > max_w) - input_w = max_w; - max_h = mf->height * (16 * 1024 - 1) / 1024; - if (input_h > max_h) - input_h = max_h; - - output_w = mf->width; - output_h = mf->height; - - ret = rj54n1_sensor_scale(sd, &input_w, &input_h, &output_w, &output_h); - if (ret < 0) - return ret; - - fmt = rj54n1_find_datafmt(mf->code, rj54n1_colour_fmts, - ARRAY_SIZE(rj54n1_colour_fmts)); - - rj54n1->fmt = fmt; - rj54n1->resize = ret; - rj54n1->rect.width = input_w; - rj54n1->rect.height = input_h; - rj54n1->width = output_w; - rj54n1->height = output_h; - - mf->width = output_w; - mf->height = output_h; - mf->field = V4L2_FIELD_NONE; - mf->colorspace = fmt->colorspace; - - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int rj54n1_g_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->reg < 0x400 || reg->reg > 0x1fff) - /* Registers > 0x0800 are only available from Sharp support */ - return -EINVAL; - - reg->size = 1; - reg->val = reg_read(client, reg->reg); - - if (reg->val > 0xff) - return -EIO; - - return 0; -} - -static int rj54n1_s_register(struct v4l2_subdev *sd, - const struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->reg < 0x400 || reg->reg > 0x1fff) - /* Registers >= 0x0800 are only available from Sharp support */ - return -EINVAL; - - if (reg_write(client, reg->reg, reg->val) < 0) - return -EIO; - - return 0; -} -#endif - -static int rj54n1_s_power(struct v4l2_subdev *sd, int on) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - struct rj54n1 *rj54n1 = to_rj54n1(client); - - return soc_camera_set_power(&client->dev, ssdd, rj54n1->clk, on); -} - -static int rj54n1_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct rj54n1 *rj54n1 = container_of(ctrl->handler, struct rj54n1, hdl); - struct v4l2_subdev *sd = &rj54n1->subdev; - struct i2c_client *client = v4l2_get_subdevdata(sd); - int data; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - if (ctrl->val) - data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 0, 1); - else - data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 1, 1); - if (data < 0) - return -EIO; - return 0; - case V4L2_CID_HFLIP: - if (ctrl->val) - data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 0, 2); - else - data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 2, 2); - if (data < 0) - return -EIO; - return 0; - case V4L2_CID_GAIN: - if (reg_write(client, RJ54N1_Y_GAIN, ctrl->val * 2) < 0) - return -EIO; - return 0; - case V4L2_CID_AUTO_WHITE_BALANCE: - /* Auto WB area - whole image */ - if (reg_set(client, RJ54N1_WB_SEL_WEIGHT_I, ctrl->val << 7, - 0x80) < 0) - return -EIO; - rj54n1->auto_wb = ctrl->val; - return 0; - } - - return -EINVAL; -} - -static const struct v4l2_ctrl_ops rj54n1_ctrl_ops = { - .s_ctrl = rj54n1_s_ctrl, -}; - -static const struct v4l2_subdev_core_ops rj54n1_subdev_core_ops = { -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = rj54n1_g_register, - .s_register = rj54n1_s_register, -#endif - .s_power = rj54n1_s_power, -}; - -static int rj54n1_g_mbus_config(struct v4l2_subdev *sd, - struct v4l2_mbus_config *cfg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - - cfg->flags = - V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | - V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH | - V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH; - cfg->type = V4L2_MBUS_PARALLEL; - cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); - - return 0; -} - -static int rj54n1_s_mbus_config(struct v4l2_subdev *sd, - const struct v4l2_mbus_config *cfg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - - /* Figures 2.5-1 to 2.5-3 - default falling pixclk edge */ - if (soc_camera_apply_board_flags(ssdd, cfg) & - V4L2_MBUS_PCLK_SAMPLE_RISING) - return reg_write(client, RJ54N1_OUT_SIGPO, 1 << 4); - else - return reg_write(client, RJ54N1_OUT_SIGPO, 0); -} - -static const struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = { - .s_stream = rj54n1_s_stream, - .g_mbus_config = rj54n1_g_mbus_config, - .s_mbus_config = rj54n1_s_mbus_config, -}; - -static const struct v4l2_subdev_pad_ops rj54n1_subdev_pad_ops = { - .enum_mbus_code = rj54n1_enum_mbus_code, - .get_selection = rj54n1_get_selection, - .set_selection = rj54n1_set_selection, - .get_fmt = rj54n1_get_fmt, - .set_fmt = rj54n1_set_fmt, -}; - -static const struct v4l2_subdev_ops rj54n1_subdev_ops = { - .core = &rj54n1_subdev_core_ops, - .video = &rj54n1_subdev_video_ops, - .pad = &rj54n1_subdev_pad_ops, -}; - -/* - * Interface active, can use i2c. If it fails, it can indeed mean, that - * this wasn't our capture interface, so, we wait for the right one - */ -static int rj54n1_video_probe(struct i2c_client *client, - struct rj54n1_pdata *priv) -{ - struct rj54n1 *rj54n1 = to_rj54n1(client); - int data1, data2; - int ret; - - ret = rj54n1_s_power(&rj54n1->subdev, 1); - if (ret < 0) - return ret; - - /* Read out the chip version register */ - data1 = reg_read(client, RJ54N1_DEV_CODE); - data2 = reg_read(client, RJ54N1_DEV_CODE2); - - if (data1 != 0x51 || data2 != 0x10) { - ret = -ENODEV; - dev_info(&client->dev, "No RJ54N1CB0C found, read 0x%x:0x%x\n", - data1, data2); - goto done; - } - - /* Configure IOCTL polarity from the platform data: 0 or 1 << 7. */ - ret = reg_write(client, RJ54N1_IOC, priv->ioctl_high << 7); - if (ret < 0) - goto done; - - dev_info(&client->dev, "Detected a RJ54N1CB0C chip ID 0x%x:0x%x\n", - data1, data2); - - ret = v4l2_ctrl_handler_setup(&rj54n1->hdl); - -done: - rj54n1_s_power(&rj54n1->subdev, 0); - return ret; -} - -static int rj54n1_probe(struct i2c_client *client, - const struct i2c_device_id *did) -{ - struct rj54n1 *rj54n1; - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct rj54n1_pdata *rj54n1_priv; - int ret; - - if (!ssdd || !ssdd->drv_priv) { - dev_err(&client->dev, "RJ54N1CB0C: missing platform data!\n"); - return -EINVAL; - } - - rj54n1_priv = ssdd->drv_priv; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { - dev_warn(&adapter->dev, - "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE\n"); - return -EIO; - } - - rj54n1 = devm_kzalloc(&client->dev, sizeof(struct rj54n1), GFP_KERNEL); - if (!rj54n1) - return -ENOMEM; - - v4l2_i2c_subdev_init(&rj54n1->subdev, client, &rj54n1_subdev_ops); - v4l2_ctrl_handler_init(&rj54n1->hdl, 4); - v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops, - V4L2_CID_VFLIP, 0, 1, 1, 0); - v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops, - V4L2_CID_HFLIP, 0, 1, 1, 0); - v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops, - V4L2_CID_GAIN, 0, 127, 1, 66); - v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops, - V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); - rj54n1->subdev.ctrl_handler = &rj54n1->hdl; - if (rj54n1->hdl.error) - return rj54n1->hdl.error; - - rj54n1->clk_div = clk_div; - rj54n1->rect.left = RJ54N1_COLUMN_SKIP; - rj54n1->rect.top = RJ54N1_ROW_SKIP; - rj54n1->rect.width = RJ54N1_MAX_WIDTH; - rj54n1->rect.height = RJ54N1_MAX_HEIGHT; - rj54n1->width = RJ54N1_MAX_WIDTH; - rj54n1->height = RJ54N1_MAX_HEIGHT; - rj54n1->fmt = &rj54n1_colour_fmts[0]; - rj54n1->resize = 1024; - rj54n1->tgclk_mhz = (rj54n1_priv->mclk_freq / PLL_L * PLL_N) / - (clk_div.ratio_tg + 1) / (clk_div.ratio_t + 1); - - rj54n1->clk = v4l2_clk_get(&client->dev, "mclk"); - if (IS_ERR(rj54n1->clk)) { - ret = PTR_ERR(rj54n1->clk); - goto eclkget; - } - - ret = rj54n1_video_probe(client, rj54n1_priv); - if (ret < 0) { - v4l2_clk_put(rj54n1->clk); -eclkget: - v4l2_ctrl_handler_free(&rj54n1->hdl); - } - - return ret; -} - -static int rj54n1_remove(struct i2c_client *client) -{ - struct rj54n1 *rj54n1 = to_rj54n1(client); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - - v4l2_clk_put(rj54n1->clk); - v4l2_device_unregister_subdev(&rj54n1->subdev); - if (ssdd->free_bus) - ssdd->free_bus(ssdd); - v4l2_ctrl_handler_free(&rj54n1->hdl); - - return 0; -} - -static const struct i2c_device_id rj54n1_id[] = { - { "rj54n1cb0c", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, rj54n1_id); - -static struct i2c_driver rj54n1_i2c_driver = { - .driver = { - .name = "rj54n1cb0c", - }, - .probe = rj54n1_probe, - .remove = rj54n1_remove, - .id_table = rj54n1_id, -}; - -module_i2c_driver(rj54n1_i2c_driver); - -MODULE_DESCRIPTION("Sharp RJ54N1CB0C Camera driver"); -MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/soc_camera/soc_tw9910.c b/drivers/media/i2c/soc_camera/soc_tw9910.c deleted file mode 100644 index bdb5e0a431e9..000000000000 --- a/drivers/media/i2c/soc_camera/soc_tw9910.c +++ /dev/null @@ -1,999 +0,0 @@ -/* - * tw9910 Video Driver - * - * Copyright (C) 2008 Renesas Solutions Corp. - * Kuninori Morimoto <morimoto.kuninori@renesas.com> - * - * Based on ov772x driver, - * - * Copyright (C) 2008 Kuninori Morimoto <morimoto.kuninori@renesas.com> - * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net> - * Copyright (C) 2008 Magnus Damm - * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/i2c.h> -#include <linux/slab.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/v4l2-mediabus.h> -#include <linux/videodev2.h> - -#include <media/soc_camera.h> -#include <media/i2c/tw9910.h> -#include <media/v4l2-clk.h> -#include <media/v4l2-subdev.h> - -#define GET_ID(val) ((val & 0xF8) >> 3) -#define GET_REV(val) (val & 0x07) - -/* - * register offset - */ -#define ID 0x00 /* Product ID Code Register */ -#define STATUS1 0x01 /* Chip Status Register I */ -#define INFORM 0x02 /* Input Format */ -#define OPFORM 0x03 /* Output Format Control Register */ -#define DLYCTR 0x04 /* Hysteresis and HSYNC Delay Control */ -#define OUTCTR1 0x05 /* Output Control I */ -#define ACNTL1 0x06 /* Analog Control Register 1 */ -#define CROP_HI 0x07 /* Cropping Register, High */ -#define VDELAY_LO 0x08 /* Vertical Delay Register, Low */ -#define VACTIVE_LO 0x09 /* Vertical Active Register, Low */ -#define HDELAY_LO 0x0A /* Horizontal Delay Register, Low */ -#define HACTIVE_LO 0x0B /* Horizontal Active Register, Low */ -#define CNTRL1 0x0C /* Control Register I */ -#define VSCALE_LO 0x0D /* Vertical Scaling Register, Low */ -#define SCALE_HI 0x0E /* Scaling Register, High */ -#define HSCALE_LO 0x0F /* Horizontal Scaling Register, Low */ -#define BRIGHT 0x10 /* BRIGHTNESS Control Register */ -#define CONTRAST 0x11 /* CONTRAST Control Register */ -#define SHARPNESS 0x12 /* SHARPNESS Control Register I */ -#define SAT_U 0x13 /* Chroma (U) Gain Register */ -#define SAT_V 0x14 /* Chroma (V) Gain Register */ -#define HUE 0x15 /* Hue Control Register */ -#define CORING1 0x17 -#define CORING2 0x18 /* Coring and IF compensation */ -#define VBICNTL 0x19 /* VBI Control Register */ -#define ACNTL2 0x1A /* Analog Control 2 */ -#define OUTCTR2 0x1B /* Output Control 2 */ -#define SDT 0x1C /* Standard Selection */ -#define SDTR 0x1D /* Standard Recognition */ -#define TEST 0x1F /* Test Control Register */ -#define CLMPG 0x20 /* Clamping Gain */ -#define IAGC 0x21 /* Individual AGC Gain */ -#define AGCGAIN 0x22 /* AGC Gain */ -#define PEAKWT 0x23 /* White Peak Threshold */ -#define CLMPL 0x24 /* Clamp level */ -#define SYNCT 0x25 /* Sync Amplitude */ -#define MISSCNT 0x26 /* Sync Miss Count Register */ -#define PCLAMP 0x27 /* Clamp Position Register */ -#define VCNTL1 0x28 /* Vertical Control I */ -#define VCNTL2 0x29 /* Vertical Control II */ -#define CKILL 0x2A /* Color Killer Level Control */ -#define COMB 0x2B /* Comb Filter Control */ -#define LDLY 0x2C /* Luma Delay and H Filter Control */ -#define MISC1 0x2D /* Miscellaneous Control I */ -#define LOOP 0x2E /* LOOP Control Register */ -#define MISC2 0x2F /* Miscellaneous Control II */ -#define MVSN 0x30 /* Macrovision Detection */ -#define STATUS2 0x31 /* Chip STATUS II */ -#define HFREF 0x32 /* H monitor */ -#define CLMD 0x33 /* CLAMP MODE */ -#define IDCNTL 0x34 /* ID Detection Control */ -#define CLCNTL1 0x35 /* Clamp Control I */ -#define ANAPLLCTL 0x4C -#define VBIMIN 0x4D -#define HSLOWCTL 0x4E -#define WSS3 0x4F -#define FILLDATA 0x50 -#define SDID 0x51 -#define DID 0x52 -#define WSS1 0x53 -#define WSS2 0x54 -#define VVBI 0x55 -#define LCTL6 0x56 -#define LCTL7 0x57 -#define LCTL8 0x58 -#define LCTL9 0x59 -#define LCTL10 0x5A -#define LCTL11 0x5B -#define LCTL12 0x5C -#define LCTL13 0x5D -#define LCTL14 0x5E -#define LCTL15 0x5F -#define LCTL16 0x60 -#define LCTL17 0x61 -#define LCTL18 0x62 -#define LCTL19 0x63 -#define LCTL20 0x64 -#define LCTL21 0x65 -#define LCTL22 0x66 -#define LCTL23 0x67 -#define LCTL24 0x68 -#define LCTL25 0x69 -#define LCTL26 0x6A -#define HSBEGIN 0x6B -#define HSEND 0x6C -#define OVSDLY 0x6D -#define OVSEND 0x6E -#define VBIDELAY 0x6F - -/* - * register detail - */ - -/* INFORM */ -#define FC27_ON 0x40 /* 1 : Input crystal clock frequency is 27MHz */ -#define FC27_FF 0x00 /* 0 : Square pixel mode. */ - /* Must use 24.54MHz for 60Hz field rate */ - /* source or 29.5MHz for 50Hz field rate */ -#define IFSEL_S 0x10 /* 01 : S-video decoding */ -#define IFSEL_C 0x00 /* 00 : Composite video decoding */ - /* Y input video selection */ -#define YSEL_M0 0x00 /* 00 : Mux0 selected */ -#define YSEL_M1 0x04 /* 01 : Mux1 selected */ -#define YSEL_M2 0x08 /* 10 : Mux2 selected */ -#define YSEL_M3 0x10 /* 11 : Mux3 selected */ - -/* OPFORM */ -#define MODE 0x80 /* 0 : CCIR601 compatible YCrCb 4:2:2 format */ - /* 1 : ITU-R-656 compatible data sequence format */ -#define LEN 0x40 /* 0 : 8-bit YCrCb 4:2:2 output format */ - /* 1 : 16-bit YCrCb 4:2:2 output format.*/ -#define LLCMODE 0x20 /* 1 : LLC output mode. */ - /* 0 : free-run output mode */ -#define AINC 0x10 /* Serial interface auto-indexing control */ - /* 0 : auto-increment */ - /* 1 : non-auto */ -#define VSCTL 0x08 /* 1 : Vertical out ctrl by DVALID */ - /* 0 : Vertical out ctrl by HACTIVE and DVALID */ -#define OEN_TRI_SEL_MASK 0x07 -#define OEN_TRI_SEL_ALL_ON 0x00 /* Enable output for Rev0/Rev1 */ -#define OEN_TRI_SEL_ALL_OFF_r0 0x06 /* All tri-stated for Rev0 */ -#define OEN_TRI_SEL_ALL_OFF_r1 0x07 /* All tri-stated for Rev1 */ - -/* OUTCTR1 */ -#define VSP_LO 0x00 /* 0 : VS pin output polarity is active low */ -#define VSP_HI 0x80 /* 1 : VS pin output polarity is active high. */ - /* VS pin output control */ -#define VSSL_VSYNC 0x00 /* 0 : VSYNC */ -#define VSSL_VACT 0x10 /* 1 : VACT */ -#define VSSL_FIELD 0x20 /* 2 : FIELD */ -#define VSSL_VVALID 0x30 /* 3 : VVALID */ -#define VSSL_ZERO 0x70 /* 7 : 0 */ -#define HSP_LOW 0x00 /* 0 : HS pin output polarity is active low */ -#define HSP_HI 0x08 /* 1 : HS pin output polarity is active high.*/ - /* HS pin output control */ -#define HSSL_HACT 0x00 /* 0 : HACT */ -#define HSSL_HSYNC 0x01 /* 1 : HSYNC */ -#define HSSL_DVALID 0x02 /* 2 : DVALID */ -#define HSSL_HLOCK 0x03 /* 3 : HLOCK */ -#define HSSL_ASYNCW 0x04 /* 4 : ASYNCW */ -#define HSSL_ZERO 0x07 /* 7 : 0 */ - -/* ACNTL1 */ -#define SRESET 0x80 /* resets the device to its default state - * but all register content remain unchanged. - * This bit is self-resetting. - */ -#define ACNTL1_PDN_MASK 0x0e -#define CLK_PDN 0x08 /* system clock power down */ -#define Y_PDN 0x04 /* Luma ADC power down */ -#define C_PDN 0x02 /* Chroma ADC power down */ - -/* ACNTL2 */ -#define ACNTL2_PDN_MASK 0x40 -#define PLL_PDN 0x40 /* PLL power down */ - -/* VBICNTL */ - -/* RTSEL : control the real time signal output from the MPOUT pin */ -#define RTSEL_MASK 0x07 -#define RTSEL_VLOSS 0x00 /* 0000 = Video loss */ -#define RTSEL_HLOCK 0x01 /* 0001 = H-lock */ -#define RTSEL_SLOCK 0x02 /* 0010 = S-lock */ -#define RTSEL_VLOCK 0x03 /* 0011 = V-lock */ -#define RTSEL_MONO 0x04 /* 0100 = MONO */ -#define RTSEL_DET50 0x05 /* 0101 = DET50 */ -#define RTSEL_FIELD 0x06 /* 0110 = FIELD */ -#define RTSEL_RTCO 0x07 /* 0111 = RTCO ( Real Time Control ) */ - -/* HSYNC start and end are constant for now */ -#define HSYNC_START 0x0260 -#define HSYNC_END 0x0300 - -/* - * structure - */ - -struct regval_list { - unsigned char reg_num; - unsigned char value; -}; - -struct tw9910_scale_ctrl { - char *name; - unsigned short width; - unsigned short height; - u16 hscale; - u16 vscale; -}; - -struct tw9910_priv { - struct v4l2_subdev subdev; - struct v4l2_clk *clk; - struct tw9910_video_info *info; - const struct tw9910_scale_ctrl *scale; - v4l2_std_id norm; - u32 revision; -}; - -static const struct tw9910_scale_ctrl tw9910_ntsc_scales[] = { - { - .name = "NTSC SQ", - .width = 640, - .height = 480, - .hscale = 0x0100, - .vscale = 0x0100, - }, - { - .name = "NTSC CCIR601", - .width = 720, - .height = 480, - .hscale = 0x0100, - .vscale = 0x0100, - }, - { - .name = "NTSC SQ (CIF)", - .width = 320, - .height = 240, - .hscale = 0x0200, - .vscale = 0x0200, - }, - { - .name = "NTSC CCIR601 (CIF)", - .width = 360, - .height = 240, - .hscale = 0x0200, - .vscale = 0x0200, - }, - { - .name = "NTSC SQ (QCIF)", - .width = 160, - .height = 120, - .hscale = 0x0400, - .vscale = 0x0400, - }, - { - .name = "NTSC CCIR601 (QCIF)", - .width = 180, - .height = 120, - .hscale = 0x0400, - .vscale = 0x0400, - }, -}; - -static const struct tw9910_scale_ctrl tw9910_pal_scales[] = { - { - .name = "PAL SQ", - .width = 768, - .height = 576, - .hscale = 0x0100, - .vscale = 0x0100, - }, - { - .name = "PAL CCIR601", - .width = 720, - .height = 576, - .hscale = 0x0100, - .vscale = 0x0100, - }, - { - .name = "PAL SQ (CIF)", - .width = 384, - .height = 288, - .hscale = 0x0200, - .vscale = 0x0200, - }, - { - .name = "PAL CCIR601 (CIF)", - .width = 360, - .height = 288, - .hscale = 0x0200, - .vscale = 0x0200, - }, - { - .name = "PAL SQ (QCIF)", - .width = 192, - .height = 144, - .hscale = 0x0400, - .vscale = 0x0400, - }, - { - .name = "PAL CCIR601 (QCIF)", - .width = 180, - .height = 144, - .hscale = 0x0400, - .vscale = 0x0400, - }, -}; - -/* - * general function - */ -static struct tw9910_priv *to_tw9910(const struct i2c_client *client) -{ - return container_of(i2c_get_clientdata(client), struct tw9910_priv, - subdev); -} - -static int tw9910_mask_set(struct i2c_client *client, u8 command, - u8 mask, u8 set) -{ - s32 val = i2c_smbus_read_byte_data(client, command); - if (val < 0) - return val; - - val &= ~mask; - val |= set & mask; - - return i2c_smbus_write_byte_data(client, command, val); -} - -static int tw9910_set_scale(struct i2c_client *client, - const struct tw9910_scale_ctrl *scale) -{ - int ret; - - ret = i2c_smbus_write_byte_data(client, SCALE_HI, - (scale->vscale & 0x0F00) >> 4 | - (scale->hscale & 0x0F00) >> 8); - if (ret < 0) - return ret; - - ret = i2c_smbus_write_byte_data(client, HSCALE_LO, - scale->hscale & 0x00FF); - if (ret < 0) - return ret; - - ret = i2c_smbus_write_byte_data(client, VSCALE_LO, - scale->vscale & 0x00FF); - - return ret; -} - -static int tw9910_set_hsync(struct i2c_client *client) -{ - struct tw9910_priv *priv = to_tw9910(client); - int ret; - - /* bit 10 - 3 */ - ret = i2c_smbus_write_byte_data(client, HSBEGIN, - (HSYNC_START & 0x07F8) >> 3); - if (ret < 0) - return ret; - - /* bit 10 - 3 */ - ret = i2c_smbus_write_byte_data(client, HSEND, - (HSYNC_END & 0x07F8) >> 3); - if (ret < 0) - return ret; - - /* So far only revisions 0 and 1 have been seen */ - /* bit 2 - 0 */ - if (1 == priv->revision) - ret = tw9910_mask_set(client, HSLOWCTL, 0x77, - (HSYNC_START & 0x0007) << 4 | - (HSYNC_END & 0x0007)); - - return ret; -} - -static void tw9910_reset(struct i2c_client *client) -{ - tw9910_mask_set(client, ACNTL1, SRESET, SRESET); - msleep(1); -} - -static int tw9910_power(struct i2c_client *client, int enable) -{ - int ret; - u8 acntl1; - u8 acntl2; - - if (enable) { - acntl1 = 0; - acntl2 = 0; - } else { - acntl1 = CLK_PDN | Y_PDN | C_PDN; - acntl2 = PLL_PDN; - } - - ret = tw9910_mask_set(client, ACNTL1, ACNTL1_PDN_MASK, acntl1); - if (ret < 0) - return ret; - - return tw9910_mask_set(client, ACNTL2, ACNTL2_PDN_MASK, acntl2); -} - -static const struct tw9910_scale_ctrl *tw9910_select_norm(v4l2_std_id norm, - u32 width, u32 height) -{ - const struct tw9910_scale_ctrl *scale; - const struct tw9910_scale_ctrl *ret = NULL; - __u32 diff = 0xffffffff, tmp; - int size, i; - - if (norm & V4L2_STD_NTSC) { - scale = tw9910_ntsc_scales; - size = ARRAY_SIZE(tw9910_ntsc_scales); - } else if (norm & V4L2_STD_PAL) { - scale = tw9910_pal_scales; - size = ARRAY_SIZE(tw9910_pal_scales); - } else { - return NULL; - } - - for (i = 0; i < size; i++) { - tmp = abs(width - scale[i].width) + - abs(height - scale[i].height); - if (tmp < diff) { - diff = tmp; - ret = scale + i; - } - } - - return ret; -} - -/* - * subdevice operations - */ -static int tw9910_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct tw9910_priv *priv = to_tw9910(client); - u8 val; - int ret; - - if (!enable) { - switch (priv->revision) { - case 0: - val = OEN_TRI_SEL_ALL_OFF_r0; - break; - case 1: - val = OEN_TRI_SEL_ALL_OFF_r1; - break; - default: - dev_err(&client->dev, "un-supported revision\n"); - return -EINVAL; - } - } else { - val = OEN_TRI_SEL_ALL_ON; - - if (!priv->scale) { - dev_err(&client->dev, "norm select error\n"); - return -EPERM; - } - - dev_dbg(&client->dev, "%s %dx%d\n", - priv->scale->name, - priv->scale->width, - priv->scale->height); - } - - ret = tw9910_mask_set(client, OPFORM, OEN_TRI_SEL_MASK, val); - if (ret < 0) - return ret; - - return tw9910_power(client, enable); -} - -static int tw9910_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct tw9910_priv *priv = to_tw9910(client); - - *norm = priv->norm; - - return 0; -} - -static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct tw9910_priv *priv = to_tw9910(client); - const unsigned hact = 720; - const unsigned hdelay = 15; - unsigned vact; - unsigned vdelay; - int ret; - - if (!(norm & (V4L2_STD_NTSC | V4L2_STD_PAL))) - return -EINVAL; - - priv->norm = norm; - if (norm & V4L2_STD_525_60) { - vact = 240; - vdelay = 18; - ret = tw9910_mask_set(client, VVBI, 0x10, 0x10); - } else { - vact = 288; - vdelay = 24; - ret = tw9910_mask_set(client, VVBI, 0x10, 0x00); - } - if (!ret) - ret = i2c_smbus_write_byte_data(client, CROP_HI, - ((vdelay >> 2) & 0xc0) | - ((vact >> 4) & 0x30) | - ((hdelay >> 6) & 0x0c) | - ((hact >> 8) & 0x03)); - if (!ret) - ret = i2c_smbus_write_byte_data(client, VDELAY_LO, - vdelay & 0xff); - if (!ret) - ret = i2c_smbus_write_byte_data(client, VACTIVE_LO, - vact & 0xff); - - return ret; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int tw9910_g_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - if (reg->reg > 0xff) - return -EINVAL; - - reg->size = 1; - ret = i2c_smbus_read_byte_data(client, reg->reg); - if (ret < 0) - return ret; - - /* - * ret = int - * reg->val = __u64 - */ - reg->val = (__u64)ret; - - return 0; -} - -static int tw9910_s_register(struct v4l2_subdev *sd, - const struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->reg > 0xff || - reg->val > 0xff) - return -EINVAL; - - return i2c_smbus_write_byte_data(client, reg->reg, reg->val); -} -#endif - -static int tw9910_s_power(struct v4l2_subdev *sd, int on) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - struct tw9910_priv *priv = to_tw9910(client); - - return soc_camera_set_power(&client->dev, ssdd, priv->clk, on); -} - -static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct tw9910_priv *priv = to_tw9910(client); - int ret = -EINVAL; - u8 val; - - /* - * select suitable norm - */ - priv->scale = tw9910_select_norm(priv->norm, *width, *height); - if (!priv->scale) - goto tw9910_set_fmt_error; - - /* - * reset hardware - */ - tw9910_reset(client); - - /* - * set bus width - */ - val = 0x00; - if (SOCAM_DATAWIDTH_16 == priv->info->buswidth) - val = LEN; - - ret = tw9910_mask_set(client, OPFORM, LEN, val); - if (ret < 0) - goto tw9910_set_fmt_error; - - /* - * select MPOUT behavior - */ - switch (priv->info->mpout) { - case TW9910_MPO_VLOSS: - val = RTSEL_VLOSS; break; - case TW9910_MPO_HLOCK: - val = RTSEL_HLOCK; break; - case TW9910_MPO_SLOCK: - val = RTSEL_SLOCK; break; - case TW9910_MPO_VLOCK: - val = RTSEL_VLOCK; break; - case TW9910_MPO_MONO: - val = RTSEL_MONO; break; - case TW9910_MPO_DET50: - val = RTSEL_DET50; break; - case TW9910_MPO_FIELD: - val = RTSEL_FIELD; break; - case TW9910_MPO_RTCO: - val = RTSEL_RTCO; break; - default: - val = 0; - } - - ret = tw9910_mask_set(client, VBICNTL, RTSEL_MASK, val); - if (ret < 0) - goto tw9910_set_fmt_error; - - /* - * set scale - */ - ret = tw9910_set_scale(client, priv->scale); - if (ret < 0) - goto tw9910_set_fmt_error; - - /* - * set hsync - */ - ret = tw9910_set_hsync(client); - if (ret < 0) - goto tw9910_set_fmt_error; - - *width = priv->scale->width; - *height = priv->scale->height; - - return ret; - -tw9910_set_fmt_error: - - tw9910_reset(client); - priv->scale = NULL; - - return ret; -} - -static int tw9910_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct tw9910_priv *priv = to_tw9910(client); - - if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - /* Only CROP, CROP_DEFAULT and CROP_BOUNDS are supported */ - if (sel->target > V4L2_SEL_TGT_CROP_BOUNDS) - return -EINVAL; - - sel->r.left = 0; - sel->r.top = 0; - if (priv->norm & V4L2_STD_NTSC) { - sel->r.width = 640; - sel->r.height = 480; - } else { - sel->r.width = 768; - sel->r.height = 576; - } - return 0; -} - -static int tw9910_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *mf = &format->format; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct tw9910_priv *priv = to_tw9910(client); - - if (format->pad) - return -EINVAL; - - if (!priv->scale) { - priv->scale = tw9910_select_norm(priv->norm, 640, 480); - if (!priv->scale) - return -EINVAL; - } - - mf->width = priv->scale->width; - mf->height = priv->scale->height; - mf->code = MEDIA_BUS_FMT_UYVY8_2X8; - mf->colorspace = V4L2_COLORSPACE_SMPTE170M; - mf->field = V4L2_FIELD_INTERLACED_BT; - - return 0; -} - -static int tw9910_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - u32 width = mf->width, height = mf->height; - int ret; - - WARN_ON(mf->field != V4L2_FIELD_ANY && - mf->field != V4L2_FIELD_INTERLACED_BT); - - /* - * check color format - */ - if (mf->code != MEDIA_BUS_FMT_UYVY8_2X8) - return -EINVAL; - - mf->colorspace = V4L2_COLORSPACE_SMPTE170M; - - ret = tw9910_set_frame(sd, &width, &height); - if (!ret) { - mf->width = width; - mf->height = height; - } - return ret; -} - -static int tw9910_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *mf = &format->format; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct tw9910_priv *priv = to_tw9910(client); - const struct tw9910_scale_ctrl *scale; - - if (format->pad) - return -EINVAL; - - if (V4L2_FIELD_ANY == mf->field) { - mf->field = V4L2_FIELD_INTERLACED_BT; - } else if (V4L2_FIELD_INTERLACED_BT != mf->field) { - dev_err(&client->dev, "Field type %d invalid.\n", mf->field); - return -EINVAL; - } - - mf->code = MEDIA_BUS_FMT_UYVY8_2X8; - mf->colorspace = V4L2_COLORSPACE_SMPTE170M; - - /* - * select suitable norm - */ - scale = tw9910_select_norm(priv->norm, mf->width, mf->height); - if (!scale) - return -EINVAL; - - mf->width = scale->width; - mf->height = scale->height; - - if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) - return tw9910_s_fmt(sd, mf); - cfg->try_fmt = *mf; - return 0; -} - -static int tw9910_video_probe(struct i2c_client *client) -{ - struct tw9910_priv *priv = to_tw9910(client); - s32 id; - int ret; - - /* - * tw9910 only use 8 or 16 bit bus width - */ - if (SOCAM_DATAWIDTH_16 != priv->info->buswidth && - SOCAM_DATAWIDTH_8 != priv->info->buswidth) { - dev_err(&client->dev, "bus width error\n"); - return -ENODEV; - } - - ret = tw9910_s_power(&priv->subdev, 1); - if (ret < 0) - return ret; - - /* - * check and show Product ID - * So far only revisions 0 and 1 have been seen - */ - id = i2c_smbus_read_byte_data(client, ID); - priv->revision = GET_REV(id); - id = GET_ID(id); - - if (0x0B != id || - 0x01 < priv->revision) { - dev_err(&client->dev, - "Product ID error %x:%x\n", - id, priv->revision); - ret = -ENODEV; - goto done; - } - - dev_info(&client->dev, - "tw9910 Product ID %0x:%0x\n", id, priv->revision); - - priv->norm = V4L2_STD_NTSC; - priv->scale = &tw9910_ntsc_scales[0]; - -done: - tw9910_s_power(&priv->subdev, 0); - return ret; -} - -static const struct v4l2_subdev_core_ops tw9910_subdev_core_ops = { -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = tw9910_g_register, - .s_register = tw9910_s_register, -#endif - .s_power = tw9910_s_power, -}; - -static int tw9910_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (code->pad || code->index) - return -EINVAL; - - code->code = MEDIA_BUS_FMT_UYVY8_2X8; - return 0; -} - -static int tw9910_g_mbus_config(struct v4l2_subdev *sd, - struct v4l2_mbus_config *cfg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - - cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | - V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | - V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW | - V4L2_MBUS_DATA_ACTIVE_HIGH; - cfg->type = V4L2_MBUS_PARALLEL; - cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); - - return 0; -} - -static int tw9910_s_mbus_config(struct v4l2_subdev *sd, - const struct v4l2_mbus_config *cfg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - u8 val = VSSL_VVALID | HSSL_DVALID; - unsigned long flags = soc_camera_apply_board_flags(ssdd, cfg); - - /* - * set OUTCTR1 - * - * We use VVALID and DVALID signals to control VSYNC and HSYNC - * outputs, in this mode their polarity is inverted. - */ - if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) - val |= HSP_HI; - - if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) - val |= VSP_HI; - - return i2c_smbus_write_byte_data(client, OUTCTR1, val); -} - -static int tw9910_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *norm) -{ - *norm = V4L2_STD_NTSC | V4L2_STD_PAL; - return 0; -} - -static const struct v4l2_subdev_video_ops tw9910_subdev_video_ops = { - .s_std = tw9910_s_std, - .g_std = tw9910_g_std, - .s_stream = tw9910_s_stream, - .g_mbus_config = tw9910_g_mbus_config, - .s_mbus_config = tw9910_s_mbus_config, - .g_tvnorms = tw9910_g_tvnorms, -}; - -static const struct v4l2_subdev_pad_ops tw9910_subdev_pad_ops = { - .enum_mbus_code = tw9910_enum_mbus_code, - .get_selection = tw9910_get_selection, - .get_fmt = tw9910_get_fmt, - .set_fmt = tw9910_set_fmt, -}; - -static const struct v4l2_subdev_ops tw9910_subdev_ops = { - .core = &tw9910_subdev_core_ops, - .video = &tw9910_subdev_video_ops, - .pad = &tw9910_subdev_pad_ops, -}; - -/* - * i2c_driver function - */ - -static int tw9910_probe(struct i2c_client *client, - const struct i2c_device_id *did) - -{ - struct tw9910_priv *priv; - struct tw9910_video_info *info; - struct i2c_adapter *adapter = - to_i2c_adapter(client->dev.parent); - struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); - int ret; - - if (!ssdd || !ssdd->drv_priv) { - dev_err(&client->dev, "TW9910: missing platform data!\n"); - return -EINVAL; - } - - info = ssdd->drv_priv; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { - dev_err(&client->dev, - "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE_DATA\n"); - return -EIO; - } - - priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->info = info; - - v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops); - - priv->clk = v4l2_clk_get(&client->dev, "mclk"); - if (IS_ERR(priv->clk)) - return PTR_ERR(priv->clk); - - ret = tw9910_video_probe(client); - if (ret < 0) - v4l2_clk_put(priv->clk); - - return ret; -} - -static int tw9910_remove(struct i2c_client *client) -{ - struct tw9910_priv *priv = to_tw9910(client); - v4l2_clk_put(priv->clk); - return 0; -} - -static const struct i2c_device_id tw9910_id[] = { - { "tw9910", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, tw9910_id); - -static struct i2c_driver tw9910_i2c_driver = { - .driver = { - .name = "tw9910", - }, - .probe = tw9910_probe, - .remove = tw9910_remove, - .id_table = tw9910_id, -}; - -module_i2c_driver(tw9910_i2c_driver); - -MODULE_DESCRIPTION("SoC Camera driver for tw9910"); -MODULE_AUTHOR("Kuninori Morimoto"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c index e8613e364403..a62ede096636 100644 --- a/drivers/media/i2c/tda1997x.c +++ b/drivers/media/i2c/tda1997x.c @@ -1884,6 +1884,10 @@ static int tda1997x_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) for (i = 0; i < 128; i++) io_write(sd, REG_EDID_IN_BYTE128 + i, edid->edid[i+128]); + /* store state */ + memcpy(state->edid.edid, edid->edid, 256); + state->edid.blocks = edid->blocks; + tda1997x_enable_edid(sd); return 0; diff --git a/drivers/media/i2c/tda1997x_regs.h b/drivers/media/i2c/tda1997x_regs.h index f55dfc423a86..ecf87534613b 100644 --- a/drivers/media/i2c/tda1997x_regs.h +++ b/drivers/media/i2c/tda1997x_regs.h @@ -596,7 +596,7 @@ #define RESET_AUDIO BIT(0) /* Reset Audio FIFO control */ /* HDCP_BCAPS bits */ -#define HDCP_HDMI BIT(7) /* HDCP suports HDMI (vs DVI only) */ +#define HDCP_HDMI BIT(7) /* HDCP supports HDMI (vs DVI only) */ #define HDCP_REPEATER BIT(6) /* HDCP supports repeater function */ #define HDCP_READY BIT(5) /* set by repeater function */ #define HDCP_FAST BIT(4) /* Up to 400kHz */ diff --git a/drivers/media/i2c/tda9840.c b/drivers/media/i2c/tda9840.c index 0dd6ff3e6201..6ba53f3a6dd2 100644 --- a/drivers/media/i2c/tda9840.c +++ b/drivers/media/i2c/tda9840.c @@ -7,7 +7,7 @@ The tda9840 is a stereo/dual sound processor with digital identification. It can be found at address 0x84 on the i2c-bus. - For detailed informations download the specifications directly + For detailed information download the specifications directly from SGS Thomson at http://www.st.com This program is free software; you can redistribute it and/or modify diff --git a/drivers/media/i2c/tea6415c.c b/drivers/media/i2c/tea6415c.c index 084bd75bb32c..965c6ccc4fee 100644 --- a/drivers/media/i2c/tea6415c.c +++ b/drivers/media/i2c/tea6415c.c @@ -9,7 +9,7 @@ It is cascadable, i.e. it can be found at the addresses 0x86 and 0x06 on the i2c-bus. - For detailed informations download the specifications directly + For detailed information download the specifications directly from SGS Thomson at http://www.st.com This program is free software; you can redistribute it and/or modify diff --git a/drivers/media/i2c/tea6420.c b/drivers/media/i2c/tea6420.c index b7f4e58f3624..2701a4c9734d 100644 --- a/drivers/media/i2c/tea6420.c +++ b/drivers/media/i2c/tea6420.c @@ -9,7 +9,7 @@ It is cascadable, i.e. it can be found at the addresses 0x98 and 0x9a on the i2c-bus. - For detailed informations download the specifications directly + For detailed information download the specifications directly from SGS Thomson at http://www.st.com This program is free software; you can redistribute it and/or modify diff --git a/drivers/media/i2c/tvaudio.c b/drivers/media/i2c/tvaudio.c index af2da977a685..e6796e94dadf 100644 --- a/drivers/media/i2c/tvaudio.c +++ b/drivers/media/i2c/tvaudio.c @@ -538,7 +538,7 @@ static int tda9840_checkit(struct CHIPSTATE *chip) #define TDA9855_INT 0 /* Selects inputs LOR and LOL. (internal) */ /* Unique to TDA9850: */ -/* lower 4 bits contol SAP noise threshold, over which SAP turns off +/* lower 4 bits control SAP noise threshold, over which SAP turns off * set to values of 0x00 through 0x0f for SAP1 through SAP16 */ @@ -546,7 +546,7 @@ static int tda9840_checkit(struct CHIPSTATE *chip) /* Common to TDA9855 and TDA9850: */ #define TDA985x_SAP 3<<6 /* Selects SAP output, mute if not received */ #define TDA985x_MONOSAP 2<<6 /* Selects Mono on left, SAP on right */ -#define TDA985x_STEREO 1<<6 /* Selects Stereo ouput, mono if not received */ +#define TDA985x_STEREO 1<<6 /* Selects Stereo output, mono if not received */ #define TDA985x_MONO 0 /* Forces Mono output */ #define TDA985x_LMU 1<<3 /* Mute (LOR/LOL for 9855, OUTL/OUTR for 9850) */ diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index 1cc83cb934e2..3ada3bb27402 100644 --- a/drivers/media/i2c/tvp514x.c +++ b/drivers/media/i2c/tvp514x.c @@ -67,7 +67,7 @@ enum tvp514x_std { }; /** - * struct tvp514x_std_info - Structure to store standard informations + * struct tvp514x_std_info - Structure to store standard information * @width: Line width in pixels * @height:Number of active lines * @video_std: Value to write in REG_VIDEO_STD register diff --git a/drivers/media/i2c/tw9910.c b/drivers/media/i2c/tw9910.c index a54548cc4285..4d7cd736b930 100644 --- a/drivers/media/i2c/tw9910.c +++ b/drivers/media/i2c/tw9910.c @@ -584,6 +584,14 @@ static int tw9910_s_register(struct v4l2_subdev *sd, } #endif +static void tw9910_set_gpio_value(struct gpio_desc *desc, int value) +{ + if (desc) { + gpiod_set_value(desc, value); + usleep_range(500, 1000); + } +} + static int tw9910_power_on(struct tw9910_priv *priv) { struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev); @@ -595,10 +603,7 @@ static int tw9910_power_on(struct tw9910_priv *priv) return ret; } - if (priv->pdn_gpio) { - gpiod_set_value(priv->pdn_gpio, 0); - usleep_range(500, 1000); - } + tw9910_set_gpio_value(priv->pdn_gpio, 0); /* * FIXME: The reset signal is connected to a shared GPIO on some @@ -610,14 +615,14 @@ static int tw9910_power_on(struct tw9910_priv *priv) GPIOD_OUT_LOW); if (IS_ERR(priv->rstb_gpio)) { dev_info(&client->dev, "Unable to get GPIO \"rstb\""); + clk_disable_unprepare(priv->clk); + tw9910_set_gpio_value(priv->pdn_gpio, 1); return PTR_ERR(priv->rstb_gpio); } if (priv->rstb_gpio) { - gpiod_set_value(priv->rstb_gpio, 1); - usleep_range(500, 1000); - gpiod_set_value(priv->rstb_gpio, 0); - usleep_range(500, 1000); + tw9910_set_gpio_value(priv->rstb_gpio, 1); + tw9910_set_gpio_value(priv->rstb_gpio, 0); gpiod_put(priv->rstb_gpio); } @@ -628,11 +633,7 @@ static int tw9910_power_on(struct tw9910_priv *priv) static int tw9910_power_off(struct tw9910_priv *priv) { clk_disable_unprepare(priv->clk); - - if (priv->pdn_gpio) { - gpiod_set_value(priv->pdn_gpio, 1); - usleep_range(500, 1000); - } + tw9910_set_gpio_value(priv->pdn_gpio, 1); return 0; } @@ -1000,7 +1001,7 @@ static int tw9910_remove(struct i2c_client *client) if (priv->pdn_gpio) gpiod_put(priv->pdn_gpio); clk_put(priv->clk); - v4l2_device_unregister_subdev(&priv->subdev); + v4l2_async_unregister_subdev(&priv->subdev); return 0; } diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c index 01dcf179f203..abd3152df7d0 100644 --- a/drivers/media/i2c/video-i2c.c +++ b/drivers/media/i2c/video-i2c.c @@ -6,6 +6,7 @@ * * Supported: * - Panasonic AMG88xx Grid-Eye Sensors + * - Melexis MLX90640 Thermal Cameras */ #include <linux/delay.h> @@ -18,6 +19,7 @@ #include <linux/mutex.h> #include <linux/of_device.h> #include <linux/pm_runtime.h> +#include <linux/nvmem-provider.h> #include <linux/regmap.h> #include <linux/sched.h> #include <linux/slab.h> @@ -66,12 +68,26 @@ static const struct v4l2_frmsize_discrete amg88xx_size = { .height = 8, }; +static const struct v4l2_fmtdesc mlx90640_format = { + .pixelformat = V4L2_PIX_FMT_Y16_BE, +}; + +static const struct v4l2_frmsize_discrete mlx90640_size = { + .width = 32, + .height = 26, /* 24 lines of pixel data + 2 lines of processing data */ +}; + static const struct regmap_config amg88xx_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = 0xff }; +static const struct regmap_config mlx90640_regmap_config = { + .reg_bits = 16, + .val_bits = 16, +}; + struct video_i2c_chip { /* video dimensions */ const struct v4l2_fmtdesc *format; @@ -88,6 +104,7 @@ struct video_i2c_chip { unsigned int bpp; const struct regmap_config *regmap_config; + struct nvmem_config *nvmem_config; /* setup function */ int (*setup)(struct video_i2c_data *data); @@ -102,6 +119,22 @@ struct video_i2c_chip { int (*hwmon_init)(struct video_i2c_data *data); }; +static int mlx90640_nvram_read(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + struct video_i2c_data *data = priv; + + return regmap_bulk_read(data->regmap, 0x2400 + offset, val, bytes); +} + +static struct nvmem_config mlx90640_nvram_config = { + .name = "mlx90640_nvram", + .word_size = 2, + .stride = 1, + .size = 1664, + .reg_read = mlx90640_nvram_read, +}; + /* Power control register */ #define AMG88XX_REG_PCTL 0x00 #define AMG88XX_PCTL_NORMAL 0x00 @@ -122,12 +155,23 @@ struct video_i2c_chip { /* Temperature register */ #define AMG88XX_REG_T01L 0x80 +/* Control register */ +#define MLX90640_REG_CTL1 0x800d +#define MLX90640_REG_CTL1_MASK 0x0380 +#define MLX90640_REG_CTL1_MASK_SHIFT 7 + static int amg88xx_xfer(struct video_i2c_data *data, char *buf) { return regmap_bulk_read(data->regmap, AMG88XX_REG_T01L, buf, data->chip->buffer_size); } +static int mlx90640_xfer(struct video_i2c_data *data, char *buf) +{ + return regmap_bulk_read(data->regmap, 0x400, buf, + data->chip->buffer_size); +} + static int amg88xx_setup(struct video_i2c_data *data) { unsigned int mask = AMG88XX_FPSC_1FPS; @@ -141,6 +185,27 @@ static int amg88xx_setup(struct video_i2c_data *data) return regmap_update_bits(data->regmap, AMG88XX_REG_FPSC, mask, val); } +static int mlx90640_setup(struct video_i2c_data *data) +{ + unsigned int n, idx; + + for (n = 0; n < data->chip->num_frame_intervals - 1; n++) { + if (data->frame_interval.numerator + != data->chip->frame_intervals[n].numerator) + continue; + + if (data->frame_interval.denominator + == data->chip->frame_intervals[n].denominator) + break; + } + + idx = data->chip->num_frame_intervals - n - 1; + + return regmap_update_bits(data->regmap, MLX90640_REG_CTL1, + MLX90640_REG_CTL1_MASK, + idx << MLX90640_REG_CTL1_MASK_SHIFT); +} + static int amg88xx_set_power_on(struct video_i2c_data *data) { int ret; @@ -274,13 +339,27 @@ static int amg88xx_hwmon_init(struct video_i2c_data *data) #define amg88xx_hwmon_init NULL #endif -#define AMG88XX 0 +enum { + AMG88XX, + MLX90640, +}; static const struct v4l2_fract amg88xx_frame_intervals[] = { { 1, 10 }, { 1, 1 }, }; +static const struct v4l2_fract mlx90640_frame_intervals[] = { + { 1, 64 }, + { 1, 32 }, + { 1, 16 }, + { 1, 8 }, + { 1, 4 }, + { 1, 2 }, + { 1, 1 }, + { 2, 1 }, +}; + static const struct video_i2c_chip video_i2c_chip[] = { [AMG88XX] = { .size = &amg88xx_size, @@ -295,6 +374,18 @@ static const struct video_i2c_chip video_i2c_chip[] = { .set_power = amg88xx_set_power, .hwmon_init = amg88xx_hwmon_init, }, + [MLX90640] = { + .size = &mlx90640_size, + .format = &mlx90640_format, + .frame_intervals = mlx90640_frame_intervals, + .num_frame_intervals = ARRAY_SIZE(mlx90640_frame_intervals), + .buffer_size = 1664, + .bpp = 16, + .regmap_config = &mlx90640_regmap_config, + .nvmem_config = &mlx90640_nvram_config, + .setup = mlx90640_setup, + .xfer = mlx90640_xfer, + }, }; static const struct v4l2_file_operations video_i2c_fops = { @@ -756,6 +847,21 @@ static int video_i2c_probe(struct i2c_client *client, } } + if (data->chip->nvmem_config) { + struct nvmem_config *config = data->chip->nvmem_config; + struct nvmem_device *device; + + config->priv = data; + config->dev = &client->dev; + + device = devm_nvmem_register(&client->dev, config); + + if (IS_ERR(device)) { + dev_warn(&client->dev, + "failed to register nvmem device\n"); + } + } + ret = video_register_device(&data->vdev, VFL_TYPE_GRABBER, -1); if (ret < 0) goto error_pm_disable; @@ -835,12 +941,14 @@ static const struct dev_pm_ops video_i2c_pm_ops = { static const struct i2c_device_id video_i2c_id_table[] = { { "amg88xx", AMG88XX }, + { "mlx90640", MLX90640 }, {} }; MODULE_DEVICE_TABLE(i2c, video_i2c_id_table); static const struct of_device_id video_i2c_of_match[] = { { .compatible = "panasonic,amg88xx", .data = &video_i2c_chip[AMG88XX] }, + { .compatible = "melexis,mlx90640", .data = &video_i2c_chip[MLX90640] }, {} }; MODULE_DEVICE_TABLE(of, video_i2c_of_match); diff --git a/drivers/media/media-request.c b/drivers/media/media-request.c index c71a34ae6383..eec2e2b2f6ec 100644 --- a/drivers/media/media-request.c +++ b/drivers/media/media-request.c @@ -100,6 +100,7 @@ static __poll_t media_request_poll(struct file *filp, if (!(poll_requested_events(wait) & EPOLLPRI)) return 0; + poll_wait(filp, &req->poll_wait, wait); spin_lock_irqsave(&req->lock, flags); if (req->state == MEDIA_REQUEST_STATE_COMPLETE) { ret = EPOLLPRI; @@ -110,8 +111,6 @@ static __poll_t media_request_poll(struct file *filp, goto unlock; } - poll_wait(filp, &req->poll_wait, wait); - unlock: spin_unlock_irqrestore(&req->lock, flags); return ret; diff --git a/drivers/media/pci/bt8xx/bttv-audio-hook.c b/drivers/media/pci/bt8xx/bttv-audio-hook.c index 346fc7f58839..8febe7358a8f 100644 --- a/drivers/media/pci/bt8xx/bttv-audio-hook.c +++ b/drivers/media/pci/bt8xx/bttv-audio-hook.c @@ -1,5 +1,5 @@ /* - * Handlers for board audio hooks, splitted from bttv-cards + * Handlers for board audio hooks, split from bttv-cards * * Copyright (c) 2006 Mauro Carvalho Chehab <mchehab@kernel.org> * This code is placed under the terms of the GNU General Public License diff --git a/drivers/media/pci/bt8xx/bttv-audio-hook.h b/drivers/media/pci/bt8xx/bttv-audio-hook.h index be16a537a03a..c61b9ac4f4e3 100644 --- a/drivers/media/pci/bt8xx/bttv-audio-hook.h +++ b/drivers/media/pci/bt8xx/bttv-audio-hook.h @@ -1,5 +1,5 @@ /* - * Handlers for board audio hooks, splitted from bttv-cards + * Handlers for board audio hooks, split from bttv-cards * * Copyright (c) 2006 Mauro Carvalho Chehab <mchehab@kernel.org> * This code is placed under the terms of the GNU General Public License diff --git a/drivers/media/pci/bt8xx/bttv-cards.c b/drivers/media/pci/bt8xx/bttv-cards.c index 2616243b2c49..b1c6f3e9c3d0 100644 --- a/drivers/media/pci/bt8xx/bttv-cards.c +++ b/drivers/media/pci/bt8xx/bttv-cards.c @@ -2,7 +2,7 @@ bttv-cards.c - this file has configuration informations - card-specific stuff + this file has configuration information - card-specific stuff like the big tvcards array for the most part Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) @@ -1391,7 +1391,7 @@ struct tvcard bttv_tvcards[] = { .gpiomux = {0x947fff, 0x987fff,0x947fff,0x947fff }, .gpiomute = 0x947fff, /* tvtuner, radio, external,internal, mute, stereo - * tuner, Composit, SVid, Composit-on-Svid-adapter */ + * tuner, Composite, SVid, Composite-on-Svid-adapter */ .muxsel = MUXSEL(2, 3, 0, 1), .tuner_type = TUNER_MT2032, .tuner_addr = ADDR_UNSET, @@ -1411,7 +1411,7 @@ struct tvcard bttv_tvcards[] = { .gpiomux = {0x947fff, 0x987fff,0x947fff,0x947fff }, .gpiomute = 0x947fff, /* tvtuner, radio, external,internal, mute, stereo - * tuner, Composit, SVid, Composit-on-Svid-adapter */ + * tuner, Composite, SVid, Composite-on-Svid-adapter */ .muxsel = MUXSEL(2, 3, 0, 1), .tuner_type = TUNER_MT2032, .tuner_addr = ADDR_UNSET, @@ -4180,7 +4180,7 @@ static void init_PXC200(struct bttv *btv) bttv_I2CWrite(btv,0x5E,0,0x80,1); /* Initialise 12C508 PIC */ - /* The I2CWrite and I2CRead commmands are actually to the + /* The I2CWrite and I2CRead commands are actually to the * same chips - but the R/W bit is included in the address * argument so the numbers are different */ @@ -4289,7 +4289,7 @@ init_RTV24 (struct bttv *btv) /* ----------------------------------------------------------------------- */ /* * The PCI-8604PW contains a CPLD, probably an ispMACH 4A, that filters - * the PCI REQ signals comming from the four BT878 chips. After power + * the PCI REQ signals coming from the four BT878 chips. After power * up, the CPLD does not forward requests to the bus, which prevents * the BT878 from fetching RISC instructions from memory. While the * CPLD is connected to most of the GPIOs of PCI device 0xD, only @@ -4405,7 +4405,7 @@ static void rv605_muxsel(struct bttv *btv, unsigned int input) gpio_bits(0x07f, muxgpio[input]); - /* reset all conections */ + /* reset all connections */ gpio_bits(0x200,0x200); mdelay(1); gpio_bits(0x200,0x000); diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index d09785fd37a8..b7150648081d 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -2435,7 +2435,7 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.field = field; - /* update our state informations */ + /* update our state information */ fh->fmt = fmt; fh->cap.field = f->fmt.pix.field; fh->cap.last = V4L2_FIELD_NONE; @@ -3064,7 +3064,7 @@ static int bttv_open(struct file *file) V4L2 apps we now reset the cropping parameters as seen through this fh, which is to say VIDIOC_G_SELECTION and scaling limit checks will use btv->crop[0], the default cropping parameters for the - current video standard, and VIDIOC_S_FMT will not implicitely + current video standard, and VIDIOC_S_FMT will not implicitly change the cropping parameters until VIDIOC_S_SELECTION has been called. */ fh->do_crop = !reset_crop; /* module parameter */ @@ -3600,9 +3600,7 @@ static void bttv_irq_wakeup_video(struct bttv *btv, struct bttv_buffer_set *wakeup, struct bttv_buffer_set *curr, unsigned int state) { - struct timeval ts; - - v4l2_get_timestamp(&ts); + u64 ts = ktime_get_ns(); if (wakeup->top == wakeup->bottom) { if (NULL != wakeup->top && curr->top != wakeup->top) { @@ -3643,7 +3641,7 @@ bttv_irq_wakeup_vbi(struct bttv *btv, struct bttv_buffer *wakeup, if (NULL == wakeup) return; - v4l2_get_timestamp(&wakeup->vb.ts); + wakeup->vb.ts = ktime_get_ns(); wakeup->vb.field_count = btv->field_count; wakeup->vb.state = state; wake_up(&wakeup->vb.done); @@ -3713,7 +3711,7 @@ bttv_irq_wakeup_top(struct bttv *btv) btv->curr.top = NULL; bttv_risc_hook(btv, RISC_SLOT_O_FIELD, NULL, 0); - v4l2_get_timestamp(&wakeup->vb.ts); + wakeup->vb.ts = ktime_get_ns(); wakeup->vb.field_count = btv->field_count; wakeup->vb.state = VIDEOBUF_DONE; wake_up(&wakeup->vb.done); diff --git a/drivers/media/pci/bt8xx/bttv-risc.c b/drivers/media/pci/bt8xx/bttv-risc.c index 74aff6877d9c..6b3c73674a3c 100644 --- a/drivers/media/pci/bt8xx/bttv-risc.c +++ b/drivers/media/pci/bt8xx/bttv-risc.c @@ -93,7 +93,7 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc, *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); offset+=bpl; } else { - /* scanline needs to be splitted */ + /* scanline needs to be split */ todo = bpl; *(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL| (sg_dma_len(sg)-offset)); diff --git a/drivers/media/pci/bt8xx/bttv.h b/drivers/media/pci/bt8xx/bttv.h index a27384adadd2..d24b9ef9f59f 100644 --- a/drivers/media/pci/bt8xx/bttv.h +++ b/drivers/media/pci/bt8xx/bttv.h @@ -288,7 +288,7 @@ extern void bttv_init_card1(struct bttv *btv); extern void bttv_init_card2(struct bttv *btv); extern void bttv_init_tuner(struct bttv *btv); -/* card-specific funtions */ +/* card-specific functions */ extern void tea5757_set_freq(struct bttv *btv, unsigned short freq); extern u32 bttv_tda9880_setnorm(struct bttv *btv, u32 gpiobits); diff --git a/drivers/media/pci/bt8xx/dst.c b/drivers/media/pci/bt8xx/dst.c index b98de2a22f78..c94318c71a0c 100644 --- a/drivers/media/pci/bt8xx/dst.c +++ b/drivers/media/pci/bt8xx/dst.c @@ -1295,15 +1295,15 @@ static int dst_get_signal(struct dst_state *state) static int dst_tone_power_cmd(struct dst_state *state) { - u8 paket[8] = { 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 }; + u8 packet[8] = { 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 }; if (state->dst_type != DST_TYPE_IS_SAT) return -EOPNOTSUPP; - paket[4] = state->tx_tuna[4]; - paket[2] = state->tx_tuna[2]; - paket[3] = state->tx_tuna[3]; - paket[7] = dst_check_sum (paket, 7); - return dst_command(state, paket, 8); + packet[4] = state->tx_tuna[4]; + packet[2] = state->tx_tuna[2]; + packet[3] = state->tx_tuna[3]; + packet[7] = dst_check_sum (packet, 7); + return dst_command(state, packet, 8); } static int dst_get_tuna(struct dst_state *state) @@ -1429,18 +1429,18 @@ error: static int dst_set_diseqc(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd) { struct dst_state *state = fe->demodulator_priv; - u8 paket[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec }; + u8 packet[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec }; if (state->dst_type != DST_TYPE_IS_SAT) return -EOPNOTSUPP; if (cmd->msg_len > 0 && cmd->msg_len < 5) - memcpy(&paket[3], cmd->msg, cmd->msg_len); + memcpy(&packet[3], cmd->msg, cmd->msg_len); else if (cmd->msg_len == 5 && state->dst_hw_cap & DST_TYPE_HAS_DISEQC5) - memcpy(&paket[2], cmd->msg, cmd->msg_len); + memcpy(&packet[2], cmd->msg, cmd->msg_len); else return -EINVAL; - paket[7] = dst_check_sum(&paket[0], 7); - return dst_command(state, paket, 8); + packet[7] = dst_check_sum(&packet[0], 7); + return dst_command(state, packet, 8); } static int dst_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage voltage) diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.c b/drivers/media/pci/cobalt/cobalt-v4l2.c index c088de551081..f9fa3a7c3b8f 100644 --- a/drivers/media/pci/cobalt/cobalt-v4l2.c +++ b/drivers/media/pci/cobalt/cobalt-v4l2.c @@ -375,7 +375,7 @@ static void cobalt_dma_stop_streaming(struct cobalt_stream *s) } spin_unlock_irqrestore(&s->irqlock, flags); - /* Wait 100 milisecond for DMA to finish, abort on timeout. */ + /* Wait 100 millisecond for DMA to finish, abort on timeout. */ if (!wait_event_timeout(s->q.done_wq, is_dma_done(s), msecs_to_jiffies(timeout_msec))) { omni_sg_dma_abort_channel(s); diff --git a/drivers/media/pci/cx18/cx18-cards.h b/drivers/media/pci/cx18/cx18-cards.h index 02d0fb703a41..c563cc2358ba 100644 --- a/drivers/media/pci/cx18/cx18-cards.h +++ b/drivers/media/pci/cx18/cx18-cards.h @@ -83,7 +83,7 @@ struct cx18_gpio_i2c_slave_reset { u32 active_hi_mask; /* GPIO outputs that reset i2c chips when high */ int msecs_asserted; /* time period reset must remain asserted */ int msecs_recovery; /* time after deassert for chips to be ready */ - u32 ir_reset_mask; /* GPIO to reset the Zilog Z8F0811 IR contoller */ + u32 ir_reset_mask; /* GPIO to reset the Zilog Z8F0811 IR controller */ }; struct cx18_gpio_audio_input { /* select tuner/line in input */ diff --git a/drivers/media/pci/cx18/cx18-dvb.c b/drivers/media/pci/cx18/cx18-dvb.c index a3a7f7065349..61452c50a9c3 100644 --- a/drivers/media/pci/cx18/cx18-dvb.c +++ b/drivers/media/pci/cx18/cx18-dvb.c @@ -120,8 +120,8 @@ static struct zl10353_config leadtek_dvr3100h_demod = { /* * Due to * - * 1. an absence of information on how to prgram the MT352 - * 2. the Linux mt352 module pushing MT352 initialzation off onto us here + * 1. an absence of information on how to program the MT352 + * 2. the Linux mt352 module pushing MT352 initialization off onto us here * * We have to use an init sequence that *you* must extract from the Windows * driver (yuanrap.sys) and which we load as a firmware. @@ -458,7 +458,7 @@ void cx18_dvb_unregister(struct cx18_stream *stream) dvb_unregister_adapter(dvb_adapter); } -/* All the DVB attach calls go here, this function get's modified +/* All the DVB attach calls go here, this function gets modified * for each new card. cx18_dvb_start_feed() will also need changes. */ static int dvb_register(struct cx18_stream *stream) diff --git a/drivers/media/pci/cx18/cx18-fileops.c b/drivers/media/pci/cx18/cx18-fileops.c index a3f44e30f821..f778965a2eb8 100644 --- a/drivers/media/pci/cx18/cx18-fileops.c +++ b/drivers/media/pci/cx18/cx18-fileops.c @@ -403,7 +403,7 @@ static size_t cx18_copy_mdl_to_user(struct cx18_stream *s, tot_written += rc; if (stop || /* Forced stopping point for VBI insertion */ - tot_written >= ucount || /* Reader request statisfied */ + tot_written >= ucount || /* Reader request satisfied */ mdl->curr_buf->readpos < mdl->curr_buf->bytesused || mdl->readpos >= mdl->bytesused) /* MDL buffers drained */ break; diff --git a/drivers/media/pci/cx18/cx18-io.h b/drivers/media/pci/cx18/cx18-io.h index a3c96fb5d28d..da7871fdb56d 100644 --- a/drivers/media/pci/cx18/cx18-io.h +++ b/drivers/media/pci/cx18/cx18-io.h @@ -23,7 +23,7 @@ /* * Readback and retry of MMIO access for reliability: * The concept was suggested by Steve Toth <stoth@linuxtv.org>. - * The implmentation is the fault of Andy Walls <awalls@md.metrocast.net>. + * The implementation is the fault of Andy Walls <awalls@md.metrocast.net>. * * *write* functions are implied to retry the mmio unless suffixed with _noretry * *read* functions never retry the mmio (it never helps to do so) diff --git a/drivers/media/pci/cx18/cx18-mailbox.c b/drivers/media/pci/cx18/cx18-mailbox.c index f66dd63e1994..0ffd2196a980 100644 --- a/drivers/media/pci/cx18/cx18-mailbox.c +++ b/drivers/media/pci/cx18/cx18-mailbox.c @@ -197,7 +197,7 @@ static void cx18_mdl_send_to_videobuf(struct cx18_stream *s, } if (dispatch) { - v4l2_get_timestamp(&vb_buf->vb.ts); + vb_buf->vb.ts = ktime_get_ns(); list_del(&vb_buf->vb.queue); vb_buf->vb.state = VIDEOBUF_DONE; wake_up(&vb_buf->vb.done); diff --git a/drivers/media/pci/cx18/cx18-vbi.c b/drivers/media/pci/cx18/cx18-vbi.c index 81f1e27436fd..48cb96f953a0 100644 --- a/drivers/media/pci/cx18/cx18-vbi.c +++ b/drivers/media/pci/cx18/cx18-vbi.c @@ -24,7 +24,7 @@ /* * Raster Reference/Protection (RP) bytes, used in Start/End Active * Video codes emitted from the digitzer in VIP 1.x mode, that flag the start - * of VBI sample or VBI ancillary data regions in the digitial ratser line. + * of VBI sample or VBI ancillary data regions in the digital ratser line. * * Task FieldEven VerticalBlank HorizontalBlank 0 0 0 0 */ diff --git a/drivers/media/pci/cx18/cx23418.h b/drivers/media/pci/cx18/cx23418.h index 15205b662952..e9f6e50ca5b4 100644 --- a/drivers/media/pci/cx18/cx23418.h +++ b/drivers/media/pci/cx18/cx23418.h @@ -439,7 +439,7 @@ /* Error in I2C data xfer (but I2C device is present) */ #define CXERR_I2CDEV_XFERERR 0x000011 -/* Chanel changing component not ready */ +/* Channel changing component not ready */ #define CXERR_CHANNELNOTREADY 0x000012 /* PPU (Presensation/Decoder) mail box is corrupted */ diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index a00b77d80ed9..4863bd4ea5d0 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -1561,7 +1561,7 @@ int cx23885_417_register(struct cx23885_dev *dev) pr_info("%s: registered device %s [mpeg]\n", dev->name, video_device_node_name(dev->v4l_device)); - /* ST: Configure the encoder paramaters, but don't begin + /* ST: Configure the encoder parameters, but don't begin * encoding, this resolves an issue where the first time the * encoder is started video can be choppy. */ diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c index ee9d329c4038..c9c1385208f9 100644 --- a/drivers/media/pci/cx23885/cx23885-alsa.c +++ b/drivers/media/pci/cx23885/cx23885-alsa.c @@ -59,7 +59,7 @@ module_param(audio_debug, int, 0644); MODULE_PARM_DESC(audio_debug, "enable debug messages [analog audio]"); /**************************************************************************** - Board specific funtions + Board specific functions ****************************************************************************/ /* Constants taken from cx88-reg.h */ diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index fd5c52b21436..cec3cbca8d32 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -1996,9 +1996,9 @@ static inline int encoder_on_portc(struct cx23885_dev *dev) * and report errors if we think we're tampering with a GPIo that might * be assigned to the encoder (and used for the host bus). * - * GPIO 2 thru 0 - On the cx23885 bridge - * GPIO 18 thru 3 - On the cx23417 host bus interface - * GPIO 23 thru 19 - On the cx25840 a/v core + * GPIO 2 through 0 - On the cx23885 bridge + * GPIO 18 through 3 - On the cx23417 host bus interface + * GPIO 23 through 19 - On the cx25840 a/v core */ void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask) { diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index cf965efabe66..4d34799431dc 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -246,7 +246,7 @@ struct cx23885_i2c { struct i2c_client i2c_client; u32 i2c_rc; - /* 885 registers used for raw addess */ + /* 885 registers used for raw address */ u32 i2c_period; u32 reg_ctrl; u32 reg_stat; diff --git a/drivers/media/pci/cx23885/cx23888-ir.c b/drivers/media/pci/cx23885/cx23888-ir.c index 1d775c90df51..a4d66141c4bb 100644 --- a/drivers/media/pci/cx23885/cx23888-ir.c +++ b/drivers/media/pci/cx23885/cx23888-ir.c @@ -548,7 +548,7 @@ static int cx23888_ir_irq_handler(struct v4l2_subdev *sd, u32 status, ror = stats & STATS_ROR; /* Rx FIFO Over Run */ tse = irqen & IRQEN_TSE; /* Tx FIFO Service Request IRQ Enable */ - rse = irqen & IRQEN_RSE; /* Rx FIFO Service Reuqest IRQ Enable */ + rse = irqen & IRQEN_RSE; /* Rx FIFO Service Request IRQ Enable */ rte = irqen & IRQEN_RTE; /* Rx Pulse Width Timer Time Out IRQ Enable */ roe = irqen & IRQEN_ROE; /* Rx FIFO Over Run IRQ Enable */ @@ -638,7 +638,7 @@ static int cx23888_ir_irq_handler(struct v4l2_subdev *sd, u32 status, events |= V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED; } if (v) { - /* Clear STATS_ROR & STATS_RTO as needed by reseting hardware */ + /* Clear STATS_ROR & STATS_RTO as needed by resetting hardware */ cx23888_ir_write4(dev, CX23888_IR_CNTRL_REG, cntrl & ~v); cx23888_ir_write4(dev, CX23888_IR_CNTRL_REG, cntrl); *handled = true; diff --git a/drivers/media/pci/cx25821/cx25821-alsa.c b/drivers/media/pci/cx25821/cx25821-alsa.c index 0a6c90e92557..926e12a1554a 100644 --- a/drivers/media/pci/cx25821/cx25821-alsa.c +++ b/drivers/media/pci/cx25821/cx25821-alsa.c @@ -120,7 +120,7 @@ module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable debug messages"); /**************************************************************************** - Module specific funtions + Module specific functions ****************************************************************************/ /* Constants taken from cx88-reg.h */ #define AUD_INT_DN_RISCI1 (1 << 0) diff --git a/drivers/media/pci/cx25821/cx25821-sram.h b/drivers/media/pci/cx25821/cx25821-sram.h index b94e0d4df664..a907662dbb1c 100644 --- a/drivers/media/pci/cx25821/cx25821-sram.h +++ b/drivers/media/pci/cx25821/cx25821-sram.h @@ -24,7 +24,7 @@ #define AUDIO_CMDS_SIZE 80 /* AUDIO CMDS size in bytes */ #define MBIF_CMDS_SIZE 80 /* MBIF CMDS size in bytes */ -/* #define RX_SRAM_POOL_START_SIZE = 0; // Start of useable RX SRAM for buffers */ +/* #define RX_SRAM_POOL_START_SIZE = 0; // Start of usable RX SRAM for buffers */ #define VID_IQ_SIZE 64 /* VID instruction queue size in bytes */ #define MBIF_IQ_SIZE 64 #define AUDIO_IQ_SIZE 64 /* AUD instruction queue size in bytes */ diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h index 25eba4ac4499..b422275ff4f1 100644 --- a/drivers/media/pci/cx25821/cx25821.h +++ b/drivers/media/pci/cx25821/cx25821.h @@ -156,7 +156,7 @@ struct cx25821_i2c { struct i2c_client i2c_client; u32 i2c_rc; - /* cx25821 registers used for raw addess */ + /* cx25821 registers used for raw address */ u32 i2c_period; u32 reg_ctrl; u32 reg_stat; diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c index a84c8270ea13..60138ca3372b 100644 --- a/drivers/media/pci/dm1105/dm1105.c +++ b/drivers/media/pci/dm1105/dm1105.c @@ -517,7 +517,7 @@ static int dm1105_i2c_xfer(struct i2c_adapter *i2c_adap, msgs[i].buf[byte] = rc; } } else if ((msgs[i].buf[0] == 0xf7) && (msgs[i].addr == 0x55)) { - /* prepaired for cx24116 firmware */ + /* prepared for cx24116 firmware */ /* Write in small blocks */ len = msgs[i].len - 1; k = 1; diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index cdb79ae2d8dc..617fb2e944dc 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -264,7 +264,7 @@ static void cio2_fbpt_exit(struct cio2_queue *q, struct device *dev) */ /* - * shift for keeping value range suitable for 32-bit integer arithmetics + * shift for keeping value range suitable for 32-bit integer arithmetic */ #define LIMIT_SHIFT 8 @@ -1810,7 +1810,8 @@ static int cio2_pci_probe(struct pci_dev *pci_dev, /* Register notifier for subdevices we care */ r = cio2_notifier_init(cio2); - if (r) + /* Proceed without sensors connected to allow the device to suspend. */ + if (r && r != -ENODEV) goto fail_cio2_queue_exit; r = devm_request_irq(&pci_dev->dev, pci_dev->irq, cio2_irq, @@ -2047,7 +2048,7 @@ module_pci_driver(cio2_pci_driver); MODULE_AUTHOR("Tuukka Toivonen <tuukka.toivonen@intel.com>"); MODULE_AUTHOR("Tianshu Qiu <tian.shu.qiu@intel.com>"); -MODULE_AUTHOR("Jian Xu Zheng <jian.xu.zheng@intel.com>"); +MODULE_AUTHOR("Jian Xu Zheng"); MODULE_AUTHOR("Yuning Pu <yuning.pu@intel.com>"); MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/pci/ivtv/Kconfig b/drivers/media/pci/ivtv/Kconfig index c72cbbd2d40c..06ca4e23f9fb 100644 --- a/drivers/media/pci/ivtv/Kconfig +++ b/drivers/media/pci/ivtv/Kconfig @@ -70,8 +70,25 @@ config VIDEO_FB_IVTV This is used in the Hauppauge PVR-350 card. There is a driver homepage at <http://www.ivtvdriver.org>. - In order to use this module, you will need to boot with PAT disabled - on x86 systems, using the nopat kernel parameter. - To compile this driver as a module, choose M here: the module will be called ivtvfb. + +config VIDEO_FB_IVTV_FORCE_PAT + bool "force cx23415 framebuffer init with x86 PAT enabled" + depends on VIDEO_FB_IVTV && X86_PAT + default n + ---help--- + With PAT enabled, the cx23415 framebuffer driver does not + utilize write-combined caching on the framebuffer memory. + For this reason, the driver will by default disable itself + when initializied on a kernel with PAT enabled (i.e. not + using the nopat kernel parameter). + + The driver is not easily upgradable to the PAT-aware + ioremap_wc() API since the firmware hides the address + ranges that should be marked write-combined from the driver. + + With this setting enabled, the framebuffer will initialize on + PAT-enabled systems but the framebuffer memory will be uncached. + + If unsure, say N. diff --git a/drivers/media/pci/ivtv/ivtv-yuv.c b/drivers/media/pci/ivtv/ivtv-yuv.c index 1380474519f2..c3c2c79585f5 100644 --- a/drivers/media/pci/ivtv/ivtv-yuv.c +++ b/drivers/media/pci/ivtv/ivtv-yuv.c @@ -110,7 +110,7 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, /* * Inherit the -EFAULT from rc's * initialization, but allow it to be - * overriden by uv_pages above if it was an + * overridden by uv_pages above if it was an * actual errno. */ } else { diff --git a/drivers/media/pci/ivtv/ivtvfb.c b/drivers/media/pci/ivtv/ivtvfb.c index 8ec2525d8ef5..cfd21040d0e3 100644 --- a/drivers/media/pci/ivtv/ivtvfb.c +++ b/drivers/media/pci/ivtv/ivtvfb.c @@ -55,6 +55,7 @@ /* card parameters */ static int ivtvfb_card_id = -1; static int ivtvfb_debug = 0; +static bool ivtvfb_force_pat = IS_ENABLED(CONFIG_VIDEO_FB_IVTV_FORCE_PAT); static bool osd_laced; static int osd_depth; static int osd_upper; @@ -64,6 +65,7 @@ static int osd_xres; module_param(ivtvfb_card_id, int, 0444); module_param_named(debug,ivtvfb_debug, int, 0644); +module_param_named(force_pat, ivtvfb_force_pat, bool, 0644); module_param(osd_laced, bool, 0444); module_param(osd_depth, int, 0444); module_param(osd_upper, int, 0444); @@ -79,6 +81,9 @@ MODULE_PARM_DESC(debug, "Debug level (bitmask). Default: errors only\n" "\t\t\t(debug = 3 gives full debugging)"); +MODULE_PARM_DESC(force_pat, + "Force initialization on x86 PAT-enabled systems (bool).\n"); + /* Why upper, left, xres, yres, depth, laced ? To match terminology used by fbset. Why start at 1 for left & upper coordinate ? Because X doesn't allow 0 */ @@ -1167,8 +1172,15 @@ static int ivtvfb_init_card(struct ivtv *itv) #ifdef CONFIG_X86_64 if (pat_enabled()) { - pr_warn("ivtvfb needs PAT disabled, boot with nopat kernel parameter\n"); - return -ENODEV; + if (ivtvfb_force_pat) { + pr_info("PAT is enabled. Write-combined framebuffer caching will be disabled.\n"); + pr_info("To enable caching, boot with nopat kernel parameter\n"); + } else { + pr_warn("ivtvfb needs PAT disabled for write-combined framebuffer caching.\n"); + pr_warn("Boot with nopat kernel parameter to use caching, or use the\n"); + pr_warn("force_pat module parameter to run with caching disabled\n"); + return -ENODEV; + } } #endif diff --git a/drivers/media/pci/meye/meye.c b/drivers/media/pci/meye/meye.c index bd870e60c32b..896d2d856795 100644 --- a/drivers/media/pci/meye/meye.c +++ b/drivers/media/pci/meye/meye.c @@ -805,7 +805,7 @@ again: mchip_hsize() * mchip_vsize() * 2); meye.grab_buffer[reqnr].size = mchip_hsize() * mchip_vsize() * 2; meye.grab_buffer[reqnr].state = MEYE_BUF_DONE; - v4l2_get_timestamp(&meye.grab_buffer[reqnr].timestamp); + meye.grab_buffer[reqnr].ts = ktime_get_ns(); meye.grab_buffer[reqnr].sequence = sequence++; kfifo_in_locked(&meye.doneq, (unsigned char *)&reqnr, sizeof(int), &meye.doneq_lock); @@ -826,7 +826,7 @@ again: size); meye.grab_buffer[reqnr].size = size; meye.grab_buffer[reqnr].state = MEYE_BUF_DONE; - v4l2_get_timestamp(&meye.grab_buffer[reqnr].timestamp); + meye.grab_buffer[reqnr].ts = ktime_get_ns(); meye.grab_buffer[reqnr].sequence = sequence++; kfifo_in_locked(&meye.doneq, (unsigned char *)&reqnr, sizeof(int), &meye.doneq_lock); @@ -1283,7 +1283,7 @@ static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf) buf->flags |= V4L2_BUF_FLAG_DONE; buf->field = V4L2_FIELD_NONE; - buf->timestamp = meye.grab_buffer[index].timestamp; + buf->timestamp = ns_to_timeval(meye.grab_buffer[index].ts); buf->sequence = meye.grab_buffer[index].sequence; buf->memory = V4L2_MEMORY_MMAP; buf->m.offset = index * gbufsize; @@ -1349,7 +1349,7 @@ static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) buf->bytesused = meye.grab_buffer[reqnr].size; buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; buf->field = V4L2_FIELD_NONE; - buf->timestamp = meye.grab_buffer[reqnr].timestamp; + buf->timestamp = ns_to_timeval(meye.grab_buffer[reqnr].ts); buf->sequence = meye.grab_buffer[reqnr].sequence; buf->memory = V4L2_MEMORY_MMAP; buf->m.offset = reqnr * gbufsize; diff --git a/drivers/media/pci/meye/meye.h b/drivers/media/pci/meye/meye.h index c4a8a5fe040c..aff6631535be 100644 --- a/drivers/media/pci/meye/meye.h +++ b/drivers/media/pci/meye/meye.h @@ -277,11 +277,11 @@ struct meye_grab_buffer { int state; /* state of buffer */ unsigned long size; /* size of jpg frame */ - struct timeval timestamp; /* timestamp */ + u64 ts; /* timestamp */ unsigned long sequence; /* sequence number */ }; -/* size of kfifos containings buffer indices */ +/* size of kfifos containing buffer indices */ #define MEYE_QUEUE_SIZE MEYE_MAX_BUFNBRS /* Motion Eye device structure */ diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c index 25f16833a475..27953b3610a3 100644 --- a/drivers/media/pci/ngene/ngene-core.c +++ b/drivers/media/pci/ngene/ngene-core.c @@ -1014,7 +1014,7 @@ static int FillTSIdleBuffer(struct SRingBufferDescriptor *pIdleBuffer, /* Point to first buffer entry */ struct SBufferHeader *Cur = pRingBuffer->Head; int i; - /* Loop thru all buffer and set Buffer 2 pointers to TSIdlebuffer */ + /* Loop through all buffer and set Buffer 2 pointers to TSIdlebuffer */ for (i = 0; i < n; i++) { Cur->Buffer2 = pIdleBuffer->Head->Buffer1; Cur->scList2 = pIdleBuffer->Head->scList1; diff --git a/drivers/media/pci/pt1/pt1.c b/drivers/media/pci/pt1/pt1.c index f4b8030e2369..393f4c596819 100644 --- a/drivers/media/pci/pt1/pt1.c +++ b/drivers/media/pci/pt1/pt1.c @@ -200,16 +200,10 @@ static const u8 va1j5jf8007t_25mhz_configs[][2] = { static int config_demod(struct i2c_client *cl, enum pt1_fe_clk clk) { int ret; - u8 buf[2] = {0x01, 0x80}; bool is_sat; const u8 (*cfg_data)[2]; int i, len; - ret = i2c_master_send(cl, buf, 2); - if (ret < 0) - return ret; - usleep_range(30000, 50000); - is_sat = !strncmp(cl->name, TC90522_I2C_DEV_SAT, strlen(TC90522_I2C_DEV_SAT)); if (is_sat) { @@ -260,6 +254,46 @@ static int config_demod(struct i2c_client *cl, enum pt1_fe_clk clk) return 0; } +/* + * Init registers for (each pair of) terrestrial/satellite block in demod. + * Note that resetting terr. block also resets its peer sat. block as well. + * This function must be called before configuring any demod block + * (before pt1_wakeup(), fe->ops.init()). + */ +static int pt1_demod_block_init(struct pt1 *pt1) +{ + struct i2c_client *cl; + u8 buf[2] = {0x01, 0x80}; + int ret; + int i; + + /* reset all terr. & sat. pairs first */ + for (i = 0; i < PT1_NR_ADAPS; i++) { + cl = pt1->adaps[i]->demod_i2c_client; + if (strncmp(cl->name, TC90522_I2C_DEV_TER, + strlen(TC90522_I2C_DEV_TER))) + continue; + + ret = i2c_master_send(cl, buf, 2); + if (ret < 0) + return ret; + usleep_range(30000, 50000); + } + + for (i = 0; i < PT1_NR_ADAPS; i++) { + cl = pt1->adaps[i]->demod_i2c_client; + if (strncmp(cl->name, TC90522_I2C_DEV_SAT, + strlen(TC90522_I2C_DEV_SAT))) + continue; + + ret = i2c_master_send(cl, buf, 2); + if (ret < 0) + return ret; + usleep_range(30000, 50000); + } + return 0; +} + static void pt1_write_reg(struct pt1 *pt1, int reg, u32 data) { writel(data, pt1->regs + reg * 4); @@ -987,6 +1021,10 @@ static int pt1_init_frontends(struct pt1 *pt1) goto tuner_release; } + ret = pt1_demod_block_init(pt1); + if (ret < 0) + goto fe_unregister; + return 0; tuner_release: @@ -1245,6 +1283,10 @@ static int pt1_resume(struct device *dev) pt1_update_power(pt1); usleep_range(1000, 2000); + ret = pt1_demod_block_init(pt1); + if (ret < 0) + goto resume_err; + for (i = 0; i < PT1_NR_ADAPS; i++) dvb_frontend_reinitialise(pt1->adaps[i]->fe); diff --git a/drivers/media/pci/pt3/pt3.h b/drivers/media/pci/pt3/pt3.h index 495891a4ee17..a53124438f51 100644 --- a/drivers/media/pci/pt3/pt3.h +++ b/drivers/media/pci/pt3/pt3.h @@ -76,7 +76,7 @@ struct xfer_desc { u32 addr_l; /* bus address of target data buffer */ u32 addr_h; u32 size; - u32 next_l; /* bus adddress of the next xfer_desc */ + u32 next_l; /* bus address of the next xfer_desc */ u32 next_h; }; diff --git a/drivers/media/pci/saa7134/saa7134-cards.c b/drivers/media/pci/saa7134/saa7134-cards.c index 40ce033cb884..94d6484a3afe 100644 --- a/drivers/media/pci/saa7134/saa7134-cards.c +++ b/drivers/media/pci/saa7134/saa7134-cards.c @@ -6423,7 +6423,7 @@ struct pci_device_id saa7134_pci_tbl[] = { .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x5168, - .subdevice = 0x3502, /* whats the difference to 0x3306 ?*/ + .subdevice = 0x3502, /* what's the difference to 0x3306 ?*/ .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS, },{ .vendor = PCI_VENDOR_ID_PHILIPS, diff --git a/drivers/media/pci/saa7146/mxb.c b/drivers/media/pci/saa7146/mxb.c index 44440c6208df..e94324b1de68 100644 --- a/drivers/media/pci/saa7146/mxb.c +++ b/drivers/media/pci/saa7146/mxb.c @@ -399,7 +399,7 @@ static int mxb_init_done(struct saa7146_dev* dev) /* check if the saa7740 (aka 'sound arena module') is present on the mxb. if so, we must initialize it. due to lack of - informations about the saa7740, the values were reverse + information about the saa7740, the values were reverse engineered. */ msg.addr = 0x1b; msg.flags = 0; @@ -495,7 +495,7 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input) input_port_selection[input].hps_sync); /* prepare switching of tea6415c and saa7111a; - have a look at the 'background'-file for further informations */ + have a look at the 'background'-file for further information */ switch (input) { case TUNER: i = SAA7115_COMPOSITE0; diff --git a/drivers/media/pci/saa7164/saa7164-api.c b/drivers/media/pci/saa7164/saa7164-api.c index e318ccf81277..d6c996f39cf2 100644 --- a/drivers/media/pci/saa7164/saa7164-api.c +++ b/drivers/media/pci/saa7164/saa7164-api.c @@ -749,7 +749,7 @@ int saa7164_api_initialize_dif(struct saa7164_port *port) if (port->type == SAA7164_MPEG_ENCODER) { /* Pick any analog standard to init the diff. * we'll come back during encoder_init' - * and set the correct standard if requried. + * and set the correct standard if required. */ std = V4L2_STD_NTSC; } else diff --git a/drivers/media/pci/saa7164/saa7164-cards.c b/drivers/media/pci/saa7164/saa7164-cards.c index 3af16062e79d..9a6fe7cd4d59 100644 --- a/drivers/media/pci/saa7164/saa7164-cards.c +++ b/drivers/media/pci/saa7164/saa7164-cards.c @@ -685,7 +685,7 @@ struct saa7164_subid saa7164_subids[] = { .subvendor = 0x0070, .subdevice = 0xf111, .card = SAA7164_BOARD_HAUPPAUGE_HVR2255, - /* Prototype card left here for documenation purposes. + /* Prototype card left here for documentation purposes. .card = SAA7164_BOARD_HAUPPAUGE_HVR2255proto, */ }, { @@ -866,7 +866,7 @@ void saa7164_card_setup(struct saa7164_dev *dev) * access to I2C. Instead we have to communicate through the device f/w for * register access to 'processing units'. Each unit has a unique * id, regardless of how the physical implementation occurs across - * the three physical i2c busses. The being said if we want leverge of + * the three physical i2c buses. The being said if we want leverge of * the existing kernel drivers for tuners and demods we have to 'speak i2c', * to this bridge implements 3 virtual i2c buses. This is a helper function * for those. diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c index f33349e16359..05f25c9bb308 100644 --- a/drivers/media/pci/saa7164/saa7164-core.c +++ b/drivers/media/pci/saa7164/saa7164-core.c @@ -157,7 +157,7 @@ static void saa7164_ts_verifier(struct saa7164_buffer *buf) } - /* Only report errors if we've been through this function atleast + /* Only report errors if we've been through this function at least * once already and the cached cc values are primed. First time through * always generates errors. */ @@ -1020,7 +1020,7 @@ static int saa7164_dev_setup(struct saa7164_dev *dev) dev->bmmio = (u8 __iomem *)dev->lmmio; dev->bmmio2 = (u8 __iomem *)dev->lmmio2; - /* Inerrupt and ack register locations offset of bmmio */ + /* Interrupt and ack register locations offset of bmmio */ dev->int_status = 0x183000 + 0xf80; dev->int_ack = 0x183000 + 0xf90; diff --git a/drivers/media/pci/saa7164/saa7164-dvb.c b/drivers/media/pci/saa7164/saa7164-dvb.c index dfb118d7d1ec..3e73cb3c7e88 100644 --- a/drivers/media/pci/saa7164/saa7164-dvb.c +++ b/drivers/media/pci/saa7164/saa7164-dvb.c @@ -529,7 +529,7 @@ int saa7164_dvb_unregister(struct saa7164_port *port) return 0; } -/* All the DVB attach calls go here, this function get's modified +/* All the DVB attach calls go here, this function gets modified * for each new card. */ int saa7164_dvb_register(struct saa7164_port *port) diff --git a/drivers/media/pci/saa7164/saa7164-fw.c b/drivers/media/pci/saa7164/saa7164-fw.c index a50461861133..ed27b3ce5e8e 100644 --- a/drivers/media/pci/saa7164/saa7164-fw.c +++ b/drivers/media/pci/saa7164/saa7164-fw.c @@ -409,7 +409,7 @@ int saa7164_downloadfirmware(struct saa7164_dev *dev) (version & 0x0000001f), (version & 0xffff0000) >> 16); - /* Load the firmwware from the disk if required */ + /* Load the firmware from the disk if required */ if (version == 0) { printk(KERN_INFO "%s() Waiting for firmware upload (%s)\n", diff --git a/drivers/media/pci/smipcie/smipcie-ir.c b/drivers/media/pci/smipcie/smipcie-ir.c index c5595af6b976..d292cdfb3671 100644 --- a/drivers/media/pci/smipcie/smipcie-ir.c +++ b/drivers/media/pci/smipcie/smipcie-ir.c @@ -16,6 +16,9 @@ #include "smipcie.h" +#define SMI_SAMPLE_PERIOD 83 +#define SMI_SAMPLE_IDLEMIN (10000 / SMI_SAMPLE_PERIOD) + static void smi_ir_enableInterrupt(struct smi_rc *ir) { struct smi_dev *dev = ir->dev; @@ -42,114 +45,64 @@ static void smi_ir_stop(struct smi_rc *ir) struct smi_dev *dev = ir->dev; smi_ir_disableInterrupt(ir); - smi_clear(IR_Init_Reg, 0x80); + smi_clear(IR_Init_Reg, rbIRen); } -#define BITS_PER_COMMAND 14 -#define GROUPS_PER_BIT 2 -#define IR_RC5_MIN_BIT 36 -#define IR_RC5_MAX_BIT 52 -static u32 smi_decode_rc5(u8 *pData, u8 size) +static void smi_raw_process(struct rc_dev *rc_dev, const u8 *buffer, + const u8 length) { - u8 index, current_bit, bit_count; - u8 group_array[BITS_PER_COMMAND * GROUPS_PER_BIT + 4]; - u8 group_index = 0; - u32 command = 0xFFFFFFFF; - - group_array[group_index++] = 1; - - for (index = 0; index < size; index++) { - - current_bit = (pData[index] & 0x80) ? 1 : 0; - bit_count = pData[index] & 0x7f; - - if ((current_bit == 1) && (bit_count >= 2*IR_RC5_MAX_BIT + 1)) { - goto process_code; - } else if ((bit_count >= IR_RC5_MIN_BIT) && - (bit_count <= IR_RC5_MAX_BIT)) { - group_array[group_index++] = current_bit; - } else if ((bit_count > IR_RC5_MAX_BIT) && - (bit_count <= 2*IR_RC5_MAX_BIT)) { - group_array[group_index++] = current_bit; - group_array[group_index++] = current_bit; - } else { - goto invalid_timing; - } - if (group_index >= BITS_PER_COMMAND*GROUPS_PER_BIT) - goto process_code; - - if ((group_index == BITS_PER_COMMAND*GROUPS_PER_BIT - 1) - && (group_array[group_index-1] == 0)) { - group_array[group_index++] = 1; - goto process_code; - } - } - -process_code: - if (group_index == (BITS_PER_COMMAND*GROUPS_PER_BIT-1)) - group_array[group_index++] = 1; - - if (group_index == BITS_PER_COMMAND*GROUPS_PER_BIT) { - command = 0; - for (index = 0; index < (BITS_PER_COMMAND*GROUPS_PER_BIT); - index = index + 2) { - if ((group_array[index] == 1) && - (group_array[index+1] == 0)) { - command |= (1 << (BITS_PER_COMMAND - - (index/2) - 1)); - } else if ((group_array[index] == 0) && - (group_array[index+1] == 1)) { - /* */ - } else { - command = 0xFFFFFFFF; - goto invalid_timing; - } + struct ir_raw_event rawir = {}; + int cnt; + + for (cnt = 0; cnt < length; cnt++) { + if (buffer[cnt] & 0x7f) { + rawir.pulse = (buffer[cnt] & 0x80) == 0; + rawir.duration = ((buffer[cnt] & 0x7f) + + (rawir.pulse ? 0 : -1)) * + rc_dev->rx_resolution; + ir_raw_event_store_with_filter(rc_dev, &rawir); } } - -invalid_timing: - return command; } -static void smi_ir_decode(struct work_struct *work) +static void smi_ir_decode(struct smi_rc *ir) { - struct smi_rc *ir = container_of(work, struct smi_rc, work); struct smi_dev *dev = ir->dev; struct rc_dev *rc_dev = ir->rc_dev; - u32 dwIRControl, dwIRData, dwIRCode, scancode; - u8 index, ucIRCount, readLoop, rc5_command, rc5_system, toggle; + u32 dwIRControl, dwIRData; + u8 index, ucIRCount, readLoop; dwIRControl = smi_read(IR_Init_Reg); + if (dwIRControl & rbIRVld) { ucIRCount = (u8) smi_read(IR_Data_Cnt); - if (ucIRCount < 4) - goto end_ir_decode; - readLoop = ucIRCount/4; if (ucIRCount % 4) readLoop += 1; for (index = 0; index < readLoop; index++) { - dwIRData = smi_read(IR_DATA_BUFFER_BASE + (index*4)); + dwIRData = smi_read(IR_DATA_BUFFER_BASE + (index * 4)); ir->irData[index*4 + 0] = (u8)(dwIRData); ir->irData[index*4 + 1] = (u8)(dwIRData >> 8); ir->irData[index*4 + 2] = (u8)(dwIRData >> 16); ir->irData[index*4 + 3] = (u8)(dwIRData >> 24); } - dwIRCode = smi_decode_rc5(ir->irData, ucIRCount); - - if (dwIRCode != 0xFFFFFFFF) { - rc5_command = dwIRCode & 0x3F; - rc5_system = (dwIRCode & 0x7C0) >> 6; - toggle = (dwIRCode & 0x800) ? 1 : 0; - scancode = rc5_system << 8 | rc5_command; - rc_keydown(rc_dev, RC_PROTO_RC5, scancode, toggle); - } + smi_raw_process(rc_dev, ir->irData, ucIRCount); + smi_set(IR_Init_Reg, rbIRVld); } -end_ir_decode: - smi_set(IR_Init_Reg, 0x04); - smi_ir_enableInterrupt(ir); + + if (dwIRControl & rbIRhighidle) { + struct ir_raw_event rawir = {}; + + rawir.pulse = 0; + rawir.duration = US_TO_NS(SMI_SAMPLE_PERIOD * + SMI_SAMPLE_IDLEMIN); + ir_raw_event_store_with_filter(rc_dev, &rawir); + smi_set(IR_Init_Reg, rbIRhighidle); + } + + ir_raw_event_handle(rc_dev); } /* ir functions call by main driver.*/ @@ -160,7 +113,8 @@ int smi_ir_irq(struct smi_rc *ir, u32 int_status) if (int_status & IR_X_INT) { smi_ir_disableInterrupt(ir); smi_ir_clearInterrupt(ir); - schedule_work(&ir->work); + smi_ir_decode(ir); + smi_ir_enableInterrupt(ir); handled = 1; } return handled; @@ -170,9 +124,11 @@ void smi_ir_start(struct smi_rc *ir) { struct smi_dev *dev = ir->dev; - smi_write(IR_Idle_Cnt_Low, 0x00140070); + smi_write(IR_Idle_Cnt_Low, + (((SMI_SAMPLE_PERIOD - 1) & 0xFFFF) << 16) | + (SMI_SAMPLE_IDLEMIN & 0xFFFF)); msleep(20); - smi_set(IR_Init_Reg, 0x90); + smi_set(IR_Init_Reg, rbIRen | rbIRhighidle); smi_ir_enableInterrupt(ir); } @@ -183,7 +139,7 @@ int smi_ir_init(struct smi_dev *dev) struct rc_dev *rc_dev; struct smi_rc *ir = &dev->ir; - rc_dev = rc_allocate_device(RC_DRIVER_SCANCODE); + rc_dev = rc_allocate_device(RC_DRIVER_IR_RAW); if (!rc_dev) return -ENOMEM; @@ -193,6 +149,7 @@ int smi_ir_init(struct smi_dev *dev) snprintf(ir->input_phys, sizeof(ir->input_phys), "pci-%s/ir0", pci_name(dev->pci_dev)); + rc_dev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; rc_dev->driver_name = "SMI_PCIe"; rc_dev->input_phys = ir->input_phys; rc_dev->device_name = ir->device_name; @@ -203,11 +160,12 @@ int smi_ir_init(struct smi_dev *dev) rc_dev->dev.parent = &dev->pci_dev->dev; rc_dev->map_name = dev->info->rc_map; + rc_dev->timeout = MS_TO_NS(100); + rc_dev->rx_resolution = US_TO_NS(SMI_SAMPLE_PERIOD); ir->rc_dev = rc_dev; ir->dev = dev; - INIT_WORK(&ir->work, smi_ir_decode); smi_ir_disableInterrupt(ir); ret = rc_register_device(rc_dev); diff --git a/drivers/media/pci/smipcie/smipcie.h b/drivers/media/pci/smipcie/smipcie.h index a6c5b1bd7edb..e52229a87b84 100644 --- a/drivers/media/pci/smipcie/smipcie.h +++ b/drivers/media/pci/smipcie/smipcie.h @@ -241,7 +241,6 @@ struct smi_rc { struct rc_dev *rc_dev; char input_phys[64]; char device_name[64]; - struct work_struct work; u8 irData[256]; int users; diff --git a/drivers/media/pci/solo6x10/solo6x10-disp.c b/drivers/media/pci/solo6x10/solo6x10-disp.c index 11c98f0625e4..f61007022471 100644 --- a/drivers/media/pci/solo6x10/solo6x10-disp.c +++ b/drivers/media/pci/solo6x10/solo6x10-disp.c @@ -71,7 +71,7 @@ static void solo_vin_config(struct solo_dev *solo_dev) solo_reg_write(solo_dev, SOLO_VI_CH_FORMAT, SOLO_VI_FD_SEL_MASK(0) | SOLO_VI_PROG_MASK(0)); - /* On 6110, initialize mozaic darkness stength */ + /* On 6110, initialize mozaic darkness strength */ if (solo_dev->type == SOLO_DEV_6010) solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 0); else @@ -230,7 +230,7 @@ int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch, } /* First 8k is motion flag (512 bytes * 16). Following that is an 8k+8k - * threshold and working table for each channel. Atleast that's what the + * threshold and working table for each channel. At least that's what the * spec says. However, this code (taken from rdk) has some mystery 8k * block right after the flag area, before the first thresh table. */ static void solo_motion_config(struct solo_dev *solo_dev) diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c index 411177ec4d72..2452d8f59cb0 100644 --- a/drivers/media/pci/sta2x11/sta2x11_vip.c +++ b/drivers/media/pci/sta2x11/sta2x11_vip.c @@ -110,7 +110,7 @@ static inline struct vip_buffer *to_vip_buffer(struct vb2_v4l2_buffer *vb2) * @std: video standard (e.g. PAL/NTSC) * @input: input line for video signal ( 0 or 1 ) * @disabled: Device is in power down state - * @slock: for excluse acces of registers + * @slock: for excluse access of registers * @vb_vidq: queue maintained by videobuf2 layer * @buffer_list: list of buffer in use * @sequence: sequence number of acquired buffer diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c index 409defc75c05..9345287ad963 100644 --- a/drivers/media/pci/ttpci/av7110.c +++ b/drivers/media/pci/ttpci/av7110.c @@ -2313,7 +2313,7 @@ static int frontend_init(struct av7110 *av7110) * (n in defined in the RPS_THRESH1 counter threshold) * I think HS is raised high on the beginning of the n-th line * and remains high until this n-th line that triggered - * it is completely received. When the receiption of n-th line + * it is completely received. When the reception of n-th line * ends, HS is lowered. * * To transmit data over DMA, 7146 needs changing state at @@ -2347,7 +2347,7 @@ static int frontend_init(struct av7110 *av7110) * hardware debug note: a working budget card (including budget patch) * with vpeirq() interrupt setup in mode "0x90" (every 64K) will * generate 3 interrupts per 25-Hz DMA frame of 2*188*512 bytes - * and that means 3*25=75 Hz of interrupt freqency, as seen by + * and that means 3*25=75 Hz of interrupt frequency, as seen by * watch cat /proc/interrupts * * If this frequency is 3x lower (and data received in the DMA @@ -2356,7 +2356,7 @@ static int frontend_init(struct av7110 *av7110) * this means VSYNC line is not connected in the hardware. * (check soldering pcb and pins) * The same behaviour of missing VSYNC can be duplicated on budget - * cards, by seting DD1_INIT trigger mode 7 in 3rd nibble. + * cards, by setting DD1_INIT trigger mode 7 in 3rd nibble. */ static int av7110_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *pci_ext) diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c index d3f727045ae8..4f74b14c3b4f 100644 --- a/drivers/media/pci/tw68/tw68-video.c +++ b/drivers/media/pci/tw68/tw68-video.c @@ -446,7 +446,7 @@ static void tw68_buf_queue(struct vb2_buffer *vb) /* * buffer_prepare * - * Set the ancilliary information into the buffer structure. This + * Set the ancillary information into the buffer structure. This * includes generating the necessary risc program if it hasn't already * been done for the current buffer format. * The structure fh contains the details of the format requested by the diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index a505e9f5a1e2..4acbed189644 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -141,7 +141,6 @@ config VIDEO_RENESAS_CEU ---help--- This is a v4l2 driver for the Renesas CEU Interface -source "drivers/media/platform/soc_camera/Kconfig" source "drivers/media/platform/exynos4-is/Kconfig" source "drivers/media/platform/am437x/Kconfig" source "drivers/media/platform/xilinx/Kconfig" @@ -650,7 +649,7 @@ config VIDEO_SECO_CEC config VIDEO_SECO_RC bool "SECO Boards IR RC5 support" depends on VIDEO_SECO_CEC - select RC_CORE + depends on RC_CORE help If you say yes here you will get support for the SECO Boards Consumer-IR in seco-cec driver. @@ -669,7 +668,7 @@ menuconfig SDR_PLATFORM_DRIVERS if SDR_PLATFORM_DRIVERS config VIDEO_RCAR_DRIF - tristate "Renesas Digitial Radio Interface (DRIF)" + tristate "Renesas Digital Radio Interface (DRIF)" depends on VIDEO_V4L2 depends on ARCH_RENESAS || COMPILE_TEST select VIDEOBUF2_VMALLOC diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index e6deb2597738..7cbbd925124c 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -62,8 +62,6 @@ obj-y += davinci/ obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o -obj-$(CONFIG_SOC_CAMERA) += soc_camera/ - obj-$(CONFIG_VIDEO_RCAR_DRIF) += rcar_drif.o obj-$(CONFIG_VIDEO_RENESAS_CEU) += renesas-ceu.o obj-$(CONFIG_VIDEO_RENESAS_FCP) += rcar-fcp.o diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c index dfec813f50a9..692e08ef38c0 100644 --- a/drivers/media/platform/aspeed-video.c +++ b/drivers/media/platform/aspeed-video.c @@ -1661,6 +1661,7 @@ static int aspeed_video_probe(struct platform_device *pdev) video->frame_rate = 30; video->dev = &pdev->dev; + spin_lock_init(&video->lock); mutex_init(&video->video_lock); init_waitqueue_head(&video->wait); INIT_DELAYED_WORK(&video->res_work, aspeed_video_resolution_work); diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c index fdb255e4a956..08b8d5583080 100644 --- a/drivers/media/platform/atmel/atmel-isi.c +++ b/drivers/media/platform/atmel/atmel-isi.c @@ -110,7 +110,7 @@ struct atmel_isi { bool enable_preview_path; struct completion complete; - /* ISI peripherial clock */ + /* ISI peripheral clock */ struct clk *pclk; unsigned int irq; @@ -1078,7 +1078,7 @@ static void isi_graph_notify_unbind(struct v4l2_async_notifier *notifier, dev_dbg(isi->dev, "Removing %s\n", video_device_node_name(isi->vdev)); - /* Checks internaly if vdev have been init or not */ + /* Checks internally if vdev have been init or not */ video_unregister_device(isi->vdev); } diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 8e0194993a52..b4f396c2e72c 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -1010,7 +1010,11 @@ static int coda_start_encoding(struct coda_ctx *ctx) CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET) | ((ctx->params.h264_slice_beta_offset_div2 & CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK) << - CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET); + CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET) | + (ctx->params.h264_constrained_intra_pred_flag << + CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_OFFSET) | + (ctx->params.h264_chroma_qp_index_offset & + CODA_264PARAM_CHROMAQPOFFSET_MASK); coda_write(dev, value, CODA_CMD_ENC_SEQ_264_PARA); break; case V4L2_PIX_FMT_JPEG: @@ -2020,7 +2024,6 @@ static void coda_finish_decode(struct coda_ctx *ctx) struct coda_q_data *q_data_dst; struct vb2_v4l2_buffer *dst_buf; struct coda_buffer_meta *meta; - unsigned long payload; int width, height; int decoded_idx; int display_idx; @@ -2226,21 +2229,8 @@ static void coda_finish_decode(struct coda_ctx *ctx) trace_coda_dec_rot_done(ctx, dst_buf, meta); - switch (q_data_dst->fourcc) { - case V4L2_PIX_FMT_YUYV: - payload = width * height * 2; - break; - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_YVU420: - case V4L2_PIX_FMT_NV12: - default: - payload = width * height * 3 / 2; - break; - case V4L2_PIX_FMT_YUV422P: - payload = width * height * 2; - break; - } - vb2_set_plane_payload(&dst_buf->vb2_buf, 0, payload); + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, + q_data_dst->sizeimage); if (ctx->frame_errors[ctx->display_idx] || err_vdoa) coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_ERROR); diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 7518f01c48f7..fa0b22fb7991 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -728,7 +728,7 @@ static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f, ctx->tiled_map_type = GDI_TILED_FRAME_MB_RASTER_MAP; break; case V4L2_PIX_FMT_NV12: - if (!disable_tiling) { + if (!disable_tiling && ctx->dev->devtype->product == CODA_960) { ctx->tiled_map_type = GDI_TILED_FRAME_MB_RASTER_MAP; break; } @@ -1839,6 +1839,12 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: ctx->params.h264_disable_deblocking_filter_idc = ctrl->val; break; + case V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION: + ctx->params.h264_constrained_intra_pred_flag = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET: + ctx->params.h264_chroma_qp_index_offset = ctrl->val; + break; case V4L2_CID_MPEG_VIDEO_H264_PROFILE: /* TODO: switch between baseline and constrained baseline */ if (ctx->inst_type == CODA_INST_ENCODER) @@ -1925,6 +1931,11 @@ static void coda_encode_ctrls(struct coda_ctx *ctx) V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY, 0x0, V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION, 0, 1, 1, + 0); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET, -12, 12, 1, 0); v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_PROFILE, V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, 0x0, diff --git a/drivers/media/platform/coda/coda-jpeg.c b/drivers/media/platform/coda/coda-jpeg.c index 9f899a6cefed..39a2351c1e48 100644 --- a/drivers/media/platform/coda/coda-jpeg.c +++ b/drivers/media/platform/coda/coda-jpeg.c @@ -103,7 +103,7 @@ static const unsigned char chroma_ac_value[162 + 2] = { /* * Quantization tables for luminance and chrominance components in - * zig-zag scan order from the Freescale i.MX VPU libaries + * zig-zag scan order from the Freescale i.MX VPU libraries */ static unsigned char luma_q[64] = { diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index 31cea72f5b2a..31c80bda2c0b 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -118,6 +118,8 @@ struct coda_params { u8 h264_disable_deblocking_filter_idc; s8 h264_slice_alpha_c0_offset_div2; s8 h264_slice_beta_offset_div2; + bool h264_constrained_intra_pred_flag; + s8 h264_chroma_qp_index_offset; u8 h264_profile_idc; u8 h264_level_idc; u8 mpeg4_intra_qp; diff --git a/drivers/media/platform/davinci/isif.c b/drivers/media/platform/davinci/isif.c index 340f8218f54d..47cecd10eb9f 100644 --- a/drivers/media/platform/davinci/isif.c +++ b/drivers/media/platform/davinci/isif.c @@ -328,7 +328,7 @@ static void isif_config_bclamp(struct isif_black_clamp *bc) if (bc->en) { val = bc->bc_mode_color << ISIF_BC_MODE_COLOR_SHIFT; - /* Enable BC and horizontal clamp caculation paramaters */ + /* Enable BC and horizontal clamp calculation parameters */ val = val | 1 | (bc->horz.mode << ISIF_HORZ_BC_MODE_SHIFT); regw(val, CLAMPCFG); @@ -358,7 +358,7 @@ static void isif_config_bclamp(struct isif_black_clamp *bc) regw(bc->horz.win_start_v_calc, CLHWIN2); } - /* vertical clamp caculation paramaters */ + /* vertical clamp calculation parameters */ /* Reset clamp value sel for previous line */ val |= diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c index 4766a7a23d16..8339163a5231 100644 --- a/drivers/media/platform/davinci/vpbe.c +++ b/drivers/media/platform/davinci/vpbe.c @@ -242,7 +242,7 @@ static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index) goto unlock; /* - * It is assumed that venc or extenal encoder will set a default + * It is assumed that venc or external encoder will set a default * mode in the sub device. For external encoder or LCD pannel output, * we also need to set up the lcd port for the required mode. So setup * the lcd port for the default mode that is configured in the board diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index 9996bab98fe3..26dadbba930f 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -518,7 +518,7 @@ static void vpfe_schedule_bottom_field(struct vpfe_device *vpfe_dev) static void vpfe_process_buffer_complete(struct vpfe_device *vpfe_dev) { - v4l2_get_timestamp(&vpfe_dev->cur_frm->ts); + vpfe_dev->cur_frm->ts = ktime_get_ns(); vpfe_dev->cur_frm->state = VIDEOBUF_DONE; vpfe_dev->cur_frm->size = vpfe_dev->fmt.fmt.pix.sizeimage; wake_up_interruptible(&vpfe_dev->cur_frm->done); diff --git a/drivers/media/platform/davinci/vpif.c b/drivers/media/platform/davinci/vpif.c index 16352e2263d2..df66461f5d4f 100644 --- a/drivers/media/platform/davinci/vpif.c +++ b/drivers/media/platform/davinci/vpif.c @@ -1,7 +1,7 @@ /* * vpif - Video Port Interface driver * VPIF is a receiver and transmitter for video data. It has two channels(0, 1) - * that receiveing video byte stream and two channels(2, 3) for video output. + * that receiving video byte stream and two channels(2, 3) for video output. * The hardware supports SDTV, HDTV formats, raw data capture. * Currently, the driver supports NTSC and PAL standards. * diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index 3517487d9760..f4b4f2a1dfc0 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -138,7 +138,7 @@ static int vpif_buffer_queue_setup(struct vb2_queue *vq, * vpif_buffer_queue : Callback function to add buffer to DMA queue * @vb: ptr to vb2_buffer * - * This callback fucntion queues the buffer to DMA engine + * This callback function queues the buffer to DMA engine */ static void vpif_buffer_queue(struct vb2_buffer *vb) { @@ -635,7 +635,7 @@ static int vpif_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; /* - * to supress v4l-compliance warnings silently correct + * to suppress v4l-compliance warnings silently correct * the pixelformat */ if (pixfmt->pixelformat != V4L2_PIX_FMT_YUV422P) diff --git a/drivers/media/platform/exynos4-is/fimc-is-command.h b/drivers/media/platform/exynos4-is/fimc-is-command.h index 0d1f52e394b1..b06b56b890d5 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-command.h +++ b/drivers/media/platform/exynos4-is/fimc-is-command.h @@ -18,7 +18,7 @@ #define FIMC_IS_COMMAND_VER 110 /* FIMC-IS command set version 1.10 */ -/* Enumeration of commands beetween the FIMC-IS and the host processor. */ +/* Enumeration of commands between the FIMC-IS and the host processor. */ /* HOST to FIMC-IS */ #define HIC_PREVIEW_STILL 0x0001 diff --git a/drivers/media/platform/exynos4-is/fimc-is-param.h b/drivers/media/platform/exynos4-is/fimc-is-param.h index 8e31f7642776..22923a3d405e 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-param.h +++ b/drivers/media/platform/exynos4-is/fimc-is-param.h @@ -298,7 +298,7 @@ enum isp_af_mode { #define ISP_FLASH_COMMAND_AUTO 2 #define ISP_FLASH_COMMAND_TORCH 3 /* 3 sec */ -/* Flash red-eye commads */ +/* Flash red-eye commands */ #define ISP_FLASH_REDEYE_DISABLE 0 #define ISP_FLASH_REDEYE_ENABLE 1 diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c index f5fc54de19da..02da0b06e56a 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.c +++ b/drivers/media/platform/exynos4-is/fimc-is.c @@ -738,7 +738,7 @@ int fimc_is_hw_initialize(struct fimc_is *is) return 0; } -static int fimc_is_log_show(struct seq_file *s, void *data) +static int fimc_is_show(struct seq_file *s, void *data) { struct fimc_is *is = s->private; const u8 *buf = is->memory.vaddr + FIMC_IS_DEBUG_REGION_OFFSET; @@ -752,17 +752,7 @@ static int fimc_is_log_show(struct seq_file *s, void *data) return 0; } -static int fimc_is_debugfs_open(struct inode *inode, struct file *file) -{ - return single_open(file, fimc_is_log_show, inode->i_private); -} - -static const struct file_operations fimc_is_debugfs_fops = { - .open = fimc_is_debugfs_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(fimc_is); static void fimc_is_debugfs_remove(struct fimc_is *is) { @@ -777,7 +767,7 @@ static int fimc_is_debugfs_create(struct fimc_is *is) is->debugfs_entry = debugfs_create_dir("fimc_is", NULL); dentry = debugfs_create_file("fw_log", S_IRUGO, is->debugfs_entry, - is, &fimc_is_debugfs_fops); + is, &fimc_is_fops); if (!dentry) fimc_is_debugfs_remove(is); diff --git a/drivers/media/platform/exynos4-is/fimc-isp-video.c b/drivers/media/platform/exynos4-is/fimc-isp-video.c index de6bd28f7e31..bb35a2017f21 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp-video.c +++ b/drivers/media/platform/exynos4-is/fimc-isp-video.c @@ -606,9 +606,7 @@ int fimc_isp_video_device_register(struct fimc_isp *isp, vdev = &iv->ve.vdev; memset(vdev, 0, sizeof(*vdev)); - snprintf(vdev->name, sizeof(vdev->name), "fimc-is-isp.%s", - type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ? - "capture" : "output"); + strscpy(vdev->name, "fimc-is-isp.capture", sizeof(vdev->name)); vdev->queue = q; vdev->fops = &isp_video_fops; vdev->ioctl_ops = &isp_video_ioctl_ops; diff --git a/drivers/media/platform/exynos4-is/media-dev.h b/drivers/media/platform/exynos4-is/media-dev.h index 9f527670395a..a7c9490bbcb4 100644 --- a/drivers/media/platform/exynos4-is/media-dev.h +++ b/drivers/media/platform/exynos4-is/media-dev.h @@ -79,7 +79,7 @@ struct fimc_camclk_info { /** * struct fimc_sensor_info - image data source subdev information - * @pdata: sensor's atrributes passed as media device's platform data + * @pdata: sensor's attributes passed as media device's platform data * @asd: asynchronous subdev registration data structure * @subdev: image sensor v4l2 subdev * @host: fimc device the sensor is currently linked to diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c index 35cb0162085b..234e047e3e8f 100644 --- a/drivers/media/platform/exynos4-is/mipi-csis.c +++ b/drivers/media/platform/exynos4-is/mipi-csis.c @@ -183,7 +183,7 @@ struct csis_drvdata { * @index: the hardware instance index * @pdev: CSIS platform device * @phy: pointer to the CSIS generic PHY - * @regs: mmaped I/O registers memory + * @regs: mmapped I/O registers memory * @supplies: CSIS regulator supplies * @clock: CSIS clocks * @irq: requested s5p-mipi-csis irq number @@ -745,7 +745,7 @@ static int s5pcsis_parse_dt(struct platform_device *pdev, goto err; } - /* Get MIPI CSI-2 bus configration from the endpoint node. */ + /* Get MIPI CSI-2 bus configuration from the endpoint node. */ of_property_read_u32(node, "samsung,csis-hs-settle", &state->hs_settle); state->wclk_ext = of_property_read_bool(node, diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c index ca6d0317ab42..cffebcaacb90 100644 --- a/drivers/media/platform/fsl-viu.c +++ b/drivers/media/platform/fsl-viu.c @@ -1090,7 +1090,7 @@ static void viu_capture_intr(struct viu_dev *dev, u32 status) if (waitqueue_active(&buf->vb.done)) { list_del(&buf->vb.queue); - v4l2_get_timestamp(&buf->vb.ts); + buf->vb.ts = ktime_get_ns(); buf->vb.state = VIDEOBUF_DONE; buf->vb.field_count++; wake_up(&buf->vb.done); diff --git a/drivers/media/platform/imx-pxp.c b/drivers/media/platform/imx-pxp.c index c1c255408d16..0bcfc5aa8f3d 100644 --- a/drivers/media/platform/imx-pxp.c +++ b/drivers/media/platform/imx-pxp.c @@ -90,7 +90,11 @@ static struct pxp_fmt formats[] = { .depth = 16, .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, }, { - .fourcc = V4L2_PIX_FMT_YUV32, + .fourcc = V4L2_PIX_FMT_VUYA32, + .depth = 32, + .types = MEM2MEM_CAPTURE, + }, { + .fourcc = V4L2_PIX_FMT_VUYX32, .depth = 32, .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, }, { @@ -236,7 +240,7 @@ static u32 pxp_v4l2_pix_fmt_to_ps_format(u32 v4l2_pix_fmt) case V4L2_PIX_FMT_RGB555: return BV_PXP_PS_CTRL_FORMAT__RGB555; case V4L2_PIX_FMT_RGB444: return BV_PXP_PS_CTRL_FORMAT__RGB444; case V4L2_PIX_FMT_RGB565: return BV_PXP_PS_CTRL_FORMAT__RGB565; - case V4L2_PIX_FMT_YUV32: return BV_PXP_PS_CTRL_FORMAT__YUV1P444; + case V4L2_PIX_FMT_VUYX32: return BV_PXP_PS_CTRL_FORMAT__YUV1P444; case V4L2_PIX_FMT_UYVY: return BV_PXP_PS_CTRL_FORMAT__UYVY1P422; case V4L2_PIX_FMT_YUYV: return BM_PXP_PS_CTRL_WB_SWAP | BV_PXP_PS_CTRL_FORMAT__UYVY1P422; @@ -265,7 +269,8 @@ static u32 pxp_v4l2_pix_fmt_to_out_format(u32 v4l2_pix_fmt) case V4L2_PIX_FMT_RGB555: return BV_PXP_OUT_CTRL_FORMAT__RGB555; case V4L2_PIX_FMT_RGB444: return BV_PXP_OUT_CTRL_FORMAT__RGB444; case V4L2_PIX_FMT_RGB565: return BV_PXP_OUT_CTRL_FORMAT__RGB565; - case V4L2_PIX_FMT_YUV32: return BV_PXP_OUT_CTRL_FORMAT__YUV1P444; + case V4L2_PIX_FMT_VUYA32: + case V4L2_PIX_FMT_VUYX32: return BV_PXP_OUT_CTRL_FORMAT__YUV1P444; case V4L2_PIX_FMT_UYVY: return BV_PXP_OUT_CTRL_FORMAT__UYVY1P422; case V4L2_PIX_FMT_VYUY: return BV_PXP_OUT_CTRL_FORMAT__VYUY1P422; case V4L2_PIX_FMT_GREY: return BV_PXP_OUT_CTRL_FORMAT__Y8; @@ -281,7 +286,8 @@ static u32 pxp_v4l2_pix_fmt_to_out_format(u32 v4l2_pix_fmt) static bool pxp_v4l2_pix_fmt_is_yuv(u32 v4l2_pix_fmt) { switch (v4l2_pix_fmt) { - case V4L2_PIX_FMT_YUV32: + case V4L2_PIX_FMT_VUYA32: + case V4L2_PIX_FMT_VUYX32: case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_VYUY: @@ -680,7 +686,7 @@ static void pxp_setup_csc(struct pxp_ctx *ctx) csc2_coef = csc2_coef_rec709_full; else csc2_coef = csc2_coef_rec709_lim; - } else if (ycbcr_enc == V4L2_YCBCR_ENC_709) { + } else if (ycbcr_enc == V4L2_YCBCR_ENC_BT2020) { if (quantization == V4L2_QUANTIZATION_FULL_RANGE) csc2_coef = csc2_coef_bt2020_full; else diff --git a/drivers/media/platform/marvell-ccic/mmp-driver.c b/drivers/media/platform/marvell-ccic/mmp-driver.c index 70a2833db0d1..af76eb637773 100644 --- a/drivers/media/platform/marvell-ccic/mmp-driver.c +++ b/drivers/media/platform/marvell-ccic/mmp-driver.c @@ -240,8 +240,8 @@ static void mmpcam_calc_dphy(struct mcam_camera *mcam) * bit 8 ~ bit 15: HS_SETTLE * Time interval during which the HS * receiver shall ignore any Data Lane - * HS transistions. - * The vaule has been calibrated on + * HS transitions. + * The value has been calibrated on * different boards. It seems to work well. * * More detail please refer diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c index 2a5d5002c27e..f761e4d8bf2a 100644 --- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c @@ -702,7 +702,7 @@ end: v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, to_vb2_v4l2_buffer(vb)); } -static void *mtk_jpeg_buf_remove(struct mtk_jpeg_ctx *ctx, +static struct vb2_v4l2_buffer *mtk_jpeg_buf_remove(struct mtk_jpeg_ctx *ctx, enum v4l2_buf_type type) { if (V4L2_TYPE_IS_OUTPUT(type)) @@ -714,7 +714,7 @@ static void *mtk_jpeg_buf_remove(struct mtk_jpeg_ctx *ctx, static int mtk_jpeg_start_streaming(struct vb2_queue *q, unsigned int count) { struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(q); - struct vb2_buffer *vb; + struct vb2_v4l2_buffer *vb; int ret = 0; ret = pm_runtime_get_sync(ctx->jpeg->dev); @@ -724,14 +724,14 @@ static int mtk_jpeg_start_streaming(struct vb2_queue *q, unsigned int count) return 0; err: while ((vb = mtk_jpeg_buf_remove(ctx, q->type))) - v4l2_m2m_buf_done(to_vb2_v4l2_buffer(vb), VB2_BUF_STATE_QUEUED); + v4l2_m2m_buf_done(vb, VB2_BUF_STATE_QUEUED); return ret; } static void mtk_jpeg_stop_streaming(struct vb2_queue *q) { struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(q); - struct vb2_buffer *vb; + struct vb2_v4l2_buffer *vb; /* * STREAMOFF is an acknowledgment for source change event. @@ -743,7 +743,7 @@ static void mtk_jpeg_stop_streaming(struct vb2_queue *q) struct mtk_jpeg_src_buf *src_buf; vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - src_buf = mtk_jpeg_vb2_to_srcbuf(vb); + src_buf = mtk_jpeg_vb2_to_srcbuf(&vb->vb2_buf); mtk_jpeg_set_queue_data(ctx, &src_buf->dec_param); ctx->state = MTK_JPEG_RUNNING; } else if (V4L2_TYPE_IS_OUTPUT(q->type)) { @@ -751,7 +751,7 @@ static void mtk_jpeg_stop_streaming(struct vb2_queue *q) } while ((vb = mtk_jpeg_buf_remove(ctx, q->type))) - v4l2_m2m_buf_done(to_vb2_v4l2_buffer(vb), VB2_BUF_STATE_ERROR); + v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR); pm_runtime_put_sync(ctx->jpeg->dev); } @@ -807,7 +807,7 @@ static void mtk_jpeg_device_run(void *priv) { struct mtk_jpeg_ctx *ctx = priv; struct mtk_jpeg_dev *jpeg = ctx->jpeg; - struct vb2_buffer *src_buf, *dst_buf; + struct vb2_v4l2_buffer *src_buf, *dst_buf; enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR; unsigned long flags; struct mtk_jpeg_src_buf *jpeg_src_buf; @@ -817,11 +817,11 @@ static void mtk_jpeg_device_run(void *priv) src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(src_buf); + jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(&src_buf->vb2_buf); if (jpeg_src_buf->flags & MTK_JPEG_BUF_FLAGS_LAST_FRAME) { - for (i = 0; i < dst_buf->num_planes; i++) - vb2_set_plane_payload(dst_buf, i, 0); + for (i = 0; i < dst_buf->vb2_buf.num_planes; i++) + vb2_set_plane_payload(&dst_buf->vb2_buf, i, 0); buf_state = VB2_BUF_STATE_DONE; goto dec_end; } @@ -833,8 +833,8 @@ static void mtk_jpeg_device_run(void *priv) return; } - mtk_jpeg_set_dec_src(ctx, src_buf, &bs); - if (mtk_jpeg_set_dec_dst(ctx, &jpeg_src_buf->dec_param, dst_buf, &fb)) + mtk_jpeg_set_dec_src(ctx, &src_buf->vb2_buf, &bs); + if (mtk_jpeg_set_dec_dst(ctx, &jpeg_src_buf->dec_param, &dst_buf->vb2_buf, &fb)) goto dec_end; spin_lock_irqsave(&jpeg->hw_lock, flags); @@ -849,8 +849,8 @@ static void mtk_jpeg_device_run(void *priv) dec_end: v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), buf_state); - v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), buf_state); + v4l2_m2m_buf_done(src_buf, buf_state); + v4l2_m2m_buf_done(dst_buf, buf_state); v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx); } @@ -921,7 +921,7 @@ static irqreturn_t mtk_jpeg_dec_irq(int irq, void *priv) { struct mtk_jpeg_dev *jpeg = priv; struct mtk_jpeg_ctx *ctx; - struct vb2_buffer *src_buf, *dst_buf; + struct vb2_v4l2_buffer *src_buf, *dst_buf; struct mtk_jpeg_src_buf *jpeg_src_buf; enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR; u32 dec_irq_ret; @@ -938,7 +938,7 @@ static irqreturn_t mtk_jpeg_dec_irq(int irq, void *priv) src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(src_buf); + jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(&src_buf->vb2_buf); if (dec_irq_ret >= MTK_JPEG_DEC_RESULT_UNDERFLOW) mtk_jpeg_dec_reset(jpeg->dec_reg_base); @@ -948,15 +948,15 @@ static irqreturn_t mtk_jpeg_dec_irq(int irq, void *priv) goto dec_end; } - for (i = 0; i < dst_buf->num_planes; i++) - vb2_set_plane_payload(dst_buf, i, + for (i = 0; i < dst_buf->vb2_buf.num_planes; i++) + vb2_set_plane_payload(&dst_buf->vb2_buf, i, jpeg_src_buf->dec_param.comp_size[i]); buf_state = VB2_BUF_STATE_DONE; dec_end: - v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), buf_state); - v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), buf_state); + v4l2_m2m_buf_done(src_buf, buf_state); + v4l2_m2m_buf_done(dst_buf, buf_state); v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx); return IRQ_HANDLED; } diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_core.h b/drivers/media/platform/mtk-mdp/mtk_mdp_core.h index ad1cff306efd..e5abb1abb3a3 100644 --- a/drivers/media/platform/mtk-mdp/mtk_mdp_core.h +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_core.h @@ -41,7 +41,7 @@ #define MTK_MDP_CTX_ERROR BIT(5) /** - * struct mtk_mdp_pix_align - alignement of image + * struct mtk_mdp_pix_align - alignment of image * @org_w: source alignment of width * @org_h: source alignment of height * @target_w: dst alignment of width @@ -122,8 +122,8 @@ struct mtk_mdp_frame { /** * struct mtk_mdp_variant - image processor variant information * @pix_max: maximum limit of image size - * @pix_min: minimun limit of image size - * @pix_align: alignement of image + * @pix_min: minimum limit of image size + * @pix_align: alignment of image * @h_scale_up_max: maximum scale-up in horizontal * @v_scale_up_max: maximum scale-up in vertical * @h_scale_down_max: maximum scale-down in horizontal diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c index 51a13466261e..7d15c06e9db9 100644 --- a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c @@ -473,20 +473,17 @@ static void mtk_mdp_prepare_addr(struct mtk_mdp_ctx *ctx, static void mtk_mdp_m2m_get_bufs(struct mtk_mdp_ctx *ctx) { struct mtk_mdp_frame *s_frame, *d_frame; - struct vb2_buffer *src_vb, *dst_vb; struct vb2_v4l2_buffer *src_vbuf, *dst_vbuf; s_frame = &ctx->s_frame; d_frame = &ctx->d_frame; - src_vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx); - mtk_mdp_prepare_addr(ctx, src_vb, s_frame, &s_frame->addr); + src_vbuf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); + mtk_mdp_prepare_addr(ctx, &src_vbuf->vb2_buf, s_frame, &s_frame->addr); - dst_vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); - mtk_mdp_prepare_addr(ctx, dst_vb, d_frame, &d_frame->addr); + dst_vbuf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + mtk_mdp_prepare_addr(ctx, &dst_vbuf->vb2_buf, d_frame, &d_frame->addr); - src_vbuf = to_vb2_v4l2_buffer(src_vb); - dst_vbuf = to_vb2_v4l2_buffer(dst_vb); dst_vbuf->vb2_buf.timestamp = src_vbuf->vb2_buf.timestamp; } @@ -494,17 +491,14 @@ static void mtk_mdp_process_done(void *priv, int vb_state) { struct mtk_mdp_dev *mdp = priv; struct mtk_mdp_ctx *ctx; - struct vb2_buffer *src_vb, *dst_vb; - struct vb2_v4l2_buffer *src_vbuf = NULL, *dst_vbuf = NULL; + struct vb2_v4l2_buffer *src_vbuf, *dst_vbuf; ctx = v4l2_m2m_get_curr_priv(mdp->m2m_dev); if (!ctx) return; - src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); - src_vbuf = to_vb2_v4l2_buffer(src_vb); - dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); - dst_vbuf = to_vb2_v4l2_buffer(dst_vb); + src_vbuf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + dst_vbuf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); dst_vbuf->vb2_buf.timestamp = src_vbuf->vb2_buf.timestamp; dst_vbuf->timecode = src_vbuf->timecode; diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c index ba619647bc10..d022c65bb34c 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c @@ -325,13 +325,12 @@ static void mtk_vdec_worker(struct work_struct *work) struct mtk_vcodec_ctx *ctx = container_of(work, struct mtk_vcodec_ctx, decode_work); struct mtk_vcodec_dev *dev = ctx->dev; - struct vb2_buffer *src_buf, *dst_buf; + struct vb2_v4l2_buffer *src_buf, *dst_buf; struct mtk_vcodec_mem buf; struct vdec_fb *pfb; bool res_chg = false; int ret; struct mtk_video_dec_buf *dst_buf_info, *src_buf_info; - struct vb2_v4l2_buffer *dst_vb2_v4l2, *src_vb2_v4l2; src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); if (src_buf == NULL) { @@ -347,26 +346,23 @@ static void mtk_vdec_worker(struct work_struct *work) return; } - src_vb2_v4l2 = container_of(src_buf, struct vb2_v4l2_buffer, vb2_buf); - src_buf_info = container_of(src_vb2_v4l2, struct mtk_video_dec_buf, vb); - - dst_vb2_v4l2 = container_of(dst_buf, struct vb2_v4l2_buffer, vb2_buf); - dst_buf_info = container_of(dst_vb2_v4l2, struct mtk_video_dec_buf, vb); + src_buf_info = container_of(src_buf, struct mtk_video_dec_buf, vb); + dst_buf_info = container_of(dst_buf, struct mtk_video_dec_buf, vb); pfb = &dst_buf_info->frame_buffer; - pfb->base_y.va = vb2_plane_vaddr(dst_buf, 0); - pfb->base_y.dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); + pfb->base_y.va = vb2_plane_vaddr(&dst_buf->vb2_buf, 0); + pfb->base_y.dma_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); pfb->base_y.size = ctx->picinfo.y_bs_sz + ctx->picinfo.y_len_sz; - pfb->base_c.va = vb2_plane_vaddr(dst_buf, 1); - pfb->base_c.dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 1); + pfb->base_c.va = vb2_plane_vaddr(&dst_buf->vb2_buf, 1); + pfb->base_c.dma_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 1); pfb->base_c.size = ctx->picinfo.c_bs_sz + ctx->picinfo.c_len_sz; pfb->status = 0; mtk_v4l2_debug(3, "===>[%d] vdec_if_decode() ===>", ctx->id); mtk_v4l2_debug(3, "id=%d Framebuf pfb=%p VA=%p Y_DMA=%pad C_DMA=%pad Size=%zx", - dst_buf->index, pfb, + dst_buf->vb2_buf.index, pfb, pfb->base_y.va, &pfb->base_y.dma_addr, &pfb->base_c.dma_addr, pfb->base_y.size); @@ -384,19 +380,19 @@ static void mtk_vdec_worker(struct work_struct *work) clean_display_buffer(ctx); vb2_set_plane_payload(&dst_buf_info->vb.vb2_buf, 0, 0); vb2_set_plane_payload(&dst_buf_info->vb.vb2_buf, 1, 0); - dst_vb2_v4l2->flags |= V4L2_BUF_FLAG_LAST; + dst_buf->flags |= V4L2_BUF_FLAG_LAST; v4l2_m2m_buf_done(&dst_buf_info->vb, VB2_BUF_STATE_DONE); clean_free_buffer(ctx); v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); return; } - buf.va = vb2_plane_vaddr(src_buf, 0); - buf.dma_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0); + buf.va = vb2_plane_vaddr(&src_buf->vb2_buf, 0); + buf.dma_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); buf.size = (size_t)src_buf->planes[0].bytesused; if (!buf.va) { v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); mtk_v4l2_err("[%d] id=%d src_addr is NULL!!", - ctx->id, src_buf->index); + ctx->id, src_buf->vb2_buf.index); return; } mtk_v4l2_debug(3, "[%d] Bitstream VA=%p DMA=%pad Size=%zx vb=%p", @@ -416,10 +412,10 @@ static void mtk_vdec_worker(struct work_struct *work) mtk_v4l2_err( " <===[%d], src_buf[%d] sz=0x%zx pts=%llu dst_buf[%d] vdec_if_decode() ret=%d res_chg=%d===>", ctx->id, - src_buf->index, + src_buf->vb2_buf.index, buf.size, src_buf_info->vb.vb2_buf.timestamp, - dst_buf->index, + dst_buf->vb2_buf.index, ret, res_chg); src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); if (ret == -EIO) { @@ -1103,7 +1099,7 @@ static int vb2ops_vdec_buf_prepare(struct vb2_buffer *vb) static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb) { - struct vb2_buffer *src_buf; + struct vb2_v4l2_buffer *src_buf; struct mtk_vcodec_mem src_mem; bool res_chg = false; int ret = 0; @@ -1149,8 +1145,7 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb) mtk_v4l2_err("No src buffer"); return; } - vb2_v4l2 = to_vb2_v4l2_buffer(src_buf); - buf = container_of(vb2_v4l2, struct mtk_video_dec_buf, vb); + buf = container_of(src_buf, struct mtk_video_dec_buf, vb); if (buf->lastframe) { /* This shouldn't happen. Just in case. */ mtk_v4l2_err("Invalid flush buffer."); @@ -1158,8 +1153,8 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb) return; } - src_mem.va = vb2_plane_vaddr(src_buf, 0); - src_mem.dma_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0); + src_mem.va = vb2_plane_vaddr(&src_buf->vb2_buf, 0); + src_mem.dma_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); src_mem.size = (size_t)src_buf->planes[0].bytesused; mtk_v4l2_debug(2, "[%d] buf id=%d va=%p dma=%pad size=%zx", @@ -1170,7 +1165,7 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb) ret = vdec_if_decode(ctx, &src_mem, NULL, &res_chg); if (ret || !res_chg) { /* - * fb == NULL menas to parse SPS/PPS header or + * fb == NULL means to parse SPS/PPS header or * resolution info in src_mem. Decode can fail * if there is no SPS header or picture info * in bs @@ -1181,11 +1176,9 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb) mtk_v4l2_err("[%d] Unrecoverable error in vdec_if_decode.", ctx->id); ctx->state = MTK_STATE_ABORT; - v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), - VB2_BUF_STATE_ERROR); + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); } else { - v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), - VB2_BUF_STATE_DONE); + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); } mtk_v4l2_debug(ret ? 0 : 1, "[%d] vdec_if_decode() src_buf=%d, size=%zu, fail=%d, res_chg=%d", @@ -1281,7 +1274,7 @@ static int vb2ops_vdec_start_streaming(struct vb2_queue *q, unsigned int count) static void vb2ops_vdec_stop_streaming(struct vb2_queue *q) { - struct vb2_buffer *src_buf = NULL, *dst_buf = NULL; + struct vb2_v4l2_buffer *src_buf = NULL, *dst_buf = NULL; struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(q); mtk_v4l2_debug(3, "[%d] (%d) state=(%x) ctx->decoded_frame_cnt=%d", @@ -1289,12 +1282,10 @@ static void vb2ops_vdec_stop_streaming(struct vb2_queue *q) if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { while ((src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx))) { - struct vb2_v4l2_buffer *vb2_v4l2 = - to_vb2_v4l2_buffer(src_buf); struct mtk_video_dec_buf *buf_info = container_of( - vb2_v4l2, struct mtk_video_dec_buf, vb); + src_buf, struct mtk_video_dec_buf, vb); if (!buf_info->lastframe) - v4l2_m2m_buf_done(vb2_v4l2, + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); } return; @@ -1323,10 +1314,9 @@ static void vb2ops_vdec_stop_streaming(struct vb2_queue *q) ctx->state = MTK_STATE_FLUSH; while ((dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx))) { - vb2_set_plane_payload(dst_buf, 0, 0); - vb2_set_plane_payload(dst_buf, 1, 0); - v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), - VB2_BUF_STATE_ERROR); + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0); + vb2_set_plane_payload(&dst_buf->vb2_buf, 1, 0); + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); } } diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c index 79ca03ac449c..7884465afcd2 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c @@ -27,11 +27,14 @@ int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *mtkdev) struct device_node *node; struct platform_device *pdev; struct mtk_vcodec_pm *pm; - int ret = 0; + struct mtk_vcodec_clk *dec_clk; + struct mtk_vcodec_clk_info *clk_info; + int i = 0, ret = 0; pdev = mtkdev->plat_dev; pm = &mtkdev->pm; pm->mtkdev = mtkdev; + dec_clk = &pm->vdec_clk; node = of_parse_phandle(pdev->dev.of_node, "mediatek,larb", 0); if (!node) { mtk_v4l2_err("of_parse_phandle mediatek,larb fail!"); @@ -47,52 +50,34 @@ int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *mtkdev) pdev = mtkdev->plat_dev; pm->dev = &pdev->dev; - pm->vcodecpll = devm_clk_get(&pdev->dev, "vcodecpll"); - if (IS_ERR(pm->vcodecpll)) { - mtk_v4l2_err("devm_clk_get vcodecpll fail"); - ret = PTR_ERR(pm->vcodecpll); + dec_clk->clk_num = + of_property_count_strings(pdev->dev.of_node, "clock-names"); + if (dec_clk->clk_num > 0) { + dec_clk->clk_info = devm_kcalloc(&pdev->dev, + dec_clk->clk_num, sizeof(*clk_info), + GFP_KERNEL); + if (!dec_clk->clk_info) + return -ENOMEM; + } else { + mtk_v4l2_err("Failed to get vdec clock count"); + return -EINVAL; } - pm->univpll_d2 = devm_clk_get(&pdev->dev, "univpll_d2"); - if (IS_ERR(pm->univpll_d2)) { - mtk_v4l2_err("devm_clk_get univpll_d2 fail"); - ret = PTR_ERR(pm->univpll_d2); - } - - pm->clk_cci400_sel = devm_clk_get(&pdev->dev, "clk_cci400_sel"); - if (IS_ERR(pm->clk_cci400_sel)) { - mtk_v4l2_err("devm_clk_get clk_cci400_sel fail"); - ret = PTR_ERR(pm->clk_cci400_sel); - } - - pm->vdec_sel = devm_clk_get(&pdev->dev, "vdec_sel"); - if (IS_ERR(pm->vdec_sel)) { - mtk_v4l2_err("devm_clk_get vdec_sel fail"); - ret = PTR_ERR(pm->vdec_sel); - } - - pm->vdecpll = devm_clk_get(&pdev->dev, "vdecpll"); - if (IS_ERR(pm->vdecpll)) { - mtk_v4l2_err("devm_clk_get vdecpll fail"); - ret = PTR_ERR(pm->vdecpll); - } - - pm->vencpll = devm_clk_get(&pdev->dev, "vencpll"); - if (IS_ERR(pm->vencpll)) { - mtk_v4l2_err("devm_clk_get vencpll fail"); - ret = PTR_ERR(pm->vencpll); - } - - pm->venc_lt_sel = devm_clk_get(&pdev->dev, "venc_lt_sel"); - if (IS_ERR(pm->venc_lt_sel)) { - mtk_v4l2_err("devm_clk_get venc_lt_sel fail"); - ret = PTR_ERR(pm->venc_lt_sel); - } - - pm->vdec_bus_clk_src = devm_clk_get(&pdev->dev, "vdec_bus_clk_src"); - if (IS_ERR(pm->vdec_bus_clk_src)) { - mtk_v4l2_err("devm_clk_get vdec_bus_clk_src"); - ret = PTR_ERR(pm->vdec_bus_clk_src); + for (i = 0; i < dec_clk->clk_num; i++) { + clk_info = &dec_clk->clk_info[i]; + ret = of_property_read_string_index(pdev->dev.of_node, + "clock-names", i, &clk_info->clk_name); + if (ret) { + mtk_v4l2_err("Failed to get clock name id = %d", i); + return ret; + } + clk_info->vcodec_clk = devm_clk_get(&pdev->dev, + clk_info->clk_name); + if (IS_ERR(clk_info->vcodec_clk)) { + mtk_v4l2_err("devm_clk_get (%d)%s fail", i, + clk_info->clk_name); + return PTR_ERR(clk_info->vcodec_clk); + } } pm_runtime_enable(&pdev->dev); @@ -125,78 +110,36 @@ void mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm *pm) void mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm *pm) { - int ret; - - ret = clk_set_rate(pm->vcodecpll, 1482 * 1000000); - if (ret) - mtk_v4l2_err("clk_set_rate vcodecpll fail %d", ret); - - ret = clk_set_rate(pm->vencpll, 800 * 1000000); - if (ret) - mtk_v4l2_err("clk_set_rate vencpll fail %d", ret); - - ret = clk_prepare_enable(pm->vcodecpll); - if (ret) - mtk_v4l2_err("clk_prepare_enable vcodecpll fail %d", ret); - - ret = clk_prepare_enable(pm->vencpll); - if (ret) - mtk_v4l2_err("clk_prepare_enable vencpll fail %d", ret); - - ret = clk_prepare_enable(pm->vdec_bus_clk_src); - if (ret) - mtk_v4l2_err("clk_prepare_enable vdec_bus_clk_src fail %d", - ret); - - ret = clk_prepare_enable(pm->venc_lt_sel); - if (ret) - mtk_v4l2_err("clk_prepare_enable venc_lt_sel fail %d", ret); - - ret = clk_set_parent(pm->venc_lt_sel, pm->vdec_bus_clk_src); - if (ret) - mtk_v4l2_err("clk_set_parent venc_lt_sel vdec_bus_clk_src fail %d", - ret); - - ret = clk_prepare_enable(pm->univpll_d2); - if (ret) - mtk_v4l2_err("clk_prepare_enable univpll_d2 fail %d", ret); - - ret = clk_prepare_enable(pm->clk_cci400_sel); - if (ret) - mtk_v4l2_err("clk_prepare_enable clk_cci400_sel fail %d", ret); - - ret = clk_set_parent(pm->clk_cci400_sel, pm->univpll_d2); - if (ret) - mtk_v4l2_err("clk_set_parent clk_cci400_sel univpll_d2 fail %d", - ret); - - ret = clk_prepare_enable(pm->vdecpll); - if (ret) - mtk_v4l2_err("clk_prepare_enable vdecpll fail %d", ret); - - ret = clk_prepare_enable(pm->vdec_sel); - if (ret) - mtk_v4l2_err("clk_prepare_enable vdec_sel fail %d", ret); - - ret = clk_set_parent(pm->vdec_sel, pm->vdecpll); - if (ret) - mtk_v4l2_err("clk_set_parent vdec_sel vdecpll fail %d", ret); + struct mtk_vcodec_clk *dec_clk = &pm->vdec_clk; + int ret, i = 0; + + for (i = 0; i < dec_clk->clk_num; i++) { + ret = clk_prepare_enable(dec_clk->clk_info[i].vcodec_clk); + if (ret) { + mtk_v4l2_err("clk_prepare_enable %d %s fail %d", i, + dec_clk->clk_info[i].clk_name, ret); + goto error; + } + } ret = mtk_smi_larb_get(pm->larbvdec); - if (ret) + if (ret) { mtk_v4l2_err("mtk_smi_larb_get larbvdec fail %d", ret); + goto error; + } + return; +error: + for (i -= 1; i >= 0; i--) + clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk); } void mtk_vcodec_dec_clock_off(struct mtk_vcodec_pm *pm) { + struct mtk_vcodec_clk *dec_clk = &pm->vdec_clk; + int i = 0; + mtk_smi_larb_put(pm->larbvdec); - clk_disable_unprepare(pm->vdec_sel); - clk_disable_unprepare(pm->vdecpll); - clk_disable_unprepare(pm->univpll_d2); - clk_disable_unprepare(pm->clk_cci400_sel); - clk_disable_unprepare(pm->venc_lt_sel); - clk_disable_unprepare(pm->vdec_bus_clk_src); - clk_disable_unprepare(pm->vencpll); - clk_disable_unprepare(pm->vcodecpll); + for (i = dec_clk->clk_num - 1; i >= 0; i--) + clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk); } diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h index 3cffb381ac8e..e7e2a108def9 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h @@ -151,9 +151,9 @@ struct mtk_q_data { * @intra_period: I frame period * @gop_size: group of picture size, it's used as the intra frame period * @framerate_num: frame rate numerator. ex: framerate_num=30 and - * framerate_denom=1 menas FPS is 30 + * framerate_denom=1 means FPS is 30 * @framerate_denom: frame rate denominator. ex: framerate_num=30 and - * framerate_denom=1 menas FPS is 30 + * framerate_denom=1 means FPS is 30 * @h264_max_qp: Max value for H.264 quantization parameter * @h264_profile: V4L2 defined H.264 profile * @h264_level: V4L2 defined H.264 level @@ -176,22 +176,29 @@ struct mtk_enc_params { }; /** + * struct mtk_vcodec_clk_info - Structure used to store clock name + */ +struct mtk_vcodec_clk_info { + const char *clk_name; + struct clk *vcodec_clk; +}; + +/** + * struct mtk_vcodec_clk - Structure used to store vcodec clock information + */ +struct mtk_vcodec_clk { + struct mtk_vcodec_clk_info *clk_info; + int clk_num; +}; + +/** * struct mtk_vcodec_pm - Power management data structure */ struct mtk_vcodec_pm { - struct clk *vdec_bus_clk_src; - struct clk *vencpll; - - struct clk *vcodecpll; - struct clk *univpll_d2; - struct clk *clk_cci400_sel; - struct clk *vdecpll; - struct clk *vdec_sel; - struct clk *vencpll_d2; - struct clk *venc_sel; - struct clk *univpll1_d2; - struct clk *venc_lt_sel; + struct mtk_vcodec_clk vdec_clk; struct device *larbvdec; + + struct mtk_vcodec_clk venc_clk; struct device *larbvenc; struct device *larbvenclt; struct device *dev; diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c index d1f12257bf66..c6b48b5925fb 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c @@ -393,7 +393,7 @@ static void mtk_venc_set_param(struct mtk_vcodec_ctx *ctx, param->input_yuv_fmt = VENC_YUV_FORMAT_NV21; break; default: - mtk_v4l2_err("Unsupport fourcc =%d", q_data_src->fmt->fourcc); + mtk_v4l2_err("Unsupported fourcc =%d", q_data_src->fmt->fourcc); break; } param->h264_profile = enc_params->h264_profile; @@ -887,7 +887,7 @@ err_set_param: static void vb2ops_venc_stop_streaming(struct vb2_queue *q) { struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(q); - struct vb2_buffer *src_buf, *dst_buf; + struct vb2_v4l2_buffer *src_buf, *dst_buf; int ret; mtk_v4l2_debug(2, "[%d]-> type=%d", ctx->id, q->type); @@ -895,13 +895,11 @@ 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->planes[0].bytesused = 0; - v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), - VB2_BUF_STATE_ERROR); + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); } } else { while ((src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx))) - v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), - VB2_BUF_STATE_ERROR); + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); } if ((q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && @@ -937,8 +935,7 @@ static int mtk_venc_encode_header(void *priv) { struct mtk_vcodec_ctx *ctx = priv; int ret; - struct vb2_buffer *src_buf, *dst_buf; - struct vb2_v4l2_buffer *dst_vb2_v4l2, *src_vb2_v4l2; + struct vb2_v4l2_buffer *src_buf, *dst_buf; struct mtk_vcodec_mem bs_buf; struct venc_done_result enc_result; @@ -948,14 +945,14 @@ static int mtk_venc_encode_header(void *priv) return -EINVAL; } - bs_buf.va = vb2_plane_vaddr(dst_buf, 0); - bs_buf.dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); + bs_buf.va = vb2_plane_vaddr(&dst_buf->vb2_buf, 0); + bs_buf.dma_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); bs_buf.size = (size_t)dst_buf->planes[0].length; mtk_v4l2_debug(1, "[%d] buf id=%d va=0x%p dma_addr=0x%llx size=%zu", ctx->id, - dst_buf->index, bs_buf.va, + dst_buf->vb2_buf.index, bs_buf.va, (u64)bs_buf.dma_addr, bs_buf.size); @@ -964,26 +961,23 @@ static int mtk_venc_encode_header(void *priv) NULL, &bs_buf, &enc_result); if (ret) { - dst_buf->planes[0].bytesused = 0; + dst_buf->vb2_buf.planes[0].bytesused = 0; ctx->state = MTK_STATE_ABORT; - v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), - VB2_BUF_STATE_ERROR); + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); mtk_v4l2_err("venc_if_encode failed=%d", ret); return -EINVAL; } src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); if (src_buf) { - src_vb2_v4l2 = to_vb2_v4l2_buffer(src_buf); - dst_vb2_v4l2 = to_vb2_v4l2_buffer(dst_buf); - dst_buf->timestamp = src_buf->timestamp; - dst_vb2_v4l2->timecode = src_vb2_v4l2->timecode; + dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp; + dst_buf->timecode = src_buf->timecode; } else { mtk_v4l2_err("No timestamp for the header buffer."); } ctx->state = MTK_STATE_HEADER; dst_buf->planes[0].bytesused = enc_result.bs_size; - v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), VB2_BUF_STATE_DONE); + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); return 0; } @@ -991,9 +985,7 @@ static int mtk_venc_encode_header(void *priv) static int mtk_venc_param_change(struct mtk_vcodec_ctx *ctx) { struct venc_enc_param enc_prm; - struct vb2_buffer *vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx); - struct vb2_v4l2_buffer *vb2_v4l2 = - container_of(vb, struct vb2_v4l2_buffer, vb2_buf); + struct vb2_v4l2_buffer *vb2_v4l2 = v4l2_m2m_next_src_buf(ctx->m2m_ctx); struct mtk_video_enc_buf *mtk_buf = container_of(vb2_v4l2, struct mtk_video_enc_buf, vb); @@ -1067,12 +1059,11 @@ static void mtk_venc_worker(struct work_struct *work) { struct mtk_vcodec_ctx *ctx = container_of(work, struct mtk_vcodec_ctx, encode_work); - struct vb2_buffer *src_buf, *dst_buf; + struct vb2_v4l2_buffer *src_buf, *dst_buf; struct venc_frm_buf frm_buf; struct mtk_vcodec_mem bs_buf; struct venc_done_result enc_result; int ret, i; - struct vb2_v4l2_buffer *dst_vb2_v4l2, *src_vb2_v4l2; /* check dst_buf, dst_buf may be removed in device_run * to stored encdoe header so we need check dst_buf and @@ -1086,15 +1077,15 @@ static void mtk_venc_worker(struct work_struct *work) src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); memset(&frm_buf, 0, sizeof(frm_buf)); - for (i = 0; i < src_buf->num_planes ; i++) { + for (i = 0; i < src_buf->vb2_buf.num_planes ; i++) { frm_buf.fb_addr[i].dma_addr = - vb2_dma_contig_plane_dma_addr(src_buf, i); + vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, i); frm_buf.fb_addr[i].size = - (size_t)src_buf->planes[i].length; + (size_t)src_buf->vb2_buf.planes[i].length; } - bs_buf.va = vb2_plane_vaddr(dst_buf, 0); - bs_buf.dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); - bs_buf.size = (size_t)dst_buf->planes[0].length; + bs_buf.va = vb2_plane_vaddr(&dst_buf->vb2_buf, 0); + bs_buf.dma_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); + bs_buf.size = (size_t)dst_buf->vb2_buf.planes[0].length; mtk_v4l2_debug(2, "Framebuf PA=%llx Size=0x%zx;PA=0x%llx Size=0x%zx;PA=0x%llx Size=%zu", @@ -1108,28 +1099,21 @@ static void mtk_venc_worker(struct work_struct *work) ret = venc_if_encode(ctx, VENC_START_OPT_ENCODE_FRAME, &frm_buf, &bs_buf, &enc_result); - src_vb2_v4l2 = to_vb2_v4l2_buffer(src_buf); - dst_vb2_v4l2 = to_vb2_v4l2_buffer(dst_buf); - - dst_buf->timestamp = src_buf->timestamp; - dst_vb2_v4l2->timecode = src_vb2_v4l2->timecode; + dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp; + dst_buf->timecode = src_buf->timecode; if (enc_result.is_key_frm) - dst_vb2_v4l2->flags |= V4L2_BUF_FLAG_KEYFRAME; + dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME; if (ret) { - v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), - VB2_BUF_STATE_ERROR); + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); dst_buf->planes[0].bytesused = 0; - v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), - VB2_BUF_STATE_ERROR); + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); mtk_v4l2_err("venc_if_encode failed=%d", ret); } else { - v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), - VB2_BUF_STATE_DONE); + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); dst_buf->planes[0].bytesused = enc_result.bs_size; - v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), - VB2_BUF_STATE_DONE); + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); mtk_v4l2_debug(2, "venc_if_encode bs size=%d", enc_result.bs_size); } @@ -1137,7 +1121,7 @@ static void mtk_venc_worker(struct work_struct *work) v4l2_m2m_job_finish(ctx->dev->m2m_dev_enc, ctx->m2m_ctx); mtk_v4l2_debug(1, "<=== src_buf[%d] dst_buf[%d] venc_if_encode ret=%d Size=%u===>", - src_buf->index, dst_buf->index, ret, + src_buf->vb2_buf.index, dst_buf->vb2_buf.index, ret, enc_result.bs_size); } diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c index 7c025045ea90..39375b8ea27c 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c @@ -27,9 +27,11 @@ int mtk_vcodec_init_enc_pm(struct mtk_vcodec_dev *mtkdev) { struct device_node *node; struct platform_device *pdev; - struct device *dev; struct mtk_vcodec_pm *pm; - int ret = 0; + struct mtk_vcodec_clk *enc_clk; + struct mtk_vcodec_clk_info *clk_info; + int ret = 0, i = 0; + struct device *dev; pdev = mtkdev->plat_dev; pm = &mtkdev->pm; @@ -37,6 +39,7 @@ int mtk_vcodec_init_enc_pm(struct mtk_vcodec_dev *mtkdev) pm->mtkdev = mtkdev; pm->dev = &pdev->dev; dev = &pdev->dev; + enc_clk = &pm->venc_clk; node = of_parse_phandle(dev->of_node, "mediatek,larb", 0); if (!node) { @@ -68,28 +71,34 @@ int mtk_vcodec_init_enc_pm(struct mtk_vcodec_dev *mtkdev) pdev = mtkdev->plat_dev; pm->dev = &pdev->dev; - pm->vencpll_d2 = devm_clk_get(&pdev->dev, "venc_sel_src"); - if (IS_ERR(pm->vencpll_d2)) { - mtk_v4l2_err("devm_clk_get vencpll_d2 fail"); - ret = PTR_ERR(pm->vencpll_d2); - } - - pm->venc_sel = devm_clk_get(&pdev->dev, "venc_sel"); - if (IS_ERR(pm->venc_sel)) { - mtk_v4l2_err("devm_clk_get venc_sel fail"); - ret = PTR_ERR(pm->venc_sel); + enc_clk->clk_num = of_property_count_strings(pdev->dev.of_node, + "clock-names"); + if (enc_clk->clk_num > 0) { + enc_clk->clk_info = devm_kcalloc(&pdev->dev, + enc_clk->clk_num, sizeof(*clk_info), + GFP_KERNEL); + if (!enc_clk->clk_info) + return -ENOMEM; + } else { + mtk_v4l2_err("Failed to get venc clock count"); + return -EINVAL; } - pm->univpll1_d2 = devm_clk_get(&pdev->dev, "venc_lt_sel_src"); - if (IS_ERR(pm->univpll1_d2)) { - mtk_v4l2_err("devm_clk_get univpll1_d2 fail"); - ret = PTR_ERR(pm->univpll1_d2); - } - - pm->venc_lt_sel = devm_clk_get(&pdev->dev, "venc_lt_sel"); - if (IS_ERR(pm->venc_lt_sel)) { - mtk_v4l2_err("devm_clk_get venc_lt_sel fail"); - ret = PTR_ERR(pm->venc_lt_sel); + for (i = 0; i < enc_clk->clk_num; i++) { + clk_info = &enc_clk->clk_info[i]; + ret = of_property_read_string_index(pdev->dev.of_node, + "clock-names", i, &clk_info->clk_name); + if (ret) { + mtk_v4l2_err("venc failed to get clk name %d", i); + return ret; + } + clk_info->vcodec_clk = devm_clk_get(&pdev->dev, + clk_info->clk_name); + if (IS_ERR(clk_info->vcodec_clk)) { + mtk_v4l2_err("venc devm_clk_get (%d)%s fail", i, + clk_info->clk_name); + return PTR_ERR(clk_info->vcodec_clk); + } } return ret; @@ -102,38 +111,45 @@ void mtk_vcodec_release_enc_pm(struct mtk_vcodec_dev *mtkdev) void mtk_vcodec_enc_clock_on(struct mtk_vcodec_pm *pm) { - int ret; - - ret = clk_prepare_enable(pm->venc_sel); - if (ret) - mtk_v4l2_err("clk_prepare_enable fail %d", ret); - - ret = clk_set_parent(pm->venc_sel, pm->vencpll_d2); - if (ret) - mtk_v4l2_err("clk_set_parent fail %d", ret); - - ret = clk_prepare_enable(pm->venc_lt_sel); - if (ret) - mtk_v4l2_err("clk_prepare_enable fail %d", ret); - - ret = clk_set_parent(pm->venc_lt_sel, pm->univpll1_d2); - if (ret) - mtk_v4l2_err("clk_set_parent fail %d", ret); + struct mtk_vcodec_clk *enc_clk = &pm->venc_clk; + int ret, i = 0; + + for (i = 0; i < enc_clk->clk_num; i++) { + ret = clk_prepare_enable(enc_clk->clk_info[i].vcodec_clk); + if (ret) { + mtk_v4l2_err("venc clk_prepare_enable %d %s fail %d", i, + enc_clk->clk_info[i].clk_name, ret); + goto clkerr; + } + } ret = mtk_smi_larb_get(pm->larbvenc); - if (ret) + if (ret) { mtk_v4l2_err("mtk_smi_larb_get larb3 fail %d", ret); - + goto larbvencerr; + } ret = mtk_smi_larb_get(pm->larbvenclt); - if (ret) + if (ret) { mtk_v4l2_err("mtk_smi_larb_get larb4 fail %d", ret); + goto larbvenclterr; + } + return; +larbvenclterr: + mtk_smi_larb_put(pm->larbvenc); +larbvencerr: +clkerr: + for (i -= 1; i >= 0; i--) + clk_disable_unprepare(enc_clk->clk_info[i].vcodec_clk); } void mtk_vcodec_enc_clock_off(struct mtk_vcodec_pm *pm) { + struct mtk_vcodec_clk *enc_clk = &pm->venc_clk; + int i = 0; + mtk_smi_larb_put(pm->larbvenc); mtk_smi_larb_put(pm->larbvenclt); - clk_disable_unprepare(pm->venc_lt_sel); - clk_disable_unprepare(pm->venc_sel); + for (i = enc_clk->clk_num - 1; i >= 0; i--) + clk_disable_unprepare(enc_clk->clk_info[i].vcodec_clk); } diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c index aa3ce41898bc..02c960c63ac0 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c @@ -55,7 +55,7 @@ struct h264_fb { /** * struct h264_ring_fb_list - ring frame buffer list - * @fb_list : frame buffer arrary + * @fb_list : frame buffer array * @read_idx : read index * @write_idx : write index * @count : buffer count in list @@ -72,7 +72,7 @@ struct h264_ring_fb_list { /** * struct vdec_h264_dec_info - decode information * @dpb_sz : decoding picture buffer size - * @resolution_changed : resoltion change happen + * @resolution_changed : resolution change happen * @realloc_mv_buf : flag to notify driver to re-allocate mv buffer * @reserved : for 8 bytes alignment * @bs_dma : Input bit-stream buffer dma address diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c index 3e84a761db3a..bac3723038de 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c @@ -120,7 +120,7 @@ struct vdec_vp8_hw_reg_base { /** * struct vdec_vp8_vpu_inst - VPU instance for VP8 decode * @wq_hd : Wait queue to wait VPU message ack - * @signaled : 1 - Host has received ack message from VPU, 0 - not recevie + * @signaled : 1 - Host has received ack message from VPU, 0 - not receive * @failure : VPU execution result status 0 - success, others - fail * @inst_addr : VPU decoder instance address */ diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.h b/drivers/media/platform/mtk-vcodec/vdec_drv_if.h index ded1154481cd..9a21591f3818 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_drv_if.h +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.h @@ -80,7 +80,7 @@ void vdec_if_deinit(struct mtk_vcodec_ctx *ctx); * vdec_if_decode() - trigger decode * @ctx : [in] v4l2 context * @bs : [in] input bitstream - * @fb : [in] frame buffer to store decoded frame, when null menas parse + * @fb : [in] frame buffer to store decoded frame, when null means parse * header only * @res_chg : [out] resolution change happens if current bs have different * picture width/height diff --git a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h index cd37bb2a610f..79d8eac7f5e2 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h +++ b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h @@ -62,7 +62,7 @@ int vpu_dec_start(struct vdec_vpu_inst *vpu, uint32_t *data, unsigned int len); /** * vpu_dec_end - end decoding, basically the function will be invoked once * when HW decoding done interrupt received successfully. The - * decoder in VPU will continute to do referene frame management + * decoder in VPU will continue to do reference frame management * and check if there is a new decoded frame available to display. * * @vpu : instance for vdec_vpu_inst diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c index 27b078cf98e3..f60f499c596b 100644 --- a/drivers/media/platform/mx2_emmaprp.c +++ b/drivers/media/platform/mx2_emmaprp.c @@ -274,7 +274,7 @@ static void emmaprp_device_run(void *priv) { struct emmaprp_ctx *ctx = priv; struct emmaprp_q_data *s_q_data, *d_q_data; - struct vb2_buffer *src_buf, *dst_buf; + struct vb2_v4l2_buffer *src_buf, *dst_buf; struct emmaprp_dev *pcdev = ctx->dev; unsigned int s_width, s_height; unsigned int d_width, d_height; @@ -294,8 +294,8 @@ static void emmaprp_device_run(void *priv) d_height = d_q_data->height; d_size = d_width * d_height; - p_in = vb2_dma_contig_plane_dma_addr(src_buf, 0); - p_out = vb2_dma_contig_plane_dma_addr(dst_buf, 0); + p_in = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); + p_out = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); if (!p_in || !p_out) { v4l2_err(&pcdev->v4l2_dev, "Acquiring kernel pointers to buffers failed\n"); diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c index f447ae3bb465..37f0d7146dfa 100644 --- a/drivers/media/platform/omap/omap_vout.c +++ b/drivers/media/platform/omap/omap_vout.c @@ -513,7 +513,7 @@ static int omapvid_apply_changes(struct omap_vout_device *vout) } static int omapvid_handle_interlace_display(struct omap_vout_device *vout, - unsigned int irqstatus, struct timeval timevalue) + unsigned int irqstatus, u64 ts) { u32 fid; @@ -537,7 +537,7 @@ static int omapvid_handle_interlace_display(struct omap_vout_device *vout, if (vout->cur_frm == vout->next_frm) goto err; - vout->cur_frm->ts = timevalue; + vout->cur_frm->ts = ts; vout->cur_frm->state = VIDEOBUF_DONE; wake_up_interruptible(&vout->cur_frm->done); vout->cur_frm = vout->next_frm; @@ -557,7 +557,7 @@ static void omap_vout_isr(void *arg, unsigned int irqstatus) int ret, fid, mgr_id; u32 addr, irq; struct omap_overlay *ovl; - struct timeval timevalue; + u64 ts; struct omapvideo_info *ovid; struct omap_dss_device *cur_display; struct omap_vout_device *vout = (struct omap_vout_device *)arg; @@ -577,7 +577,7 @@ static void omap_vout_isr(void *arg, unsigned int irqstatus) return; spin_lock(&vout->vbq_lock); - v4l2_get_timestamp(&timevalue); + ts = ktime_get_ns(); switch (cur_display->type) { case OMAP_DISPLAY_TYPE_DSI: @@ -595,7 +595,7 @@ static void omap_vout_isr(void *arg, unsigned int irqstatus) break; case OMAP_DISPLAY_TYPE_VENC: fid = omapvid_handle_interlace_display(vout, irqstatus, - timevalue); + ts); if (!fid) goto vout_isr_err; break; @@ -608,7 +608,7 @@ static void omap_vout_isr(void *arg, unsigned int irqstatus) } if (!vout->first_int && (vout->cur_frm != vout->next_frm)) { - vout->cur_frm->ts = timevalue; + vout->cur_frm->ts = ts; vout->cur_frm->state = VIDEOBUF_DONE; wake_up_interruptible(&vout->cur_frm->done); vout->cur_frm = vout->next_frm; @@ -1129,7 +1129,7 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *fh, } timing = &dssdev->panel.timings; - /* We dont support RGB24-packed mode if vrfb rotation + /* We don't support RGB24-packed mode if vrfb rotation * is enabled*/ if ((is_rotation_enabled(vout)) && f->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) { @@ -1147,7 +1147,7 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *fh, vout->fbuf.fmt.width = timing->x_res; } - /* change to samller size is OK */ + /* change to smaller size is OK */ bpp = omap_vout_try_format(&f->fmt.pix); f->fmt.pix.sizeimage = f->fmt.pix.width * f->fmt.pix.height * bpp; diff --git a/drivers/media/platform/omap/omap_voutdef.h b/drivers/media/platform/omap/omap_voutdef.h index 56b630b1c8b4..c740393c8509 100644 --- a/drivers/media/platform/omap/omap_voutdef.h +++ b/drivers/media/platform/omap/omap_voutdef.h @@ -37,7 +37,7 @@ #define VID_MAX_WIDTH 1280 /* Largest width */ #define VID_MAX_HEIGHT 720 /* Largest height */ -/* Mimimum requirement is 2x2 for DSS */ +/* Minimum requirement is 2x2 for DSS */ #define VID_MIN_WIDTH 2 #define VID_MIN_HEIGHT 2 @@ -135,7 +135,7 @@ struct omap_vout_device { enum omap_color_mode dss_mode; /* we don't allow to request new buffer when old buffers are - * still mmaped + * still mmapped */ int mmap_count; diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 13f2828d880d..bd57174d81a7 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -1517,7 +1517,7 @@ void omap3isp_print_status(struct isp_device *isp) * * To solve this problem power management support is split into prepare/complete * and suspend/resume operations. The pipelines are stopped in prepare() and the - * ISP clocks get disabled in suspend(). Similarly, the clocks are reenabled in + * ISP clocks get disabled in suspend(). Similarly, the clocks are re-enabled in * resume(), and the the pipelines are restarted in complete(). * * TODO: PM dependencies between the ISP and sensors are not modelled explicitly diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 14a1c24037c4..261ad1175f98 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -1594,7 +1594,7 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc) return 0; /* We're in continuous mode, and memory writes were disabled due to a - * buffer underrun. Reenable them now that we have a buffer. The buffer + * buffer underrun. Re-enable them now that we have a buffer. The buffer * address has been set in ccdc_video_queue. */ if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS && ccdc->underrun) { @@ -1712,7 +1712,7 @@ static void ccdc_vd1_isr(struct isp_ccdc_device *ccdc) * data to memory the CCDC and LSC are stopped immediately but * without change the CCDC stopping state machine. The CCDC * stopping state machine should be used only when user request - * for stopping is received (SINGLESHOT is an exeption). + * for stopping is received (SINGLESHOT is an exception). */ switch (ccdc->state) { case ISP_PIPELINE_STREAM_SINGLESHOT: diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c index 9c180f607bcb..da66ea65be5d 100644 --- a/drivers/media/platform/omap3isp/ispcsi2.c +++ b/drivers/media/platform/omap3isp/ispcsi2.c @@ -710,7 +710,7 @@ static void csi2_isr_ctx(struct isp_csi2_device *csi2, /* Skip interrupts until we reach the frame skip count. The CSI2 will be * automatically disabled, as the frame skip count has been programmed - * in the CSI2_CTx_CTRL1::COUNT field, so reenable it. + * in the CSI2_CTx_CTRL1::COUNT field, so re-enable it. * * It would have been nice to rely on the FRAME_NUMBER interrupt instead * but it turned out that the interrupt is only generated when the CSI2 diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c index 5f930560eb30..4fe228752a43 100644 --- a/drivers/media/platform/pxa_camera.c +++ b/drivers/media/platform/pxa_camera.c @@ -1631,7 +1631,7 @@ static int pxa_camera_set_bus_param(struct pxa_camera_dev *pcdev) pcdev->channels = 1; - /* Make choises, based on platform preferences */ + /* Make choices, based on platform preferences */ if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { if (pcdev->platform_flags & PXA_CAMERA_HSP) @@ -2394,15 +2394,17 @@ static int pxa_camera_probe(struct platform_device *pdev) pcdev->res = res; pcdev->pdata = pdev->dev.platform_data; - if (pdev->dev.of_node && !pcdev->pdata) { - err = pxa_camera_pdata_from_dt(&pdev->dev, pcdev, &pcdev->asd); - } else { + if (pcdev->pdata) { pcdev->platform_flags = pcdev->pdata->flags; pcdev->mclk = pcdev->pdata->mclk_10khz * 10000; pcdev->asd.match_type = V4L2_ASYNC_MATCH_I2C; pcdev->asd.match.i2c.adapter_id = pcdev->pdata->sensor_i2c_adapter_id; pcdev->asd.match.i2c.address = pcdev->pdata->sensor_i2c_address; + } else if (pdev->dev.of_node) { + err = pxa_camera_pdata_from_dt(&pdev->dev, pcdev, &pcdev->asd); + } else { + return -ENODEV; } if (err < 0) return err; diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index cb411eb85ee4..739366744e0f 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -455,7 +455,7 @@ static const struct venus_resources msm8996_res = { .reg_tbl_size = ARRAY_SIZE(msm8996_reg_preset), .clks = {"core", "iface", "bus", "mbus" }, .clks_num = 4, - .max_load = 2563200, + .max_load = 3110400, /* 4096x2160@90 */ .hfi_version = HFI_VERSION_3XX, .vmem_id = VIDC_RESOURCE_NONE, .vmem_size = 0, @@ -465,10 +465,12 @@ static const struct venus_resources msm8996_res = { }; static const struct freq_tbl sdm845_freq_table[] = { - { 1944000, 380000000 }, /* 4k UHD @ 60 */ - { 972000, 320000000 }, /* 4k UHD @ 30 */ - { 489600, 200000000 }, /* 1080p @ 60 */ - { 244800, 100000000 }, /* 1080p @ 30 */ + { 3110400, 533000000 }, /* 4096x2160@90 */ + { 2073600, 444000000 }, /* 4096x2160@60 */ + { 1944000, 404000000 }, /* 3840x2160@60 */ + { 972000, 330000000 }, /* 3840x2160@30 */ + { 489600, 200000000 }, /* 1920x1080@60 */ + { 244800, 100000000 }, /* 1920x1080@30 */ }; static const struct venus_resources sdm845_res = { diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index 6382cea29185..7a3feb5cee00 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -134,6 +134,7 @@ struct venus_core { struct video_firmware { struct device *dev; struct iommu_domain *iommu_domain; + size_t mapped_mem_size; } fw; struct mutex lock; struct list_head instances; @@ -218,7 +219,7 @@ struct venus_buffer { #define to_venus_buffer(ptr) container_of(ptr, struct venus_buffer, vb) /** - * struct venus_inst - holds per instance paramerters + * struct venus_inst - holds per instance parameters * * @list: used for attach an instance to the core * @lock: instance lock diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c index c29acfd70c1b..6cfa8021721e 100644 --- a/drivers/media/platform/qcom/venus/firmware.c +++ b/drivers/media/platform/qcom/venus/firmware.c @@ -35,14 +35,15 @@ static void venus_reset_cpu(struct venus_core *core) { + u32 fw_size = core->fw.mapped_mem_size; void __iomem *base = core->base; writel(0, base + WRAPPER_FW_START_ADDR); - writel(VENUS_FW_MEM_SIZE, base + WRAPPER_FW_END_ADDR); + writel(fw_size, base + WRAPPER_FW_END_ADDR); writel(0, base + WRAPPER_CPA_START_ADDR); - writel(VENUS_FW_MEM_SIZE, base + WRAPPER_CPA_END_ADDR); - writel(VENUS_FW_MEM_SIZE, base + WRAPPER_NONPIX_START_ADDR); - writel(VENUS_FW_MEM_SIZE, base + WRAPPER_NONPIX_END_ADDR); + writel(fw_size, base + WRAPPER_CPA_END_ADDR); + writel(fw_size, base + WRAPPER_NONPIX_START_ADDR); + writel(fw_size, base + WRAPPER_NONPIX_END_ADDR); writel(0x0, base + WRAPPER_CPU_CGC_DIS); writel(0x0, base + WRAPPER_CPU_CLOCK_CONFIG); @@ -74,6 +75,9 @@ static int venus_load_fw(struct venus_core *core, const char *fwname, void *mem_va; int ret; + *mem_phys = 0; + *mem_size = 0; + dev = core->dev; node = of_parse_phandle(dev->of_node, "memory-region", 0); if (!node) { @@ -85,28 +89,30 @@ static int venus_load_fw(struct venus_core *core, const char *fwname, if (ret) return ret; + ret = request_firmware(&mdt, fwname, dev); + if (ret < 0) + return ret; + + fw_size = qcom_mdt_get_size(mdt); + if (fw_size < 0) { + ret = fw_size; + goto err_release_fw; + } + *mem_phys = r.start; *mem_size = resource_size(&r); - if (*mem_size < VENUS_FW_MEM_SIZE) - return -EINVAL; + if (*mem_size < fw_size || fw_size > VENUS_FW_MEM_SIZE) { + ret = -EINVAL; + goto err_release_fw; + } mem_va = memremap(r.start, *mem_size, MEMREMAP_WC); if (!mem_va) { dev_err(dev, "unable to map memory region: %pa+%zx\n", &r.start, *mem_size); - return -ENOMEM; - } - - ret = request_firmware(&mdt, fwname, dev); - if (ret < 0) - goto err_unmap; - - fw_size = qcom_mdt_get_size(mdt); - if (fw_size < 0) { - ret = fw_size; - release_firmware(mdt); - goto err_unmap; + ret = -ENOMEM; + goto err_release_fw; } if (core->use_tz) @@ -116,10 +122,9 @@ static int venus_load_fw(struct venus_core *core, const char *fwname, ret = qcom_mdt_load_no_init(dev, mdt, fwname, VENUS_PAS_ID, mem_va, *mem_phys, *mem_size, NULL); - release_firmware(mdt); - -err_unmap: memunmap(mem_va); +err_release_fw: + release_firmware(mdt); return ret; } @@ -135,6 +140,7 @@ static int venus_boot_no_tz(struct venus_core *core, phys_addr_t mem_phys, return -EPROBE_DEFER; iommu = core->fw.iommu_domain; + core->fw.mapped_mem_size = mem_size; ret = iommu_map(iommu, VENUS_FW_START_ADDR, mem_phys, mem_size, IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV); @@ -150,6 +156,7 @@ static int venus_boot_no_tz(struct venus_core *core, phys_addr_t mem_phys, static int venus_shutdown_no_tz(struct venus_core *core) { + const size_t mapped = core->fw.mapped_mem_size; struct iommu_domain *iommu; size_t unmapped; u32 reg; @@ -166,8 +173,8 @@ static int venus_shutdown_no_tz(struct venus_core *core) iommu = core->fw.iommu_domain; - unmapped = iommu_unmap(iommu, VENUS_FW_START_ADDR, VENUS_FW_MEM_SIZE); - if (unmapped != VENUS_FW_MEM_SIZE) + unmapped = iommu_unmap(iommu, VENUS_FW_START_ADDR, mapped); + if (unmapped != mapped) dev_err(dev, "failed to unmap firmware\n"); return 0; diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c index e436385bc5ab..5cad601d4c57 100644 --- a/drivers/media/platform/qcom/venus/helpers.c +++ b/drivers/media/platform/qcom/venus/helpers.c @@ -439,9 +439,6 @@ session_process_buf(struct venus_inst *inst, struct vb2_v4l2_buffer *vbuf) fdata.flags = 0; fdata.clnt_data = vbuf->vb2_buf.index; - if (!fdata.timestamp) - fdata.flags |= HFI_BUFFERFLAG_TIMESTAMPINVALID; - if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { fdata.buffer_type = HFI_BUFFER_INPUT; fdata.filled_len = vb2_get_plane_payload(vb, 0); diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index f0719ce24b97..594d80434004 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -131,9 +131,13 @@ static int rvin_group_link_notify(struct media_link *link, u32 flags, !is_media_entity_v4l2_video_device(link->sink->entity)) return 0; - /* If any entity is in use don't allow link changes. */ + /* + * Don't allow link changes if any entity in the graph is + * streaming, modifying the CHSEL register fields can disrupt + * running streams. + */ media_device_for_each_entity(entity, &group->mdev) - if (entity->use_count) + if (entity->stream_count) return -EBUSY; mutex_lock(&group->lock); @@ -542,9 +546,7 @@ static void rvin_parallel_notify_unbind(struct v4l2_async_notifier *notifier, vin_dbg(vin, "unbind parallel subdev %s\n", subdev->name); - mutex_lock(&vin->lock); rvin_parallel_subdevice_detach(vin); - mutex_unlock(&vin->lock); } static int rvin_parallel_notify_bound(struct v4l2_async_notifier *notifier, @@ -554,9 +556,7 @@ static int rvin_parallel_notify_bound(struct v4l2_async_notifier *notifier, struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev); int ret; - mutex_lock(&vin->lock); ret = rvin_parallel_subdevice_attach(vin, subdev); - mutex_unlock(&vin->lock); if (ret) return ret; @@ -664,7 +664,6 @@ static int rvin_group_notify_complete(struct v4l2_async_notifier *notifier) } /* Create all media device links between VINs and CSI-2's. */ - mutex_lock(&vin->group->lock); for (route = vin->info->routes; route->mask; route++) { struct media_pad *source_pad, *sink_pad; struct media_entity *source, *sink; @@ -700,7 +699,6 @@ static int rvin_group_notify_complete(struct v4l2_async_notifier *notifier) break; } } - mutex_unlock(&vin->group->lock); return ret; } @@ -716,8 +714,6 @@ static void rvin_group_notify_unbind(struct v4l2_async_notifier *notifier, if (vin->group->vin[i]) rvin_v4l2_unregister(vin->group->vin[i]); - mutex_lock(&vin->group->lock); - for (i = 0; i < RVIN_CSI_MAX; i++) { if (vin->group->csi[i].fwnode != asd->match.fwnode) continue; @@ -725,8 +721,6 @@ static void rvin_group_notify_unbind(struct v4l2_async_notifier *notifier, vin_dbg(vin, "Unbind CSI-2 %s from slot %u\n", subdev->name, i); break; } - - mutex_unlock(&vin->group->lock); } static int rvin_group_notify_bound(struct v4l2_async_notifier *notifier, @@ -736,8 +730,6 @@ static int rvin_group_notify_bound(struct v4l2_async_notifier *notifier, struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev); unsigned int i; - mutex_lock(&vin->group->lock); - for (i = 0; i < RVIN_CSI_MAX; i++) { if (vin->group->csi[i].fwnode != asd->match.fwnode) continue; @@ -746,8 +738,6 @@ static int rvin_group_notify_bound(struct v4l2_async_notifier *notifier, break; } - mutex_unlock(&vin->group->lock); - return 0; } @@ -1146,6 +1136,10 @@ static const struct rvin_info rcar_info_r8a77995 = { static const struct of_device_id rvin_of_id_table[] = { { + .compatible = "renesas,vin-r8a774c0", + .data = &rcar_info_r8a77990, + }, + { .compatible = "renesas,vin-r8a7778", .data = &rcar_info_m1, }, diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c index 6d356f5a9456..f64528d2be3c 100644 --- a/drivers/media/platform/rcar-vin/rcar-csi2.c +++ b/drivers/media/platform/rcar-vin/rcar-csi2.c @@ -152,37 +152,37 @@ static const struct rcsi2_mbps_reg phtw_mbps_h3_v3h_m3n[] = { }; static const struct rcsi2_mbps_reg phtw_mbps_v3m_e3[] = { - { .mbps = 89, .reg = 0x00 }, - { .mbps = 99, .reg = 0x20 }, - { .mbps = 109, .reg = 0x40 }, - { .mbps = 129, .reg = 0x02 }, - { .mbps = 139, .reg = 0x22 }, - { .mbps = 149, .reg = 0x42 }, - { .mbps = 169, .reg = 0x04 }, - { .mbps = 179, .reg = 0x24 }, - { .mbps = 199, .reg = 0x44 }, - { .mbps = 219, .reg = 0x06 }, - { .mbps = 239, .reg = 0x26 }, - { .mbps = 249, .reg = 0x46 }, - { .mbps = 269, .reg = 0x08 }, - { .mbps = 299, .reg = 0x28 }, - { .mbps = 329, .reg = 0x0a }, - { .mbps = 359, .reg = 0x2a }, - { .mbps = 399, .reg = 0x4a }, - { .mbps = 449, .reg = 0x0c }, - { .mbps = 499, .reg = 0x2c }, - { .mbps = 549, .reg = 0x0e }, - { .mbps = 599, .reg = 0x2e }, - { .mbps = 649, .reg = 0x10 }, - { .mbps = 699, .reg = 0x30 }, - { .mbps = 749, .reg = 0x12 }, - { .mbps = 799, .reg = 0x32 }, - { .mbps = 849, .reg = 0x52 }, - { .mbps = 899, .reg = 0x72 }, - { .mbps = 949, .reg = 0x14 }, - { .mbps = 999, .reg = 0x34 }, - { .mbps = 1049, .reg = 0x54 }, - { .mbps = 1099, .reg = 0x74 }, + { .mbps = 80, .reg = 0x00 }, + { .mbps = 90, .reg = 0x20 }, + { .mbps = 100, .reg = 0x40 }, + { .mbps = 110, .reg = 0x02 }, + { .mbps = 130, .reg = 0x22 }, + { .mbps = 140, .reg = 0x42 }, + { .mbps = 150, .reg = 0x04 }, + { .mbps = 170, .reg = 0x24 }, + { .mbps = 180, .reg = 0x44 }, + { .mbps = 200, .reg = 0x06 }, + { .mbps = 220, .reg = 0x26 }, + { .mbps = 240, .reg = 0x46 }, + { .mbps = 250, .reg = 0x08 }, + { .mbps = 270, .reg = 0x28 }, + { .mbps = 300, .reg = 0x0a }, + { .mbps = 330, .reg = 0x2a }, + { .mbps = 360, .reg = 0x4a }, + { .mbps = 400, .reg = 0x0c }, + { .mbps = 450, .reg = 0x2c }, + { .mbps = 500, .reg = 0x0e }, + { .mbps = 550, .reg = 0x2e }, + { .mbps = 600, .reg = 0x10 }, + { .mbps = 650, .reg = 0x30 }, + { .mbps = 700, .reg = 0x12 }, + { .mbps = 750, .reg = 0x32 }, + { .mbps = 800, .reg = 0x52 }, + { .mbps = 850, .reg = 0x72 }, + { .mbps = 900, .reg = 0x14 }, + { .mbps = 950, .reg = 0x34 }, + { .mbps = 1000, .reg = 0x54 }, + { .mbps = 1050, .reg = 0x74 }, { .mbps = 1125, .reg = 0x16 }, { /* sentinel */ }, }; @@ -986,6 +986,10 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a77990 = { static const struct of_device_id rcar_csi2_of_table[] = { { + .compatible = "renesas,r8a774c0-csi2", + .data = &rcar_csi2_info_r8a77990, + }, + { .compatible = "renesas,r8a7795-csi2", .data = &rcar_csi2_info_r8a7795, }, diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c index 92323310f735..2207a31d355e 100644 --- a/drivers/media/platform/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/rcar-vin/rcar-dma.c @@ -681,7 +681,7 @@ static int rvin_setup(struct rvin_dev *vin) break; } - /* Enable VSYNC Field Toogle mode after one VSYNC input */ + /* Enable VSYNC Field Toggle mode after one VSYNC input */ if (vin->info->model == RCAR_GEN3) dmr2 = VNDMR2_FTEV; else @@ -1341,5 +1341,5 @@ int rvin_set_channel_routing(struct rvin_dev *vin, u8 chsel) pm_runtime_put(vin->dev); - return ret; + return 0; } diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c index 7a2851790b91..7cbdcbf9b090 100644 --- a/drivers/media/platform/rcar-vin/rcar-v4l2.c +++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c @@ -665,7 +665,7 @@ static void rvin_mc_try_format(struct rvin_dev *vin, * The V4L2 specification clearly documents the colorspace fields * as being set by drivers for capture devices. Using the values * supplied by userspace thus wouldn't comply with the API. Until - * the API is updated force fixed vaules. + * the API is updated force fixed values. */ pix->colorspace = RVIN_DEFAULT_COLORSPACE; pix->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix->colorspace); @@ -964,7 +964,7 @@ void rvin_v4l2_unregister(struct rvin_dev *vin) v4l2_info(&vin->v4l2_dev, "Removing %s\n", video_device_node_name(&vin->vdev)); - /* Checks internaly if vdev have been init or not */ + /* Checks internally if vdev have been init or not */ video_unregister_device(&vin->vdev); } diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c index 96d1b1b3fe8e..843e50d17a72 100644 --- a/drivers/media/platform/rockchip/rga/rga-hw.c +++ b/drivers/media/platform/rockchip/rga/rga-hw.c @@ -256,7 +256,7 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx) } /* - * Cacluate the up/down scaling mode/factor. + * Calculate the up/down scaling mode/factor. * * RGA used to scale the picture first, and then rotate second, * so we need to swap the w/h when rotate degree is 90/270. @@ -304,7 +304,7 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx) } /* - * Cacluate the framebuffer virtual strides and active size, + * Calculate the framebuffer virtual strides and active size, * note that the step of vir_stride / vir_width is 4 byte words */ src_vir_info.data.vir_stride = ctx->in.stride >> 2; @@ -318,7 +318,7 @@ static void rga_cmd_set_trans_info(struct rga_ctx *ctx) dst_act_info.data.act_width = dst_w - 1; /* - * Cacluate the source framebuffer base address with offset pixel. + * Calculate the source framebuffer base address with offset pixel. */ src_offsets = rga_get_addr_offset(&ctx->in, src_x, src_y, src_w, src_h); diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index 5c653287185f..b096227a9722 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -43,7 +43,7 @@ static void device_run(void *prv) { struct rga_ctx *ctx = prv; struct rockchip_rga *rga = ctx->rga; - struct vb2_buffer *src, *dst; + struct vb2_v4l2_buffer *src, *dst; unsigned long flags; spin_lock_irqsave(&rga->ctrl_lock, flags); @@ -53,8 +53,8 @@ static void device_run(void *prv) src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - rga_buf_map(src); - rga_buf_map(dst); + rga_buf_map(&src->vb2_buf); + rga_buf_map(&dst->vb2_buf); rga_hw_start(rga); diff --git a/drivers/media/platform/s3c-camif/camif-core.h b/drivers/media/platform/s3c-camif/camif-core.h index 1f5c8c94ce89..be5e7357dffc 100644 --- a/drivers/media/platform/s3c-camif/camif-core.h +++ b/drivers/media/platform/s3c-camif/camif-core.h @@ -260,7 +260,7 @@ struct camif_vp { * @clock: clocks required for the CAMIF operation * @lock: mutex protecting this data structure * @slock: spinlock protecting CAMIF registers - * @io_base: start address of the mmaped CAMIF registers + * @io_base: start address of the mmapped CAMIF registers */ struct camif_dev { struct media_device media_dev; diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c index 57ab1d1085d1..971c47165010 100644 --- a/drivers/media/platform/s5p-g2d/g2d.c +++ b/drivers/media/platform/s5p-g2d/g2d.c @@ -513,7 +513,7 @@ static void device_run(void *prv) { struct g2d_ctx *ctx = prv; struct g2d_dev *dev = ctx->dev; - struct vb2_buffer *src, *dst; + struct vb2_v4l2_buffer *src, *dst; unsigned long flags; u32 cmd = 0; @@ -528,10 +528,10 @@ static void device_run(void *prv) spin_lock_irqsave(&dev->ctrl_lock, flags); g2d_set_src_size(dev, &ctx->in); - g2d_set_src_addr(dev, vb2_dma_contig_plane_dma_addr(src, 0)); + g2d_set_src_addr(dev, vb2_dma_contig_plane_dma_addr(&src->vb2_buf, 0)); g2d_set_dst_size(dev, &ctx->out); - g2d_set_dst_addr(dev, vb2_dma_contig_plane_dma_addr(dst, 0)); + g2d_set_dst_addr(dev, vb2_dma_contig_plane_dma_addr(&dst->vb2_buf, 0)); g2d_set_rop4(dev, ctx->rop); g2d_set_flip(dev, ctx->flip); diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index 3f9000b70385..8cc730eccb6c 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c @@ -3,7 +3,7 @@ * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> * Author: Jacek Anaszewski <j.anaszewski@samsung.com> * * This program is free software; you can redistribute it and/or modify @@ -793,14 +793,14 @@ static void skip(struct s5p_jpeg_buffer *buf, long len); static void exynos4_jpeg_parse_decode_h_tbl(struct s5p_jpeg_ctx *ctx) { struct s5p_jpeg *jpeg = ctx->jpeg; - struct vb2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + struct vb2_v4l2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); struct s5p_jpeg_buffer jpeg_buffer; unsigned int word; int c, x, components; jpeg_buffer.size = 2; /* Ls */ jpeg_buffer.data = - (unsigned long)vb2_plane_vaddr(vb, 0) + ctx->out_q.sos + 2; + (unsigned long)vb2_plane_vaddr(&vb->vb2_buf, 0) + ctx->out_q.sos + 2; jpeg_buffer.curr = 0; word = 0; @@ -830,14 +830,14 @@ static void exynos4_jpeg_parse_decode_h_tbl(struct s5p_jpeg_ctx *ctx) static void exynos4_jpeg_parse_huff_tbl(struct s5p_jpeg_ctx *ctx) { struct s5p_jpeg *jpeg = ctx->jpeg; - struct vb2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + struct vb2_v4l2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); struct s5p_jpeg_buffer jpeg_buffer; unsigned int word; int c, i, n, j; for (j = 0; j < ctx->out_q.dht.n; ++j) { jpeg_buffer.size = ctx->out_q.dht.len[j]; - jpeg_buffer.data = (unsigned long)vb2_plane_vaddr(vb, 0) + + jpeg_buffer.data = (unsigned long)vb2_plane_vaddr(&vb->vb2_buf, 0) + ctx->out_q.dht.marker[j]; jpeg_buffer.curr = 0; @@ -889,13 +889,13 @@ static void exynos4_jpeg_parse_huff_tbl(struct s5p_jpeg_ctx *ctx) static void exynos4_jpeg_parse_decode_q_tbl(struct s5p_jpeg_ctx *ctx) { struct s5p_jpeg *jpeg = ctx->jpeg; - struct vb2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + struct vb2_v4l2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); struct s5p_jpeg_buffer jpeg_buffer; int c, x, components; jpeg_buffer.size = ctx->out_q.sof_len; jpeg_buffer.data = - (unsigned long)vb2_plane_vaddr(vb, 0) + ctx->out_q.sof; + (unsigned long)vb2_plane_vaddr(&vb->vb2_buf, 0) + ctx->out_q.sof; jpeg_buffer.curr = 0; skip(&jpeg_buffer, 5); /* P, Y, X */ @@ -920,14 +920,14 @@ static void exynos4_jpeg_parse_decode_q_tbl(struct s5p_jpeg_ctx *ctx) static void exynos4_jpeg_parse_q_tbl(struct s5p_jpeg_ctx *ctx) { struct s5p_jpeg *jpeg = ctx->jpeg; - struct vb2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + struct vb2_v4l2_buffer *vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); struct s5p_jpeg_buffer jpeg_buffer; unsigned int word; int c, i, j; for (j = 0; j < ctx->out_q.dqt.n; ++j) { jpeg_buffer.size = ctx->out_q.dqt.len[j]; - jpeg_buffer.data = (unsigned long)vb2_plane_vaddr(vb, 0) + + jpeg_buffer.data = (unsigned long)vb2_plane_vaddr(&vb->vb2_buf, 0) + ctx->out_q.dqt.marker[j]; jpeg_buffer.curr = 0; @@ -1293,13 +1293,16 @@ static int s5p_jpeg_querycap(struct file *file, void *priv, return 0; } -static int enum_fmt(struct s5p_jpeg_fmt *sjpeg_formats, int n, +static int enum_fmt(struct s5p_jpeg_ctx *ctx, + struct s5p_jpeg_fmt *sjpeg_formats, int n, struct v4l2_fmtdesc *f, u32 type) { int i, num = 0; + unsigned int fmt_ver_flag = ctx->jpeg->variant->fmt_ver_flag; for (i = 0; i < n; ++i) { - if (sjpeg_formats[i].flags & type) { + if (sjpeg_formats[i].flags & type && + sjpeg_formats[i].flags & fmt_ver_flag) { /* index-th format of type type found ? */ if (num == f->index) break; @@ -1326,11 +1329,11 @@ static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); if (ctx->mode == S5P_JPEG_ENCODE) - return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f, + return enum_fmt(ctx, sjpeg_formats, SJPEG_NUM_FORMATS, f, SJPEG_FMT_FLAG_ENC_CAPTURE); - return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f, - SJPEG_FMT_FLAG_DEC_CAPTURE); + return enum_fmt(ctx, sjpeg_formats, SJPEG_NUM_FORMATS, f, + SJPEG_FMT_FLAG_DEC_CAPTURE); } static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv, @@ -1339,11 +1342,11 @@ static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv, struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); if (ctx->mode == S5P_JPEG_ENCODE) - return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f, + return enum_fmt(ctx, sjpeg_formats, SJPEG_NUM_FORMATS, f, SJPEG_FMT_FLAG_ENC_OUTPUT); - return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f, - SJPEG_FMT_FLAG_DEC_OUTPUT); + return enum_fmt(ctx, sjpeg_formats, SJPEG_NUM_FORMATS, f, + SJPEG_FMT_FLAG_DEC_OUTPUT); } static struct s5p_jpeg_q_data *get_q_data(struct s5p_jpeg_ctx *ctx, @@ -2002,7 +2005,7 @@ static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx) v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops, V4L2_CID_JPEG_RESTART_INTERVAL, - 0, 3, 0xffff, 0); + 0, 0xffff, 1, 0); if (ctx->jpeg->variant->version == SJPEG_S5P) mask = ~0x06; /* 422, 420 */ } @@ -2072,15 +2075,15 @@ static void s5p_jpeg_device_run(void *priv) { struct s5p_jpeg_ctx *ctx = priv; struct s5p_jpeg *jpeg = ctx->jpeg; - struct vb2_buffer *src_buf, *dst_buf; + struct vb2_v4l2_buffer *src_buf, *dst_buf; unsigned long src_addr, dst_addr, flags; spin_lock_irqsave(&ctx->jpeg->slock, flags); src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - src_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0); - dst_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); + src_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); + dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); s5p_jpeg_reset(jpeg->regs); s5p_jpeg_poweron(jpeg->regs); @@ -2153,7 +2156,7 @@ static void exynos4_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx) { struct s5p_jpeg *jpeg = ctx->jpeg; struct s5p_jpeg_fmt *fmt; - struct vb2_buffer *vb; + struct vb2_v4l2_buffer *vb; struct s5p_jpeg_addr jpeg_addr = {}; u32 pix_size, padding_bytes = 0; @@ -2172,7 +2175,7 @@ static void exynos4_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx) vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); } - jpeg_addr.y = vb2_dma_contig_plane_dma_addr(vb, 0); + jpeg_addr.y = vb2_dma_contig_plane_dma_addr(&vb->vb2_buf, 0); if (fmt->colplanes == 2) { jpeg_addr.cb = jpeg_addr.y + pix_size - padding_bytes; @@ -2190,7 +2193,7 @@ static void exynos4_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx) static void exynos4_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx) { struct s5p_jpeg *jpeg = ctx->jpeg; - struct vb2_buffer *vb; + struct vb2_v4l2_buffer *vb; unsigned int jpeg_addr = 0; if (ctx->mode == S5P_JPEG_ENCODE) @@ -2198,7 +2201,7 @@ static void exynos4_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx) else vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - jpeg_addr = vb2_dma_contig_plane_dma_addr(vb, 0); + jpeg_addr = vb2_dma_contig_plane_dma_addr(&vb->vb2_buf, 0); if (jpeg->variant->version == SJPEG_EXYNOS5433 && ctx->mode == S5P_JPEG_DECODE) jpeg_addr += ctx->out_q.sos; @@ -2314,7 +2317,7 @@ static void exynos3250_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx) { struct s5p_jpeg *jpeg = ctx->jpeg; struct s5p_jpeg_fmt *fmt; - struct vb2_buffer *vb; + struct vb2_v4l2_buffer *vb; struct s5p_jpeg_addr jpeg_addr = {}; u32 pix_size; @@ -2328,7 +2331,7 @@ static void exynos3250_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx) fmt = ctx->cap_q.fmt; } - jpeg_addr.y = vb2_dma_contig_plane_dma_addr(vb, 0); + jpeg_addr.y = vb2_dma_contig_plane_dma_addr(&vb->vb2_buf, 0); if (fmt->colplanes == 2) { jpeg_addr.cb = jpeg_addr.y + pix_size; @@ -2346,7 +2349,7 @@ static void exynos3250_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx) static void exynos3250_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx) { struct s5p_jpeg *jpeg = ctx->jpeg; - struct vb2_buffer *vb; + struct vb2_v4l2_buffer *vb; unsigned int jpeg_addr = 0; if (ctx->mode == S5P_JPEG_ENCODE) @@ -2354,7 +2357,7 @@ static void exynos3250_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx) else vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - jpeg_addr = vb2_dma_contig_plane_dma_addr(vb, 0); + jpeg_addr = vb2_dma_contig_plane_dma_addr(&vb->vb2_buf, 0); exynos3250_jpeg_jpgadr(jpeg->regs, jpeg_addr); } @@ -3220,7 +3223,7 @@ static struct platform_driver s5p_jpeg_driver = { module_platform_driver(s5p_jpeg_driver); -MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@samsung.com>"); +MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>"); MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>"); MODULE_DESCRIPTION("Samsung JPEG codec driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.h b/drivers/media/platform/s5p-jpeg/jpeg-core.h index a46465e10351..144c102ff05f 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.h +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.h @@ -3,7 +3,7 @@ * Copyright (c) 2011 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -153,7 +153,7 @@ struct s5p_jpeg_variant { /** * struct jpeg_fmt - driver's internal color format data - * @name: format descritpion + * @name: format description * @fourcc: the fourcc code, 0 if not applicable * @depth: number of bits per pixel * @colplanes: number of color planes (1 for packed formats) @@ -193,7 +193,7 @@ struct s5p_jpeg_marker { * @sos: SOS marker's position relative to the buffer beginning * @dht: DHT markers' positions relative to the buffer beginning * @dqt: DQT markers' positions relative to the buffer beginning - * @sof: SOF0 marker's postition relative to the buffer beginning + * @sof: SOF0 marker's position relative to the buffer beginning * @sof_len: SOF0 marker's payload length (without length field itself) * @components: number of image components * @size: image buffer size in bytes diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c index b5f20e722b63..59c6263a71bf 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c @@ -3,7 +3,7 @@ * Copyright (c) 2011 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h index f208fa3ed738..bfe746f8f750 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h +++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h @@ -3,7 +3,7 @@ * Copyright (c) 2011 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/media/platform/s5p-jpeg/jpeg-regs.h b/drivers/media/platform/s5p-jpeg/jpeg-regs.h index df790b10140c..574f0e8021e5 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-regs.h +++ b/drivers/media/platform/s5p-jpeg/jpeg-regs.h @@ -5,7 +5,7 @@ * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com> * Author: Jacek Anaszewski <j.anaszewski@samsung.com> * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 8a5ba3bec3af..0a9f59d89185 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1089,7 +1089,6 @@ static struct device *s5p_mfc_alloc_memdev(struct device *dev, device_initialize(child); dev_set_name(child, "%s:%s", dev_name(dev), name); child->parent = dev; - child->bus = dev->bus; child->coherent_dma_mask = dev->coherent_dma_mask; child->dma_mask = dev->dma_mask; child->release = s5p_mfc_memdev_release; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index 20442a9b9f7a..24148020baa9 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -268,7 +268,7 @@ struct s5p_mfc_priv_buf { * @enc_ctrl_handler: control framework handler for encoding * @pm: power management control * @variant: MFC hardware variant information - * @num_inst: couter of active MFC instances + * @num_inst: counter of active MFC instances * @irqlock: lock for operations on videobuf2 queues * @condlock: lock for changing/checking if a context is ready to be * processed diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c index ee7b15b335e0..9f832ba7bc8c 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c @@ -51,7 +51,7 @@ int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev) struct firmware *fw_blob; int i, err = -EINVAL; - /* Firmare has to be present as a separate file or compiled + /* Firmware has to be present as a separate file or compiled * into kernel. */ mfc_debug_enter(); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index f4c0e3a8f27d..e111f9c47179 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -602,7 +602,7 @@ static int vidioc_querybuf(struct file *file, void *priv, int i; if (buf->memory != V4L2_MEMORY_MMAP) { - mfc_err("Only mmaped buffers can be used\n"); + mfc_err("Only mmapped buffers can be used\n"); return -EINVAL; } mfc_debug(2, "State: %d, buf->type: %d\n", ctx->state, buf->type); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c index 0913881219ff..6144e95f6425 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c @@ -1293,7 +1293,7 @@ static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx) * First set the output frame buffers */ if (ctx->capture_state != QUEUE_BUFS_MMAPED) { - mfc_err("It seems that not all destination buffers were mmaped\nMFC requires that all destination are mmaped before starting processing\n"); + mfc_err("It seems that not all destination buffers were mmapped\nMFC requires that all destination are mmapped before starting processing\n"); return -EAGAIN; } if (list_empty(&ctx->src_queue)) { diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c index 7c629be43205..281699ab7fe1 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -53,7 +53,7 @@ static int s5p_mfc_alloc_dec_temp_buffers_v6(struct s5p_mfc_ctx *ctx) return 0; } -/* Release temproary buffers for decoding */ +/* Release temporary buffers for decoding */ static void s5p_mfc_release_dec_desc_buffer_v6(struct s5p_mfc_ctx *ctx) { /* NOP */ @@ -1928,7 +1928,7 @@ static inline int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx) if (ctx->capture_state != QUEUE_BUFS_MMAPED) { mfc_err("It seems that not all destination buffers were\n" - "mmaped.MFC requires that all destination are mmaped\n" + "mmapped.MFC requires that all destination are mmapped\n" "before starting processing.\n"); return -EAGAIN; } diff --git a/drivers/media/platform/seco-cec/seco-cec.h b/drivers/media/platform/seco-cec/seco-cec.h index e632c4a2a044..843de8c7dfd4 100644 --- a/drivers/media/platform/seco-cec/seco-cec.h +++ b/drivers/media/platform/seco-cec/seco-cec.h @@ -106,7 +106,7 @@ #define SECOCEC_IR_COMMAND_MASK 0x007F #define SECOCEC_IR_COMMAND_SHL 0 #define SECOCEC_IR_ADDRESS_MASK 0x1F00 -#define SECOCEC_IR_ADDRESS_SHL 7 +#define SECOCEC_IR_ADDRESS_SHL 8 #define SECOCEC_IR_TOGGLE_MASK 0x8000 #define SECOCEC_IR_TOGGLE_SHL 15 diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c index 09ae64a0004c..d277cc674349 100644 --- a/drivers/media/platform/sh_veu.c +++ b/drivers/media/platform/sh_veu.c @@ -273,13 +273,13 @@ static void sh_veu_process(struct sh_veu_dev *veu, static void sh_veu_device_run(void *priv) { struct sh_veu_dev *veu = priv; - struct vb2_buffer *src_buf, *dst_buf; + struct vb2_v4l2_buffer *src_buf, *dst_buf; src_buf = v4l2_m2m_next_src_buf(veu->m2m_ctx); dst_buf = v4l2_m2m_next_dst_buf(veu->m2m_ctx); if (src_buf && dst_buf) - sh_veu_process(veu, src_buf, dst_buf); + sh_veu_process(veu, &src_buf->vb2_buf, &dst_buf->vb2_buf); } /* ========== video ioctls ========== */ diff --git a/drivers/media/platform/soc_camera/Kconfig b/drivers/media/platform/soc_camera/Kconfig deleted file mode 100644 index 669d116b8f09..000000000000 --- a/drivers/media/platform/soc_camera/Kconfig +++ /dev/null @@ -1,26 +0,0 @@ -config SOC_CAMERA - tristate "SoC camera support" - depends on VIDEO_V4L2 && HAS_DMA && I2C - select VIDEOBUF2_CORE - help - SoC Camera is a common API to several cameras, not connecting - over a bus like PCI or USB. For example some i2c camera connected - directly to the data bus of an SoC. - -config SOC_CAMERA_SCALE_CROP - tristate - -config SOC_CAMERA_PLATFORM - tristate "platform camera support" - depends on SOC_CAMERA - help - This is a generic SoC camera platform driver, useful for testing - -config VIDEO_SH_MOBILE_CEU - tristate "SuperH Mobile CEU Interface driver" - depends on VIDEO_DEV && SOC_CAMERA && HAVE_CLK - depends on ARCH_SHMOBILE || COMPILE_TEST - select VIDEOBUF2_DMA_CONTIG - select SOC_CAMERA_SCALE_CROP - ---help--- - This is a v4l2 driver for the SuperH Mobile CEU Interface diff --git a/drivers/media/platform/soc_camera/Makefile b/drivers/media/platform/soc_camera/Makefile deleted file mode 100644 index 07a451e8b228..000000000000 --- a/drivers/media/platform/soc_camera/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -obj-$(CONFIG_SOC_CAMERA) += soc_camera.o soc_mediabus.o -obj-$(CONFIG_SOC_CAMERA_SCALE_CROP) += soc_scale_crop.o - -# a platform subdevice driver stub, allowing to support cameras by adding a -# couple of callback functions to the board code -obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o - -# soc-camera host drivers have to be linked after camera drivers -obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c deleted file mode 100644 index 6803f744e307..000000000000 --- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c +++ /dev/null @@ -1,1810 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * V4L2 Driver for SuperH Mobile CEU interface - * - * Copyright (C) 2008 Magnus Damm - * - * Based on V4L2 Driver for PXA camera host - "pxa_camera.c", - * - * Copyright (C) 2006, Sascha Hauer, Pengutronix - * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/io.h> -#include <linux/completion.h> -#include <linux/delay.h> -#include <linux/dma-mapping.h> -#include <linux/err.h> -#include <linux/errno.h> -#include <linux/fs.h> -#include <linux/interrupt.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/moduleparam.h> -#include <linux/of.h> -#include <linux/time.h> -#include <linux/slab.h> -#include <linux/device.h> -#include <linux/platform_device.h> -#include <linux/videodev2.h> -#include <linux/pm_runtime.h> -#include <linux/sched.h> - -#include <media/v4l2-async.h> -#include <media/v4l2-common.h> -#include <media/v4l2-dev.h> -#include <media/soc_camera.h> -#include <media/drv-intf/sh_mobile_ceu.h> -#include <media/videobuf2-dma-contig.h> -#include <media/v4l2-mediabus.h> -#include <media/drv-intf/soc_mediabus.h> - -#include "soc_scale_crop.h" - -/* register offsets for sh7722 / sh7723 */ - -#define CAPSR 0x00 /* Capture start register */ -#define CAPCR 0x04 /* Capture control register */ -#define CAMCR 0x08 /* Capture interface control register */ -#define CMCYR 0x0c /* Capture interface cycle register */ -#define CAMOR 0x10 /* Capture interface offset register */ -#define CAPWR 0x14 /* Capture interface width register */ -#define CAIFR 0x18 /* Capture interface input format register */ -#define CSTCR 0x20 /* Camera strobe control register (<= sh7722) */ -#define CSECR 0x24 /* Camera strobe emission count register (<= sh7722) */ -#define CRCNTR 0x28 /* CEU register control register */ -#define CRCMPR 0x2c /* CEU register forcible control register */ -#define CFLCR 0x30 /* Capture filter control register */ -#define CFSZR 0x34 /* Capture filter size clip register */ -#define CDWDR 0x38 /* Capture destination width register */ -#define CDAYR 0x3c /* Capture data address Y register */ -#define CDACR 0x40 /* Capture data address C register */ -#define CDBYR 0x44 /* Capture data bottom-field address Y register */ -#define CDBCR 0x48 /* Capture data bottom-field address C register */ -#define CBDSR 0x4c /* Capture bundle destination size register */ -#define CFWCR 0x5c /* Firewall operation control register */ -#define CLFCR 0x60 /* Capture low-pass filter control register */ -#define CDOCR 0x64 /* Capture data output control register */ -#define CDDCR 0x68 /* Capture data complexity level register */ -#define CDDAR 0x6c /* Capture data complexity level address register */ -#define CEIER 0x70 /* Capture event interrupt enable register */ -#define CETCR 0x74 /* Capture event flag clear register */ -#define CSTSR 0x7c /* Capture status register */ -#define CSRTR 0x80 /* Capture software reset register */ -#define CDSSR 0x84 /* Capture data size register */ -#define CDAYR2 0x90 /* Capture data address Y register 2 */ -#define CDACR2 0x94 /* Capture data address C register 2 */ -#define CDBYR2 0x98 /* Capture data bottom-field address Y register 2 */ -#define CDBCR2 0x9c /* Capture data bottom-field address C register 2 */ - -#undef DEBUG_GEOMETRY -#ifdef DEBUG_GEOMETRY -#define dev_geo dev_info -#else -#define dev_geo dev_dbg -#endif - -/* per video frame buffer */ -struct sh_mobile_ceu_buffer { - struct vb2_v4l2_buffer vb; /* v4l buffer must be first */ - struct list_head queue; -}; - -struct sh_mobile_ceu_dev { - struct soc_camera_host ici; - - unsigned int irq; - void __iomem *base; - size_t video_limit; - size_t buf_total; - - spinlock_t lock; /* Protects video buffer lists */ - struct list_head capture; - struct vb2_v4l2_buffer *active; - - struct sh_mobile_ceu_info *pdata; - struct completion complete; - - u32 cflcr; - - /* static max sizes either from platform data or default */ - int max_width; - int max_height; - - enum v4l2_field field; - int sequence; - unsigned long flags; - - unsigned int image_mode:1; - unsigned int is_16bit:1; - unsigned int frozen:1; -}; - -struct sh_mobile_ceu_cam { - /* CEU offsets within the camera output, before the CEU scaler */ - unsigned int ceu_left; - unsigned int ceu_top; - /* Client output, as seen by the CEU */ - unsigned int width; - unsigned int height; - /* - * User window from S_SELECTION / G_SELECTION, produced by client cropping and - * scaling, CEU scaling and CEU cropping, mapped back onto the client - * input window - */ - struct v4l2_rect subrect; - /* Camera cropping rectangle */ - struct v4l2_rect rect; - const struct soc_mbus_pixelfmt *extra_fmt; - u32 code; -}; - -static struct sh_mobile_ceu_buffer *to_ceu_vb(struct vb2_v4l2_buffer *vbuf) -{ - return container_of(vbuf, struct sh_mobile_ceu_buffer, vb); -} - -static void ceu_write(struct sh_mobile_ceu_dev *priv, - unsigned long reg_offs, u32 data) -{ - iowrite32(data, priv->base + reg_offs); -} - -static u32 ceu_read(struct sh_mobile_ceu_dev *priv, unsigned long reg_offs) -{ - return ioread32(priv->base + reg_offs); -} - -static int sh_mobile_ceu_soft_reset(struct sh_mobile_ceu_dev *pcdev) -{ - int i, success = 0; - - ceu_write(pcdev, CAPSR, 1 << 16); /* reset */ - - /* wait CSTSR.CPTON bit */ - for (i = 0; i < 1000; i++) { - if (!(ceu_read(pcdev, CSTSR) & 1)) { - success++; - break; - } - udelay(1); - } - - /* wait CAPSR.CPKIL bit */ - for (i = 0; i < 1000; i++) { - if (!(ceu_read(pcdev, CAPSR) & (1 << 16))) { - success++; - break; - } - udelay(1); - } - - if (2 != success) { - dev_warn(pcdev->ici.v4l2_dev.dev, "soft reset time out\n"); - return -EIO; - } - - return 0; -} - -/* - * Videobuf operations - */ - -/* - * .queue_setup() is called to check, whether the driver can accept the - * requested number of buffers and to fill in plane sizes - * for the current frame format if required - */ -static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq, - unsigned int *count, unsigned int *num_planes, - unsigned int sizes[], struct device *alloc_devs[]) -{ - struct soc_camera_device *icd = soc_camera_from_vb2q(vq); - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - - if (!vq->num_buffers) - pcdev->sequence = 0; - - if (!*count) - *count = 2; - - /* Called from VIDIOC_REQBUFS or in compatibility mode */ - if (!*num_planes) - sizes[0] = icd->sizeimage; - else if (sizes[0] < icd->sizeimage) - return -EINVAL; - - /* If *num_planes != 0, we have already verified *count. */ - if (pcdev->video_limit) { - size_t size = PAGE_ALIGN(sizes[0]) * *count; - - if (size + pcdev->buf_total > pcdev->video_limit) - *count = (pcdev->video_limit - pcdev->buf_total) / - PAGE_ALIGN(sizes[0]); - } - - *num_planes = 1; - - dev_dbg(icd->parent, "count=%d, size=%u\n", *count, sizes[0]); - - return 0; -} - -#define CEU_CETCR_MAGIC 0x0317f313 /* acknowledge magical interrupt sources */ -#define CEU_CETCR_IGRW (1 << 4) /* prohibited register access interrupt bit */ -#define CEU_CEIER_CPEIE (1 << 0) /* one-frame capture end interrupt */ -#define CEU_CEIER_VBP (1 << 20) /* vbp error */ -#define CEU_CAPCR_CTNCP (1 << 16) /* continuous capture mode (if set) */ -#define CEU_CEIER_MASK (CEU_CEIER_CPEIE | CEU_CEIER_VBP) - - -/* - * return value doesn't reflex the success/failure to queue the new buffer, - * but rather the status of the previous buffer. - */ -static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) -{ - struct soc_camera_device *icd = pcdev->ici.icd; - dma_addr_t phys_addr_top, phys_addr_bottom; - unsigned long top1, top2; - unsigned long bottom1, bottom2; - u32 status; - bool planar; - int ret = 0; - - /* - * The hardware is _very_ picky about this sequence. Especially - * the CEU_CETCR_MAGIC value. It seems like we need to acknowledge - * several not-so-well documented interrupt sources in CETCR. - */ - ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) & ~CEU_CEIER_MASK); - status = ceu_read(pcdev, CETCR); - ceu_write(pcdev, CETCR, ~status & CEU_CETCR_MAGIC); - if (!pcdev->frozen) - ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) | CEU_CEIER_MASK); - ceu_write(pcdev, CAPCR, ceu_read(pcdev, CAPCR) & ~CEU_CAPCR_CTNCP); - ceu_write(pcdev, CETCR, CEU_CETCR_MAGIC ^ CEU_CETCR_IGRW); - - /* - * When a VBP interrupt occurs, a capture end interrupt does not occur - * and the image of that frame is not captured correctly. So, soft reset - * is needed here. - */ - if (status & CEU_CEIER_VBP) { - sh_mobile_ceu_soft_reset(pcdev); - ret = -EIO; - } - - if (pcdev->frozen) { - complete(&pcdev->complete); - return ret; - } - - if (!pcdev->active) - return ret; - - if (V4L2_FIELD_INTERLACED_BT == pcdev->field) { - top1 = CDBYR; - top2 = CDBCR; - bottom1 = CDAYR; - bottom2 = CDACR; - } else { - top1 = CDAYR; - top2 = CDACR; - bottom1 = CDBYR; - bottom2 = CDBCR; - } - - phys_addr_top = - vb2_dma_contig_plane_dma_addr(&pcdev->active->vb2_buf, 0); - - switch (icd->current_fmt->host_fmt->fourcc) { - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - planar = true; - break; - default: - planar = false; - } - - ceu_write(pcdev, top1, phys_addr_top); - if (V4L2_FIELD_NONE != pcdev->field) { - phys_addr_bottom = phys_addr_top + icd->bytesperline; - ceu_write(pcdev, bottom1, phys_addr_bottom); - } - - if (planar) { - phys_addr_top += icd->bytesperline * icd->user_height; - ceu_write(pcdev, top2, phys_addr_top); - if (V4L2_FIELD_NONE != pcdev->field) { - phys_addr_bottom = phys_addr_top + icd->bytesperline; - ceu_write(pcdev, bottom2, phys_addr_bottom); - } - } - - ceu_write(pcdev, CAPSR, 0x1); /* start capture */ - - return ret; -} - -static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vbuf); - - /* Added list head initialization on alloc */ - WARN(!list_empty(&buf->queue), "Buffer %p on queue!\n", vb); - - return 0; -} - -static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vbuf); - unsigned long size; - - size = icd->sizeimage; - - if (vb2_plane_size(vb, 0) < size) { - dev_err(icd->parent, "Buffer #%d too small (%lu < %lu)\n", - vb->index, vb2_plane_size(vb, 0), size); - goto error; - } - - vb2_set_plane_payload(vb, 0, size); - - dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, - vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); - -#ifdef DEBUG - /* - * This can be useful if you want to see if we actually fill - * the buffer with something - */ - if (vb2_plane_vaddr(vb, 0)) - memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0)); -#endif - - spin_lock_irq(&pcdev->lock); - list_add_tail(&buf->queue, &pcdev->capture); - - if (!pcdev->active) { - /* - * Because there were no active buffer at this moment, - * we are not interested in the return value of - * sh_mobile_ceu_capture here. - */ - pcdev->active = vbuf; - sh_mobile_ceu_capture(pcdev); - } - spin_unlock_irq(&pcdev->lock); - - return; - -error: - vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); -} - -static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vbuf); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - - spin_lock_irq(&pcdev->lock); - - if (pcdev->active == vbuf) { - /* disable capture (release DMA buffer), reset */ - ceu_write(pcdev, CAPSR, 1 << 16); - pcdev->active = NULL; - } - - /* - * Doesn't hurt also if the list is empty, but it hurts, if queuing the - * buffer failed, and .buf_init() hasn't been called - */ - if (buf->queue.next) - list_del_init(&buf->queue); - - pcdev->buf_total -= PAGE_ALIGN(vb2_plane_size(vb, 0)); - dev_dbg(icd->parent, "%s() %zu bytes buffers\n", __func__, - pcdev->buf_total); - - spin_unlock_irq(&pcdev->lock); -} - -static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - - pcdev->buf_total += PAGE_ALIGN(vb2_plane_size(vb, 0)); - dev_dbg(icd->parent, "%s() %zu bytes buffers\n", __func__, - pcdev->buf_total); - - /* This is for locking debugging only */ - INIT_LIST_HEAD(&to_ceu_vb(vbuf)->queue); - return 0; -} - -static void sh_mobile_ceu_stop_streaming(struct vb2_queue *q) -{ - struct soc_camera_device *icd = soc_camera_from_vb2q(q); - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - struct list_head *buf_head, *tmp; - struct vb2_v4l2_buffer *vbuf; - - spin_lock_irq(&pcdev->lock); - - pcdev->active = NULL; - - list_for_each_safe(buf_head, tmp, &pcdev->capture) { - vbuf = &list_entry(buf_head, struct sh_mobile_ceu_buffer, - queue)->vb; - vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE); - list_del_init(buf_head); - } - - spin_unlock_irq(&pcdev->lock); - - sh_mobile_ceu_soft_reset(pcdev); -} - -static const struct vb2_ops sh_mobile_ceu_videobuf_ops = { - .queue_setup = sh_mobile_ceu_videobuf_setup, - .buf_prepare = sh_mobile_ceu_videobuf_prepare, - .buf_queue = sh_mobile_ceu_videobuf_queue, - .buf_cleanup = sh_mobile_ceu_videobuf_release, - .buf_init = sh_mobile_ceu_videobuf_init, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, - .stop_streaming = sh_mobile_ceu_stop_streaming, -}; - -static irqreturn_t sh_mobile_ceu_irq(int irq, void *data) -{ - struct sh_mobile_ceu_dev *pcdev = data; - struct vb2_v4l2_buffer *vbuf; - int ret; - - spin_lock(&pcdev->lock); - - vbuf = pcdev->active; - if (!vbuf) - /* Stale interrupt from a released buffer */ - goto out; - - list_del_init(&to_ceu_vb(vbuf)->queue); - - if (!list_empty(&pcdev->capture)) - pcdev->active = &list_entry(pcdev->capture.next, - struct sh_mobile_ceu_buffer, queue)->vb; - else - pcdev->active = NULL; - - ret = sh_mobile_ceu_capture(pcdev); - vbuf->vb2_buf.timestamp = ktime_get_ns(); - if (!ret) { - vbuf->field = pcdev->field; - vbuf->sequence = pcdev->sequence++; - } - vb2_buffer_done(&vbuf->vb2_buf, - ret < 0 ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); - -out: - spin_unlock(&pcdev->lock); - - return IRQ_HANDLED; -} - -static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) -{ - dev_info(icd->parent, - "SuperH Mobile CEU driver attached to camera %d\n", - icd->devnum); - - return 0; -} - -static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd) -{ - dev_info(icd->parent, - "SuperH Mobile CEU driver detached from camera %d\n", - icd->devnum); -} - -/* Called with .host_lock held */ -static int sh_mobile_ceu_clock_start(struct soc_camera_host *ici) -{ - struct sh_mobile_ceu_dev *pcdev = ici->priv; - - pm_runtime_get_sync(ici->v4l2_dev.dev); - - pcdev->buf_total = 0; - - sh_mobile_ceu_soft_reset(pcdev); - - return 0; -} - -/* Called with .host_lock held */ -static void sh_mobile_ceu_clock_stop(struct soc_camera_host *ici) -{ - struct sh_mobile_ceu_dev *pcdev = ici->priv; - - /* disable capture, disable interrupts */ - ceu_write(pcdev, CEIER, 0); - sh_mobile_ceu_soft_reset(pcdev); - - /* make sure active buffer is canceled */ - spin_lock_irq(&pcdev->lock); - if (pcdev->active) { - list_del_init(&to_ceu_vb(pcdev->active)->queue); - vb2_buffer_done(&pcdev->active->vb2_buf, VB2_BUF_STATE_ERROR); - pcdev->active = NULL; - } - spin_unlock_irq(&pcdev->lock); - - pm_runtime_put(ici->v4l2_dev.dev); -} - -/* - * See chapter 29.4.12 "Capture Filter Control Register (CFLCR)" - * in SH7722 Hardware Manual - */ -static unsigned int size_dst(unsigned int src, unsigned int scale) -{ - unsigned int mant_pre = scale >> 12; - if (!src || !scale) - return src; - return ((mant_pre + 2 * (src - 1)) / (2 * mant_pre) - 1) * - mant_pre * 4096 / scale + 1; -} - -static u16 calc_scale(unsigned int src, unsigned int *dst) -{ - u16 scale; - - if (src == *dst) - return 0; - - scale = (src * 4096 / *dst) & ~7; - - while (scale > 4096 && size_dst(src, scale) < *dst) - scale -= 8; - - *dst = size_dst(src, scale); - - return scale; -} - -/* rect is guaranteed to not exceed the scaled camera rectangle */ -static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct sh_mobile_ceu_cam *cam = icd->host_priv; - struct sh_mobile_ceu_dev *pcdev = ici->priv; - unsigned int height, width, cdwdr_width, in_width, in_height; - unsigned int left_offset, top_offset; - u32 camor; - - dev_geo(icd->parent, "Crop %ux%u@%u:%u\n", - icd->user_width, icd->user_height, cam->ceu_left, cam->ceu_top); - - left_offset = cam->ceu_left; - top_offset = cam->ceu_top; - - WARN_ON(icd->user_width & 3 || icd->user_height & 3); - - width = icd->user_width; - - if (pcdev->image_mode) { - in_width = cam->width; - if (!pcdev->is_16bit) { - in_width *= 2; - left_offset *= 2; - } - } else { - unsigned int w_factor; - - switch (icd->current_fmt->host_fmt->packing) { - case SOC_MBUS_PACKING_2X8_PADHI: - w_factor = 2; - break; - default: - w_factor = 1; - } - - in_width = cam->width * w_factor; - left_offset *= w_factor; - } - - cdwdr_width = icd->bytesperline; - - height = icd->user_height; - in_height = cam->height; - if (V4L2_FIELD_NONE != pcdev->field) { - height = (height / 2) & ~3; - in_height /= 2; - top_offset /= 2; - cdwdr_width *= 2; - } - - /* Set CAMOR, CAPWR, CFSZR, take care of CDWDR */ - camor = left_offset | (top_offset << 16); - - dev_geo(icd->parent, - "CAMOR 0x%x, CAPWR 0x%x, CFSZR 0x%x, CDWDR 0x%x\n", camor, - (in_height << 16) | in_width, (height << 16) | width, - cdwdr_width); - - ceu_write(pcdev, CAMOR, camor); - ceu_write(pcdev, CAPWR, (in_height << 16) | in_width); - /* CFSZR clipping is applied _after_ the scaling filter (CFLCR) */ - ceu_write(pcdev, CFSZR, (height << 16) | width); - ceu_write(pcdev, CDWDR, cdwdr_width); -} - -static u32 capture_save_reset(struct sh_mobile_ceu_dev *pcdev) -{ - u32 capsr = ceu_read(pcdev, CAPSR); - ceu_write(pcdev, CAPSR, 1 << 16); /* reset, stop capture */ - return capsr; -} - -static void capture_restore(struct sh_mobile_ceu_dev *pcdev, u32 capsr) -{ - unsigned long timeout = jiffies + 10 * HZ; - - /* - * Wait until the end of the current frame. It can take a long time, - * but if it has been aborted by a CAPSR reset, it shoule exit sooner. - */ - while ((ceu_read(pcdev, CSTSR) & 1) && time_before(jiffies, timeout)) - msleep(1); - - if (time_after(jiffies, timeout)) { - dev_err(pcdev->ici.v4l2_dev.dev, - "Timeout waiting for frame end! Interface problem?\n"); - return; - } - - /* Wait until reset clears, this shall not hang... */ - while (ceu_read(pcdev, CAPSR) & (1 << 16)) - udelay(10); - - /* Anything to restore? */ - if (capsr & ~(1 << 16)) - ceu_write(pcdev, CAPSR, capsr); -} - -#define CEU_BUS_FLAGS (V4L2_MBUS_MASTER | \ - V4L2_MBUS_PCLK_SAMPLE_RISING | \ - V4L2_MBUS_HSYNC_ACTIVE_HIGH | \ - V4L2_MBUS_HSYNC_ACTIVE_LOW | \ - V4L2_MBUS_VSYNC_ACTIVE_HIGH | \ - V4L2_MBUS_VSYNC_ACTIVE_LOW | \ - V4L2_MBUS_DATA_ACTIVE_HIGH) - -/* Capture is not running, no interrupts, no locking needed */ -static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct sh_mobile_ceu_cam *cam = icd->host_priv; - struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; - unsigned long value, common_flags = CEU_BUS_FLAGS; - u32 capsr = capture_save_reset(pcdev); - unsigned int yuv_lineskip; - int ret; - - /* - * If the client doesn't implement g_mbus_config, we just use our - * platform data - */ - ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); - if (!ret) { - common_flags = soc_mbus_config_compatible(&cfg, - common_flags); - if (!common_flags) - return -EINVAL; - } else if (ret != -ENOIOCTLCMD) { - return ret; - } - - /* Make choises, based on platform preferences */ - if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) && - (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) { - if (pcdev->flags & SH_CEU_FLAG_HSYNC_LOW) - common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH; - else - common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW; - } - - if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) && - (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) { - if (pcdev->flags & SH_CEU_FLAG_VSYNC_LOW) - common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH; - else - common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW; - } - - cfg.flags = common_flags; - ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg); - if (ret < 0 && ret != -ENOIOCTLCMD) - return ret; - - if (icd->current_fmt->host_fmt->bits_per_sample > 8) - pcdev->is_16bit = 1; - else - pcdev->is_16bit = 0; - - ceu_write(pcdev, CRCNTR, 0); - ceu_write(pcdev, CRCMPR, 0); - - value = 0x00000010; /* data fetch by default */ - yuv_lineskip = 0x10; - - switch (icd->current_fmt->host_fmt->fourcc) { - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - /* convert 4:2:2 -> 4:2:0 */ - yuv_lineskip = 0; /* skip for NV12/21, no skip for NV16/61 */ - /* fall-through */ - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - switch (cam->code) { - case MEDIA_BUS_FMT_UYVY8_2X8: - value = 0x00000000; /* Cb0, Y0, Cr0, Y1 */ - break; - case MEDIA_BUS_FMT_VYUY8_2X8: - value = 0x00000100; /* Cr0, Y0, Cb0, Y1 */ - break; - case MEDIA_BUS_FMT_YUYV8_2X8: - value = 0x00000200; /* Y0, Cb0, Y1, Cr0 */ - break; - case MEDIA_BUS_FMT_YVYU8_2X8: - value = 0x00000300; /* Y0, Cr0, Y1, Cb0 */ - break; - default: - BUG(); - } - } - - if (icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_NV21 || - icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_NV61) - value ^= 0x00000100; /* swap U, V to change from NV1x->NVx1 */ - - value |= common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW ? 1 << 1 : 0; - value |= common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW ? 1 << 0 : 0; - - if (pcdev->is_16bit) - value |= 1 << 12; - else if (pcdev->flags & SH_CEU_FLAG_LOWER_8BIT) - value |= 2 << 12; - - ceu_write(pcdev, CAMCR, value); - - ceu_write(pcdev, CAPCR, 0x00300000); - - switch (pcdev->field) { - case V4L2_FIELD_INTERLACED_TB: - value = 0x101; - break; - case V4L2_FIELD_INTERLACED_BT: - value = 0x102; - break; - default: - value = 0; - break; - } - ceu_write(pcdev, CAIFR, value); - - sh_mobile_ceu_set_rect(icd); - mdelay(1); - - dev_geo(icd->parent, "CFLCR 0x%x\n", pcdev->cflcr); - ceu_write(pcdev, CFLCR, pcdev->cflcr); - - /* - * A few words about byte order (observed in Big Endian mode) - * - * In data fetch mode bytes are received in chunks of 8 bytes. - * D0, D1, D2, D3, D4, D5, D6, D7 (D0 received first) - * - * The data is however by default written to memory in reverse order: - * D7, D6, D5, D4, D3, D2, D1, D0 (D7 written to lowest byte) - * - * The lowest three bits of CDOCR allows us to do swapping, - * using 7 we swap the data bytes to match the incoming order: - * D0, D1, D2, D3, D4, D5, D6, D7 - */ - value = 0x00000007 | yuv_lineskip; - - ceu_write(pcdev, CDOCR, value); - ceu_write(pcdev, CFWCR, 0); /* keep "datafetch firewall" disabled */ - - capture_restore(pcdev, capsr); - - /* not in bundle mode: skip CBDSR, CDAYR2, CDACR2, CDBYR2, CDBCR2 */ - return 0; -} - -static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd, - unsigned char buswidth) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - unsigned long common_flags = CEU_BUS_FLAGS; - struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; - int ret; - - ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); - if (!ret) - common_flags = soc_mbus_config_compatible(&cfg, - common_flags); - else if (ret != -ENOIOCTLCMD) - return ret; - - if (!common_flags || buswidth > 16) - return -EINVAL; - - return 0; -} - -static const struct soc_mbus_pixelfmt sh_mobile_ceu_formats[] = { - { - .fourcc = V4L2_PIX_FMT_NV12, - .name = "NV12", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_1_5X8, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PLANAR_2Y_C, - }, { - .fourcc = V4L2_PIX_FMT_NV21, - .name = "NV21", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_1_5X8, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PLANAR_2Y_C, - }, { - .fourcc = V4L2_PIX_FMT_NV16, - .name = "NV16", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PLANAR_Y_C, - }, { - .fourcc = V4L2_PIX_FMT_NV61, - .name = "NV61", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PLANAR_Y_C, - }, -}; - -/* This will be corrected as we get more formats */ -static bool sh_mobile_ceu_packing_supported(const struct soc_mbus_pixelfmt *fmt) -{ - return fmt->packing == SOC_MBUS_PACKING_NONE || - (fmt->bits_per_sample == 8 && - fmt->packing == SOC_MBUS_PACKING_1_5X8) || - (fmt->bits_per_sample == 8 && - fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) || - (fmt->bits_per_sample > 8 && - fmt->packing == SOC_MBUS_PACKING_EXTEND16); -} - -static struct soc_camera_device *ctrl_to_icd(struct v4l2_ctrl *ctrl) -{ - return container_of(ctrl->handler, struct soc_camera_device, - ctrl_handler); -} - -static int sh_mobile_ceu_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct soc_camera_device *icd = ctrl_to_icd(ctrl); - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - - switch (ctrl->id) { - case V4L2_CID_SHARPNESS: - switch (icd->current_fmt->host_fmt->fourcc) { - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - ceu_write(pcdev, CLFCR, !ctrl->val); - return 0; - } - break; - } - - return -EINVAL; -} - -static const struct v4l2_ctrl_ops sh_mobile_ceu_ctrl_ops = { - .s_ctrl = sh_mobile_ceu_s_ctrl, -}; - -static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int idx, - struct soc_camera_format_xlate *xlate) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct device *dev = icd->parent; - struct soc_camera_host *ici = to_soc_camera_host(dev); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - int ret, k, n; - int formats = 0; - struct sh_mobile_ceu_cam *cam; - struct v4l2_subdev_mbus_code_enum code = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - .index = idx, - }; - const struct soc_mbus_pixelfmt *fmt; - - ret = v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code); - if (ret < 0) - /* No more formats */ - return 0; - - fmt = soc_mbus_get_fmtdesc(code.code); - if (!fmt) { - dev_warn(dev, "unsupported format code #%u: %d\n", idx, code.code); - return 0; - } - - ret = sh_mobile_ceu_try_bus_param(icd, fmt->bits_per_sample); - if (ret < 0) - return 0; - - if (!icd->host_priv) { - struct v4l2_subdev_format fmt = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - struct v4l2_mbus_framefmt *mf = &fmt.format; - struct v4l2_rect rect; - int shift = 0; - - /* Add our control */ - v4l2_ctrl_new_std(&icd->ctrl_handler, &sh_mobile_ceu_ctrl_ops, - V4L2_CID_SHARPNESS, 0, 1, 1, 1); - if (icd->ctrl_handler.error) - return icd->ctrl_handler.error; - - /* FIXME: subwindow is lost between close / open */ - - /* Cache current client geometry */ - ret = soc_camera_client_g_rect(sd, &rect); - if (ret < 0) - return ret; - - /* First time */ - ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); - if (ret < 0) - return ret; - - /* - * All currently existing CEU implementations support 2560x1920 - * or larger frames. If the sensor is proposing too big a frame, - * don't bother with possibly supportred by the CEU larger - * sizes, just try VGA multiples. If needed, this can be - * adjusted in the future. - */ - while ((mf->width > pcdev->max_width || - mf->height > pcdev->max_height) && shift < 4) { - /* Try 2560x1920, 1280x960, 640x480, 320x240 */ - mf->width = 2560 >> shift; - mf->height = 1920 >> shift; - ret = v4l2_device_call_until_err(sd->v4l2_dev, - soc_camera_grp_id(icd), pad, - set_fmt, NULL, &fmt); - if (ret < 0) - return ret; - shift++; - } - - if (shift == 4) { - dev_err(dev, "Failed to configure the client below %ux%x\n", - mf->width, mf->height); - return -EIO; - } - - dev_geo(dev, "camera fmt %ux%u\n", mf->width, mf->height); - - cam = kzalloc(sizeof(*cam), GFP_KERNEL); - if (!cam) - return -ENOMEM; - - /* We are called with current camera crop, initialise subrect with it */ - cam->rect = rect; - cam->subrect = rect; - - cam->width = mf->width; - cam->height = mf->height; - - icd->host_priv = cam; - } else { - cam = icd->host_priv; - } - - /* Beginning of a pass */ - if (!idx) - cam->extra_fmt = NULL; - - switch (code.code) { - case MEDIA_BUS_FMT_UYVY8_2X8: - case MEDIA_BUS_FMT_VYUY8_2X8: - case MEDIA_BUS_FMT_YUYV8_2X8: - case MEDIA_BUS_FMT_YVYU8_2X8: - if (cam->extra_fmt) - break; - - /* - * Our case is simple so far: for any of the above four camera - * formats we add all our four synthesized NV* formats, so, - * just marking the device with a single flag suffices. If - * the format generation rules are more complex, you would have - * to actually hang your already added / counted formats onto - * the host_priv pointer and check whether the format you're - * going to add now is already there. - */ - cam->extra_fmt = sh_mobile_ceu_formats; - - n = ARRAY_SIZE(sh_mobile_ceu_formats); - formats += n; - for (k = 0; xlate && k < n; k++) { - xlate->host_fmt = &sh_mobile_ceu_formats[k]; - xlate->code = code.code; - xlate++; - dev_dbg(dev, "Providing format %s using code %d\n", - sh_mobile_ceu_formats[k].name, code.code); - } - break; - default: - if (!sh_mobile_ceu_packing_supported(fmt)) - return 0; - } - - /* Generic pass-through */ - formats++; - if (xlate) { - xlate->host_fmt = fmt; - xlate->code = code.code; - xlate++; - dev_dbg(dev, "Providing format %s in pass-through mode\n", - fmt->name); - } - - return formats; -} - -static void sh_mobile_ceu_put_formats(struct soc_camera_device *icd) -{ - kfree(icd->host_priv); - icd->host_priv = NULL; -} - -#define scale_down(size, scale) soc_camera_shift_scale(size, 12, scale) -#define calc_generic_scale(in, out) soc_camera_calc_scale(in, 12, out) - -/* - * CEU can scale and crop, but we don't want to waste bandwidth and kill the - * framerate by always requesting the maximum image from the client. See - * Documentation/media/v4l-drivers/sh_mobile_ceu_camera.rst for a description of - * scaling and cropping algorithms and for the meaning of referenced here steps. - */ -static int sh_mobile_ceu_set_selection(struct soc_camera_device *icd, - struct v4l2_selection *sel) -{ - struct v4l2_rect *rect = &sel->r; - struct device *dev = icd->parent; - struct soc_camera_host *ici = to_soc_camera_host(dev); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - struct v4l2_selection cam_sel; - struct sh_mobile_ceu_cam *cam = icd->host_priv; - struct v4l2_rect *cam_rect = &cam_sel.r; - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct v4l2_subdev_format fmt = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - struct v4l2_mbus_framefmt *mf = &fmt.format; - unsigned int scale_cam_h, scale_cam_v, scale_ceu_h, scale_ceu_v, - out_width, out_height; - int interm_width, interm_height; - u32 capsr, cflcr; - int ret; - - dev_geo(dev, "S_SELECTION(%ux%u@%u:%u)\n", rect->width, rect->height, - rect->left, rect->top); - - /* During camera cropping its output window can change too, stop CEU */ - capsr = capture_save_reset(pcdev); - dev_dbg(dev, "CAPSR 0x%x, CFLCR 0x%x\n", capsr, pcdev->cflcr); - - /* - * 1. - 2. Apply iterative camera S_SELECTION for new input window, read back - * actual camera rectangle. - */ - ret = soc_camera_client_s_selection(sd, sel, &cam_sel, - &cam->rect, &cam->subrect); - if (ret < 0) - return ret; - - dev_geo(dev, "1-2: camera cropped to %ux%u@%u:%u\n", - cam_rect->width, cam_rect->height, - cam_rect->left, cam_rect->top); - - /* On success cam_crop contains current camera crop */ - - /* 3. Retrieve camera output window */ - ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); - if (ret < 0) - return ret; - - if (mf->width > pcdev->max_width || mf->height > pcdev->max_height) - return -EINVAL; - - /* 4. Calculate camera scales */ - scale_cam_h = calc_generic_scale(cam_rect->width, mf->width); - scale_cam_v = calc_generic_scale(cam_rect->height, mf->height); - - /* Calculate intermediate window */ - interm_width = scale_down(rect->width, scale_cam_h); - interm_height = scale_down(rect->height, scale_cam_v); - - if (interm_width < icd->user_width) { - u32 new_scale_h; - - new_scale_h = calc_generic_scale(rect->width, icd->user_width); - - mf->width = scale_down(cam_rect->width, new_scale_h); - } - - if (interm_height < icd->user_height) { - u32 new_scale_v; - - new_scale_v = calc_generic_scale(rect->height, icd->user_height); - - mf->height = scale_down(cam_rect->height, new_scale_v); - } - - if (interm_width < icd->user_width || interm_height < icd->user_height) { - ret = v4l2_device_call_until_err(sd->v4l2_dev, - soc_camera_grp_id(icd), pad, - set_fmt, NULL, &fmt); - if (ret < 0) - return ret; - - dev_geo(dev, "New camera output %ux%u\n", mf->width, mf->height); - scale_cam_h = calc_generic_scale(cam_rect->width, mf->width); - scale_cam_v = calc_generic_scale(cam_rect->height, mf->height); - interm_width = scale_down(rect->width, scale_cam_h); - interm_height = scale_down(rect->height, scale_cam_v); - } - - /* Cache camera output window */ - cam->width = mf->width; - cam->height = mf->height; - - if (pcdev->image_mode) { - out_width = min(interm_width, icd->user_width); - out_height = min(interm_height, icd->user_height); - } else { - out_width = interm_width; - out_height = interm_height; - } - - /* - * 5. Calculate CEU scales from camera scales from results of (5) and - * the user window - */ - scale_ceu_h = calc_scale(interm_width, &out_width); - scale_ceu_v = calc_scale(interm_height, &out_height); - - dev_geo(dev, "5: CEU scales %u:%u\n", scale_ceu_h, scale_ceu_v); - - /* Apply CEU scales. */ - cflcr = scale_ceu_h | (scale_ceu_v << 16); - if (cflcr != pcdev->cflcr) { - pcdev->cflcr = cflcr; - ceu_write(pcdev, CFLCR, cflcr); - } - - icd->user_width = out_width & ~3; - icd->user_height = out_height & ~3; - /* Offsets are applied at the CEU scaling filter input */ - cam->ceu_left = scale_down(rect->left - cam_rect->left, scale_cam_h) & ~1; - cam->ceu_top = scale_down(rect->top - cam_rect->top, scale_cam_v) & ~1; - - /* 6. Use CEU cropping to crop to the new window. */ - sh_mobile_ceu_set_rect(icd); - - cam->subrect = *rect; - - dev_geo(dev, "6: CEU cropped to %ux%u@%u:%u\n", - icd->user_width, icd->user_height, - cam->ceu_left, cam->ceu_top); - - /* Restore capture. The CE bit can be cleared by the hardware */ - if (pcdev->active) - capsr |= 1; - capture_restore(pcdev, capsr); - - /* Even if only camera cropping succeeded */ - return ret; -} - -static int sh_mobile_ceu_get_selection(struct soc_camera_device *icd, - struct v4l2_selection *sel) -{ - struct sh_mobile_ceu_cam *cam = icd->host_priv; - - sel->r = cam->subrect; - - return 0; -} - -/* Similar to set_crop multistage iterative algorithm */ -static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, - struct v4l2_format *f) -{ - struct device *dev = icd->parent; - struct soc_camera_host *ici = to_soc_camera_host(dev); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - struct sh_mobile_ceu_cam *cam = icd->host_priv; - struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; - __u32 pixfmt = pix->pixelformat; - const struct soc_camera_format_xlate *xlate; - unsigned int ceu_sub_width = pcdev->max_width, - ceu_sub_height = pcdev->max_height; - u16 scale_v, scale_h; - int ret; - bool image_mode; - enum v4l2_field field; - - switch (pix->field) { - default: - pix->field = V4L2_FIELD_NONE; - /* fall-through */ - case V4L2_FIELD_INTERLACED_TB: - case V4L2_FIELD_INTERLACED_BT: - case V4L2_FIELD_NONE: - field = pix->field; - break; - case V4L2_FIELD_INTERLACED: - field = V4L2_FIELD_INTERLACED_TB; - break; - } - - xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); - if (!xlate) { - dev_warn(dev, "Format %x not found\n", pixfmt); - return -EINVAL; - } - - /* 1.-4. Calculate desired client output geometry */ - soc_camera_calc_client_output(icd, &cam->rect, &cam->subrect, pix, &mf, 12); - mf.field = pix->field; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; - - switch (pixfmt) { - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - image_mode = true; - break; - default: - image_mode = false; - } - - dev_geo(dev, "S_FMT(pix=0x%x, fld 0x%x, code 0x%x, %ux%u)\n", pixfmt, mf.field, mf.code, - pix->width, pix->height); - - dev_geo(dev, "4: request camera output %ux%u\n", mf.width, mf.height); - - /* 5. - 9. */ - ret = soc_camera_client_scale(icd, &cam->rect, &cam->subrect, - &mf, &ceu_sub_width, &ceu_sub_height, - image_mode && V4L2_FIELD_NONE == field, 12); - - dev_geo(dev, "5-9: client scale return %d\n", ret); - - /* Done with the camera. Now see if we can improve the result */ - - dev_geo(dev, "fmt %ux%u, requested %ux%u\n", - mf.width, mf.height, pix->width, pix->height); - if (ret < 0) - return ret; - - if (mf.code != xlate->code) - return -EINVAL; - - /* 9. Prepare CEU crop */ - cam->width = mf.width; - cam->height = mf.height; - - /* 10. Use CEU scaling to scale to the requested user window. */ - - /* We cannot scale up */ - if (pix->width > ceu_sub_width) - ceu_sub_width = pix->width; - - if (pix->height > ceu_sub_height) - ceu_sub_height = pix->height; - - pix->colorspace = mf.colorspace; - - if (image_mode) { - /* Scale pix->{width x height} down to width x height */ - scale_h = calc_scale(ceu_sub_width, &pix->width); - scale_v = calc_scale(ceu_sub_height, &pix->height); - } else { - pix->width = ceu_sub_width; - pix->height = ceu_sub_height; - scale_h = 0; - scale_v = 0; - } - - pcdev->cflcr = scale_h | (scale_v << 16); - - /* - * We have calculated CFLCR, the actual configuration will be performed - * in sh_mobile_ceu_set_bus_param() - */ - - dev_geo(dev, "10: W: %u : 0x%x = %u, H: %u : 0x%x = %u\n", - ceu_sub_width, scale_h, pix->width, - ceu_sub_height, scale_v, pix->height); - - cam->code = xlate->code; - icd->current_fmt = xlate; - - pcdev->field = field; - pcdev->image_mode = image_mode; - - /* CFSZR requirement */ - pix->width &= ~3; - pix->height &= ~3; - - return 0; -} - -#define CEU_CHDW_MAX 8188U /* Maximum line stride */ - -static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, - struct v4l2_format *f) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - const struct soc_camera_format_xlate *xlate; - struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct v4l2_subdev_pad_config pad_cfg; - struct v4l2_subdev_format format = { - .which = V4L2_SUBDEV_FORMAT_TRY, - }; - struct v4l2_mbus_framefmt *mf = &format.format; - __u32 pixfmt = pix->pixelformat; - int width, height; - int ret; - - dev_geo(icd->parent, "TRY_FMT(pix=0x%x, %ux%u)\n", - pixfmt, pix->width, pix->height); - - xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); - if (!xlate) { - xlate = icd->current_fmt; - dev_dbg(icd->parent, "Format %x not found, keeping %x\n", - pixfmt, xlate->host_fmt->fourcc); - pixfmt = xlate->host_fmt->fourcc; - pix->pixelformat = pixfmt; - pix->colorspace = icd->colorspace; - } - - /* FIXME: calculate using depth and bus width */ - - /* CFSZR requires height and width to be 4-pixel aligned */ - v4l_bound_align_image(&pix->width, 2, pcdev->max_width, 2, - &pix->height, 4, pcdev->max_height, 2, 0); - - width = pix->width; - height = pix->height; - - /* limit to sensor capabilities */ - mf->width = pix->width; - mf->height = pix->height; - mf->field = pix->field; - mf->code = xlate->code; - mf->colorspace = pix->colorspace; - - ret = v4l2_device_call_until_err(sd->v4l2_dev, soc_camera_grp_id(icd), - pad, set_fmt, &pad_cfg, &format); - if (ret < 0) - return ret; - - pix->width = mf->width; - pix->height = mf->height; - pix->field = mf->field; - pix->colorspace = mf->colorspace; - - switch (pixfmt) { - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - /* FIXME: check against rect_max after converting soc-camera */ - /* We can scale precisely, need a bigger image from camera */ - if (pix->width < width || pix->height < height) { - /* - * We presume, the sensor behaves sanely, i.e., if - * requested a bigger rectangle, it will not return a - * smaller one. - */ - mf->width = pcdev->max_width; - mf->height = pcdev->max_height; - ret = v4l2_device_call_until_err(sd->v4l2_dev, - soc_camera_grp_id(icd), pad, - set_fmt, &pad_cfg, &format); - if (ret < 0) { - /* Shouldn't actually happen... */ - dev_err(icd->parent, - "FIXME: client try_fmt() = %d\n", ret); - return ret; - } - } - /* We will scale exactly */ - if (mf->width > width) - pix->width = width; - if (mf->height > height) - pix->height = height; - - pix->bytesperline = max(pix->bytesperline, pix->width); - pix->bytesperline = min(pix->bytesperline, CEU_CHDW_MAX); - pix->bytesperline &= ~3; - break; - - default: - /* Configurable stride isn't supported in pass-through mode. */ - pix->bytesperline = 0; - } - - pix->width &= ~3; - pix->height &= ~3; - pix->sizeimage = 0; - - dev_geo(icd->parent, "%s(): return %d, fmt 0x%x, %ux%u\n", - __func__, ret, pix->pixelformat, pix->width, pix->height); - - return ret; -} - -static int sh_mobile_ceu_set_liveselection(struct soc_camera_device *icd, - struct v4l2_selection *sel) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - u32 out_width = icd->user_width, out_height = icd->user_height; - int ret; - - /* Freeze queue */ - pcdev->frozen = 1; - /* Wait for frame */ - ret = wait_for_completion_interruptible(&pcdev->complete); - /* Stop the client */ - ret = v4l2_subdev_call(sd, video, s_stream, 0); - if (ret < 0) - dev_warn(icd->parent, - "Client failed to stop the stream: %d\n", ret); - else - /* Do the crop, if it fails, there's nothing more we can do */ - sh_mobile_ceu_set_selection(icd, sel); - - dev_geo(icd->parent, "Output after crop: %ux%u\n", icd->user_width, icd->user_height); - - if (icd->user_width != out_width || icd->user_height != out_height) { - struct v4l2_format f = { - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .fmt.pix = { - .width = out_width, - .height = out_height, - .pixelformat = icd->current_fmt->host_fmt->fourcc, - .field = pcdev->field, - .colorspace = icd->colorspace, - }, - }; - ret = sh_mobile_ceu_set_fmt(icd, &f); - if (!ret && (out_width != f.fmt.pix.width || - out_height != f.fmt.pix.height)) - ret = -EINVAL; - if (!ret) { - icd->user_width = out_width & ~3; - icd->user_height = out_height & ~3; - ret = sh_mobile_ceu_set_bus_param(icd); - } - } - - /* Thaw the queue */ - pcdev->frozen = 0; - spin_lock_irq(&pcdev->lock); - sh_mobile_ceu_capture(pcdev); - spin_unlock_irq(&pcdev->lock); - /* Start the client */ - ret = v4l2_subdev_call(sd, video, s_stream, 1); - return ret; -} - -static __poll_t sh_mobile_ceu_poll(struct file *file, poll_table *pt) -{ - struct soc_camera_device *icd = file->private_data; - - return vb2_poll(&icd->vb2_vidq, file, pt); -} - -static int sh_mobile_ceu_querycap(struct soc_camera_host *ici, - struct v4l2_capability *cap) -{ - strscpy(cap->card, "SuperH_Mobile_CEU", sizeof(cap->card)); - strscpy(cap->driver, "sh_mobile_ceu", sizeof(cap->driver)); - strscpy(cap->bus_info, "platform:sh_mobile_ceu", sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - - return 0; -} - -static int sh_mobile_ceu_init_videobuf(struct vb2_queue *q, - struct soc_camera_device *icd) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - - q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - q->io_modes = VB2_MMAP | VB2_USERPTR; - q->drv_priv = icd; - q->ops = &sh_mobile_ceu_videobuf_ops; - q->mem_ops = &vb2_dma_contig_memops; - q->buf_struct_size = sizeof(struct sh_mobile_ceu_buffer); - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->lock = &ici->host_lock; - q->dev = ici->v4l2_dev.dev; - - return vb2_queue_init(q); -} - -static struct soc_camera_host_ops sh_mobile_ceu_host_ops = { - .owner = THIS_MODULE, - .add = sh_mobile_ceu_add_device, - .remove = sh_mobile_ceu_remove_device, - .clock_start = sh_mobile_ceu_clock_start, - .clock_stop = sh_mobile_ceu_clock_stop, - .get_formats = sh_mobile_ceu_get_formats, - .put_formats = sh_mobile_ceu_put_formats, - .get_selection = sh_mobile_ceu_get_selection, - .set_selection = sh_mobile_ceu_set_selection, - .set_liveselection = sh_mobile_ceu_set_liveselection, - .set_fmt = sh_mobile_ceu_set_fmt, - .try_fmt = sh_mobile_ceu_try_fmt, - .poll = sh_mobile_ceu_poll, - .querycap = sh_mobile_ceu_querycap, - .set_bus_param = sh_mobile_ceu_set_bus_param, - .init_videobuf2 = sh_mobile_ceu_init_videobuf, -}; - -struct bus_wait { - struct notifier_block notifier; - struct completion completion; - struct device *dev; -}; - -static int bus_notify(struct notifier_block *nb, - unsigned long action, void *data) -{ - struct device *dev = data; - struct bus_wait *wait = container_of(nb, struct bus_wait, notifier); - - if (wait->dev != dev) - return NOTIFY_DONE; - - switch (action) { - case BUS_NOTIFY_UNBOUND_DRIVER: - /* Protect from module unloading */ - wait_for_completion(&wait->completion); - return NOTIFY_OK; - } - return NOTIFY_DONE; -} - -static int sh_mobile_ceu_probe(struct platform_device *pdev) -{ - struct sh_mobile_ceu_dev *pcdev; - struct resource *res; - void __iomem *base; - unsigned int irq; - int err; - struct bus_wait wait = { - .completion = COMPLETION_INITIALIZER_ONSTACK(wait.completion), - .notifier.notifier_call = bus_notify, - }; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irq = platform_get_irq(pdev, 0); - if (!res || (int)irq <= 0) { - dev_err(&pdev->dev, "Not enough CEU platform resources.\n"); - return -ENODEV; - } - - pcdev = devm_kzalloc(&pdev->dev, sizeof(*pcdev), GFP_KERNEL); - if (!pcdev) { - dev_err(&pdev->dev, "Could not allocate pcdev\n"); - return -ENOMEM; - } - - INIT_LIST_HEAD(&pcdev->capture); - spin_lock_init(&pcdev->lock); - init_completion(&pcdev->complete); - - pcdev->pdata = pdev->dev.platform_data; - if (!pcdev->pdata && !pdev->dev.of_node) { - dev_err(&pdev->dev, "CEU platform data not set.\n"); - return -EINVAL; - } - - /* TODO: implement per-device bus flags */ - if (pcdev->pdata) { - pcdev->max_width = pcdev->pdata->max_width; - pcdev->max_height = pcdev->pdata->max_height; - pcdev->flags = pcdev->pdata->flags; - } - pcdev->field = V4L2_FIELD_NONE; - - if (!pcdev->max_width) { - unsigned int v; - err = of_property_read_u32(pdev->dev.of_node, "renesas,max-width", &v); - if (!err) - pcdev->max_width = v; - - if (!pcdev->max_width) - pcdev->max_width = 2560; - } - if (!pcdev->max_height) { - unsigned int v; - err = of_property_read_u32(pdev->dev.of_node, "renesas,max-height", &v); - if (!err) - pcdev->max_height = v; - - if (!pcdev->max_height) - pcdev->max_height = 1920; - } - - base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(base)) - return PTR_ERR(base); - - pcdev->irq = irq; - pcdev->base = base; - pcdev->video_limit = 0; /* only enabled if second resource exists */ - - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (res) { - err = dma_declare_coherent_memory(&pdev->dev, res->start, - res->start, - resource_size(res), - DMA_MEMORY_EXCLUSIVE); - if (err) { - dev_err(&pdev->dev, "Unable to declare CEU memory.\n"); - return err; - } - - pcdev->video_limit = resource_size(res); - } - - /* request irq */ - err = devm_request_irq(&pdev->dev, pcdev->irq, sh_mobile_ceu_irq, - 0, dev_name(&pdev->dev), pcdev); - if (err) { - dev_err(&pdev->dev, "Unable to register CEU interrupt.\n"); - goto exit_release_mem; - } - - pm_suspend_ignore_children(&pdev->dev, true); - pm_runtime_enable(&pdev->dev); - pm_runtime_resume(&pdev->dev); - - pcdev->ici.priv = pcdev; - pcdev->ici.v4l2_dev.dev = &pdev->dev; - pcdev->ici.nr = pdev->id; - pcdev->ici.drv_name = dev_name(&pdev->dev); - pcdev->ici.ops = &sh_mobile_ceu_host_ops; - pcdev->ici.capabilities = SOCAM_HOST_CAP_STRIDE; - - if (pcdev->pdata && pcdev->pdata->asd_sizes) { - pcdev->ici.asd = pcdev->pdata->asd; - pcdev->ici.asd_sizes = pcdev->pdata->asd_sizes; - } - - err = soc_camera_host_register(&pcdev->ici); - if (err) - goto exit_free_clk; - - return 0; - -exit_free_clk: - pm_runtime_disable(&pdev->dev); -exit_release_mem: - if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) - dma_release_declared_memory(&pdev->dev); - return err; -} - -static int sh_mobile_ceu_remove(struct platform_device *pdev) -{ - struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); - - soc_camera_host_unregister(soc_host); - pm_runtime_disable(&pdev->dev); - if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) - dma_release_declared_memory(&pdev->dev); - - return 0; -} - -static int sh_mobile_ceu_runtime_nop(struct device *dev) -{ - /* Runtime PM callback shared between ->runtime_suspend() - * and ->runtime_resume(). Simply returns success. - * - * This driver re-initializes all registers after - * pm_runtime_get_sync() anyway so there is no need - * to save and restore registers here. - */ - return 0; -} - -static const struct dev_pm_ops sh_mobile_ceu_dev_pm_ops = { - .runtime_suspend = sh_mobile_ceu_runtime_nop, - .runtime_resume = sh_mobile_ceu_runtime_nop, -}; - -static const struct of_device_id sh_mobile_ceu_of_match[] = { - { .compatible = "renesas,sh-mobile-ceu" }, - { } -}; -MODULE_DEVICE_TABLE(of, sh_mobile_ceu_of_match); - -static struct platform_driver sh_mobile_ceu_driver = { - .driver = { - .name = "sh_mobile_ceu", - .pm = &sh_mobile_ceu_dev_pm_ops, - .of_match_table = sh_mobile_ceu_of_match, - }, - .probe = sh_mobile_ceu_probe, - .remove = sh_mobile_ceu_remove, -}; - -module_platform_driver(sh_mobile_ceu_driver); - -MODULE_DESCRIPTION("SuperH Mobile CEU driver"); -MODULE_AUTHOR("Magnus Damm"); -MODULE_LICENSE("GPL"); -MODULE_VERSION("0.1.0"); -MODULE_ALIAS("platform:sh_mobile_ceu"); diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c deleted file mode 100644 index 21034339cdcb..000000000000 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ /dev/null @@ -1,2170 +0,0 @@ -/* - * camera image capture (abstract) bus driver - * - * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> - * - * This driver provides an interface between platform-specific camera - * busses and camera devices. It should be used if the camera is - * connected not over a "proper" bus like PCI or USB, but over a - * special bus, like, for example, the Quick Capture interface on PXA270 - * SoCs. Later it should also be used for i.MX31 SoCs from Freescale. - * It can handle multiple cameras and / or multiple busses, which can - * be used, e.g., in stereo-vision applications. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/device.h> -#include <linux/err.h> -#include <linux/i2c.h> -#include <linux/init.h> -#include <linux/list.h> -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/of_graph.h> -#include <linux/platform_device.h> -#include <linux/pm_runtime.h> -#include <linux/regulator/consumer.h> -#include <linux/slab.h> -#include <linux/vmalloc.h> - -#include <media/soc_camera.h> -#include <media/drv-intf/soc_mediabus.h> -#include <media/v4l2-async.h> -#include <media/v4l2-clk.h> -#include <media/v4l2-common.h> -#include <media/v4l2-ioctl.h> -#include <media/v4l2-dev.h> -#include <media/v4l2-fwnode.h> -#include <media/videobuf2-v4l2.h> - -/* Default to VGA resolution */ -#define DEFAULT_WIDTH 640 -#define DEFAULT_HEIGHT 480 - -#define MAP_MAX_NUM 32 -static DECLARE_BITMAP(device_map, MAP_MAX_NUM); -static LIST_HEAD(hosts); -static LIST_HEAD(devices); -/* - * Protects lists and bitmaps of hosts and devices. - * Lock nesting: Ok to take ->host_lock under list_lock. - */ -static DEFINE_MUTEX(list_lock); - -struct soc_camera_async_client { - struct v4l2_async_subdev *sensor; - struct v4l2_async_notifier notifier; - struct platform_device *pdev; - struct list_head list; /* needed for clean up */ -}; - -static int soc_camera_video_start(struct soc_camera_device *icd); -static int video_dev_create(struct soc_camera_device *icd); - -int soc_camera_power_on(struct device *dev, struct soc_camera_subdev_desc *ssdd, - struct v4l2_clk *clk) -{ - int ret; - bool clock_toggle; - - if (clk && (!ssdd->unbalanced_power || - !test_and_set_bit(0, &ssdd->clock_state))) { - ret = v4l2_clk_enable(clk); - if (ret < 0) { - dev_err(dev, "Cannot enable clock: %d\n", ret); - return ret; - } - clock_toggle = true; - } else { - clock_toggle = false; - } - - ret = regulator_bulk_enable(ssdd->sd_pdata.num_regulators, - ssdd->sd_pdata.regulators); - if (ret < 0) { - dev_err(dev, "Cannot enable regulators\n"); - goto eregenable; - } - - if (ssdd->power) { - ret = ssdd->power(dev, 1); - if (ret < 0) { - dev_err(dev, - "Platform failed to power-on the camera.\n"); - goto epwron; - } - } - - return 0; - -epwron: - regulator_bulk_disable(ssdd->sd_pdata.num_regulators, - ssdd->sd_pdata.regulators); -eregenable: - if (clock_toggle) - v4l2_clk_disable(clk); - - return ret; -} -EXPORT_SYMBOL(soc_camera_power_on); - -int soc_camera_power_off(struct device *dev, struct soc_camera_subdev_desc *ssdd, - struct v4l2_clk *clk) -{ - int ret = 0; - int err; - - if (ssdd->power) { - err = ssdd->power(dev, 0); - if (err < 0) { - dev_err(dev, - "Platform failed to power-off the camera.\n"); - ret = err; - } - } - - err = regulator_bulk_disable(ssdd->sd_pdata.num_regulators, - ssdd->sd_pdata.regulators); - if (err < 0) { - dev_err(dev, "Cannot disable regulators\n"); - ret = ret ? : err; - } - - if (clk && (!ssdd->unbalanced_power || test_and_clear_bit(0, &ssdd->clock_state))) - v4l2_clk_disable(clk); - - return ret; -} -EXPORT_SYMBOL(soc_camera_power_off); - -int soc_camera_power_init(struct device *dev, struct soc_camera_subdev_desc *ssdd) -{ - /* Should not have any effect in synchronous case */ - return devm_regulator_bulk_get(dev, ssdd->sd_pdata.num_regulators, - ssdd->sd_pdata.regulators); -} -EXPORT_SYMBOL(soc_camera_power_init); - -static int __soc_camera_power_on(struct soc_camera_device *icd) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - int ret; - - ret = v4l2_subdev_call(sd, core, s_power, 1); - if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) - return ret; - - return 0; -} - -static int __soc_camera_power_off(struct soc_camera_device *icd) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - int ret; - - ret = v4l2_subdev_call(sd, core, s_power, 0); - if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) - return ret; - - return 0; -} - -static int soc_camera_clock_start(struct soc_camera_host *ici) -{ - int ret; - - if (!ici->ops->clock_start) - return 0; - - mutex_lock(&ici->clk_lock); - ret = ici->ops->clock_start(ici); - mutex_unlock(&ici->clk_lock); - - return ret; -} - -static void soc_camera_clock_stop(struct soc_camera_host *ici) -{ - if (!ici->ops->clock_stop) - return; - - mutex_lock(&ici->clk_lock); - ici->ops->clock_stop(ici); - mutex_unlock(&ici->clk_lock); -} - -const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc( - struct soc_camera_device *icd, unsigned int fourcc) -{ - unsigned int i; - - for (i = 0; i < icd->num_user_formats; i++) - if (icd->user_formats[i].host_fmt->fourcc == fourcc) - return icd->user_formats + i; - return NULL; -} -EXPORT_SYMBOL(soc_camera_xlate_by_fourcc); - -/** - * soc_camera_apply_board_flags() - apply platform SOCAM_SENSOR_INVERT_* flags - * @ssdd: camera platform parameters - * @cfg: media bus configuration - * @return: resulting flags - */ -unsigned long soc_camera_apply_board_flags(struct soc_camera_subdev_desc *ssdd, - const struct v4l2_mbus_config *cfg) -{ - unsigned long f, flags = cfg->flags; - - /* If only one of the two polarities is supported, switch to the opposite */ - if (ssdd->flags & SOCAM_SENSOR_INVERT_HSYNC) { - f = flags & (V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW); - if (f == V4L2_MBUS_HSYNC_ACTIVE_HIGH || f == V4L2_MBUS_HSYNC_ACTIVE_LOW) - flags ^= V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW; - } - - if (ssdd->flags & SOCAM_SENSOR_INVERT_VSYNC) { - f = flags & (V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW); - if (f == V4L2_MBUS_VSYNC_ACTIVE_HIGH || f == V4L2_MBUS_VSYNC_ACTIVE_LOW) - flags ^= V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW; - } - - if (ssdd->flags & SOCAM_SENSOR_INVERT_PCLK) { - f = flags & (V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING); - if (f == V4L2_MBUS_PCLK_SAMPLE_RISING || f == V4L2_MBUS_PCLK_SAMPLE_FALLING) - flags ^= V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING; - } - - return flags; -} -EXPORT_SYMBOL(soc_camera_apply_board_flags); - -#define pixfmtstr(x) (x) & 0xff, ((x) >> 8) & 0xff, ((x) >> 16) & 0xff, \ - ((x) >> 24) & 0xff - -static int soc_camera_try_fmt(struct soc_camera_device *icd, - struct v4l2_format *f) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - const struct soc_camera_format_xlate *xlate; - struct v4l2_pix_format *pix = &f->fmt.pix; - int ret; - - dev_dbg(icd->pdev, "TRY_FMT(%c%c%c%c, %ux%u)\n", - pixfmtstr(pix->pixelformat), pix->width, pix->height); - - if (pix->pixelformat != V4L2_PIX_FMT_JPEG && - !(ici->capabilities & SOCAM_HOST_CAP_STRIDE)) { - pix->bytesperline = 0; - pix->sizeimage = 0; - } - - ret = ici->ops->try_fmt(icd, f); - if (ret < 0) - return ret; - - xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); - if (!xlate) - return -EINVAL; - - ret = soc_mbus_bytes_per_line(pix->width, xlate->host_fmt); - if (ret < 0) - return ret; - - pix->bytesperline = max_t(u32, pix->bytesperline, ret); - - ret = soc_mbus_image_size(xlate->host_fmt, pix->bytesperline, - pix->height); - if (ret < 0) - return ret; - - pix->sizeimage = max_t(u32, pix->sizeimage, ret); - - return 0; -} - -static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct soc_camera_device *icd = file->private_data; - - WARN_ON(priv != file->private_data); - - /* Only single-plane capture is supported so far */ - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - /* limit format to hardware capabilities */ - return soc_camera_try_fmt(icd, f); -} - -static int soc_camera_enum_input(struct file *file, void *priv, - struct v4l2_input *inp) -{ - struct soc_camera_device *icd = file->private_data; - - if (inp->index != 0) - return -EINVAL; - - /* default is camera */ - inp->type = V4L2_INPUT_TYPE_CAMERA; - inp->std = icd->vdev->tvnorms; - strscpy(inp->name, "Camera", sizeof(inp->name)); - - return 0; -} - -static int soc_camera_g_input(struct file *file, void *priv, unsigned int *i) -{ - *i = 0; - - return 0; -} - -static int soc_camera_s_input(struct file *file, void *priv, unsigned int i) -{ - if (i > 0) - return -EINVAL; - - return 0; -} - -static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id a) -{ - struct soc_camera_device *icd = file->private_data; - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - - return v4l2_subdev_call(sd, video, s_std, a); -} - -static int soc_camera_g_std(struct file *file, void *priv, v4l2_std_id *a) -{ - struct soc_camera_device *icd = file->private_data; - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - - return v4l2_subdev_call(sd, video, g_std, a); -} - -static int soc_camera_enum_framesizes(struct file *file, void *fh, - struct v4l2_frmsizeenum *fsize) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - - return ici->ops->enum_framesizes(icd, fsize); -} - -static int soc_camera_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - int ret; - struct soc_camera_device *icd = file->private_data; - - WARN_ON(priv != file->private_data); - - if (icd->streamer && icd->streamer != file) - return -EBUSY; - - ret = vb2_reqbufs(&icd->vb2_vidq, p); - if (!ret) - icd->streamer = p->count ? file : NULL; - return ret; -} - -static int soc_camera_querybuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct soc_camera_device *icd = file->private_data; - - WARN_ON(priv != file->private_data); - - return vb2_querybuf(&icd->vb2_vidq, p); -} - -static int soc_camera_qbuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct soc_camera_device *icd = file->private_data; - - WARN_ON(priv != file->private_data); - - if (icd->streamer != file) - return -EBUSY; - - return vb2_qbuf(&icd->vb2_vidq, NULL, p); -} - -static int soc_camera_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct soc_camera_device *icd = file->private_data; - - WARN_ON(priv != file->private_data); - - if (icd->streamer != file) - return -EBUSY; - - return vb2_dqbuf(&icd->vb2_vidq, p, file->f_flags & O_NONBLOCK); -} - -static int soc_camera_create_bufs(struct file *file, void *priv, - struct v4l2_create_buffers *create) -{ - struct soc_camera_device *icd = file->private_data; - int ret; - - if (icd->streamer && icd->streamer != file) - return -EBUSY; - - ret = vb2_create_bufs(&icd->vb2_vidq, create); - if (!ret) - icd->streamer = file; - return ret; -} - -static int soc_camera_prepare_buf(struct file *file, void *priv, - struct v4l2_buffer *b) -{ - struct soc_camera_device *icd = file->private_data; - - return vb2_prepare_buf(&icd->vb2_vidq, NULL, b); -} - -static int soc_camera_expbuf(struct file *file, void *priv, - struct v4l2_exportbuffer *p) -{ - struct soc_camera_device *icd = file->private_data; - - if (icd->streamer && icd->streamer != file) - return -EBUSY; - return vb2_expbuf(&icd->vb2_vidq, p); -} - -/* Always entered with .host_lock held */ -static int soc_camera_init_user_formats(struct soc_camera_device *icd) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - unsigned int i, fmts = 0, raw_fmts = 0; - int ret; - struct v4l2_subdev_mbus_code_enum code = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - - while (!v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code)) { - raw_fmts++; - code.index++; - } - - if (!ici->ops->get_formats) - /* - * Fallback mode - the host will have to serve all - * sensor-provided formats one-to-one to the user - */ - fmts = raw_fmts; - else - /* - * First pass - only count formats this host-sensor - * configuration can provide - */ - for (i = 0; i < raw_fmts; i++) { - ret = ici->ops->get_formats(icd, i, NULL); - if (ret < 0) - return ret; - fmts += ret; - } - - if (!fmts) - return -ENXIO; - - icd->user_formats = - vmalloc(array_size(fmts, - sizeof(struct soc_camera_format_xlate))); - if (!icd->user_formats) - return -ENOMEM; - - dev_dbg(icd->pdev, "Found %d supported formats.\n", fmts); - - /* Second pass - actually fill data formats */ - fmts = 0; - for (i = 0; i < raw_fmts; i++) - if (!ici->ops->get_formats) { - code.index = i; - v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code); - icd->user_formats[fmts].host_fmt = - soc_mbus_get_fmtdesc(code.code); - if (icd->user_formats[fmts].host_fmt) - icd->user_formats[fmts++].code = code.code; - } else { - ret = ici->ops->get_formats(icd, i, - &icd->user_formats[fmts]); - if (ret < 0) - goto egfmt; - fmts += ret; - } - - icd->num_user_formats = fmts; - icd->current_fmt = &icd->user_formats[0]; - - return 0; - -egfmt: - vfree(icd->user_formats); - return ret; -} - -/* Always entered with .host_lock held */ -static void soc_camera_free_user_formats(struct soc_camera_device *icd) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - - if (ici->ops->put_formats) - ici->ops->put_formats(icd); - icd->current_fmt = NULL; - icd->num_user_formats = 0; - vfree(icd->user_formats); - icd->user_formats = NULL; -} - -/* Called with .vb_lock held, or from the first open(2), see comment there */ -static int soc_camera_set_fmt(struct soc_camera_device *icd, - struct v4l2_format *f) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct v4l2_pix_format *pix = &f->fmt.pix; - int ret; - - dev_dbg(icd->pdev, "S_FMT(%c%c%c%c, %ux%u)\n", - pixfmtstr(pix->pixelformat), pix->width, pix->height); - - /* We always call try_fmt() before set_fmt() or set_selection() */ - ret = soc_camera_try_fmt(icd, f); - if (ret < 0) - return ret; - - ret = ici->ops->set_fmt(icd, f); - if (ret < 0) { - return ret; - } else if (!icd->current_fmt || - icd->current_fmt->host_fmt->fourcc != pix->pixelformat) { - dev_err(icd->pdev, - "Host driver hasn't set up current format correctly!\n"); - return -EINVAL; - } - - icd->user_width = pix->width; - icd->user_height = pix->height; - icd->bytesperline = pix->bytesperline; - icd->sizeimage = pix->sizeimage; - icd->colorspace = pix->colorspace; - icd->field = pix->field; - - dev_dbg(icd->pdev, "set width: %d height: %d\n", - icd->user_width, icd->user_height); - - /* set physical bus parameters */ - return ici->ops->set_bus_param(icd); -} - -static int soc_camera_add_device(struct soc_camera_device *icd) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - int ret; - - if (ici->icd) - return -EBUSY; - - if (!icd->clk) { - ret = soc_camera_clock_start(ici); - if (ret < 0) - return ret; - } - - if (ici->ops->add) { - ret = ici->ops->add(icd); - if (ret < 0) - goto eadd; - } - - ici->icd = icd; - - return 0; - -eadd: - if (!icd->clk) - soc_camera_clock_stop(ici); - return ret; -} - -static void soc_camera_remove_device(struct soc_camera_device *icd) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - - if (WARN_ON(icd != ici->icd)) - return; - - if (ici->ops->remove) - ici->ops->remove(icd); - if (!icd->clk) - soc_camera_clock_stop(ici); - ici->icd = NULL; -} - -static int soc_camera_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct soc_camera_device *icd; - struct soc_camera_host *ici; - int ret; - - /* - * Don't mess with the host during probe: wait until the loop in - * scan_add_host() completes. Also protect against a race with - * soc_camera_host_unregister(). - */ - if (mutex_lock_interruptible(&list_lock)) - return -ERESTARTSYS; - - if (!vdev || !video_is_registered(vdev)) { - mutex_unlock(&list_lock); - return -ENODEV; - } - - icd = video_get_drvdata(vdev); - ici = to_soc_camera_host(icd->parent); - - ret = try_module_get(ici->ops->owner) ? 0 : -ENODEV; - mutex_unlock(&list_lock); - - if (ret < 0) { - dev_err(icd->pdev, "Couldn't lock capture bus driver.\n"); - return ret; - } - - if (!to_soc_camera_control(icd)) { - /* No device driver attached */ - ret = -ENODEV; - goto econtrol; - } - - if (mutex_lock_interruptible(&ici->host_lock)) { - ret = -ERESTARTSYS; - goto elockhost; - } - icd->use_count++; - - /* Now we really have to activate the camera */ - if (icd->use_count == 1) { - struct soc_camera_desc *sdesc = to_soc_camera_desc(icd); - /* Restore parameters before the last close() per V4L2 API */ - struct v4l2_format f = { - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .fmt.pix = { - .width = icd->user_width, - .height = icd->user_height, - .field = icd->field, - .colorspace = icd->colorspace, - .pixelformat = - icd->current_fmt->host_fmt->fourcc, - }, - }; - - /* The camera could have been already on, try to reset */ - if (sdesc->subdev_desc.reset) - if (icd->control) - sdesc->subdev_desc.reset(icd->control); - - ret = soc_camera_add_device(icd); - if (ret < 0) { - dev_err(icd->pdev, "Couldn't activate the camera: %d\n", ret); - goto eiciadd; - } - - ret = __soc_camera_power_on(icd); - if (ret < 0) - goto epower; - - pm_runtime_enable(&icd->vdev->dev); - ret = pm_runtime_resume(&icd->vdev->dev); - if (ret < 0 && ret != -ENOSYS) - goto eresume; - - /* - * Try to configure with default parameters. Notice: this is the - * very first open, so, we cannot race against other calls, - * apart from someone else calling open() simultaneously, but - * .host_lock is protecting us against it. - */ - ret = soc_camera_set_fmt(icd, &f); - if (ret < 0) - goto esfmt; - - ret = ici->ops->init_videobuf2(&icd->vb2_vidq, icd); - if (ret < 0) - goto einitvb; - v4l2_ctrl_handler_setup(&icd->ctrl_handler); - } - mutex_unlock(&ici->host_lock); - - file->private_data = icd; - dev_dbg(icd->pdev, "camera device open\n"); - - return 0; - - /* - * All errors are entered with the .host_lock held, first four also - * with use_count == 1 - */ -einitvb: -esfmt: - pm_runtime_disable(&icd->vdev->dev); -eresume: - __soc_camera_power_off(icd); -epower: - soc_camera_remove_device(icd); -eiciadd: - icd->use_count--; - mutex_unlock(&ici->host_lock); -elockhost: -econtrol: - module_put(ici->ops->owner); - - return ret; -} - -static int soc_camera_close(struct file *file) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - - mutex_lock(&ici->host_lock); - if (icd->streamer == file) { - if (ici->ops->init_videobuf2) - vb2_queue_release(&icd->vb2_vidq); - icd->streamer = NULL; - } - icd->use_count--; - if (!icd->use_count) { - pm_runtime_suspend(&icd->vdev->dev); - pm_runtime_disable(&icd->vdev->dev); - - __soc_camera_power_off(icd); - - soc_camera_remove_device(icd); - } - - mutex_unlock(&ici->host_lock); - - module_put(ici->ops->owner); - - dev_dbg(icd->pdev, "camera device close\n"); - - return 0; -} - -static ssize_t soc_camera_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - - dev_dbg(icd->pdev, "read called, buf %p\n", buf); - - if (ici->ops->init_videobuf2 && icd->vb2_vidq.io_modes & VB2_READ) - return vb2_read(&icd->vb2_vidq, buf, count, ppos, - file->f_flags & O_NONBLOCK); - - dev_err(icd->pdev, "camera device read not implemented\n"); - - return -EINVAL; -} - -static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - int err; - - dev_dbg(icd->pdev, "mmap called, vma=%p\n", vma); - - if (icd->streamer != file) - return -EBUSY; - - if (mutex_lock_interruptible(&ici->host_lock)) - return -ERESTARTSYS; - err = vb2_mmap(&icd->vb2_vidq, vma); - mutex_unlock(&ici->host_lock); - - dev_dbg(icd->pdev, "vma start=0x%08lx, size=%ld, ret=%d\n", - (unsigned long)vma->vm_start, - (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, - err); - - return err; -} - -static __poll_t soc_camera_poll(struct file *file, poll_table *pt) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - __poll_t res = EPOLLERR; - - if (icd->streamer != file) - return EPOLLERR; - - mutex_lock(&ici->host_lock); - res = ici->ops->poll(file, pt); - mutex_unlock(&ici->host_lock); - return res; -} - -static const struct v4l2_file_operations soc_camera_fops = { - .owner = THIS_MODULE, - .open = soc_camera_open, - .release = soc_camera_close, - .unlocked_ioctl = video_ioctl2, - .read = soc_camera_read, - .mmap = soc_camera_mmap, - .poll = soc_camera_poll, -}; - -static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct soc_camera_device *icd = file->private_data; - int ret; - - WARN_ON(priv != file->private_data); - - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - dev_warn(icd->pdev, "Wrong buf-type %d\n", f->type); - return -EINVAL; - } - - if (icd->streamer && icd->streamer != file) - return -EBUSY; - - if (vb2_is_streaming(&icd->vb2_vidq)) { - dev_err(icd->pdev, "S_FMT denied: queue initialised\n"); - return -EBUSY; - } - - ret = soc_camera_set_fmt(icd, f); - - if (!ret && !icd->streamer) - icd->streamer = file; - - return ret; -} - -static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - struct soc_camera_device *icd = file->private_data; - const struct soc_mbus_pixelfmt *format; - - WARN_ON(priv != file->private_data); - - if (f->index >= icd->num_user_formats) - return -EINVAL; - - format = icd->user_formats[f->index].host_fmt; - - if (format->name) - strscpy(f->description, format->name, sizeof(f->description)); - f->pixelformat = format->fourcc; - return 0; -} - -static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct soc_camera_device *icd = file->private_data; - struct v4l2_pix_format *pix = &f->fmt.pix; - - WARN_ON(priv != file->private_data); - - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - pix->width = icd->user_width; - pix->height = icd->user_height; - pix->bytesperline = icd->bytesperline; - pix->sizeimage = icd->sizeimage; - pix->field = icd->field; - pix->pixelformat = icd->current_fmt->host_fmt->fourcc; - pix->colorspace = icd->colorspace; - dev_dbg(icd->pdev, "current_fmt->fourcc: 0x%08x\n", - icd->current_fmt->host_fmt->fourcc); - return 0; -} - -static int soc_camera_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - - WARN_ON(priv != file->private_data); - - strscpy(cap->driver, ici->drv_name, sizeof(cap->driver)); - return ici->ops->querycap(ici, cap); -} - -static int soc_camera_streamon(struct file *file, void *priv, - enum v4l2_buf_type i) -{ - struct soc_camera_device *icd = file->private_data; - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - int ret; - - WARN_ON(priv != file->private_data); - - if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (icd->streamer != file) - return -EBUSY; - - /* This calls buf_queue from host driver's videobuf2_queue_ops */ - ret = vb2_streamon(&icd->vb2_vidq, i); - if (!ret) - v4l2_subdev_call(sd, video, s_stream, 1); - - return ret; -} - -static int soc_camera_streamoff(struct file *file, void *priv, - enum v4l2_buf_type i) -{ - struct soc_camera_device *icd = file->private_data; - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - int ret; - - WARN_ON(priv != file->private_data); - - if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (icd->streamer != file) - return -EBUSY; - - /* - * This calls buf_release from host driver's videobuf2_queue_ops for all - * remaining buffers. When the last buffer is freed, stop capture - */ - ret = vb2_streamoff(&icd->vb2_vidq, i); - - v4l2_subdev_call(sd, video, s_stream, 0); - - return ret; -} - -static int soc_camera_g_selection(struct file *file, void *fh, - struct v4l2_selection *s) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - - /* With a wrong type no need to try to fall back to cropping */ - if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - return ici->ops->get_selection(icd, s); -} - -static int soc_camera_s_selection(struct file *file, void *fh, - struct v4l2_selection *s) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - int ret; - - /* In all these cases cropping emulation will not help */ - if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - (s->target != V4L2_SEL_TGT_COMPOSE && - s->target != V4L2_SEL_TGT_CROP)) - return -EINVAL; - - if (s->target == V4L2_SEL_TGT_COMPOSE) { - /* No output size change during a running capture! */ - if (vb2_is_streaming(&icd->vb2_vidq) && - (icd->user_width != s->r.width || - icd->user_height != s->r.height)) - return -EBUSY; - - /* - * Only one user is allowed to change the output format, touch - * buffers, start / stop streaming, poll for data - */ - if (icd->streamer && icd->streamer != file) - return -EBUSY; - } - - if (s->target == V4L2_SEL_TGT_CROP && - vb2_is_streaming(&icd->vb2_vidq) && - ici->ops->set_liveselection) - ret = ici->ops->set_liveselection(icd, s); - else - ret = ici->ops->set_selection(icd, s); - if (!ret && - s->target == V4L2_SEL_TGT_COMPOSE) { - icd->user_width = s->r.width; - icd->user_height = s->r.height; - if (!icd->streamer) - icd->streamer = file; - } - - return ret; -} - -static int soc_camera_g_parm(struct file *file, void *fh, - struct v4l2_streamparm *a) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - - if (ici->ops->get_parm) - return ici->ops->get_parm(icd, a); - - return -ENOIOCTLCMD; -} - -static int soc_camera_s_parm(struct file *file, void *fh, - struct v4l2_streamparm *a) -{ - struct soc_camera_device *icd = file->private_data; - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - - if (ici->ops->set_parm) - return ici->ops->set_parm(icd, a); - - return -ENOIOCTLCMD; -} - -static int soc_camera_probe(struct soc_camera_host *ici, - struct soc_camera_device *icd); - -/* So far this function cannot fail */ -static void scan_add_host(struct soc_camera_host *ici) -{ - struct soc_camera_device *icd; - - mutex_lock(&list_lock); - - list_for_each_entry(icd, &devices, list) - if (icd->iface == ici->nr) { - struct soc_camera_desc *sdesc = to_soc_camera_desc(icd); - struct soc_camera_subdev_desc *ssdd = &sdesc->subdev_desc; - - /* The camera could have been already on, try to reset */ - if (ssdd->reset) - if (icd->control) - ssdd->reset(icd->control); - - icd->parent = ici->v4l2_dev.dev; - - /* Ignore errors */ - soc_camera_probe(ici, icd); - } - - mutex_unlock(&list_lock); -} - -/* - * It is invalid to call v4l2_clk_enable() after a successful probing - * asynchronously outside of V4L2 operations, i.e. with .host_lock not held. - */ -static int soc_camera_clk_enable(struct v4l2_clk *clk) -{ - struct soc_camera_device *icd = clk->priv; - struct soc_camera_host *ici; - - if (!icd || !icd->parent) - return -ENODEV; - - ici = to_soc_camera_host(icd->parent); - - if (!try_module_get(ici->ops->owner)) - return -ENODEV; - - /* - * If a different client is currently being probed, the host will tell - * you to go - */ - return soc_camera_clock_start(ici); -} - -static void soc_camera_clk_disable(struct v4l2_clk *clk) -{ - struct soc_camera_device *icd = clk->priv; - struct soc_camera_host *ici; - - if (!icd || !icd->parent) - return; - - ici = to_soc_camera_host(icd->parent); - - soc_camera_clock_stop(ici); - - module_put(ici->ops->owner); -} - -/* - * Eventually, it would be more logical to make the respective host the clock - * owner, but then we would have to copy this struct for each ici. Besides, it - * would introduce the circular dependency problem, unless we port all client - * drivers to release the clock, when not in use. - */ -static const struct v4l2_clk_ops soc_camera_clk_ops = { - .owner = THIS_MODULE, - .enable = soc_camera_clk_enable, - .disable = soc_camera_clk_disable, -}; - -static int soc_camera_dyn_pdev(struct soc_camera_desc *sdesc, - struct soc_camera_async_client *sasc) -{ - struct platform_device *pdev; - int ret, i; - - mutex_lock(&list_lock); - i = find_first_zero_bit(device_map, MAP_MAX_NUM); - if (i < MAP_MAX_NUM) - set_bit(i, device_map); - mutex_unlock(&list_lock); - if (i >= MAP_MAX_NUM) - return -ENOMEM; - - pdev = platform_device_alloc("soc-camera-pdrv", i); - if (!pdev) - return -ENOMEM; - - ret = platform_device_add_data(pdev, sdesc, sizeof(*sdesc)); - if (ret < 0) { - platform_device_put(pdev); - return ret; - } - - sasc->pdev = pdev; - - return 0; -} - -static struct soc_camera_device *soc_camera_add_pdev(struct soc_camera_async_client *sasc) -{ - struct platform_device *pdev = sasc->pdev; - int ret; - - ret = platform_device_add(pdev); - if (ret < 0 || !pdev->dev.driver) - return NULL; - - return platform_get_drvdata(pdev); -} - -/* Locking: called with .host_lock held */ -static int soc_camera_probe_finish(struct soc_camera_device *icd) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct v4l2_subdev_format fmt = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - struct v4l2_mbus_framefmt *mf = &fmt.format; - int ret; - - sd->grp_id = soc_camera_grp_id(icd); - v4l2_set_subdev_hostdata(sd, icd); - - v4l2_subdev_call(sd, video, g_tvnorms, &icd->vdev->tvnorms); - - ret = v4l2_ctrl_add_handler(&icd->ctrl_handler, sd->ctrl_handler, - NULL, true); - if (ret < 0) - return ret; - - ret = soc_camera_add_device(icd); - if (ret < 0) { - dev_err(icd->pdev, "Couldn't activate the camera: %d\n", ret); - return ret; - } - - /* At this point client .probe() should have run already */ - ret = soc_camera_init_user_formats(icd); - if (ret < 0) - goto eusrfmt; - - icd->field = V4L2_FIELD_ANY; - - ret = soc_camera_video_start(icd); - if (ret < 0) - goto evidstart; - - /* Try to improve our guess of a reasonable window format */ - if (!v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt)) { - icd->user_width = mf->width; - icd->user_height = mf->height; - icd->colorspace = mf->colorspace; - icd->field = mf->field; - } - soc_camera_remove_device(icd); - - return 0; - -evidstart: - soc_camera_free_user_formats(icd); -eusrfmt: - soc_camera_remove_device(icd); - - return ret; -} - -#ifdef CONFIG_I2C_BOARDINFO -static int soc_camera_i2c_init(struct soc_camera_device *icd, - struct soc_camera_desc *sdesc) -{ - struct soc_camera_subdev_desc *ssdd; - struct i2c_client *client; - struct soc_camera_host *ici; - struct soc_camera_host_desc *shd = &sdesc->host_desc; - struct i2c_adapter *adap; - struct v4l2_subdev *subdev; - char clk_name[V4L2_CLK_NAME_SIZE]; - int ret; - - /* First find out how we link the main client */ - if (icd->sasc) { - /* Async non-OF probing handled by the subdevice list */ - return -EPROBE_DEFER; - } - - ici = to_soc_camera_host(icd->parent); - adap = i2c_get_adapter(shd->i2c_adapter_id); - if (!adap) { - dev_err(icd->pdev, "Cannot get I2C adapter #%d. No driver?\n", - shd->i2c_adapter_id); - return -ENODEV; - } - - ssdd = kmemdup(&sdesc->subdev_desc, sizeof(*ssdd), GFP_KERNEL); - if (!ssdd) { - ret = -ENOMEM; - goto ealloc; - } - /* - * In synchronous case we request regulators ourselves in - * soc_camera_pdrv_probe(), make sure the subdevice driver doesn't try - * to allocate them again. - */ - ssdd->sd_pdata.num_regulators = 0; - ssdd->sd_pdata.regulators = NULL; - shd->board_info->platform_data = ssdd; - - v4l2_clk_name_i2c(clk_name, sizeof(clk_name), - shd->i2c_adapter_id, shd->board_info->addr); - - icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, icd); - if (IS_ERR(icd->clk)) { - ret = PTR_ERR(icd->clk); - goto eclkreg; - } - - subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap, - shd->board_info, NULL); - if (!subdev) { - ret = -ENODEV; - goto ei2cnd; - } - - client = v4l2_get_subdevdata(subdev); - - /* Use to_i2c_client(dev) to recover the i2c client */ - icd->control = &client->dev; - - return 0; -ei2cnd: - v4l2_clk_unregister(icd->clk); - icd->clk = NULL; -eclkreg: - kfree(ssdd); -ealloc: - i2c_put_adapter(adap); - return ret; -} - -static void soc_camera_i2c_free(struct soc_camera_device *icd) -{ - struct i2c_client *client = - to_i2c_client(to_soc_camera_control(icd)); - struct i2c_adapter *adap; - struct soc_camera_subdev_desc *ssdd; - - icd->control = NULL; - if (icd->sasc) - return; - - adap = client->adapter; - ssdd = client->dev.platform_data; - v4l2_device_unregister_subdev(i2c_get_clientdata(client)); - i2c_unregister_device(client); - i2c_put_adapter(adap); - kfree(ssdd); - v4l2_clk_unregister(icd->clk); - icd->clk = NULL; -} - -/* - * V4L2 asynchronous notifier callbacks. They are all called under a v4l2-async - * internal global mutex, therefore cannot race against other asynchronous - * events. Until notifier->complete() (soc_camera_async_complete()) is called, - * the video device node is not registered and no V4L fops can occur. Unloading - * of the host driver also calls a v4l2-async function, so also there we're - * protected. - */ -static int soc_camera_async_bound(struct v4l2_async_notifier *notifier, - struct v4l2_subdev *sd, - struct v4l2_async_subdev *asd) -{ - struct soc_camera_async_client *sasc = container_of(notifier, - struct soc_camera_async_client, notifier); - struct soc_camera_device *icd = platform_get_drvdata(sasc->pdev); - - if (asd == sasc->sensor && !WARN_ON(icd->control)) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - - /* - * Only now we get subdevice-specific information like - * regulators, flags, callbacks, etc. - */ - if (client) { - struct soc_camera_desc *sdesc = to_soc_camera_desc(icd); - struct soc_camera_subdev_desc *ssdd = - soc_camera_i2c_to_desc(client); - if (ssdd) { - memcpy(&sdesc->subdev_desc, ssdd, - sizeof(sdesc->subdev_desc)); - if (ssdd->reset) - ssdd->reset(&client->dev); - } - - icd->control = &client->dev; - } - } - - return 0; -} - -static void soc_camera_async_unbind(struct v4l2_async_notifier *notifier, - struct v4l2_subdev *sd, - struct v4l2_async_subdev *asd) -{ - struct soc_camera_async_client *sasc = container_of(notifier, - struct soc_camera_async_client, notifier); - struct soc_camera_device *icd = platform_get_drvdata(sasc->pdev); - - icd->control = NULL; - - if (icd->clk) { - v4l2_clk_unregister(icd->clk); - icd->clk = NULL; - } -} - -static int soc_camera_async_complete(struct v4l2_async_notifier *notifier) -{ - struct soc_camera_async_client *sasc = container_of(notifier, - struct soc_camera_async_client, notifier); - struct soc_camera_device *icd = platform_get_drvdata(sasc->pdev); - - if (to_soc_camera_control(icd)) { - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - int ret; - - mutex_lock(&list_lock); - ret = soc_camera_probe(ici, icd); - mutex_unlock(&list_lock); - if (ret < 0) - return ret; - } - - return 0; -} - -static const struct v4l2_async_notifier_operations soc_camera_async_ops = { - .bound = soc_camera_async_bound, - .unbind = soc_camera_async_unbind, - .complete = soc_camera_async_complete, -}; - -static int scan_async_group(struct soc_camera_host *ici, - struct v4l2_async_subdev **asd, unsigned int size) -{ - struct soc_camera_async_subdev *sasd; - struct soc_camera_async_client *sasc; - struct soc_camera_device *icd; - struct soc_camera_desc sdesc = {.host_desc.bus_id = ici->nr,}; - char clk_name[V4L2_CLK_NAME_SIZE]; - unsigned int i; - int ret; - - /* First look for a sensor */ - for (i = 0; i < size; i++) { - sasd = container_of(asd[i], struct soc_camera_async_subdev, asd); - if (sasd->role == SOCAM_SUBDEV_DATA_SOURCE) - break; - } - - if (i >= size || asd[i]->match_type != V4L2_ASYNC_MATCH_I2C) { - /* All useless */ - dev_err(ici->v4l2_dev.dev, "No I2C data source found!\n"); - return -ENODEV; - } - - /* Or shall this be managed by the soc-camera device? */ - sasc = devm_kzalloc(ici->v4l2_dev.dev, sizeof(*sasc), GFP_KERNEL); - if (!sasc) - return -ENOMEM; - - /* HACK: just need a != NULL */ - sdesc.host_desc.board_info = ERR_PTR(-ENODATA); - - ret = soc_camera_dyn_pdev(&sdesc, sasc); - if (ret < 0) - goto eallocpdev; - - sasc->sensor = &sasd->asd; - - icd = soc_camera_add_pdev(sasc); - if (!icd) { - ret = -ENOMEM; - goto eaddpdev; - } - - v4l2_async_notifier_init(&sasc->notifier); - - for (i = 0; i < size; i++) { - ret = v4l2_async_notifier_add_subdev(&sasc->notifier, asd[i]); - if (ret) - goto eaddasd; - } - - sasc->notifier.ops = &soc_camera_async_ops; - - icd->sasc = sasc; - icd->parent = ici->v4l2_dev.dev; - - v4l2_clk_name_i2c(clk_name, sizeof(clk_name), - sasd->asd.match.i2c.adapter_id, - sasd->asd.match.i2c.address); - - icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, icd); - if (IS_ERR(icd->clk)) { - ret = PTR_ERR(icd->clk); - goto eclkreg; - } - - ret = v4l2_async_notifier_register(&ici->v4l2_dev, &sasc->notifier); - if (!ret) - return 0; - - v4l2_clk_unregister(icd->clk); -eclkreg: - icd->clk = NULL; -eaddasd: - v4l2_async_notifier_cleanup(&sasc->notifier); - platform_device_del(sasc->pdev); -eaddpdev: - platform_device_put(sasc->pdev); -eallocpdev: - devm_kfree(ici->v4l2_dev.dev, sasc); - dev_err(ici->v4l2_dev.dev, "group probe failed: %d\n", ret); - - return ret; -} - -static void scan_async_host(struct soc_camera_host *ici) -{ - struct v4l2_async_subdev **asd; - int j; - - for (j = 0, asd = ici->asd; ici->asd_sizes[j]; j++) { - scan_async_group(ici, asd, ici->asd_sizes[j]); - asd += ici->asd_sizes[j]; - } -} -#else -#define soc_camera_i2c_init(icd, sdesc) (-ENODEV) -#define soc_camera_i2c_free(icd) do {} while (0) -#define scan_async_host(ici) do {} while (0) -#endif - -#ifdef CONFIG_OF - -struct soc_of_info { - struct soc_camera_async_subdev sasd; - struct soc_camera_async_client sasc; - struct v4l2_async_subdev *subdev; -}; - -static int soc_of_bind(struct soc_camera_host *ici, - struct device_node *ep, - struct device_node *remote) -{ - struct soc_camera_device *icd; - struct soc_camera_desc sdesc = {.host_desc.bus_id = ici->nr,}; - struct soc_camera_async_client *sasc; - struct soc_of_info *info; - struct i2c_client *client; - char clk_name[V4L2_CLK_NAME_SIZE]; - int ret; - - /* allocate a new subdev and add match info to it */ - info = devm_kzalloc(ici->v4l2_dev.dev, sizeof(struct soc_of_info), - GFP_KERNEL); - if (!info) - return -ENOMEM; - - info->sasd.asd.match.fwnode = of_fwnode_handle(remote); - info->sasd.asd.match_type = V4L2_ASYNC_MATCH_FWNODE; - info->subdev = &info->sasd.asd; - - /* Or shall this be managed by the soc-camera device? */ - sasc = &info->sasc; - - /* HACK: just need a != NULL */ - sdesc.host_desc.board_info = ERR_PTR(-ENODATA); - - ret = soc_camera_dyn_pdev(&sdesc, sasc); - if (ret < 0) - goto eallocpdev; - - sasc->sensor = &info->sasd.asd; - - icd = soc_camera_add_pdev(sasc); - if (!icd) { - ret = -ENOMEM; - goto eaddpdev; - } - - v4l2_async_notifier_init(&sasc->notifier); - - ret = v4l2_async_notifier_add_subdev(&sasc->notifier, info->subdev); - if (ret) { - of_node_put(remote); - goto eaddasd; - } - - sasc->notifier.ops = &soc_camera_async_ops; - - icd->sasc = sasc; - icd->parent = ici->v4l2_dev.dev; - - client = of_find_i2c_device_by_node(remote); - - if (client) - v4l2_clk_name_i2c(clk_name, sizeof(clk_name), - client->adapter->nr, client->addr); - else - v4l2_clk_name_of(clk_name, sizeof(clk_name), remote); - - icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, icd); - if (IS_ERR(icd->clk)) { - ret = PTR_ERR(icd->clk); - goto eclkreg; - } - - ret = v4l2_async_notifier_register(&ici->v4l2_dev, &sasc->notifier); - if (!ret) - return 0; - - v4l2_clk_unregister(icd->clk); -eclkreg: - icd->clk = NULL; -eaddasd: - v4l2_async_notifier_cleanup(&sasc->notifier); - platform_device_del(sasc->pdev); -eaddpdev: - platform_device_put(sasc->pdev); -eallocpdev: - devm_kfree(ici->v4l2_dev.dev, info); - dev_err(ici->v4l2_dev.dev, "group probe failed: %d\n", ret); - - return ret; -} - -static void scan_of_host(struct soc_camera_host *ici) -{ - struct device *dev = ici->v4l2_dev.dev; - struct device_node *np = dev->of_node; - struct device_node *epn = NULL, *rem; - unsigned int i; - - for (i = 0; ; i++) { - epn = of_graph_get_next_endpoint(np, epn); - if (!epn) - break; - - rem = of_graph_get_remote_port_parent(epn); - if (!rem) { - dev_notice(dev, "no remote for %pOF\n", epn); - continue; - } - - /* so we now have a remote node to connect */ - if (!i) - soc_of_bind(ici, epn, rem); - - if (i) { - dev_err(dev, "multiple subdevices aren't supported yet!\n"); - break; - } - } - - of_node_put(epn); -} - -#else -static inline void scan_of_host(struct soc_camera_host *ici) { } -#endif - -/* Called during host-driver probe */ -static int soc_camera_probe(struct soc_camera_host *ici, - struct soc_camera_device *icd) -{ - struct soc_camera_desc *sdesc = to_soc_camera_desc(icd); - struct soc_camera_host_desc *shd = &sdesc->host_desc; - struct device *control = NULL; - int ret; - - dev_info(icd->pdev, "Probing %s\n", dev_name(icd->pdev)); - - /* - * Currently the subdev with the largest number of controls (13) is - * ov6550. So let's pick 16 as a hint for the control handler. Note - * that this is a hint only: too large and you waste some memory, too - * small and there is a (very) small performance hit when looking up - * controls in the internal hash. - */ - ret = v4l2_ctrl_handler_init(&icd->ctrl_handler, 16); - if (ret < 0) - return ret; - - /* Must have icd->vdev before registering the device */ - ret = video_dev_create(icd); - if (ret < 0) - goto evdc; - - /* - * ..._video_start() will create a device node, video_register_device() - * itself is protected against concurrent open() calls, but we also have - * to protect our data also during client probing. - */ - - /* Non-i2c cameras, e.g., soc_camera_platform, have no board_info */ - if (shd->board_info) { - ret = soc_camera_i2c_init(icd, sdesc); - if (ret < 0 && ret != -EPROBE_DEFER) - goto eadd; - } else if (!shd->add_device || !shd->del_device) { - ret = -EINVAL; - goto eadd; - } else { - ret = soc_camera_clock_start(ici); - if (ret < 0) - goto eadd; - - if (shd->module_name) - ret = request_module(shd->module_name); - - ret = shd->add_device(icd); - if (ret < 0) - goto eadddev; - - /* - * FIXME: this is racy, have to use driver-binding notification, - * when it is available - */ - control = to_soc_camera_control(icd); - if (!control || !control->driver || !dev_get_drvdata(control) || - !try_module_get(control->driver->owner)) { - shd->del_device(icd); - ret = -ENODEV; - goto enodrv; - } - } - - mutex_lock(&ici->host_lock); - ret = soc_camera_probe_finish(icd); - mutex_unlock(&ici->host_lock); - if (ret < 0) - goto efinish; - - return 0; - -efinish: - if (shd->board_info) { - soc_camera_i2c_free(icd); - } else { - shd->del_device(icd); - module_put(control->driver->owner); -enodrv: -eadddev: - soc_camera_clock_stop(ici); - } -eadd: - if (icd->vdev) { - video_device_release(icd->vdev); - icd->vdev = NULL; - } -evdc: - v4l2_ctrl_handler_free(&icd->ctrl_handler); - return ret; -} - -/* - * This is called on device_unregister, which only means we have to disconnect - * from the host, but not remove ourselves from the device list. With - * asynchronous client probing this can also be called without - * soc_camera_probe_finish() having run. Careful with clean up. - */ -static int soc_camera_remove(struct soc_camera_device *icd) -{ - struct soc_camera_desc *sdesc = to_soc_camera_desc(icd); - struct video_device *vdev = icd->vdev; - - v4l2_ctrl_handler_free(&icd->ctrl_handler); - if (vdev) { - video_unregister_device(vdev); - icd->vdev = NULL; - } - - if (sdesc->host_desc.board_info) { - soc_camera_i2c_free(icd); - } else { - struct device *dev = to_soc_camera_control(icd); - struct device_driver *drv = dev ? dev->driver : NULL; - if (drv) { - sdesc->host_desc.del_device(icd); - module_put(drv->owner); - } - } - - if (icd->num_user_formats) - soc_camera_free_user_formats(icd); - - if (icd->clk) { - /* For the synchronous case */ - v4l2_clk_unregister(icd->clk); - icd->clk = NULL; - } - - if (icd->sasc) - platform_device_unregister(icd->sasc->pdev); - - return 0; -} - -static int default_g_selection(struct soc_camera_device *icd, - struct v4l2_selection *sel) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct v4l2_subdev_selection sdsel = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - .target = sel->target, - }; - int ret; - - ret = v4l2_subdev_call(sd, pad, get_selection, NULL, &sdsel); - if (ret) - return ret; - sel->r = sdsel.r; - return 0; -} - -static int default_s_selection(struct soc_camera_device *icd, - struct v4l2_selection *sel) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct v4l2_subdev_selection sdsel = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - .target = sel->target, - .flags = sel->flags, - .r = sel->r, - }; - int ret; - - ret = v4l2_subdev_call(sd, pad, set_selection, NULL, &sdsel); - if (ret) - return ret; - sel->r = sdsel.r; - return 0; -} - -static int default_g_parm(struct soc_camera_device *icd, - struct v4l2_streamparm *a) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - - return v4l2_g_parm_cap(icd->vdev, sd, a); -} - -static int default_s_parm(struct soc_camera_device *icd, - struct v4l2_streamparm *a) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - - return v4l2_s_parm_cap(icd->vdev, sd, a); -} - -static int default_enum_framesizes(struct soc_camera_device *icd, - struct v4l2_frmsizeenum *fsize) -{ - int ret; - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - const struct soc_camera_format_xlate *xlate; - struct v4l2_subdev_frame_size_enum fse = { - .index = fsize->index, - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - - xlate = soc_camera_xlate_by_fourcc(icd, fsize->pixel_format); - if (!xlate) - return -EINVAL; - fse.code = xlate->code; - - ret = v4l2_subdev_call(sd, pad, enum_frame_size, NULL, &fse); - if (ret < 0) - return ret; - - if (fse.min_width == fse.max_width && - fse.min_height == fse.max_height) { - fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; - fsize->discrete.width = fse.min_width; - fsize->discrete.height = fse.min_height; - return 0; - } - fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; - fsize->stepwise.min_width = fse.min_width; - fsize->stepwise.max_width = fse.max_width; - fsize->stepwise.min_height = fse.min_height; - fsize->stepwise.max_height = fse.max_height; - fsize->stepwise.step_width = 1; - fsize->stepwise.step_height = 1; - return 0; -} - -int soc_camera_host_register(struct soc_camera_host *ici) -{ - struct soc_camera_host *ix; - int ret; - - if (!ici || !ici->ops || - !ici->ops->try_fmt || - !ici->ops->set_fmt || - !ici->ops->set_bus_param || - !ici->ops->querycap || - !ici->ops->init_videobuf2 || - !ici->ops->poll || - !ici->v4l2_dev.dev) - return -EINVAL; - - if (!ici->ops->set_selection) - ici->ops->set_selection = default_s_selection; - if (!ici->ops->get_selection) - ici->ops->get_selection = default_g_selection; - if (!ici->ops->set_parm) - ici->ops->set_parm = default_s_parm; - if (!ici->ops->get_parm) - ici->ops->get_parm = default_g_parm; - if (!ici->ops->enum_framesizes) - ici->ops->enum_framesizes = default_enum_framesizes; - - mutex_lock(&list_lock); - list_for_each_entry(ix, &hosts, list) { - if (ix->nr == ici->nr) { - ret = -EBUSY; - goto edevreg; - } - } - - ret = v4l2_device_register(ici->v4l2_dev.dev, &ici->v4l2_dev); - if (ret < 0) - goto edevreg; - - list_add_tail(&ici->list, &hosts); - mutex_unlock(&list_lock); - - mutex_init(&ici->host_lock); - mutex_init(&ici->clk_lock); - - if (ici->v4l2_dev.dev->of_node) - scan_of_host(ici); - else if (ici->asd_sizes) - /* - * No OF, host with a list of subdevices. Don't try to mix - * modes by initialising some groups statically and some - * dynamically! - */ - scan_async_host(ici); - else - /* Legacy: static platform devices from board data */ - scan_add_host(ici); - - return 0; - -edevreg: - mutex_unlock(&list_lock); - return ret; -} -EXPORT_SYMBOL(soc_camera_host_register); - -/* Unregister all clients! */ -void soc_camera_host_unregister(struct soc_camera_host *ici) -{ - struct soc_camera_device *icd, *tmp; - struct soc_camera_async_client *sasc; - LIST_HEAD(notifiers); - - mutex_lock(&list_lock); - list_del(&ici->list); - list_for_each_entry(icd, &devices, list) - if (icd->iface == ici->nr && icd->sasc) { - /* as long as we hold the device, sasc won't be freed */ - get_device(icd->pdev); - list_add(&icd->sasc->list, ¬ifiers); - } - mutex_unlock(&list_lock); - - list_for_each_entry(sasc, ¬ifiers, list) { - /* Must call unlocked to avoid AB-BA dead-lock */ - v4l2_async_notifier_unregister(&sasc->notifier); - v4l2_async_notifier_cleanup(&sasc->notifier); - put_device(&sasc->pdev->dev); - } - - mutex_lock(&list_lock); - - list_for_each_entry_safe(icd, tmp, &devices, list) - if (icd->iface == ici->nr) - soc_camera_remove(icd); - - mutex_unlock(&list_lock); - - v4l2_device_unregister(&ici->v4l2_dev); -} -EXPORT_SYMBOL(soc_camera_host_unregister); - -/* Image capture device */ -static int soc_camera_device_register(struct soc_camera_device *icd) -{ - struct soc_camera_device *ix; - int num = -1, i; - - mutex_lock(&list_lock); - for (i = 0; i < 256 && num < 0; i++) { - num = i; - /* Check if this index is available on this interface */ - list_for_each_entry(ix, &devices, list) { - if (ix->iface == icd->iface && ix->devnum == i) { - num = -1; - break; - } - } - } - - if (num < 0) { - /* - * ok, we have 256 cameras on this host... - * man, stay reasonable... - */ - mutex_unlock(&list_lock); - return -ENOMEM; - } - - icd->devnum = num; - icd->use_count = 0; - icd->host_priv = NULL; - - /* - * Dynamically allocated devices set the bit earlier, but it doesn't hurt setting - * it again - */ - i = to_platform_device(icd->pdev)->id; - if (i < 0) - /* One static (legacy) soc-camera platform device */ - i = 0; - if (i >= MAP_MAX_NUM) { - mutex_unlock(&list_lock); - return -EBUSY; - } - set_bit(i, device_map); - list_add_tail(&icd->list, &devices); - mutex_unlock(&list_lock); - - return 0; -} - -static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = { - .vidioc_querycap = soc_camera_querycap, - .vidioc_try_fmt_vid_cap = soc_camera_try_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = soc_camera_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = soc_camera_s_fmt_vid_cap, - .vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap, - .vidioc_enum_input = soc_camera_enum_input, - .vidioc_g_input = soc_camera_g_input, - .vidioc_s_input = soc_camera_s_input, - .vidioc_s_std = soc_camera_s_std, - .vidioc_g_std = soc_camera_g_std, - .vidioc_enum_framesizes = soc_camera_enum_framesizes, - .vidioc_reqbufs = soc_camera_reqbufs, - .vidioc_querybuf = soc_camera_querybuf, - .vidioc_qbuf = soc_camera_qbuf, - .vidioc_dqbuf = soc_camera_dqbuf, - .vidioc_create_bufs = soc_camera_create_bufs, - .vidioc_prepare_buf = soc_camera_prepare_buf, - .vidioc_expbuf = soc_camera_expbuf, - .vidioc_streamon = soc_camera_streamon, - .vidioc_streamoff = soc_camera_streamoff, - .vidioc_g_selection = soc_camera_g_selection, - .vidioc_s_selection = soc_camera_s_selection, - .vidioc_g_parm = soc_camera_g_parm, - .vidioc_s_parm = soc_camera_s_parm, -}; - -static int video_dev_create(struct soc_camera_device *icd) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct video_device *vdev = video_device_alloc(); - - if (!vdev) - return -ENOMEM; - - strscpy(vdev->name, ici->drv_name, sizeof(vdev->name)); - - vdev->v4l2_dev = &ici->v4l2_dev; - vdev->fops = &soc_camera_fops; - vdev->ioctl_ops = &soc_camera_ioctl_ops; - vdev->release = video_device_release; - vdev->ctrl_handler = &icd->ctrl_handler; - vdev->lock = &ici->host_lock; - - icd->vdev = vdev; - - return 0; -} - -/* - * Called from soc_camera_probe() above with .host_lock held - */ -static int soc_camera_video_start(struct soc_camera_device *icd) -{ - const struct device_type *type = icd->vdev->dev.type; - int ret; - - if (!icd->parent) - return -ENODEV; - - video_set_drvdata(icd->vdev, icd); - if (icd->vdev->tvnorms == 0) { - /* disable the STD API if there are no tvnorms defined */ - v4l2_disable_ioctl(icd->vdev, VIDIOC_G_STD); - v4l2_disable_ioctl(icd->vdev, VIDIOC_S_STD); - v4l2_disable_ioctl(icd->vdev, VIDIOC_ENUMSTD); - } - ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER, -1); - if (ret < 0) { - dev_err(icd->pdev, "video_register_device failed: %d\n", ret); - return ret; - } - - /* Restore device type, possibly set by the subdevice driver */ - icd->vdev->dev.type = type; - - return 0; -} - -static int soc_camera_pdrv_probe(struct platform_device *pdev) -{ - struct soc_camera_desc *sdesc = pdev->dev.platform_data; - struct soc_camera_subdev_desc *ssdd = &sdesc->subdev_desc; - struct soc_camera_device *icd; - int ret; - - if (!sdesc) - return -EINVAL; - - icd = devm_kzalloc(&pdev->dev, sizeof(*icd), GFP_KERNEL); - if (!icd) - return -ENOMEM; - - /* - * In the asynchronous case ssdd->num_regulators == 0 yet, so, the below - * regulator allocation is a dummy. They are actually requested by the - * subdevice driver, using soc_camera_power_init(). Also note, that in - * that case regulators are attached to the I2C device and not to the - * camera platform device. - */ - ret = devm_regulator_bulk_get(&pdev->dev, ssdd->sd_pdata.num_regulators, - ssdd->sd_pdata.regulators); - if (ret < 0) - return ret; - - icd->iface = sdesc->host_desc.bus_id; - icd->sdesc = sdesc; - icd->pdev = &pdev->dev; - platform_set_drvdata(pdev, icd); - - icd->user_width = DEFAULT_WIDTH; - icd->user_height = DEFAULT_HEIGHT; - - return soc_camera_device_register(icd); -} - -/* - * Only called on rmmod for each platform device, since they are not - * hot-pluggable. Now we know, that all our users - hosts and devices have - * been unloaded already - */ -static int soc_camera_pdrv_remove(struct platform_device *pdev) -{ - struct soc_camera_device *icd = platform_get_drvdata(pdev); - int i; - - if (!icd) - return -EINVAL; - - i = pdev->id; - if (i < 0) - i = 0; - - /* - * In synchronous mode with static platform devices this is called in a - * loop from drivers/base/dd.c::driver_detach(), no parallel execution, - * no need to lock. In asynchronous case the caller - - * soc_camera_host_unregister() - already holds the lock - */ - if (test_bit(i, device_map)) { - clear_bit(i, device_map); - list_del(&icd->list); - } - - return 0; -} - -static struct platform_driver __refdata soc_camera_pdrv = { - .probe = soc_camera_pdrv_probe, - .remove = soc_camera_pdrv_remove, - .driver = { - .name = "soc-camera-pdrv", - }, -}; - -module_platform_driver(soc_camera_pdrv); - -MODULE_DESCRIPTION("Image capture bus driver"); -MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:soc-camera-pdrv"); diff --git a/drivers/media/platform/soc_camera/soc_camera_platform.c b/drivers/media/platform/soc_camera/soc_camera_platform.c deleted file mode 100644 index 79fbe1fea95f..000000000000 --- a/drivers/media/platform/soc_camera/soc_camera_platform.c +++ /dev/null @@ -1,188 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Generic Platform Camera Driver - * - * Copyright (C) 2008 Magnus Damm - * Based on mt9m001 driver, - * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/platform_device.h> -#include <linux/videodev2.h> -#include <media/v4l2-subdev.h> -#include <media/soc_camera.h> -#include <linux/platform_data/media/soc_camera_platform.h> - -struct soc_camera_platform_priv { - struct v4l2_subdev subdev; -}; - -static struct soc_camera_platform_priv *get_priv(struct platform_device *pdev) -{ - struct v4l2_subdev *subdev = platform_get_drvdata(pdev); - return container_of(subdev, struct soc_camera_platform_priv, subdev); -} - -static int soc_camera_platform_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); - return p->set_capture(p, enable); -} - -static int soc_camera_platform_fill_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *mf = &format->format; - - mf->width = p->format.width; - mf->height = p->format.height; - mf->code = p->format.code; - mf->colorspace = p->format.colorspace; - mf->field = p->format.field; - - return 0; -} - -static int soc_camera_platform_s_power(struct v4l2_subdev *sd, int on) -{ - struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); - - return soc_camera_set_power(p->icd->control, &p->icd->sdesc->subdev_desc, NULL, on); -} - -static const struct v4l2_subdev_core_ops platform_subdev_core_ops = { - .s_power = soc_camera_platform_s_power, -}; - -static int soc_camera_platform_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); - - if (code->pad || code->index) - return -EINVAL; - - code->code = p->format.code; - return 0; -} - -static int soc_camera_platform_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); - - if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - switch (sel->target) { - case V4L2_SEL_TGT_CROP_BOUNDS: - case V4L2_SEL_TGT_CROP_DEFAULT: - case V4L2_SEL_TGT_CROP: - sel->r.left = 0; - sel->r.top = 0; - sel->r.width = p->format.width; - sel->r.height = p->format.height; - return 0; - default: - return -EINVAL; - } -} - -static int soc_camera_platform_g_mbus_config(struct v4l2_subdev *sd, - struct v4l2_mbus_config *cfg) -{ - struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); - - cfg->flags = p->mbus_param; - cfg->type = p->mbus_type; - - return 0; -} - -static const struct v4l2_subdev_video_ops platform_subdev_video_ops = { - .s_stream = soc_camera_platform_s_stream, - .g_mbus_config = soc_camera_platform_g_mbus_config, -}; - -static const struct v4l2_subdev_pad_ops platform_subdev_pad_ops = { - .enum_mbus_code = soc_camera_platform_enum_mbus_code, - .get_selection = soc_camera_platform_get_selection, - .get_fmt = soc_camera_platform_fill_fmt, - .set_fmt = soc_camera_platform_fill_fmt, -}; - -static const struct v4l2_subdev_ops platform_subdev_ops = { - .core = &platform_subdev_core_ops, - .video = &platform_subdev_video_ops, - .pad = &platform_subdev_pad_ops, -}; - -static int soc_camera_platform_probe(struct platform_device *pdev) -{ - struct soc_camera_host *ici; - struct soc_camera_platform_priv *priv; - struct soc_camera_platform_info *p = pdev->dev.platform_data; - struct soc_camera_device *icd; - - if (!p) - return -EINVAL; - - if (!p->icd) { - dev_err(&pdev->dev, - "Platform has not set soc_camera_device pointer!\n"); - return -EINVAL; - } - - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - icd = p->icd; - - /* soc-camera convention: control's drvdata points to the subdev */ - platform_set_drvdata(pdev, &priv->subdev); - /* Set the control device reference */ - icd->control = &pdev->dev; - - ici = to_soc_camera_host(icd->parent); - - v4l2_subdev_init(&priv->subdev, &platform_subdev_ops); - v4l2_set_subdevdata(&priv->subdev, p); - strscpy(priv->subdev.name, dev_name(&pdev->dev), - sizeof(priv->subdev.name)); - - return v4l2_device_register_subdev(&ici->v4l2_dev, &priv->subdev); -} - -static int soc_camera_platform_remove(struct platform_device *pdev) -{ - struct soc_camera_platform_priv *priv = get_priv(pdev); - struct soc_camera_platform_info *p = v4l2_get_subdevdata(&priv->subdev); - - p->icd->control = NULL; - v4l2_device_unregister_subdev(&priv->subdev); - return 0; -} - -static struct platform_driver soc_camera_platform_driver = { - .driver = { - .name = "soc_camera_platform", - }, - .probe = soc_camera_platform_probe, - .remove = soc_camera_platform_remove, -}; - -module_platform_driver(soc_camera_platform_driver); - -MODULE_DESCRIPTION("SoC Camera Platform driver"); -MODULE_AUTHOR("Magnus Damm"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:soc_camera_platform"); diff --git a/drivers/media/platform/soc_camera/soc_mediabus.c b/drivers/media/platform/soc_camera/soc_mediabus.c deleted file mode 100644 index be74008ec0ca..000000000000 --- a/drivers/media/platform/soc_camera/soc_mediabus.c +++ /dev/null @@ -1,533 +0,0 @@ -/* - * soc-camera media bus helper routines - * - * Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/kernel.h> -#include <linux/module.h> - -#include <media/v4l2-device.h> -#include <media/v4l2-mediabus.h> -#include <media/drv-intf/soc_mediabus.h> - -static const struct soc_mbus_lookup mbus_fmt[] = { -{ - .code = MEDIA_BUS_FMT_YUYV8_2X8, - .fmt = { - .fourcc = V4L2_PIX_FMT_YUYV, - .name = "YUYV", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_YVYU8_2X8, - .fmt = { - .fourcc = V4L2_PIX_FMT_YVYU, - .name = "YVYU", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_UYVY8_2X8, - .fmt = { - .fourcc = V4L2_PIX_FMT_UYVY, - .name = "UYVY", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_VYUY8_2X8, - .fmt = { - .fourcc = V4L2_PIX_FMT_VYUY, - .name = "VYUY", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, - .fmt = { - .fourcc = V4L2_PIX_FMT_RGB555, - .name = "RGB555", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, - .fmt = { - .fourcc = V4L2_PIX_FMT_RGB555X, - .name = "RGB555X", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_BE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_RGB565_2X8_LE, - .fmt = { - .fourcc = V4L2_PIX_FMT_RGB565, - .name = "RGB565", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_RGB565_2X8_BE, - .fmt = { - .fourcc = V4L2_PIX_FMT_RGB565X, - .name = "RGB565X", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_BE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_RGB666_1X18, - .fmt = { - .fourcc = V4L2_PIX_FMT_RGB32, - .name = "RGB666/32bpp", - .bits_per_sample = 18, - .packing = SOC_MBUS_PACKING_EXTEND32, - .order = SOC_MBUS_ORDER_LE, - }, -}, { - .code = MEDIA_BUS_FMT_RGB888_1X24, - .fmt = { - .fourcc = V4L2_PIX_FMT_RGB32, - .name = "RGB888/32bpp", - .bits_per_sample = 24, - .packing = SOC_MBUS_PACKING_EXTEND32, - .order = SOC_MBUS_ORDER_LE, - }, -}, { - .code = MEDIA_BUS_FMT_RGB888_2X12_BE, - .fmt = { - .fourcc = V4L2_PIX_FMT_RGB32, - .name = "RGB888/32bpp", - .bits_per_sample = 12, - .packing = SOC_MBUS_PACKING_EXTEND32, - .order = SOC_MBUS_ORDER_BE, - }, -}, { - .code = MEDIA_BUS_FMT_RGB888_2X12_LE, - .fmt = { - .fourcc = V4L2_PIX_FMT_RGB32, - .name = "RGB888/32bpp", - .bits_per_sample = 12, - .packing = SOC_MBUS_PACKING_EXTEND32, - .order = SOC_MBUS_ORDER_LE, - }, -}, { - .code = MEDIA_BUS_FMT_SBGGR8_1X8, - .fmt = { - .fourcc = V4L2_PIX_FMT_SBGGR8, - .name = "Bayer 8 BGGR", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_NONE, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_SBGGR10_1X10, - .fmt = { - .fourcc = V4L2_PIX_FMT_SBGGR10, - .name = "Bayer 10 BGGR", - .bits_per_sample = 10, - .packing = SOC_MBUS_PACKING_EXTEND16, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_Y8_1X8, - .fmt = { - .fourcc = V4L2_PIX_FMT_GREY, - .name = "Grey", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_NONE, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_Y10_1X10, - .fmt = { - .fourcc = V4L2_PIX_FMT_Y10, - .name = "Grey 10bit", - .bits_per_sample = 10, - .packing = SOC_MBUS_PACKING_EXTEND16, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, - .fmt = { - .fourcc = V4L2_PIX_FMT_SBGGR10, - .name = "Bayer 10 BGGR", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE, - .fmt = { - .fourcc = V4L2_PIX_FMT_SBGGR10, - .name = "Bayer 10 BGGR", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADLO, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE, - .fmt = { - .fourcc = V4L2_PIX_FMT_SBGGR10, - .name = "Bayer 10 BGGR", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_BE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE, - .fmt = { - .fourcc = V4L2_PIX_FMT_SBGGR10, - .name = "Bayer 10 BGGR", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADLO, - .order = SOC_MBUS_ORDER_BE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_JPEG_1X8, - .fmt = { - .fourcc = V4L2_PIX_FMT_JPEG, - .name = "JPEG", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_VARIABLE, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE, - .fmt = { - .fourcc = V4L2_PIX_FMT_RGB444, - .name = "RGB444", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_BE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_YUYV8_1_5X8, - .fmt = { - .fourcc = V4L2_PIX_FMT_YUV420, - .name = "YUYV 4:2:0", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_1_5X8, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_YVYU8_1_5X8, - .fmt = { - .fourcc = V4L2_PIX_FMT_YVU420, - .name = "YVYU 4:2:0", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_1_5X8, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_UYVY8_1X16, - .fmt = { - .fourcc = V4L2_PIX_FMT_UYVY, - .name = "UYVY 16bit", - .bits_per_sample = 16, - .packing = SOC_MBUS_PACKING_EXTEND16, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_VYUY8_1X16, - .fmt = { - .fourcc = V4L2_PIX_FMT_VYUY, - .name = "VYUY 16bit", - .bits_per_sample = 16, - .packing = SOC_MBUS_PACKING_EXTEND16, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_YUYV8_1X16, - .fmt = { - .fourcc = V4L2_PIX_FMT_YUYV, - .name = "YUYV 16bit", - .bits_per_sample = 16, - .packing = SOC_MBUS_PACKING_EXTEND16, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_YVYU8_1X16, - .fmt = { - .fourcc = V4L2_PIX_FMT_YVYU, - .name = "YVYU 16bit", - .bits_per_sample = 16, - .packing = SOC_MBUS_PACKING_EXTEND16, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_SGRBG8_1X8, - .fmt = { - .fourcc = V4L2_PIX_FMT_SGRBG8, - .name = "Bayer 8 GRBG", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_NONE, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, - .fmt = { - .fourcc = V4L2_PIX_FMT_SGRBG10DPCM8, - .name = "Bayer 10 BGGR DPCM 8", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_NONE, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_SGBRG10_1X10, - .fmt = { - .fourcc = V4L2_PIX_FMT_SGBRG10, - .name = "Bayer 10 GBRG", - .bits_per_sample = 10, - .packing = SOC_MBUS_PACKING_EXTEND16, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_SGRBG10_1X10, - .fmt = { - .fourcc = V4L2_PIX_FMT_SGRBG10, - .name = "Bayer 10 GRBG", - .bits_per_sample = 10, - .packing = SOC_MBUS_PACKING_EXTEND16, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_SRGGB10_1X10, - .fmt = { - .fourcc = V4L2_PIX_FMT_SRGGB10, - .name = "Bayer 10 RGGB", - .bits_per_sample = 10, - .packing = SOC_MBUS_PACKING_EXTEND16, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_SBGGR12_1X12, - .fmt = { - .fourcc = V4L2_PIX_FMT_SBGGR12, - .name = "Bayer 12 BGGR", - .bits_per_sample = 12, - .packing = SOC_MBUS_PACKING_EXTEND16, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_SGBRG12_1X12, - .fmt = { - .fourcc = V4L2_PIX_FMT_SGBRG12, - .name = "Bayer 12 GBRG", - .bits_per_sample = 12, - .packing = SOC_MBUS_PACKING_EXTEND16, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_SGRBG12_1X12, - .fmt = { - .fourcc = V4L2_PIX_FMT_SGRBG12, - .name = "Bayer 12 GRBG", - .bits_per_sample = 12, - .packing = SOC_MBUS_PACKING_EXTEND16, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, { - .code = MEDIA_BUS_FMT_SRGGB12_1X12, - .fmt = { - .fourcc = V4L2_PIX_FMT_SRGGB12, - .name = "Bayer 12 RGGB", - .bits_per_sample = 12, - .packing = SOC_MBUS_PACKING_EXTEND16, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}, -}; - -int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf, - unsigned int *numerator, unsigned int *denominator) -{ - switch (mf->packing) { - case SOC_MBUS_PACKING_NONE: - case SOC_MBUS_PACKING_EXTEND16: - *numerator = 1; - *denominator = 1; - return 0; - case SOC_MBUS_PACKING_EXTEND32: - *numerator = 1; - *denominator = 1; - return 0; - case SOC_MBUS_PACKING_2X8_PADHI: - case SOC_MBUS_PACKING_2X8_PADLO: - *numerator = 2; - *denominator = 1; - return 0; - case SOC_MBUS_PACKING_1_5X8: - *numerator = 3; - *denominator = 2; - return 0; - case SOC_MBUS_PACKING_VARIABLE: - *numerator = 0; - *denominator = 1; - return 0; - } - return -EINVAL; -} -EXPORT_SYMBOL(soc_mbus_samples_per_pixel); - -s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf) -{ - if (mf->layout != SOC_MBUS_LAYOUT_PACKED) - return width * mf->bits_per_sample / 8; - - switch (mf->packing) { - case SOC_MBUS_PACKING_NONE: - return width * mf->bits_per_sample / 8; - case SOC_MBUS_PACKING_2X8_PADHI: - case SOC_MBUS_PACKING_2X8_PADLO: - case SOC_MBUS_PACKING_EXTEND16: - return width * 2; - case SOC_MBUS_PACKING_1_5X8: - return width * 3 / 2; - case SOC_MBUS_PACKING_VARIABLE: - return 0; - case SOC_MBUS_PACKING_EXTEND32: - return width * 4; - } - return -EINVAL; -} -EXPORT_SYMBOL(soc_mbus_bytes_per_line); - -s32 soc_mbus_image_size(const struct soc_mbus_pixelfmt *mf, - u32 bytes_per_line, u32 height) -{ - if (mf->layout == SOC_MBUS_LAYOUT_PACKED) - return bytes_per_line * height; - - switch (mf->packing) { - case SOC_MBUS_PACKING_2X8_PADHI: - case SOC_MBUS_PACKING_2X8_PADLO: - return bytes_per_line * height * 2; - case SOC_MBUS_PACKING_1_5X8: - return bytes_per_line * height * 3 / 2; - default: - return -EINVAL; - } -} -EXPORT_SYMBOL(soc_mbus_image_size); - -const struct soc_mbus_pixelfmt *soc_mbus_find_fmtdesc( - u32 code, - const struct soc_mbus_lookup *lookup, - int n) -{ - int i; - - for (i = 0; i < n; i++) - if (lookup[i].code == code) - return &lookup[i].fmt; - - return NULL; -} -EXPORT_SYMBOL(soc_mbus_find_fmtdesc); - -const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc( - u32 code) -{ - return soc_mbus_find_fmtdesc(code, mbus_fmt, ARRAY_SIZE(mbus_fmt)); -} -EXPORT_SYMBOL(soc_mbus_get_fmtdesc); - -unsigned int soc_mbus_config_compatible(const struct v4l2_mbus_config *cfg, - unsigned int flags) -{ - unsigned long common_flags; - bool hsync = true, vsync = true, pclk, data, mode; - bool mipi_lanes, mipi_clock; - - common_flags = cfg->flags & flags; - - switch (cfg->type) { - case V4L2_MBUS_PARALLEL: - hsync = common_flags & (V4L2_MBUS_HSYNC_ACTIVE_HIGH | - V4L2_MBUS_HSYNC_ACTIVE_LOW); - vsync = common_flags & (V4L2_MBUS_VSYNC_ACTIVE_HIGH | - V4L2_MBUS_VSYNC_ACTIVE_LOW); - /* fall through */ - case V4L2_MBUS_BT656: - pclk = common_flags & (V4L2_MBUS_PCLK_SAMPLE_RISING | - V4L2_MBUS_PCLK_SAMPLE_FALLING); - data = common_flags & (V4L2_MBUS_DATA_ACTIVE_HIGH | - V4L2_MBUS_DATA_ACTIVE_LOW); - mode = common_flags & (V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE); - return (!hsync || !vsync || !pclk || !data || !mode) ? - 0 : common_flags; - case V4L2_MBUS_CSI2_DPHY: - mipi_lanes = common_flags & V4L2_MBUS_CSI2_LANES; - mipi_clock = common_flags & (V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK | - V4L2_MBUS_CSI2_CONTINUOUS_CLOCK); - return (!mipi_lanes || !mipi_clock) ? 0 : common_flags; - default: - WARN_ON(1); - return -EINVAL; - } - return 0; -} -EXPORT_SYMBOL(soc_mbus_config_compatible); - -static int __init soc_mbus_init(void) -{ - return 0; -} - -static void __exit soc_mbus_exit(void) -{ -} - -module_init(soc_mbus_init); -module_exit(soc_mbus_exit); - -MODULE_DESCRIPTION("soc-camera media bus interface"); -MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/soc_camera/soc_scale_crop.c b/drivers/media/platform/soc_camera/soc_scale_crop.c deleted file mode 100644 index 8d25ca0490f7..000000000000 --- a/drivers/media/platform/soc_camera/soc_scale_crop.c +++ /dev/null @@ -1,426 +0,0 @@ -/* - * soc-camera generic scaling-cropping manipulation functions - * - * Copyright (C) 2013 Guennadi Liakhovetski <g.liakhovetski@gmx.de> - * - * 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; either version 2 of the License, or - * (at your option) any later version. - */ - -#include <linux/device.h> -#include <linux/module.h> - -#include <media/soc_camera.h> -#include <media/v4l2-common.h> - -#include "soc_scale_crop.h" - -#ifdef DEBUG_GEOMETRY -#define dev_geo dev_info -#else -#define dev_geo dev_dbg -#endif - -/* Check if any dimension of r1 is smaller than respective one of r2 */ -static bool is_smaller(const struct v4l2_rect *r1, const struct v4l2_rect *r2) -{ - return r1->width < r2->width || r1->height < r2->height; -} - -/* Check if r1 fails to cover r2 */ -static bool is_inside(const struct v4l2_rect *r1, const struct v4l2_rect *r2) -{ - return r1->left > r2->left || r1->top > r2->top || - r1->left + r1->width < r2->left + r2->width || - r1->top + r1->height < r2->top + r2->height; -} - -/* Get and store current client crop */ -int soc_camera_client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect) -{ - struct v4l2_subdev_selection sdsel = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - .target = V4L2_SEL_TGT_CROP, - }; - int ret; - - ret = v4l2_subdev_call(sd, pad, get_selection, NULL, &sdsel); - if (!ret) { - *rect = sdsel.r; - return ret; - } - - sdsel.target = V4L2_SEL_TGT_CROP_BOUNDS; - ret = v4l2_subdev_call(sd, pad, get_selection, NULL, &sdsel); - if (!ret) - *rect = sdsel.r; - - return ret; -} -EXPORT_SYMBOL(soc_camera_client_g_rect); - -/* Client crop has changed, update our sub-rectangle to remain within the area */ -static void move_and_crop_subrect(struct v4l2_rect *rect, - struct v4l2_rect *subrect) -{ - if (rect->width < subrect->width) - subrect->width = rect->width; - - if (rect->height < subrect->height) - subrect->height = rect->height; - - if (rect->left > subrect->left) - subrect->left = rect->left; - else if (rect->left + rect->width < - subrect->left + subrect->width) - subrect->left = rect->left + rect->width - - subrect->width; - - if (rect->top > subrect->top) - subrect->top = rect->top; - else if (rect->top + rect->height < - subrect->top + subrect->height) - subrect->top = rect->top + rect->height - - subrect->height; -} - -/* - * The common for both scaling and cropping iterative approach is: - * 1. try if the client can produce exactly what requested by the user - * 2. if (1) failed, try to double the client image until we get one big enough - * 3. if (2) failed, try to request the maximum image - */ -int soc_camera_client_s_selection(struct v4l2_subdev *sd, - struct v4l2_selection *sel, struct v4l2_selection *cam_sel, - struct v4l2_rect *target_rect, struct v4l2_rect *subrect) -{ - struct v4l2_subdev_selection sdsel = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - .target = sel->target, - .flags = sel->flags, - .r = sel->r, - }; - struct v4l2_subdev_selection bounds = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - .target = V4L2_SEL_TGT_CROP_BOUNDS, - }; - struct v4l2_rect *rect = &sel->r, *cam_rect = &cam_sel->r; - struct device *dev = sd->v4l2_dev->dev; - int ret; - unsigned int width, height; - - v4l2_subdev_call(sd, pad, set_selection, NULL, &sdsel); - sel->r = sdsel.r; - ret = soc_camera_client_g_rect(sd, cam_rect); - if (ret < 0) - return ret; - - /* - * Now cam_crop contains the current camera input rectangle, and it must - * be within camera cropcap bounds - */ - if (!memcmp(rect, cam_rect, sizeof(*rect))) { - /* Even if camera S_SELECTION failed, but camera rectangle matches */ - dev_dbg(dev, "Camera S_SELECTION successful for %dx%d@%d:%d\n", - rect->width, rect->height, rect->left, rect->top); - *target_rect = *cam_rect; - return 0; - } - - /* Try to fix cropping, that camera hasn't managed to set */ - dev_geo(dev, "Fix camera S_SELECTION for %dx%d@%d:%d to %dx%d@%d:%d\n", - cam_rect->width, cam_rect->height, - cam_rect->left, cam_rect->top, - rect->width, rect->height, rect->left, rect->top); - - /* We need sensor maximum rectangle */ - ret = v4l2_subdev_call(sd, pad, get_selection, NULL, &bounds); - if (ret < 0) - return ret; - - /* Put user requested rectangle within sensor bounds */ - soc_camera_limit_side(&rect->left, &rect->width, sdsel.r.left, 2, - bounds.r.width); - soc_camera_limit_side(&rect->top, &rect->height, sdsel.r.top, 4, - bounds.r.height); - - /* - * Popular special case - some cameras can only handle fixed sizes like - * QVGA, VGA,... Take care to avoid infinite loop. - */ - width = max_t(unsigned int, cam_rect->width, 2); - height = max_t(unsigned int, cam_rect->height, 2); - - /* - * Loop as long as sensor is not covering the requested rectangle and - * is still within its bounds - */ - while (!ret && (is_smaller(cam_rect, rect) || - is_inside(cam_rect, rect)) && - (bounds.r.width > width || bounds.r.height > height)) { - - width *= 2; - height *= 2; - - cam_rect->width = width; - cam_rect->height = height; - - /* - * We do not know what capabilities the camera has to set up - * left and top borders. We could try to be smarter in iterating - * them, e.g., if camera current left is to the right of the - * target left, set it to the middle point between the current - * left and minimum left. But that would add too much - * complexity: we would have to iterate each border separately. - * Instead we just drop to the left and top bounds. - */ - if (cam_rect->left > rect->left) - cam_rect->left = bounds.r.left; - - if (cam_rect->left + cam_rect->width < rect->left + rect->width) - cam_rect->width = rect->left + rect->width - - cam_rect->left; - - if (cam_rect->top > rect->top) - cam_rect->top = bounds.r.top; - - if (cam_rect->top + cam_rect->height < rect->top + rect->height) - cam_rect->height = rect->top + rect->height - - cam_rect->top; - - sdsel.r = *cam_rect; - v4l2_subdev_call(sd, pad, set_selection, NULL, &sdsel); - *cam_rect = sdsel.r; - ret = soc_camera_client_g_rect(sd, cam_rect); - dev_geo(dev, "Camera S_SELECTION %d for %dx%d@%d:%d\n", ret, - cam_rect->width, cam_rect->height, - cam_rect->left, cam_rect->top); - } - - /* S_SELECTION must not modify the rectangle */ - if (is_smaller(cam_rect, rect) || is_inside(cam_rect, rect)) { - /* - * The camera failed to configure a suitable cropping, - * we cannot use the current rectangle, set to max - */ - sdsel.r = bounds.r; - v4l2_subdev_call(sd, pad, set_selection, NULL, &sdsel); - *cam_rect = sdsel.r; - - ret = soc_camera_client_g_rect(sd, cam_rect); - dev_geo(dev, "Camera S_SELECTION %d for max %dx%d@%d:%d\n", ret, - cam_rect->width, cam_rect->height, - cam_rect->left, cam_rect->top); - } - - if (!ret) { - *target_rect = *cam_rect; - move_and_crop_subrect(target_rect, subrect); - } - - return ret; -} -EXPORT_SYMBOL(soc_camera_client_s_selection); - -/* Iterative set_fmt, also updates cached client crop on success */ -static int client_set_fmt(struct soc_camera_device *icd, - struct v4l2_rect *rect, struct v4l2_rect *subrect, - unsigned int max_width, unsigned int max_height, - struct v4l2_subdev_format *format, bool host_can_scale) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct device *dev = icd->parent; - struct v4l2_mbus_framefmt *mf = &format->format; - unsigned int width = mf->width, height = mf->height, tmp_w, tmp_h; - struct v4l2_subdev_selection sdsel = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - .target = V4L2_SEL_TGT_CROP_BOUNDS, - }; - bool host_1to1; - int ret; - - ret = v4l2_device_call_until_err(sd->v4l2_dev, - soc_camera_grp_id(icd), pad, - set_fmt, NULL, format); - if (ret < 0) - return ret; - - dev_geo(dev, "camera scaled to %ux%u\n", mf->width, mf->height); - - if (width == mf->width && height == mf->height) { - /* Perfect! The client has done it all. */ - host_1to1 = true; - goto update_cache; - } - - host_1to1 = false; - if (!host_can_scale) - goto update_cache; - - ret = v4l2_subdev_call(sd, pad, get_selection, NULL, &sdsel); - if (ret < 0) - return ret; - - if (max_width > sdsel.r.width) - max_width = sdsel.r.width; - if (max_height > sdsel.r.height) - max_height = sdsel.r.height; - - /* Camera set a format, but geometry is not precise, try to improve */ - tmp_w = mf->width; - tmp_h = mf->height; - - /* width <= max_width && height <= max_height - guaranteed by try_fmt */ - while ((width > tmp_w || height > tmp_h) && - tmp_w < max_width && tmp_h < max_height) { - tmp_w = min(2 * tmp_w, max_width); - tmp_h = min(2 * tmp_h, max_height); - mf->width = tmp_w; - mf->height = tmp_h; - ret = v4l2_device_call_until_err(sd->v4l2_dev, - soc_camera_grp_id(icd), pad, - set_fmt, NULL, format); - dev_geo(dev, "Camera scaled to %ux%u\n", - mf->width, mf->height); - if (ret < 0) { - /* This shouldn't happen */ - dev_err(dev, "Client failed to set format: %d\n", ret); - return ret; - } - } - -update_cache: - /* Update cache */ - ret = soc_camera_client_g_rect(sd, rect); - if (ret < 0) - return ret; - - if (host_1to1) - *subrect = *rect; - else - move_and_crop_subrect(rect, subrect); - - return 0; -} - -/** - * soc_camera_client_scale - * @icd: soc-camera device - * @rect: camera cropping window - * @subrect: part of rect, sent to the user - * @mf: in- / output camera output window - * @width: on input: max host input width; - * on output: user width, mapped back to input - * @height: on input: max host input height; - * on output: user height, mapped back to input - * @host_can_scale: host can scale this pixel format - * @shift: shift, used for scaling - */ -int soc_camera_client_scale(struct soc_camera_device *icd, - struct v4l2_rect *rect, struct v4l2_rect *subrect, - struct v4l2_mbus_framefmt *mf, - unsigned int *width, unsigned int *height, - bool host_can_scale, unsigned int shift) -{ - struct device *dev = icd->parent; - struct v4l2_subdev_format fmt_tmp = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - .format = *mf, - }; - struct v4l2_mbus_framefmt *mf_tmp = &fmt_tmp.format; - unsigned int scale_h, scale_v; - int ret; - - /* - * 5. Apply iterative camera S_FMT for camera user window (also updates - * client crop cache and the imaginary sub-rectangle). - */ - ret = client_set_fmt(icd, rect, subrect, *width, *height, - &fmt_tmp, host_can_scale); - if (ret < 0) - return ret; - - dev_geo(dev, "5: camera scaled to %ux%u\n", - mf_tmp->width, mf_tmp->height); - - /* 6. Retrieve camera output window (g_fmt) */ - - /* unneeded - it is already in "mf_tmp" */ - - /* 7. Calculate new client scales. */ - scale_h = soc_camera_calc_scale(rect->width, shift, mf_tmp->width); - scale_v = soc_camera_calc_scale(rect->height, shift, mf_tmp->height); - - mf->width = mf_tmp->width; - mf->height = mf_tmp->height; - mf->colorspace = mf_tmp->colorspace; - - /* - * 8. Calculate new host crop - apply camera scales to previously - * updated "effective" crop. - */ - *width = soc_camera_shift_scale(subrect->width, shift, scale_h); - *height = soc_camera_shift_scale(subrect->height, shift, scale_v); - - dev_geo(dev, "8: new client sub-window %ux%u\n", *width, *height); - - return 0; -} -EXPORT_SYMBOL(soc_camera_client_scale); - -/* - * Calculate real client output window by applying new scales to the current - * client crop. New scales are calculated from the requested output format and - * host crop, mapped backed onto the client input (subrect). - */ -void soc_camera_calc_client_output(struct soc_camera_device *icd, - struct v4l2_rect *rect, struct v4l2_rect *subrect, - const struct v4l2_pix_format *pix, struct v4l2_mbus_framefmt *mf, - unsigned int shift) -{ - struct device *dev = icd->parent; - unsigned int scale_v, scale_h; - - if (subrect->width == rect->width && - subrect->height == rect->height) { - /* No sub-cropping */ - mf->width = pix->width; - mf->height = pix->height; - return; - } - - /* 1.-2. Current camera scales and subwin - cached. */ - - dev_geo(dev, "2: subwin %ux%u@%u:%u\n", - subrect->width, subrect->height, - subrect->left, subrect->top); - - /* - * 3. Calculate new combined scales from input sub-window to requested - * user window. - */ - - /* - * TODO: CEU cannot scale images larger than VGA to smaller than SubQCIF - * (128x96) or larger than VGA. This and similar limitations have to be - * taken into account here. - */ - scale_h = soc_camera_calc_scale(subrect->width, shift, pix->width); - scale_v = soc_camera_calc_scale(subrect->height, shift, pix->height); - - dev_geo(dev, "3: scales %u:%u\n", scale_h, scale_v); - - /* - * 4. Calculate desired client output window by applying combined scales - * to client (real) input window. - */ - mf->width = soc_camera_shift_scale(rect->width, shift, scale_h); - mf->height = soc_camera_shift_scale(rect->height, shift, scale_v); -} -EXPORT_SYMBOL(soc_camera_calc_client_output); - -MODULE_DESCRIPTION("soc-camera scaling-cropping functions"); -MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/soc_camera/soc_scale_crop.h b/drivers/media/platform/soc_camera/soc_scale_crop.h deleted file mode 100644 index 9ca469312a1f..000000000000 --- a/drivers/media/platform/soc_camera/soc_scale_crop.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * soc-camera generic scaling-cropping manipulation functions - * - * Copyright (C) 2013 Guennadi Liakhovetski <g.liakhovetski@gmx.de> - * - * 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; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef SOC_SCALE_CROP_H -#define SOC_SCALE_CROP_H - -#include <linux/kernel.h> - -struct soc_camera_device; - -struct v4l2_selection; -struct v4l2_mbus_framefmt; -struct v4l2_pix_format; -struct v4l2_rect; -struct v4l2_subdev; - -static inline unsigned int soc_camera_shift_scale(unsigned int size, - unsigned int shift, unsigned int scale) -{ - return DIV_ROUND_CLOSEST(size << shift, scale); -} - -#define soc_camera_calc_scale(in, shift, out) soc_camera_shift_scale(in, shift, out) - -int soc_camera_client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect); -int soc_camera_client_s_selection(struct v4l2_subdev *sd, - struct v4l2_selection *sel, struct v4l2_selection *cam_sel, - struct v4l2_rect *target_rect, struct v4l2_rect *subrect); -int soc_camera_client_scale(struct soc_camera_device *icd, - struct v4l2_rect *rect, struct v4l2_rect *subrect, - struct v4l2_mbus_framefmt *mf, - unsigned int *width, unsigned int *height, - bool host_can_scale, unsigned int shift); -void soc_camera_calc_client_output(struct soc_camera_device *icd, - struct v4l2_rect *rect, struct v4l2_rect *subrect, - const struct v4l2_pix_format *pix, struct v4l2_mbus_framefmt *mf, - unsigned int shift); - -#endif diff --git a/drivers/media/platform/sti/bdisp/bdisp-debug.c b/drivers/media/platform/sti/bdisp/bdisp-debug.c index c6a4e2de5c0c..77ca7517fa3e 100644 --- a/drivers/media/platform/sti/bdisp/bdisp-debug.c +++ b/drivers/media/platform/sti/bdisp/bdisp-debug.c @@ -315,7 +315,7 @@ static void bdisp_dbg_dump_ivmx(struct seq_file *s, seq_puts(s, "Unknown conversion\n"); } -static int bdisp_dbg_last_nodes(struct seq_file *s, void *data) +static int last_nodes_show(struct seq_file *s, void *data) { /* Not dumping all fields, focusing on significant ones */ struct bdisp_dev *bdisp = s->private; @@ -388,7 +388,7 @@ static int bdisp_dbg_last_nodes(struct seq_file *s, void *data) return 0; } -static int bdisp_dbg_last_nodes_raw(struct seq_file *s, void *data) +static int last_nodes_raw_show(struct seq_file *s, void *data) { struct bdisp_dev *bdisp = s->private; struct bdisp_node *node; @@ -437,7 +437,7 @@ static const char *bdisp_fmt_to_str(struct bdisp_frame frame) } } -static int bdisp_dbg_last_request(struct seq_file *s, void *data) +static int last_request_show(struct seq_file *s, void *data) { struct bdisp_dev *bdisp = s->private; struct bdisp_request *request = &bdisp->dbg.copy_request; @@ -474,7 +474,7 @@ static int bdisp_dbg_last_request(struct seq_file *s, void *data) #define DUMP(reg) seq_printf(s, #reg " \t0x%08X\n", readl(bdisp->regs + reg)) -static int bdisp_dbg_regs(struct seq_file *s, void *data) +static int regs_show(struct seq_file *s, void *data) { struct bdisp_dev *bdisp = s->private; int ret; @@ -582,7 +582,7 @@ static int bdisp_dbg_regs(struct seq_file *s, void *data) #define SECOND 1000000 -static int bdisp_dbg_perf(struct seq_file *s, void *data) +static int perf_show(struct seq_file *s, void *data) { struct bdisp_dev *bdisp = s->private; struct bdisp_request *request = &bdisp->dbg.copy_request; @@ -627,27 +627,15 @@ static int bdisp_dbg_perf(struct seq_file *s, void *data) return 0; } -#define bdisp_dbg_declare(name) \ - static int bdisp_dbg_##name##_open(struct inode *i, struct file *f) \ - { \ - return single_open(f, bdisp_dbg_##name, i->i_private); \ - } \ - static const struct file_operations bdisp_dbg_##name##_fops = { \ - .open = bdisp_dbg_##name##_open, \ - .read = seq_read, \ - .llseek = seq_lseek, \ - .release = single_release, \ - } - #define bdisp_dbg_create_entry(name) \ debugfs_create_file(#name, S_IRUGO, bdisp->dbg.debugfs_entry, bdisp, \ - &bdisp_dbg_##name##_fops) + &name##_fops) -bdisp_dbg_declare(regs); -bdisp_dbg_declare(last_nodes); -bdisp_dbg_declare(last_nodes_raw); -bdisp_dbg_declare(last_request); -bdisp_dbg_declare(perf); +DEFINE_SHOW_ATTRIBUTE(regs); +DEFINE_SHOW_ATTRIBUTE(last_nodes); +DEFINE_SHOW_ATTRIBUTE(last_nodes_raw); +DEFINE_SHOW_ATTRIBUTE(last_request); +DEFINE_SHOW_ATTRIBUTE(perf); int bdisp_debugfs_create(struct bdisp_dev *bdisp) { diff --git a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.h b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.h index 3dbb3a287cc0..c9d6021904cd 100644 --- a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.h +++ b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.h @@ -193,7 +193,7 @@ struct c8sectpfei { #define C8SECTPFE_SYS_ENABLE BIT(0) /* - * Ponter record data structure required for each input block + * Pointer record data structure required for each input block * see Table 82 on page 167 of functional specification. */ diff --git a/drivers/media/platform/sti/delta/delta.h b/drivers/media/platform/sti/delta/delta.h index 2ba99922c05b..914556030e70 100644 --- a/drivers/media/platform/sti/delta/delta.h +++ b/drivers/media/platform/sti/delta/delta.h @@ -286,7 +286,7 @@ struct delta_dec { * Header parsing must be done using decode(), giving * explicitly header access unit or first access unit of bitstream. * If no valid header is found, get_streaminfo will return -ENODATA, - * in this case the next bistream access unit must be decoded till + * in this case the next bitstream access unit must be decoded till * get_streaminfo becomes successful. */ int (*get_streaminfo)(struct delta_ctx *ctx, diff --git a/drivers/media/platform/sti/hva/hva-debugfs.c b/drivers/media/platform/sti/hva/hva-debugfs.c index 9f7e8ac875d1..7d12a5b5d914 100644 --- a/drivers/media/platform/sti/hva/hva-debugfs.c +++ b/drivers/media/platform/sti/hva/hva-debugfs.c @@ -271,7 +271,7 @@ static void hva_dbg_perf_compute(struct hva_ctx *ctx) * device debug info */ -static int hva_dbg_device(struct seq_file *s, void *data) +static int device_show(struct seq_file *s, void *data) { struct hva_dev *hva = s->private; @@ -281,7 +281,7 @@ static int hva_dbg_device(struct seq_file *s, void *data) return 0; } -static int hva_dbg_encoders(struct seq_file *s, void *data) +static int encoders_show(struct seq_file *s, void *data) { struct hva_dev *hva = s->private; unsigned int i = 0; @@ -299,7 +299,7 @@ static int hva_dbg_encoders(struct seq_file *s, void *data) return 0; } -static int hva_dbg_last(struct seq_file *s, void *data) +static int last_show(struct seq_file *s, void *data) { struct hva_dev *hva = s->private; struct hva_ctx *last_ctx = &hva->dbg.last_ctx; @@ -316,7 +316,7 @@ static int hva_dbg_last(struct seq_file *s, void *data) return 0; } -static int hva_dbg_regs(struct seq_file *s, void *data) +static int regs_show(struct seq_file *s, void *data) { struct hva_dev *hva = s->private; @@ -325,26 +325,14 @@ static int hva_dbg_regs(struct seq_file *s, void *data) return 0; } -#define hva_dbg_declare(name) \ - static int hva_dbg_##name##_open(struct inode *i, struct file *f) \ - { \ - return single_open(f, hva_dbg_##name, i->i_private); \ - } \ - static const struct file_operations hva_dbg_##name##_fops = { \ - .open = hva_dbg_##name##_open, \ - .read = seq_read, \ - .llseek = seq_lseek, \ - .release = single_release, \ - } - #define hva_dbg_create_entry(name) \ debugfs_create_file(#name, 0444, hva->dbg.debugfs_entry, hva, \ - &hva_dbg_##name##_fops) + &name##_fops) -hva_dbg_declare(device); -hva_dbg_declare(encoders); -hva_dbg_declare(last); -hva_dbg_declare(regs); +DEFINE_SHOW_ATTRIBUTE(device); +DEFINE_SHOW_ATTRIBUTE(encoders); +DEFINE_SHOW_ATTRIBUTE(last); +DEFINE_SHOW_ATTRIBUTE(regs); void hva_debugfs_create(struct hva_dev *hva) { @@ -380,7 +368,7 @@ void hva_debugfs_remove(struct hva_dev *hva) * context (instance) debug info */ -static int hva_dbg_ctx(struct seq_file *s, void *data) +static int ctx_show(struct seq_file *s, void *data) { struct hva_ctx *ctx = s->private; @@ -392,7 +380,7 @@ static int hva_dbg_ctx(struct seq_file *s, void *data) return 0; } -hva_dbg_declare(ctx); +DEFINE_SHOW_ATTRIBUTE(ctx); void hva_dbg_ctx_create(struct hva_ctx *ctx) { @@ -407,7 +395,7 @@ void hva_dbg_ctx_create(struct hva_ctx *ctx) ctx->dbg.debugfs_entry = debugfs_create_file(name, 0444, hva->dbg.debugfs_entry, - ctx, &hva_dbg_ctx_fops); + ctx, &ctx_fops); } void hva_dbg_ctx_remove(struct hva_ctx *ctx) diff --git a/drivers/media/platform/sti/hva/hva-h264.c b/drivers/media/platform/sti/hva/hva-h264.c index b61a5d337d2a..c34f7cf5aed2 100644 --- a/drivers/media/platform/sti/hva/hva-h264.c +++ b/drivers/media/platform/sti/hva/hva-h264.c @@ -626,7 +626,7 @@ static int hva_h264_prepare_task(struct hva_ctx *pctx, td->frame_width = frame_width; td->frame_height = frame_height; - /* set frame alignement */ + /* set frame alignment */ td->window_width = frame_width; td->window_height = frame_height; td->window_horizontal_offset = 0; diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c index 6732874114cf..5fe5b38fa901 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c @@ -1544,7 +1544,7 @@ static void dcmi_graph_notify_unbind(struct v4l2_async_notifier *notifier, dev_dbg(dcmi->dev, "Removing %s\n", video_device_node_name(dcmi->vdev)); - /* Checks internaly if vdev has been init or not */ + /* Checks internally if vdev has been init or not */ video_unregister_device(dcmi->vdev); } diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 6950585edb5a..4c79eb64a7a7 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -15,6 +15,7 @@ #include <linux/ioctl.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> @@ -143,6 +144,15 @@ bool sun6i_csi_is_format_supported(struct sun6i_csi *csi, break; } break; + + case V4L2_PIX_FMT_RGB565: + return (mbus_code == MEDIA_BUS_FMT_RGB565_2X8_LE); + case V4L2_PIX_FMT_RGB565X: + return (mbus_code == MEDIA_BUS_FMT_RGB565_2X8_BE); + + case V4L2_PIX_FMT_JPEG: + return (mbus_code == MEDIA_BUS_FMT_JPEG_1X8); + default: dev_dbg(sdev->dev, "Unsupported pixformat: 0x%x\n", pixformat); break; @@ -154,6 +164,7 @@ bool sun6i_csi_is_format_supported(struct sun6i_csi *csi, int sun6i_csi_set_power(struct sun6i_csi *csi, bool enable) { struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi); + struct device *dev = sdev->dev; struct regmap *regmap = sdev->regmap; int ret; @@ -161,6 +172,9 @@ int sun6i_csi_set_power(struct sun6i_csi *csi, bool enable) regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 0); clk_disable_unprepare(sdev->clk_ram); + if (of_device_is_compatible(dev->of_node, + "allwinner,sun50i-a64-csi")) + clk_rate_exclusive_put(sdev->clk_mod); clk_disable_unprepare(sdev->clk_mod); reset_control_assert(sdev->rstc_bus); return 0; @@ -172,6 +186,9 @@ int sun6i_csi_set_power(struct sun6i_csi *csi, bool enable) return ret; } + if (of_device_is_compatible(dev->of_node, "allwinner,sun50i-a64-csi")) + clk_set_rate_exclusive(sdev->clk_mod, 300000000); + ret = clk_prepare_enable(sdev->clk_ram); if (ret) { dev_err(sdev->dev, "Enable clk_dram_csi clk err %d\n", ret); @@ -191,6 +208,8 @@ int sun6i_csi_set_power(struct sun6i_csi *csi, bool enable) clk_ram_disable: clk_disable_unprepare(sdev->clk_ram); clk_mod_disable: + if (of_device_is_compatible(dev->of_node, "allwinner,sun50i-a64-csi")) + clk_rate_exclusive_put(sdev->clk_mod); clk_disable_unprepare(sdev->clk_mod); return ret; } @@ -198,8 +217,8 @@ clk_mod_disable: static enum csi_input_fmt get_csi_input_format(struct sun6i_csi_dev *sdev, u32 mbus_code, u32 pixformat) { - /* bayer */ - if ((mbus_code & 0xF000) == 0x3000) + /* non-YUV */ + if ((mbus_code & 0xF000) != 0x2000) return CSI_INPUT_FORMAT_RAW; switch (pixformat) { @@ -268,6 +287,14 @@ static enum csi_output_fmt get_csi_output_format(struct sun6i_csi_dev *sdev, case V4L2_PIX_FMT_YUV422P: return buf_interlaced ? CSI_FRAME_PLANAR_YUV422 : CSI_FIELD_PLANAR_YUV422; + + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_RGB565X: + return buf_interlaced ? CSI_FRAME_RGB565 : CSI_FIELD_RGB565; + + case V4L2_PIX_FMT_JPEG: + return buf_interlaced ? CSI_FRAME_RAW_8 : CSI_FIELD_RAW_8; + default: dev_warn(sdev->dev, "Unsupported pixformat: 0x%x\n", pixformat); break; @@ -279,6 +306,10 @@ static enum csi_output_fmt get_csi_output_format(struct sun6i_csi_dev *sdev, static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_dev *sdev, u32 mbus_code, u32 pixformat) { + /* Input sequence does not apply to non-YUV formats */ + if ((mbus_code & 0xF000) != 0x2000) + return 0; + switch (pixformat) { case V4L2_PIX_FMT_HM12: case V4L2_PIX_FMT_NV12: @@ -793,7 +824,7 @@ static const struct regmap_config sun6i_csi_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, - .max_register = 0x1000, + .max_register = 0x9c, }; static int sun6i_csi_resource_request(struct sun6i_csi_dev *sdev, @@ -893,7 +924,9 @@ static int sun6i_csi_remove(struct platform_device *pdev) static const struct of_device_id sun6i_csi_of_match[] = { { .compatible = "allwinner,sun6i-a31-csi", }, + { .compatible = "allwinner,sun8i-h3-csi", }, { .compatible = "allwinner,sun8i-v3s-csi", }, + { .compatible = "allwinner,sun50i-a64-csi", }, {}, }; MODULE_DEVICE_TABLE(of, sun6i_csi_of_match); diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index 0bb000712c33..c626821aaedb 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -65,7 +65,7 @@ bool sun6i_csi_is_format_supported(struct sun6i_csi *csi, u32 pixformat, int sun6i_csi_set_power(struct sun6i_csi *csi, bool enable); /** - * sun6i_csi_update_config() - update the csi register setttings + * sun6i_csi_update_config() - update the csi register settings * @csi: pointer to the csi * @config: see struct sun6i_csi_config */ @@ -94,6 +94,7 @@ static inline int sun6i_csi_get_bpp(unsigned int pixformat) case V4L2_PIX_FMT_SGBRG8: case V4L2_PIX_FMT_SGRBG8: case V4L2_PIX_FMT_SRGGB8: + case V4L2_PIX_FMT_JPEG: return 8; case V4L2_PIX_FMT_SBGGR10: case V4L2_PIX_FMT_SGBRG10: @@ -117,6 +118,8 @@ static inline int sun6i_csi_get_bpp(unsigned int pixformat) case V4L2_PIX_FMT_NV16: case V4L2_PIX_FMT_NV61: case V4L2_PIX_FMT_YUV422P: + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_RGB565X: return 16; case V4L2_PIX_FMT_RGB24: case V4L2_PIX_FMT_BGR24: diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c index b04300c3811f..1fd16861f111 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c @@ -56,6 +56,9 @@ static const u32 supported_pixformats[] = { V4L2_PIX_FMT_NV16, V4L2_PIX_FMT_NV61, V4L2_PIX_FMT_YUV422P, + V4L2_PIX_FMT_RGB565, + V4L2_PIX_FMT_RGB565X, + V4L2_PIX_FMT_JPEG, }; static bool is_pixformat_valid(unsigned int pixformat) diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c index e2cf2b90e500..78d716c93649 100644 --- a/drivers/media/platform/ti-vpe/vpdma.c +++ b/drivers/media/platform/ti-vpe/vpdma.c @@ -404,7 +404,7 @@ EXPORT_SYMBOL(vpdma_map_desc_buf); /* * unmap descriptor/payload DMA buffer, disabling DMA access and - * allowing the main processor to acces the data + * allowing the main processor to access the data */ void vpdma_unmap_desc_buf(struct vpdma_data *vpdma, struct vpdma_buf *buf) { @@ -501,7 +501,7 @@ void vpdma_reset_desc_list(struct vpdma_desc_list *list) EXPORT_SYMBOL(vpdma_reset_desc_list); /* - * free the buffer allocated fot the VPDMA descriptor list, this should be + * free the buffer allocated for the VPDMA descriptor list, this should be * called when the user doesn't want to use VPDMA any more. */ void vpdma_free_desc_list(struct vpdma_desc_list *list) @@ -790,7 +790,7 @@ static void dump_dtd(struct vpdma_dtd *dtd) * append an outbound data transfer descriptor to the given descriptor list, * this sets up a 'client to memory' VPDMA transfer for the given VPDMA channel * - * @list: vpdma desc list to which we add this decriptor + * @list: vpdma desc list to which we add this descriptor * @width: width of the image in pixels in memory * @c_rect: compose params of output image * @fmt: vpdma data format of the buffer @@ -798,7 +798,7 @@ static void dump_dtd(struct vpdma_dtd *dtd) * max_width: enum for maximum width of data transfer * max_height: enum for maximum height of data transfer * chan: VPDMA channel - * flags: VPDMA flags to configure some descriptor fileds + * flags: VPDMA flags to configure some descriptor fields */ void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width, int stride, const struct v4l2_rect *c_rect, @@ -863,14 +863,14 @@ EXPORT_SYMBOL(vpdma_rawchan_add_out_dtd); * append an inbound data transfer descriptor to the given descriptor list, * this sets up a 'memory to client' VPDMA transfer for the given VPDMA channel * - * @list: vpdma desc list to which we add this decriptor + * @list: vpdma desc list to which we add this descriptor * @width: width of the image in pixels in memory(not the cropped width) * @c_rect: crop params of input image * @fmt: vpdma data format of the buffer * dma_addr: dma address as seen by VPDMA * chan: VPDMA channel * field: top or bottom field info of the input image - * flags: VPDMA flags to configure some descriptor fileds + * flags: VPDMA flags to configure some descriptor fields * frame_width/height: the complete width/height of the image presented to the * client (this makes sense when multiple channels are * connected to the same client, forming a larger frame) @@ -1008,7 +1008,7 @@ unsigned int vpdma_get_list_mask(struct vpdma_data *vpdma, int irq_num) } EXPORT_SYMBOL(vpdma_get_list_mask); -/* clear previosuly occured list intterupts in the LIST_STAT register */ +/* clear previously occurred list interrupts in the LIST_STAT register */ void vpdma_clear_list_stat(struct vpdma_data *vpdma, int irq_num, int list_num) { diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index d70871d0ad2d..207e7e76c048 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -876,7 +876,7 @@ static int set_srcdst_params(struct vpe_ctx *ctx) /* * we make sure that the source image has a 16 byte aligned * stride, we need to do the same for the motion vector buffer - * by aligning it's stride to the next 16 byte boundry. this + * by aligning it's stride to the next 16 byte boundary. this * extra space will not be used by the de-interlacer, but will * ensure that vpdma operates correctly */ diff --git a/drivers/media/platform/vicodec/codec-fwht.c b/drivers/media/platform/vicodec/codec-fwht.c index 5630f1dc45e6..d1d6085da9f1 100644 --- a/drivers/media/platform/vicodec/codec-fwht.c +++ b/drivers/media/platform/vicodec/codec-fwht.c @@ -10,8 +10,11 @@ */ #include <linux/string.h> +#include <linux/kernel.h> #include "codec-fwht.h" +#define OVERFLOW_BIT BIT(14) + /* * Note: bit 0 of the header must always be 0. Otherwise it cannot * be guaranteed that the magic 8 byte sequence (see below) can @@ -103,16 +106,21 @@ static int rlc(const s16 *in, __be16 *output, int blocktype) * This function will worst-case increase rlc_in by 65*2 bytes: * one s16 value for the header and 8 * 8 coefficients of type s16. */ -static s16 derlc(const __be16 **rlc_in, s16 *dwht_out) +static u16 derlc(const __be16 **rlc_in, s16 *dwht_out, + const __be16 *end_of_input) { /* header */ const __be16 *input = *rlc_in; - s16 ret = ntohs(*input++); + u16 stat; int dec_count = 0; s16 block[8 * 8 + 16]; s16 *wp = block; int i; + if (input > end_of_input) + return OVERFLOW_BIT; + stat = ntohs(*input++); + /* * Now de-compress, it expands one byte to up to 15 bytes * (or fills the remainder of the 64 bytes with zeroes if it @@ -122,9 +130,15 @@ static s16 derlc(const __be16 **rlc_in, s16 *dwht_out) * allow for overflow if the incoming data was malformed. */ while (dec_count < 8 * 8) { - s16 in = ntohs(*input++); - int length = in & 0xf; - int coeff = in >> 4; + s16 in; + int length; + int coeff; + + if (input > end_of_input) + return OVERFLOW_BIT; + in = ntohs(*input++); + length = in & 0xf; + coeff = in >> 4; /* fill remainder with zeros */ if (length == 15) { @@ -149,7 +163,7 @@ static s16 derlc(const __be16 **rlc_in, s16 *dwht_out) dwht_out[x + y * 8] = *wp++; } *rlc_in = input; - return ret; + return stat; } static const int quant_table[] = { @@ -237,8 +251,6 @@ static void fwht(const u8 *block, s16 *output_block, unsigned int stride, unsigned int i; /* stage 1 */ - stride *= input_step; - for (i = 0; i < 8; i++, tmp += stride, out += 8) { switch (input_step) { case 1: @@ -562,7 +574,7 @@ static void fill_encoder_block(const u8 *input, s16 *dst, for (i = 0; i < 8; i++) { for (j = 0; j < 8; j++, input += input_step) *dst++ = *input; - input += (stride - 8) * input_step; + input += stride - 8 * input_step; } } @@ -660,7 +672,7 @@ static void add_deltas(s16 *deltas, const u8 *ref, int stride) static u32 encode_plane(u8 *input, u8 *refp, __be16 **rlco, __be16 *rlco_max, struct fwht_cframe *cf, u32 height, u32 width, - unsigned int input_step, + u32 stride, unsigned int input_step, bool is_intra, bool next_is_intra) { u8 *input_start = input; @@ -671,7 +683,11 @@ static u32 encode_plane(u8 *input, u8 *refp, __be16 **rlco, __be16 *rlco_max, unsigned int last_size = 0; unsigned int i, j; + width = round_up(width, 8); + height = round_up(height, 8); + for (j = 0; j < height / 8; j++) { + input = input_start + j * 8 * stride; for (i = 0; i < width / 8; i++) { /* intra code, first frame is always intra coded. */ int blocktype = IBLOCK; @@ -679,9 +695,9 @@ static u32 encode_plane(u8 *input, u8 *refp, __be16 **rlco, __be16 *rlco_max, if (!is_intra) blocktype = decide_blocktype(input, refp, - deltablock, width, input_step); + deltablock, stride, input_step); if (blocktype == IBLOCK) { - fwht(input, cf->coeffs, width, input_step, 1); + fwht(input, cf->coeffs, stride, input_step, 1); quantize_intra(cf->coeffs, cf->de_coeffs, cf->i_frame_qp); } else { @@ -722,12 +738,12 @@ static u32 encode_plane(u8 *input, u8 *refp, __be16 **rlco, __be16 *rlco_max, } last_size = size; } - input += width * 7 * input_step; } exit_loop: if (encoding & FWHT_FRAME_UNENCODED) { u8 *out = (u8 *)rlco_start; + u8 *p; input = input_start; /* @@ -736,8 +752,11 @@ exit_loop: * by 0xfe. Since YUV is limited range such values * shouldn't appear anyway. */ - for (i = 0; i < height * width; i++, input += input_step) - *out++ = (*input == 0xff) ? 0xfe : *input; + for (j = 0; j < height; j++) { + for (i = 0, p = input; i < width; i++, p += input_step) + *out++ = (*p == 0xff) ? 0xfe : *p; + input += stride; + } *rlco = (__be16 *)out; encoding &= ~FWHT_FRAME_PCODED; } @@ -747,30 +766,32 @@ exit_loop: u32 fwht_encode_frame(struct fwht_raw_frame *frm, struct fwht_raw_frame *ref_frm, struct fwht_cframe *cf, - bool is_intra, bool next_is_intra) + bool is_intra, bool next_is_intra, + unsigned int width, unsigned int height, + unsigned int stride, unsigned int chroma_stride) { - unsigned int size = frm->height * frm->width; + unsigned int size = height * width; __be16 *rlco = cf->rlc_data; __be16 *rlco_max; u32 encoding; rlco_max = rlco + size / 2 - 256; encoding = encode_plane(frm->luma, ref_frm->luma, &rlco, rlco_max, cf, - frm->height, frm->width, + height, width, stride, frm->luma_alpha_step, is_intra, next_is_intra); if (encoding & FWHT_FRAME_UNENCODED) encoding |= FWHT_LUMA_UNENCODED; encoding &= ~FWHT_FRAME_UNENCODED; if (frm->components_num >= 3) { - u32 chroma_h = frm->height / frm->height_div; - u32 chroma_w = frm->width / frm->width_div; + u32 chroma_h = height / frm->height_div; + u32 chroma_w = width / frm->width_div; unsigned int chroma_size = chroma_h * chroma_w; rlco_max = rlco + chroma_size / 2 - 256; encoding |= encode_plane(frm->cb, ref_frm->cb, &rlco, rlco_max, cf, chroma_h, chroma_w, - frm->chroma_step, + chroma_stride, frm->chroma_step, is_intra, next_is_intra); if (encoding & FWHT_FRAME_UNENCODED) encoding |= FWHT_CB_UNENCODED; @@ -778,7 +799,7 @@ u32 fwht_encode_frame(struct fwht_raw_frame *frm, rlco_max = rlco + chroma_size / 2 - 256; encoding |= encode_plane(frm->cr, ref_frm->cr, &rlco, rlco_max, cf, chroma_h, chroma_w, - frm->chroma_step, + chroma_stride, frm->chroma_step, is_intra, next_is_intra); if (encoding & FWHT_FRAME_UNENCODED) encoding |= FWHT_CR_UNENCODED; @@ -787,10 +808,10 @@ u32 fwht_encode_frame(struct fwht_raw_frame *frm, if (frm->components_num == 4) { rlco_max = rlco + size / 2 - 256; - encoding = encode_plane(frm->alpha, ref_frm->alpha, &rlco, - rlco_max, cf, frm->height, frm->width, - frm->luma_alpha_step, - is_intra, next_is_intra); + encoding |= encode_plane(frm->alpha, ref_frm->alpha, &rlco, + rlco_max, cf, height, width, + stride, frm->luma_alpha_step, + is_intra, next_is_intra); if (encoding & FWHT_FRAME_UNENCODED) encoding |= FWHT_ALPHA_UNENCODED; encoding &= ~FWHT_FRAME_UNENCODED; @@ -800,18 +821,24 @@ u32 fwht_encode_frame(struct fwht_raw_frame *frm, return encoding; } -static void decode_plane(struct fwht_cframe *cf, const __be16 **rlco, u8 *ref, - u32 height, u32 width, bool uncompressed) +static bool decode_plane(struct fwht_cframe *cf, const __be16 **rlco, u8 *ref, + u32 height, u32 width, u32 coded_width, + bool uncompressed, const __be16 *end_of_rlco_buf) { unsigned int copies = 0; s16 copy[8 * 8]; - s16 stat; + u16 stat; unsigned int i, j; + width = round_up(width, 8); + height = round_up(height, 8); + if (uncompressed) { + if (end_of_rlco_buf + 1 < *rlco + width * height / 2) + return false; memcpy(ref, *rlco, width * height); *rlco += width * height / 2; - return; + return true; } /* @@ -822,19 +849,22 @@ static void decode_plane(struct fwht_cframe *cf, const __be16 **rlco, u8 *ref, */ for (j = 0; j < height / 8; j++) { for (i = 0; i < width / 8; i++) { - u8 *refp = ref + j * 8 * width + i * 8; + u8 *refp = ref + j * 8 * coded_width + i * 8; if (copies) { memcpy(cf->de_fwht, copy, sizeof(copy)); if (stat & PFRAME_BIT) - add_deltas(cf->de_fwht, refp, width); - fill_decoder_block(refp, cf->de_fwht, width); + add_deltas(cf->de_fwht, refp, + coded_width); + fill_decoder_block(refp, cf->de_fwht, + coded_width); copies--; continue; } - stat = derlc(rlco, cf->coeffs); - + stat = derlc(rlco, cf->coeffs, end_of_rlco_buf); + if (stat & OVERFLOW_BIT) + return false; if (stat & PFRAME_BIT) dequantize_inter(cf->coeffs); else @@ -847,35 +877,53 @@ static void decode_plane(struct fwht_cframe *cf, const __be16 **rlco, u8 *ref, if (copies) memcpy(copy, cf->de_fwht, sizeof(copy)); if (stat & PFRAME_BIT) - add_deltas(cf->de_fwht, refp, width); - fill_decoder_block(refp, cf->de_fwht, width); + add_deltas(cf->de_fwht, refp, coded_width); + fill_decoder_block(refp, cf->de_fwht, coded_width); } } + return true; } -void fwht_decode_frame(struct fwht_cframe *cf, struct fwht_raw_frame *ref, - u32 hdr_flags, unsigned int components_num) +bool fwht_decode_frame(struct fwht_cframe *cf, struct fwht_raw_frame *ref, + u32 hdr_flags, unsigned int components_num, + unsigned int width, unsigned int height, + unsigned int coded_width) { const __be16 *rlco = cf->rlc_data; + const __be16 *end_of_rlco_buf = cf->rlc_data + + (cf->size / sizeof(*rlco)) - 1; - decode_plane(cf, &rlco, ref->luma, cf->height, cf->width, - hdr_flags & FWHT_FL_LUMA_IS_UNCOMPRESSED); + if (!decode_plane(cf, &rlco, ref->luma, height, width, coded_width, + hdr_flags & FWHT_FL_LUMA_IS_UNCOMPRESSED, + end_of_rlco_buf)) + return false; if (components_num >= 3) { - u32 h = cf->height; - u32 w = cf->width; + u32 h = height; + u32 w = width; + u32 c = coded_width; if (!(hdr_flags & FWHT_FL_CHROMA_FULL_HEIGHT)) h /= 2; - if (!(hdr_flags & FWHT_FL_CHROMA_FULL_WIDTH)) + if (!(hdr_flags & FWHT_FL_CHROMA_FULL_WIDTH)) { w /= 2; - decode_plane(cf, &rlco, ref->cb, h, w, - hdr_flags & FWHT_FL_CB_IS_UNCOMPRESSED); - decode_plane(cf, &rlco, ref->cr, h, w, - hdr_flags & FWHT_FL_CR_IS_UNCOMPRESSED); + c /= 2; + } + if (!decode_plane(cf, &rlco, ref->cb, h, w, c, + hdr_flags & FWHT_FL_CB_IS_UNCOMPRESSED, + end_of_rlco_buf)) + return false; + if (!decode_plane(cf, &rlco, ref->cr, h, w, c, + hdr_flags & FWHT_FL_CR_IS_UNCOMPRESSED, + end_of_rlco_buf)) + return false; } if (components_num == 4) - decode_plane(cf, &rlco, ref->alpha, cf->height, cf->width, - hdr_flags & FWHT_FL_ALPHA_IS_UNCOMPRESSED); + if (!decode_plane(cf, &rlco, ref->alpha, height, width, + coded_width, + hdr_flags & FWHT_FL_ALPHA_IS_UNCOMPRESSED, + end_of_rlco_buf)) + return false; + return true; } diff --git a/drivers/media/platform/vicodec/codec-fwht.h b/drivers/media/platform/vicodec/codec-fwht.h index 90ff8962fca7..c410512d47c5 100644 --- a/drivers/media/platform/vicodec/codec-fwht.h +++ b/drivers/media/platform/vicodec/codec-fwht.h @@ -56,7 +56,7 @@ #define FWHT_MAGIC1 0x4f4f4f4f #define FWHT_MAGIC2 0xffffffff -#define FWHT_VERSION 2 +#define FWHT_VERSION 3 /* Set if this is an interlaced format */ #define FWHT_FL_IS_INTERLACED BIT(0) @@ -76,11 +76,25 @@ #define FWHT_FL_CHROMA_FULL_HEIGHT BIT(7) #define FWHT_FL_CHROMA_FULL_WIDTH BIT(8) #define FWHT_FL_ALPHA_IS_UNCOMPRESSED BIT(9) +#define FWHT_FL_I_FRAME BIT(10) /* A 4-values flag - the number of components - 1 */ -#define FWHT_FL_COMPONENTS_NUM_MSK GENMASK(17, 16) +#define FWHT_FL_COMPONENTS_NUM_MSK GENMASK(18, 16) #define FWHT_FL_COMPONENTS_NUM_OFFSET 16 +#define FWHT_FL_PIXENC_MSK GENMASK(20, 19) +#define FWHT_FL_PIXENC_OFFSET 19 +#define FWHT_FL_PIXENC_YUV (1 << FWHT_FL_PIXENC_OFFSET) +#define FWHT_FL_PIXENC_RGB (2 << FWHT_FL_PIXENC_OFFSET) +#define FWHT_FL_PIXENC_HSV (3 << FWHT_FL_PIXENC_OFFSET) + +/* + * A macro to calculate the needed padding in order to make sure + * both luma and chroma components resolutions are rounded up to + * a multiple of 8 + */ +#define vic_round_dim(dim, div) (round_up((dim) / (div), 8) * (div)) + struct fwht_cframe_hdr { u32 magic1; u32 magic2; @@ -95,7 +109,6 @@ struct fwht_cframe_hdr { }; struct fwht_cframe { - unsigned int width, height; u16 i_frame_qp; u16 p_frame_qp; __be16 *rlc_data; @@ -106,7 +119,6 @@ struct fwht_cframe { }; struct fwht_raw_frame { - unsigned int width, height; unsigned int width_div; unsigned int height_div; unsigned int luma_alpha_step; @@ -125,8 +137,12 @@ struct fwht_raw_frame { u32 fwht_encode_frame(struct fwht_raw_frame *frm, struct fwht_raw_frame *ref_frm, struct fwht_cframe *cf, - bool is_intra, bool next_is_intra); -void fwht_decode_frame(struct fwht_cframe *cf, struct fwht_raw_frame *ref, - u32 hdr_flags, unsigned int components_num); + bool is_intra, bool next_is_intra, + unsigned int width, unsigned int height, + unsigned int stride, unsigned int chroma_stride); +bool fwht_decode_frame(struct fwht_cframe *cf, struct fwht_raw_frame *ref, + u32 hdr_flags, unsigned int components_num, + unsigned int width, unsigned int height, + unsigned int coded_width); #endif diff --git a/drivers/media/platform/vicodec/codec-v4l2-fwht.c b/drivers/media/platform/vicodec/codec-v4l2-fwht.c index 8cb0212df67f..6573a471c5ca 100644 --- a/drivers/media/platform/vicodec/codec-v4l2-fwht.c +++ b/drivers/media/platform/vicodec/codec-v4l2-fwht.c @@ -11,32 +11,53 @@ #include "codec-v4l2-fwht.h" static const struct v4l2_fwht_pixfmt_info v4l2_fwht_pixfmts[] = { - { V4L2_PIX_FMT_YUV420, 1, 3, 2, 1, 1, 2, 2, 3}, - { V4L2_PIX_FMT_YVU420, 1, 3, 2, 1, 1, 2, 2, 3}, - { V4L2_PIX_FMT_YUV422P, 1, 2, 1, 1, 1, 2, 1, 3}, - { V4L2_PIX_FMT_NV12, 1, 3, 2, 1, 2, 2, 2, 3}, - { V4L2_PIX_FMT_NV21, 1, 3, 2, 1, 2, 2, 2, 3}, - { V4L2_PIX_FMT_NV16, 1, 2, 1, 1, 2, 2, 1, 3}, - { V4L2_PIX_FMT_NV61, 1, 2, 1, 1, 2, 2, 1, 3}, - { V4L2_PIX_FMT_NV24, 1, 3, 1, 1, 2, 1, 1, 3}, - { V4L2_PIX_FMT_NV42, 1, 3, 1, 1, 2, 1, 1, 3}, - { V4L2_PIX_FMT_YUYV, 2, 2, 1, 2, 4, 2, 1, 3}, - { V4L2_PIX_FMT_YVYU, 2, 2, 1, 2, 4, 2, 1, 3}, - { V4L2_PIX_FMT_UYVY, 2, 2, 1, 2, 4, 2, 1, 3}, - { V4L2_PIX_FMT_VYUY, 2, 2, 1, 2, 4, 2, 1, 3}, - { V4L2_PIX_FMT_BGR24, 3, 3, 1, 3, 3, 1, 1, 3}, - { V4L2_PIX_FMT_RGB24, 3, 3, 1, 3, 3, 1, 1, 3}, - { V4L2_PIX_FMT_HSV24, 3, 3, 1, 3, 3, 1, 1, 3}, - { V4L2_PIX_FMT_BGR32, 4, 4, 1, 4, 4, 1, 1, 3}, - { V4L2_PIX_FMT_XBGR32, 4, 4, 1, 4, 4, 1, 1, 3}, - { V4L2_PIX_FMT_RGB32, 4, 4, 1, 4, 4, 1, 1, 3}, - { V4L2_PIX_FMT_XRGB32, 4, 4, 1, 4, 4, 1, 1, 3}, - { V4L2_PIX_FMT_HSV32, 4, 4, 1, 4, 4, 1, 1, 3}, - { V4L2_PIX_FMT_ARGB32, 4, 4, 1, 4, 4, 1, 1, 4}, - { V4L2_PIX_FMT_ABGR32, 4, 4, 1, 4, 4, 1, 1, 4}, - { V4L2_PIX_FMT_GREY, 1, 1, 1, 1, 0, 1, 1, 1}, + { V4L2_PIX_FMT_YUV420, 1, 3, 2, 1, 1, 2, 2, 3, 3, FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_YVU420, 1, 3, 2, 1, 1, 2, 2, 3, 3, FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_YUV422P, 1, 2, 1, 1, 1, 2, 1, 3, 3, FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_NV12, 1, 3, 2, 1, 2, 2, 2, 3, 2, FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_NV21, 1, 3, 2, 1, 2, 2, 2, 3, 2, FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_NV16, 1, 2, 1, 1, 2, 2, 1, 3, 2, FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_NV61, 1, 2, 1, 1, 2, 2, 1, 3, 2, FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_NV24, 1, 3, 1, 1, 2, 1, 1, 3, 2, FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_NV42, 1, 3, 1, 1, 2, 1, 1, 3, 2, FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_YUYV, 2, 2, 1, 2, 4, 2, 1, 3, 1, FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_YVYU, 2, 2, 1, 2, 4, 2, 1, 3, 1, FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_UYVY, 2, 2, 1, 2, 4, 2, 1, 3, 1, FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_VYUY, 2, 2, 1, 2, 4, 2, 1, 3, 1, FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_BGR24, 3, 3, 1, 3, 3, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_RGB24, 3, 3, 1, 3, 3, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_HSV24, 3, 3, 1, 3, 3, 1, 1, 3, 1, FWHT_FL_PIXENC_HSV}, + { V4L2_PIX_FMT_BGR32, 4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_XBGR32, 4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_RGB32, 4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_XRGB32, 4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_HSV32, 4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_HSV}, + { V4L2_PIX_FMT_ARGB32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_ABGR32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_GREY, 1, 1, 1, 1, 0, 1, 1, 1, 1, FWHT_FL_PIXENC_RGB}, }; +const struct v4l2_fwht_pixfmt_info *v4l2_fwht_default_fmt(u32 width_div, + u32 height_div, + u32 components_num, + u32 pixenc, + unsigned int start_idx) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(v4l2_fwht_pixfmts); i++) { + if (v4l2_fwht_pixfmts[i].width_div == width_div && + v4l2_fwht_pixfmts[i].height_div == height_div && + (!pixenc || v4l2_fwht_pixfmts[i].pixenc == pixenc) && + v4l2_fwht_pixfmts[i].components_num == components_num) { + if (start_idx == 0) + return v4l2_fwht_pixfmts + i; + start_idx--; + } + } + return NULL; +} + const struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_pixfmt(u32 pixelformat) { unsigned int i; @@ -56,7 +77,8 @@ const struct v4l2_fwht_pixfmt_info *v4l2_fwht_get_pixfmt(u32 idx) int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) { - unsigned int size = state->width * state->height; + unsigned int size = state->stride * state->coded_height; + unsigned int chroma_stride = state->stride; const struct v4l2_fwht_pixfmt_info *info = state->info; struct fwht_cframe_hdr *p_hdr; struct fwht_cframe cf; @@ -66,8 +88,7 @@ int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) if (!info) return -EINVAL; - rf.width = state->width; - rf.height = state->height; + rf.luma = p_in; rf.width_div = info->width_div; rf.height_div = info->height_div; @@ -84,14 +105,17 @@ int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) case V4L2_PIX_FMT_YUV420: rf.cb = rf.luma + size; rf.cr = rf.cb + size / 4; + chroma_stride /= 2; break; case V4L2_PIX_FMT_YVU420: rf.cr = rf.luma + size; rf.cb = rf.cr + size / 4; + chroma_stride /= 2; break; case V4L2_PIX_FMT_YUV422P: rf.cb = rf.luma + size; rf.cr = rf.cb + size / 2; + chroma_stride /= 2; break; case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV16: @@ -163,15 +187,16 @@ int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) return -EINVAL; } - cf.width = state->width; - cf.height = state->height; cf.i_frame_qp = state->i_frame_qp; cf.p_frame_qp = state->p_frame_qp; cf.rlc_data = (__be16 *)(p_out + sizeof(*p_hdr)); encoding = fwht_encode_frame(&rf, &state->ref_frame, &cf, !state->gop_cnt, - state->gop_cnt == state->gop_size - 1); + state->gop_cnt == state->gop_size - 1, + state->visible_width, + state->visible_height, + state->stride, chroma_stride); if (!(encoding & FWHT_FRAME_PCODED)) state->gop_cnt = 0; if (++state->gop_cnt >= state->gop_size) @@ -181,9 +206,10 @@ int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) p_hdr->magic1 = FWHT_MAGIC1; p_hdr->magic2 = FWHT_MAGIC2; p_hdr->version = htonl(FWHT_VERSION); - p_hdr->width = htonl(cf.width); - p_hdr->height = htonl(cf.height); + p_hdr->width = htonl(state->visible_width); + p_hdr->height = htonl(state->visible_height); flags |= (info->components_num - 1) << FWHT_FL_COMPONENTS_NUM_OFFSET; + flags |= info->pixenc; if (encoding & FWHT_LUMA_UNENCODED) flags |= FWHT_FL_LUMA_IS_UNCOMPRESSED; if (encoding & FWHT_CB_UNENCODED) @@ -192,6 +218,8 @@ int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) flags |= FWHT_FL_CR_IS_UNCOMPRESSED; if (encoding & FWHT_ALPHA_UNENCODED) flags |= FWHT_FL_ALPHA_IS_UNCOMPRESSED; + if (!(encoding & FWHT_FRAME_PCODED)) + flags |= FWHT_FL_I_FRAME; if (rf.height_div == 1) flags |= FWHT_FL_CHROMA_FULL_HEIGHT; if (rf.width_div == 1) @@ -202,65 +230,70 @@ int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) p_hdr->ycbcr_enc = htonl(state->ycbcr_enc); p_hdr->quantization = htonl(state->quantization); p_hdr->size = htonl(cf.size); - state->ref_frame.width = cf.width; - state->ref_frame.height = cf.height; return cf.size + sizeof(*p_hdr); } int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) { - unsigned int size = state->width * state->height; - unsigned int chroma_size = size; - unsigned int i; + unsigned int i, j, k; u32 flags; - struct fwht_cframe_hdr *p_hdr; struct fwht_cframe cf; - u8 *p; + u8 *p, *ref_p; unsigned int components_num = 3; unsigned int version; + const struct v4l2_fwht_pixfmt_info *info; + unsigned int hdr_width_div, hdr_height_div; if (!state->info) return -EINVAL; - p_hdr = (struct fwht_cframe_hdr *)p_in; - cf.width = ntohl(p_hdr->width); - cf.height = ntohl(p_hdr->height); + info = state->info; - version = ntohl(p_hdr->version); + version = ntohl(state->header.version); if (!version || version > FWHT_VERSION) { pr_err("version %d is not supported, current version is %d\n", version, FWHT_VERSION); return -EINVAL; } - if (p_hdr->magic1 != FWHT_MAGIC1 || - p_hdr->magic2 != FWHT_MAGIC2 || - (cf.width & 7) || (cf.height & 7)) + if (state->header.magic1 != FWHT_MAGIC1 || + state->header.magic2 != FWHT_MAGIC2) return -EINVAL; /* TODO: support resolution changes */ - if (cf.width != state->width || cf.height != state->height) + if (ntohl(state->header.width) != state->visible_width || + ntohl(state->header.height) != state->visible_height) return -EINVAL; - flags = ntohl(p_hdr->flags); + flags = ntohl(state->header.flags); - if (version == FWHT_VERSION) { + if (version >= 2) { + if ((flags & FWHT_FL_PIXENC_MSK) != info->pixenc) + return -EINVAL; components_num = 1 + ((flags & FWHT_FL_COMPONENTS_NUM_MSK) >> - FWHT_FL_COMPONENTS_NUM_OFFSET); + FWHT_FL_COMPONENTS_NUM_OFFSET); } - state->colorspace = ntohl(p_hdr->colorspace); - state->xfer_func = ntohl(p_hdr->xfer_func); - state->ycbcr_enc = ntohl(p_hdr->ycbcr_enc); - state->quantization = ntohl(p_hdr->quantization); - cf.rlc_data = (__be16 *)(p_in + sizeof(*p_hdr)); + if (components_num != info->components_num) + return -EINVAL; - if (!(flags & FWHT_FL_CHROMA_FULL_WIDTH)) - chroma_size /= 2; - if (!(flags & FWHT_FL_CHROMA_FULL_HEIGHT)) - chroma_size /= 2; + state->colorspace = ntohl(state->header.colorspace); + state->xfer_func = ntohl(state->header.xfer_func); + state->ycbcr_enc = ntohl(state->header.ycbcr_enc); + state->quantization = ntohl(state->header.quantization); + cf.rlc_data = (__be16 *)p_in; + cf.size = ntohl(state->header.size); - fwht_decode_frame(&cf, &state->ref_frame, flags, components_num); + hdr_width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; + hdr_height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; + if (hdr_width_div != info->width_div || + hdr_height_div != info->height_div) + return -EINVAL; + + if (!fwht_decode_frame(&cf, &state->ref_frame, flags, components_num, + state->visible_width, state->visible_height, + state->coded_width)) + return -EINVAL; /* * TODO - handle the case where the compressed stream encodes a @@ -268,123 +301,226 @@ int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) */ switch (state->info->id) { case V4L2_PIX_FMT_GREY: - memcpy(p_out, state->ref_frame.luma, size); + ref_p = state->ref_frame.luma; + for (i = 0; i < state->coded_height; i++) { + memcpy(p_out, ref_p, state->visible_width); + p_out += state->stride; + ref_p += state->coded_width; + } break; case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YUV422P: - memcpy(p_out, state->ref_frame.luma, size); - p_out += size; - memcpy(p_out, state->ref_frame.cb, chroma_size); - p_out += chroma_size; - memcpy(p_out, state->ref_frame.cr, chroma_size); + ref_p = state->ref_frame.luma; + for (i = 0; i < state->coded_height; i++) { + memcpy(p_out, ref_p, state->visible_width); + p_out += state->stride; + ref_p += state->coded_width; + } + + ref_p = state->ref_frame.cb; + for (i = 0; i < state->coded_height / 2; i++) { + memcpy(p_out, ref_p, state->visible_width / 2); + p_out += state->stride / 2; + ref_p += state->coded_width / 2; + } + ref_p = state->ref_frame.cr; + for (i = 0; i < state->coded_height / 2; i++) { + memcpy(p_out, ref_p, state->visible_width / 2); + p_out += state->stride / 2; + ref_p += state->coded_width / 2; + } break; case V4L2_PIX_FMT_YVU420: - memcpy(p_out, state->ref_frame.luma, size); - p_out += size; - memcpy(p_out, state->ref_frame.cr, chroma_size); - p_out += chroma_size; - memcpy(p_out, state->ref_frame.cb, chroma_size); + ref_p = state->ref_frame.luma; + for (i = 0; i < state->coded_height; i++) { + memcpy(p_out, ref_p, state->visible_width); + p_out += state->stride; + ref_p += state->coded_width; + } + + ref_p = state->ref_frame.cr; + for (i = 0; i < state->coded_height / 2; i++) { + memcpy(p_out, ref_p, state->visible_width / 2); + p_out += state->stride / 2; + ref_p += state->coded_width / 2; + } + ref_p = state->ref_frame.cb; + for (i = 0; i < state->coded_height / 2; i++) { + memcpy(p_out, ref_p, state->visible_width / 2); + p_out += state->stride / 2; + ref_p += state->coded_width / 2; + } break; case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV16: case V4L2_PIX_FMT_NV24: - memcpy(p_out, state->ref_frame.luma, size); - p_out += size; - for (i = 0, p = p_out; i < chroma_size; i++) { - *p++ = state->ref_frame.cb[i]; - *p++ = state->ref_frame.cr[i]; + ref_p = state->ref_frame.luma; + for (i = 0; i < state->coded_height; i++) { + memcpy(p_out, ref_p, state->visible_width); + p_out += state->stride; + ref_p += state->coded_width; + } + + k = 0; + for (i = 0; i < state->coded_height / 2; i++) { + for (j = 0, p = p_out; j < state->coded_width / 2; j++) { + *p++ = state->ref_frame.cb[k]; + *p++ = state->ref_frame.cr[k]; + k++; + } + p_out += state->stride; } break; case V4L2_PIX_FMT_NV21: case V4L2_PIX_FMT_NV61: case V4L2_PIX_FMT_NV42: - memcpy(p_out, state->ref_frame.luma, size); - p_out += size; - for (i = 0, p = p_out; i < chroma_size; i++) { - *p++ = state->ref_frame.cr[i]; - *p++ = state->ref_frame.cb[i]; + ref_p = state->ref_frame.luma; + for (i = 0; i < state->coded_height; i++) { + memcpy(p_out, ref_p, state->visible_width); + p_out += state->stride; + ref_p += state->coded_width; + } + + k = 0; + for (i = 0; i < state->coded_height / 2; i++) { + for (j = 0, p = p_out; j < state->coded_width / 2; j++) { + *p++ = state->ref_frame.cr[k]; + *p++ = state->ref_frame.cb[k]; + k++; + } + p_out += state->stride; } break; case V4L2_PIX_FMT_YUYV: - for (i = 0, p = p_out; i < size; i += 2) { - *p++ = state->ref_frame.luma[i]; - *p++ = state->ref_frame.cb[i / 2]; - *p++ = state->ref_frame.luma[i + 1]; - *p++ = state->ref_frame.cr[i / 2]; + k = 0; + for (i = 0; i < state->coded_height; i++) { + for (j = 0, p = p_out; j < state->coded_width / 2; j++) { + *p++ = state->ref_frame.luma[k]; + *p++ = state->ref_frame.cb[k / 2]; + *p++ = state->ref_frame.luma[k + 1]; + *p++ = state->ref_frame.cr[k / 2]; + k += 2; + } + p_out += state->stride; } break; case V4L2_PIX_FMT_YVYU: - for (i = 0, p = p_out; i < size; i += 2) { - *p++ = state->ref_frame.luma[i]; - *p++ = state->ref_frame.cr[i / 2]; - *p++ = state->ref_frame.luma[i + 1]; - *p++ = state->ref_frame.cb[i / 2]; + k = 0; + for (i = 0; i < state->coded_height; i++) { + for (j = 0, p = p_out; j < state->coded_width / 2; j++) { + *p++ = state->ref_frame.luma[k]; + *p++ = state->ref_frame.cr[k / 2]; + *p++ = state->ref_frame.luma[k + 1]; + *p++ = state->ref_frame.cb[k / 2]; + k += 2; + } + p_out += state->stride; } break; case V4L2_PIX_FMT_UYVY: - for (i = 0, p = p_out; i < size; i += 2) { - *p++ = state->ref_frame.cb[i / 2]; - *p++ = state->ref_frame.luma[i]; - *p++ = state->ref_frame.cr[i / 2]; - *p++ = state->ref_frame.luma[i + 1]; + k = 0; + for (i = 0; i < state->coded_height; i++) { + for (j = 0, p = p_out; j < state->coded_width / 2; j++) { + *p++ = state->ref_frame.cb[k / 2]; + *p++ = state->ref_frame.luma[k]; + *p++ = state->ref_frame.cr[k / 2]; + *p++ = state->ref_frame.luma[k + 1]; + k += 2; + } + p_out += state->stride; } break; case V4L2_PIX_FMT_VYUY: - for (i = 0, p = p_out; i < size; i += 2) { - *p++ = state->ref_frame.cr[i / 2]; - *p++ = state->ref_frame.luma[i]; - *p++ = state->ref_frame.cb[i / 2]; - *p++ = state->ref_frame.luma[i + 1]; + k = 0; + for (i = 0; i < state->coded_height; i++) { + for (j = 0, p = p_out; j < state->coded_width / 2; j++) { + *p++ = state->ref_frame.cr[k / 2]; + *p++ = state->ref_frame.luma[k]; + *p++ = state->ref_frame.cb[k / 2]; + *p++ = state->ref_frame.luma[k + 1]; + k += 2; + } + p_out += state->stride; } break; case V4L2_PIX_FMT_RGB24: case V4L2_PIX_FMT_HSV24: - for (i = 0, p = p_out; i < size; i++) { - *p++ = state->ref_frame.cr[i]; - *p++ = state->ref_frame.luma[i]; - *p++ = state->ref_frame.cb[i]; + k = 0; + for (i = 0; i < state->coded_height; i++) { + for (j = 0, p = p_out; j < state->coded_width; j++) { + *p++ = state->ref_frame.cr[k]; + *p++ = state->ref_frame.luma[k]; + *p++ = state->ref_frame.cb[k]; + k++; + } + p_out += state->stride; } break; case V4L2_PIX_FMT_BGR24: - for (i = 0, p = p_out; i < size; i++) { - *p++ = state->ref_frame.cb[i]; - *p++ = state->ref_frame.luma[i]; - *p++ = state->ref_frame.cr[i]; + k = 0; + for (i = 0; i < state->coded_height; i++) { + for (j = 0, p = p_out; j < state->coded_width; j++) { + *p++ = state->ref_frame.cb[k]; + *p++ = state->ref_frame.luma[k]; + *p++ = state->ref_frame.cr[k]; + k++; + } + p_out += state->stride; } break; case V4L2_PIX_FMT_RGB32: case V4L2_PIX_FMT_XRGB32: case V4L2_PIX_FMT_HSV32: - for (i = 0, p = p_out; i < size; i++) { - *p++ = 0; - *p++ = state->ref_frame.cr[i]; - *p++ = state->ref_frame.luma[i]; - *p++ = state->ref_frame.cb[i]; + k = 0; + for (i = 0; i < state->coded_height; i++) { + for (j = 0, p = p_out; j < state->coded_width; j++) { + *p++ = 0; + *p++ = state->ref_frame.cr[k]; + *p++ = state->ref_frame.luma[k]; + *p++ = state->ref_frame.cb[k]; + k++; + } + p_out += state->stride; } break; case V4L2_PIX_FMT_BGR32: case V4L2_PIX_FMT_XBGR32: - for (i = 0, p = p_out; i < size; i++) { - *p++ = state->ref_frame.cb[i]; - *p++ = state->ref_frame.luma[i]; - *p++ = state->ref_frame.cr[i]; - *p++ = 0; + k = 0; + for (i = 0; i < state->coded_height; i++) { + for (j = 0, p = p_out; j < state->coded_width; j++) { + *p++ = state->ref_frame.cb[k]; + *p++ = state->ref_frame.luma[k]; + *p++ = state->ref_frame.cr[k]; + *p++ = 0; + k++; + } + p_out += state->stride; } break; case V4L2_PIX_FMT_ARGB32: - for (i = 0, p = p_out; i < size; i++) { - *p++ = state->ref_frame.alpha[i]; - *p++ = state->ref_frame.cr[i]; - *p++ = state->ref_frame.luma[i]; - *p++ = state->ref_frame.cb[i]; + k = 0; + for (i = 0; i < state->coded_height; i++) { + for (j = 0, p = p_out; j < state->coded_width; j++) { + *p++ = state->ref_frame.alpha[k]; + *p++ = state->ref_frame.cr[k]; + *p++ = state->ref_frame.luma[k]; + *p++ = state->ref_frame.cb[k]; + k++; + } + p_out += state->stride; } break; case V4L2_PIX_FMT_ABGR32: - for (i = 0, p = p_out; i < size; i++) { - *p++ = state->ref_frame.cb[i]; - *p++ = state->ref_frame.luma[i]; - *p++ = state->ref_frame.cr[i]; - *p++ = state->ref_frame.alpha[i]; + k = 0; + for (i = 0; i < state->coded_height; i++) { + for (j = 0, p = p_out; j < state->coded_width; j++) { + *p++ = state->ref_frame.cb[k]; + *p++ = state->ref_frame.luma[k]; + *p++ = state->ref_frame.cr[k]; + *p++ = state->ref_frame.alpha[k]; + k++; + } + p_out += state->stride; } break; default: diff --git a/drivers/media/platform/vicodec/codec-v4l2-fwht.h b/drivers/media/platform/vicodec/codec-v4l2-fwht.h index ed53e28d4f9c..aa6fa90a48be 100644 --- a/drivers/media/platform/vicodec/codec-v4l2-fwht.h +++ b/drivers/media/platform/vicodec/codec-v4l2-fwht.h @@ -19,12 +19,17 @@ struct v4l2_fwht_pixfmt_info { unsigned int width_div; unsigned int height_div; unsigned int components_num; + unsigned int planes_num; + unsigned int pixenc; }; struct v4l2_fwht_state { const struct v4l2_fwht_pixfmt_info *info; - unsigned int width; - unsigned int height; + unsigned int visible_width; + unsigned int visible_height; + unsigned int coded_width; + unsigned int coded_height; + unsigned int stride; unsigned int gop_size; unsigned int gop_cnt; u16 i_frame_qp; @@ -36,11 +41,17 @@ struct v4l2_fwht_state { enum v4l2_quantization quantization; struct fwht_raw_frame ref_frame; + struct fwht_cframe_hdr header; u8 *compressed_frame; }; const struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_pixfmt(u32 pixelformat); const struct v4l2_fwht_pixfmt_info *v4l2_fwht_get_pixfmt(u32 idx); +const struct v4l2_fwht_pixfmt_info *v4l2_fwht_default_fmt(u32 width_div, + u32 height_div, + u32 components_num, + u32 pixenc, + unsigned int start_idx); int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out); int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out); diff --git a/drivers/media/platform/vicodec/vicodec-core.c b/drivers/media/platform/vicodec/vicodec-core.c index 0d7876f5acf0..d7636fe9e174 100644 --- a/drivers/media/platform/vicodec/vicodec-core.c +++ b/drivers/media/platform/vicodec/vicodec-core.c @@ -61,7 +61,7 @@ struct pixfmt_info { }; static const struct v4l2_fwht_pixfmt_info pixfmt_fwht = { - V4L2_PIX_FMT_FWHT, 0, 3, 1, 1, 1, 1, 1, 0 + V4L2_PIX_FMT_FWHT, 0, 3, 1, 1, 1, 1, 1, 0, 1 }; static void vicodec_dev_release(struct device *dev) @@ -75,8 +75,10 @@ static struct platform_device vicodec_pdev = { /* Per-queue, driver-specific private data */ struct vicodec_q_data { - unsigned int width; - unsigned int height; + unsigned int coded_width; + unsigned int coded_height; + unsigned int visible_width; + unsigned int visible_height; unsigned int sizeimage; unsigned int sequence; const struct v4l2_fwht_pixfmt_info *info; @@ -122,10 +124,12 @@ struct vicodec_ctx { u32 cur_buf_offset; u32 comp_max_size; u32 comp_size; + u32 header_size; u32 comp_magic_cnt; - u32 comp_frame_size; bool comp_has_frame; bool comp_has_next_frame; + bool first_source_change_sent; + bool source_changed; }; static inline struct vicodec_ctx *file2ctx(struct file *file) @@ -182,6 +186,10 @@ static int device_process(struct vicodec_ctx *ctx, return ret; vb2_set_plane_payload(&dst_vb->vb2_buf, 0, ret); } else { + unsigned int comp_frame_size = ntohl(ctx->state.header.size); + + if (comp_frame_size > ctx->comp_max_size) + return -EINVAL; state->info = q_dst->info; ret = v4l2_fwht_decode(state, p_src, p_dst); if (ret < 0) @@ -190,18 +198,8 @@ static int device_process(struct vicodec_ctx *ctx, } dst_vb->sequence = q_dst->sequence++; - dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp; - - if (src_vb->flags & V4L2_BUF_FLAG_TIMECODE) - dst_vb->timecode = src_vb->timecode; - dst_vb->field = src_vb->field; dst_vb->flags &= ~V4L2_BUF_FLAG_LAST; - dst_vb->flags |= src_vb->flags & - (V4L2_BUF_FLAG_TIMECODE | - V4L2_BUF_FLAG_KEYFRAME | - V4L2_BUF_FLAG_PFRAME | - V4L2_BUF_FLAG_BFRAME | - V4L2_BUF_FLAG_TSTAMP_SRC_MASK); + v4l2_m2m_buf_copy_metadata(src_vb, dst_vb, !ctx->is_enc); return 0; } @@ -209,6 +207,63 @@ static int device_process(struct vicodec_ctx *ctx, /* * mem2mem callbacks */ +static enum vb2_buffer_state get_next_header(struct vicodec_ctx *ctx, + u8 **pp, u32 sz) +{ + static const u8 magic[] = { + 0x4f, 0x4f, 0x4f, 0x4f, 0xff, 0xff, 0xff, 0xff + }; + u8 *p = *pp; + u32 state; + u8 *header = (u8 *)&ctx->state.header; + + state = VB2_BUF_STATE_DONE; + + if (!ctx->header_size) { + state = VB2_BUF_STATE_ERROR; + for (; p < *pp + sz; p++) { + u32 copy; + + p = memchr(p, magic[ctx->comp_magic_cnt], + *pp + sz - p); + if (!p) { + ctx->comp_magic_cnt = 0; + p = *pp + sz; + break; + } + copy = sizeof(magic) - ctx->comp_magic_cnt; + if (*pp + sz - p < copy) + copy = *pp + sz - p; + + memcpy(header + ctx->comp_magic_cnt, p, copy); + ctx->comp_magic_cnt += copy; + if (!memcmp(header, magic, ctx->comp_magic_cnt)) { + p += copy; + state = VB2_BUF_STATE_DONE; + break; + } + ctx->comp_magic_cnt = 0; + } + if (ctx->comp_magic_cnt < sizeof(magic)) { + *pp = p; + return state; + } + ctx->header_size = sizeof(magic); + } + + if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) { + u32 copy = sizeof(struct fwht_cframe_hdr) - ctx->header_size; + + if (*pp + sz - p < copy) + copy = *pp + sz - p; + + memcpy(header + ctx->header_size, p, copy); + p += copy; + ctx->header_size += copy; + } + *pp = p; + return state; +} /* device_run() - prepares and starts the device */ static void device_run(void *priv) @@ -249,6 +304,7 @@ static void device_run(void *priv) } v4l2_m2m_buf_done(dst_buf, state); ctx->comp_size = 0; + ctx->header_size = 0; ctx->comp_magic_cnt = 0; ctx->comp_has_frame = false; spin_unlock(ctx->lock); @@ -273,6 +329,96 @@ static void job_remove_src_buf(struct vicodec_ctx *ctx, u32 state) spin_unlock(ctx->lock); } +static const struct v4l2_fwht_pixfmt_info * +info_from_header(const struct fwht_cframe_hdr *p_hdr) +{ + unsigned int flags = ntohl(p_hdr->flags); + unsigned int width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; + unsigned int height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; + unsigned int components_num = 3; + unsigned int pixenc = 0; + unsigned int version = ntohl(p_hdr->version); + + if (version >= 2) { + components_num = 1 + ((flags & FWHT_FL_COMPONENTS_NUM_MSK) >> + FWHT_FL_COMPONENTS_NUM_OFFSET); + pixenc = (flags & FWHT_FL_PIXENC_MSK); + } + return v4l2_fwht_default_fmt(width_div, height_div, + components_num, pixenc, 0); +} + +static bool is_header_valid(const struct fwht_cframe_hdr *p_hdr) +{ + const struct v4l2_fwht_pixfmt_info *info; + unsigned int w = ntohl(p_hdr->width); + unsigned int h = ntohl(p_hdr->height); + unsigned int version = ntohl(p_hdr->version); + unsigned int flags = ntohl(p_hdr->flags); + + if (!version || version > FWHT_VERSION) + return false; + + if (w < MIN_WIDTH || w > MAX_WIDTH || h < MIN_HEIGHT || h > MAX_HEIGHT) + return false; + + if (version >= 2) { + unsigned int components_num = 1 + + ((flags & FWHT_FL_COMPONENTS_NUM_MSK) >> + FWHT_FL_COMPONENTS_NUM_OFFSET); + unsigned int pixenc = flags & FWHT_FL_PIXENC_MSK; + + if (components_num == 0 || components_num > 4 || !pixenc) + return false; + } + + info = info_from_header(p_hdr); + if (!info) + return false; + return true; +} + +static void update_capture_data_from_header(struct vicodec_ctx *ctx) +{ + struct vicodec_q_data *q_dst = get_q_data(ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + const struct fwht_cframe_hdr *p_hdr = &ctx->state.header; + const struct v4l2_fwht_pixfmt_info *info = info_from_header(p_hdr); + unsigned int flags = ntohl(p_hdr->flags); + unsigned int hdr_width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; + unsigned int hdr_height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; + + q_dst->info = info; + q_dst->visible_width = ntohl(p_hdr->width); + q_dst->visible_height = ntohl(p_hdr->height); + q_dst->coded_width = vic_round_dim(q_dst->visible_width, hdr_width_div); + q_dst->coded_height = vic_round_dim(q_dst->visible_height, + hdr_height_div); + + q_dst->sizeimage = q_dst->coded_width * q_dst->coded_height * + q_dst->info->sizeimage_mult / q_dst->info->sizeimage_div; + ctx->state.colorspace = ntohl(p_hdr->colorspace); + + ctx->state.xfer_func = ntohl(p_hdr->xfer_func); + ctx->state.ycbcr_enc = ntohl(p_hdr->ycbcr_enc); + ctx->state.quantization = ntohl(p_hdr->quantization); +} + +static void set_last_buffer(struct vb2_v4l2_buffer *dst_buf, + const struct vb2_v4l2_buffer *src_buf, + struct vicodec_ctx *ctx) +{ + struct vicodec_q_data *q_dst = get_q_data(ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0); + dst_buf->sequence = q_dst->sequence++; + + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, !ctx->is_enc); + dst_buf->flags |= V4L2_BUF_FLAG_LAST; + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); +} + static int job_ready(void *priv) { static const u8 magic[] = { @@ -284,7 +430,16 @@ static int job_ready(void *priv) u8 *p; u32 sz; u32 state; - + struct vicodec_q_data *q_dst = get_q_data(ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + unsigned int flags; + unsigned int hdr_width_div; + unsigned int hdr_height_div; + unsigned int max_to_copy; + unsigned int comp_frame_size; + + if (ctx->source_changed) + return 0; if (ctx->is_enc || ctx->comp_has_frame) return 1; @@ -299,59 +454,27 @@ restart: state = VB2_BUF_STATE_DONE; - if (!ctx->comp_size) { - state = VB2_BUF_STATE_ERROR; - for (; p < p_src + sz; p++) { - u32 copy; - - p = memchr(p, magic[ctx->comp_magic_cnt], - p_src + sz - p); - if (!p) { - ctx->comp_magic_cnt = 0; - break; - } - copy = sizeof(magic) - ctx->comp_magic_cnt; - if (p_src + sz - p < copy) - copy = p_src + sz - p; - - memcpy(ctx->state.compressed_frame + ctx->comp_magic_cnt, - p, copy); - ctx->comp_magic_cnt += copy; - if (!memcmp(ctx->state.compressed_frame, magic, - ctx->comp_magic_cnt)) { - p += copy; - state = VB2_BUF_STATE_DONE; - break; - } - ctx->comp_magic_cnt = 0; - } - if (ctx->comp_magic_cnt < sizeof(magic)) { + if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) { + state = get_next_header(ctx, &p, p_src + sz - p); + if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) { job_remove_src_buf(ctx, state); goto restart; } - ctx->comp_size = sizeof(magic); } - if (ctx->comp_size < sizeof(struct fwht_cframe_hdr)) { - struct fwht_cframe_hdr *p_hdr = - (struct fwht_cframe_hdr *)ctx->state.compressed_frame; - u32 copy = sizeof(struct fwht_cframe_hdr) - ctx->comp_size; - if (copy > p_src + sz - p) - copy = p_src + sz - p; - memcpy(ctx->state.compressed_frame + ctx->comp_size, - p, copy); - p += copy; - ctx->comp_size += copy; - if (ctx->comp_size < sizeof(struct fwht_cframe_hdr)) { - job_remove_src_buf(ctx, state); - goto restart; - } - ctx->comp_frame_size = ntohl(p_hdr->size) + sizeof(*p_hdr); - if (ctx->comp_frame_size > ctx->comp_max_size) - ctx->comp_frame_size = ctx->comp_max_size; - } - if (ctx->comp_size < ctx->comp_frame_size) { - u32 copy = ctx->comp_frame_size - ctx->comp_size; + comp_frame_size = ntohl(ctx->state.header.size); + + /* + * The current scanned frame might be the first frame of a new + * resolution so its size might be larger than ctx->comp_max_size. + * In that case it is copied up to the current buffer capacity and + * the copy will continue after allocating new large enough buffer + * when restreaming + */ + max_to_copy = min(comp_frame_size, ctx->comp_max_size); + + if (ctx->comp_size < max_to_copy) { + u32 copy = max_to_copy - ctx->comp_size; if (copy > p_src + sz - p) copy = p_src + sz - p; @@ -360,15 +483,17 @@ restart: p, copy); p += copy; ctx->comp_size += copy; - if (ctx->comp_size < ctx->comp_frame_size) { + if (ctx->comp_size < max_to_copy) { job_remove_src_buf(ctx, state); goto restart; } } ctx->cur_buf_offset = p - p_src; - ctx->comp_has_frame = true; + if (ctx->comp_size == comp_frame_size) + ctx->comp_has_frame = true; ctx->comp_has_next_frame = false; - if (sz - ctx->cur_buf_offset >= sizeof(struct fwht_cframe_hdr)) { + if (ctx->comp_has_frame && sz - ctx->cur_buf_offset >= + sizeof(struct fwht_cframe_hdr)) { struct fwht_cframe_hdr *p_hdr = (struct fwht_cframe_hdr *)p; u32 frame_size = ntohl(p_hdr->size); u32 remaining = sz - ctx->cur_buf_offset - sizeof(*p_hdr); @@ -376,6 +501,36 @@ restart: if (!memcmp(p, magic, sizeof(magic))) ctx->comp_has_next_frame = remaining >= frame_size; } + /* + * if the header is invalid the device_run will just drop the frame + * with an error + */ + if (!is_header_valid(&ctx->state.header) && ctx->comp_has_frame) + return 1; + flags = ntohl(ctx->state.header.flags); + hdr_width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; + hdr_height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; + + if (ntohl(ctx->state.header.width) != q_dst->visible_width || + ntohl(ctx->state.header.height) != q_dst->visible_height || + !q_dst->info || + hdr_width_div != q_dst->info->width_div || + hdr_height_div != q_dst->info->height_div) { + static const struct v4l2_event rs_event = { + .type = V4L2_EVENT_SOURCE_CHANGE, + .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, + }; + + struct vb2_v4l2_buffer *dst_buf = + v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + + update_capture_data_from_header(ctx); + ctx->first_source_change_sent = true; + v4l2_event_queue_fh(&ctx->fh, &rs_event); + set_last_buffer(dst_buf, src_buf, ctx); + ctx->source_changed = true; + return 0; + } return 1; } @@ -403,9 +558,10 @@ static int vidioc_querycap(struct file *file, void *priv, return 0; } -static int enum_fmt(struct v4l2_fmtdesc *f, bool is_enc, bool is_out) +static int enum_fmt(struct v4l2_fmtdesc *f, struct vicodec_ctx *ctx, + bool is_out) { - bool is_uncomp = (is_enc && is_out) || (!is_enc && !is_out); + bool is_uncomp = (ctx->is_enc && is_out) || (!ctx->is_enc && !is_out); if (V4L2_TYPE_IS_MULTIPLANAR(f->type) && !multiplanar) return -EINVAL; @@ -414,8 +570,16 @@ static int enum_fmt(struct v4l2_fmtdesc *f, bool is_enc, bool is_out) if (is_uncomp) { const struct v4l2_fwht_pixfmt_info *info = - v4l2_fwht_get_pixfmt(f->index); + get_q_data(ctx, f->type)->info; + if (!info || ctx->is_enc) + info = v4l2_fwht_get_pixfmt(f->index); + else + info = v4l2_fwht_default_fmt(info->width_div, + info->height_div, + info->components_num, + info->pixenc, + f->index); if (!info) return -EINVAL; f->pixelformat = info->id; @@ -432,7 +596,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, { struct vicodec_ctx *ctx = file2ctx(file); - return enum_fmt(f, ctx->is_enc, false); + return enum_fmt(f, ctx, false); } static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, @@ -440,7 +604,7 @@ static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, { struct vicodec_ctx *ctx = file2ctx(file); - return enum_fmt(f, ctx->is_enc, true); + return enum_fmt(f, ctx, true); } static int vidioc_g_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) @@ -458,17 +622,21 @@ static int vidioc_g_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) q_data = get_q_data(ctx, f->type); info = q_data->info; + if (!info) + info = v4l2_fwht_get_pixfmt(0); + switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: if (multiplanar) return -EINVAL; pix = &f->fmt.pix; - pix->width = q_data->width; - pix->height = q_data->height; + pix->width = q_data->coded_width; + pix->height = q_data->coded_height; pix->field = V4L2_FIELD_NONE; pix->pixelformat = info->id; - pix->bytesperline = q_data->width * info->bytesperline_mult; + pix->bytesperline = q_data->coded_width * + info->bytesperline_mult; pix->sizeimage = q_data->sizeimage; pix->colorspace = ctx->state.colorspace; pix->xfer_func = ctx->state.xfer_func; @@ -481,13 +649,13 @@ static int vidioc_g_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) if (!multiplanar) return -EINVAL; pix_mp = &f->fmt.pix_mp; - pix_mp->width = q_data->width; - pix_mp->height = q_data->height; + pix_mp->width = q_data->coded_width; + pix_mp->height = q_data->coded_height; pix_mp->field = V4L2_FIELD_NONE; pix_mp->pixelformat = info->id; pix_mp->num_planes = 1; pix_mp->plane_fmt[0].bytesperline = - q_data->width * info->bytesperline_mult; + q_data->coded_width * info->bytesperline_mult; pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage; pix_mp->colorspace = ctx->state.colorspace; pix_mp->xfer_func = ctx->state.xfer_func; @@ -528,8 +696,13 @@ static int vidioc_try_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) pix = &f->fmt.pix; if (pix->pixelformat != V4L2_PIX_FMT_FWHT) info = find_fmt(pix->pixelformat); - pix->width = clamp(pix->width, MIN_WIDTH, MAX_WIDTH) & ~7; - pix->height = clamp(pix->height, MIN_HEIGHT, MAX_HEIGHT) & ~7; + + pix->width = clamp(pix->width, MIN_WIDTH, MAX_WIDTH); + pix->width = vic_round_dim(pix->width, info->width_div); + + pix->height = clamp(pix->height, MIN_HEIGHT, MAX_HEIGHT); + pix->height = vic_round_dim(pix->height, info->height_div); + pix->field = V4L2_FIELD_NONE; pix->bytesperline = pix->width * info->bytesperline_mult; @@ -545,9 +718,14 @@ static int vidioc_try_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) if (pix_mp->pixelformat != V4L2_PIX_FMT_FWHT) info = find_fmt(pix_mp->pixelformat); pix_mp->num_planes = 1; - pix_mp->width = clamp(pix_mp->width, MIN_WIDTH, MAX_WIDTH) & ~7; - pix_mp->height = - clamp(pix_mp->height, MIN_HEIGHT, MAX_HEIGHT) & ~7; + + pix_mp->width = clamp(pix_mp->width, MIN_WIDTH, MAX_WIDTH); + pix_mp->width = vic_round_dim(pix_mp->width, info->width_div); + + pix_mp->height = clamp(pix_mp->height, MIN_HEIGHT, MAX_HEIGHT); + pix_mp->height = vic_round_dim(pix_mp->height, + info->height_div); + pix_mp->field = V4L2_FIELD_NONE; plane->bytesperline = pix_mp->width * info->bytesperline_mult; @@ -657,9 +835,10 @@ static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) pix = &f->fmt.pix; if (ctx->is_enc && V4L2_TYPE_IS_OUTPUT(f->type)) fmt_changed = + !q_data->info || q_data->info->id != pix->pixelformat || - q_data->width != pix->width || - q_data->height != pix->height; + q_data->coded_width != pix->width || + q_data->coded_height != pix->height; if (vb2_is_busy(vq) && fmt_changed) return -EBUSY; @@ -668,8 +847,8 @@ static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) q_data->info = &pixfmt_fwht; else q_data->info = find_fmt(pix->pixelformat); - q_data->width = pix->width; - q_data->height = pix->height; + q_data->coded_width = pix->width; + q_data->coded_height = pix->height; q_data->sizeimage = pix->sizeimage; break; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: @@ -677,9 +856,10 @@ static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) pix_mp = &f->fmt.pix_mp; if (ctx->is_enc && V4L2_TYPE_IS_OUTPUT(f->type)) fmt_changed = + !q_data->info || q_data->info->id != pix_mp->pixelformat || - q_data->width != pix_mp->width || - q_data->height != pix_mp->height; + q_data->coded_width != pix_mp->width || + q_data->coded_height != pix_mp->height; if (vb2_is_busy(vq) && fmt_changed) return -EBUSY; @@ -688,17 +868,24 @@ static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) q_data->info = &pixfmt_fwht; else q_data->info = find_fmt(pix_mp->pixelformat); - q_data->width = pix_mp->width; - q_data->height = pix_mp->height; + q_data->coded_width = pix_mp->width; + q_data->coded_height = pix_mp->height; q_data->sizeimage = pix_mp->plane_fmt[0].sizeimage; break; default: return -EINVAL; } + if (q_data->visible_width > q_data->coded_width) + q_data->visible_width = q_data->coded_width; + if (q_data->visible_height > q_data->coded_height) + q_data->visible_height = q_data->coded_height; + dprintk(ctx->dev, - "Setting format for type %d, wxh: %dx%d, fourcc: %08x\n", - f->type, q_data->width, q_data->height, q_data->info->id); + "Setting format for type %d, coded wxh: %dx%d, visible wxh: %dx%d, fourcc: %08x\n", + f->type, q_data->coded_width, q_data->coded_height, + q_data->visible_width, q_data->visible_height, + q_data->info->id); return 0; } @@ -753,6 +940,84 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv, return ret; } +static int vidioc_g_selection(struct file *file, void *priv, + struct v4l2_selection *s) +{ + struct vicodec_ctx *ctx = file2ctx(file); + struct vicodec_q_data *q_data; + enum v4l2_buf_type valid_cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + enum v4l2_buf_type valid_out_type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + + if (multiplanar) { + valid_cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + valid_out_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + } + + if (s->type != valid_cap_type && s->type != valid_out_type) + return -EINVAL; + + q_data = get_q_data(ctx, s->type); + if (!q_data) + return -EINVAL; + /* + * encoder supports only cropping on the OUTPUT buffer + * decoder supports only composing on the CAPTURE buffer + */ + if ((ctx->is_enc && s->type == valid_out_type) || + (!ctx->is_enc && s->type == valid_cap_type)) { + switch (s->target) { + case V4L2_SEL_TGT_COMPOSE: + case V4L2_SEL_TGT_CROP: + s->r.left = 0; + s->r.top = 0; + s->r.width = q_data->visible_width; + s->r.height = q_data->visible_height; + return 0; + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + s->r.left = 0; + s->r.top = 0; + s->r.width = q_data->coded_width; + s->r.height = q_data->coded_height; + return 0; + } + } + return -EINVAL; +} + +static int vidioc_s_selection(struct file *file, void *priv, + struct v4l2_selection *s) +{ + struct vicodec_ctx *ctx = file2ctx(file); + struct vicodec_q_data *q_data; + enum v4l2_buf_type out_type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + + if (multiplanar) + out_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + + if (s->type != out_type) + return -EINVAL; + + q_data = get_q_data(ctx, s->type); + if (!q_data) + return -EINVAL; + + if (!ctx->is_enc || s->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + s->r.left = 0; + s->r.top = 0; + q_data->visible_width = clamp(s->r.width, MIN_WIDTH, + q_data->coded_width); + s->r.width = q_data->visible_width; + q_data->visible_height = clamp(s->r.height, MIN_HEIGHT, + q_data->coded_height); + s->r.height = q_data->visible_height; + return 0; +} + static void vicodec_mark_last_buf(struct vicodec_ctx *ctx) { static const struct v4l2_event eos_event = { @@ -853,7 +1118,13 @@ static int vicodec_enum_framesizes(struct file *file, void *fh, static int vicodec_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub) { + struct vicodec_ctx *ctx = container_of(fh, struct vicodec_ctx, fh); + switch (sub->type) { + case V4L2_EVENT_SOURCE_CHANGE: + if (ctx->is_enc) + return -EINVAL; + /* fall through */ case V4L2_EVENT_EOS: return v4l2_event_subscribe(fh, sub, 0, NULL); default: @@ -895,6 +1166,9 @@ static const struct v4l2_ioctl_ops vicodec_ioctl_ops = { .vidioc_streamon = v4l2_m2m_ioctl_streamon, .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + .vidioc_g_selection = vidioc_g_selection, + .vidioc_s_selection = vidioc_s_selection, + .vidioc_try_encoder_cmd = vicodec_try_encoder_cmd, .vidioc_encoder_cmd = vicodec_encoder_cmd, .vidioc_try_decoder_cmd = vicodec_try_decoder_cmd, @@ -960,7 +1234,71 @@ static void vicodec_buf_queue(struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + unsigned int sz = vb2_get_plane_payload(&vbuf->vb2_buf, 0); + u8 *p_src = vb2_plane_vaddr(&vbuf->vb2_buf, 0); + u8 *p = p_src; + struct vb2_queue *vq_out = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, + V4L2_BUF_TYPE_VIDEO_OUTPUT); + struct vb2_queue *vq_cap = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + bool header_valid = false; + static const struct v4l2_event rs_event = { + .type = V4L2_EVENT_SOURCE_CHANGE, + .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, + }; + /* buf_queue handles only the first source change event */ + if (ctx->first_source_change_sent) { + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); + return; + } + + /* + * if both queues are streaming, the source change event is + * handled in job_ready + */ + if (vb2_is_streaming(vq_cap) && vb2_is_streaming(vq_out)) { + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); + return; + } + + /* + * source change event is relevant only for the decoder + * in the compressed stream + */ + if (ctx->is_enc || !V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); + return; + } + + do { + enum vb2_buffer_state state = + get_next_header(ctx, &p, p_src + sz - p); + + if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) { + v4l2_m2m_buf_done(vbuf, state); + return; + } + header_valid = is_header_valid(&ctx->state.header); + /* + * p points right after the end of the header in the + * buffer. If the header is invalid we set p to point + * to the next byte after the start of the header + */ + if (!header_valid) { + p = p - sizeof(struct fwht_cframe_hdr) + 1; + if (p < p_src) + p = p_src; + ctx->header_size = 0; + ctx->comp_magic_cnt = 0; + } + + } while (!header_valid); + + ctx->cur_buf_offset = p - p_src; + update_capture_data_from_header(ctx); + ctx->first_source_change_sent = true; + v4l2_event_queue_fh(&ctx->fh, &rs_event); v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); } @@ -988,47 +1326,70 @@ static int vicodec_start_streaming(struct vb2_queue *q, struct vicodec_ctx *ctx = vb2_get_drv_priv(q); struct vicodec_q_data *q_data = get_q_data(ctx, q->type); struct v4l2_fwht_state *state = &ctx->state; - unsigned int size = q_data->width * q_data->height; const struct v4l2_fwht_pixfmt_info *info = q_data->info; - unsigned int chroma_div = info->width_div * info->height_div; + unsigned int size = q_data->coded_width * q_data->coded_height; + unsigned int chroma_div; unsigned int total_planes_size; + u8 *new_comp_frame; - /* - * we don't know ahead how many components are in the encoding type - * V4L2_PIX_FMT_FWHT, so we will allocate space for 4 planes. - */ - if (info->id == V4L2_PIX_FMT_FWHT || info->components_num == 4) + if (!info) + return -EINVAL; + + chroma_div = info->width_div * info->height_div; + q_data->sequence = 0; + + ctx->last_src_buf = NULL; + ctx->last_dst_buf = NULL; + state->gop_cnt = 0; + + if ((V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) || + (!V4L2_TYPE_IS_OUTPUT(q->type) && ctx->is_enc)) + return 0; + + if (info->id == V4L2_PIX_FMT_FWHT) { + vicodec_return_bufs(q, VB2_BUF_STATE_QUEUED); + return -EINVAL; + } + if (info->components_num == 4) total_planes_size = 2 * size + 2 * (size / chroma_div); else if (info->components_num == 3) total_planes_size = size + 2 * (size / chroma_div); else total_planes_size = size; - q_data->sequence = 0; + state->visible_width = q_data->visible_width; + state->visible_height = q_data->visible_height; + state->coded_width = q_data->coded_width; + state->coded_height = q_data->coded_height; + state->stride = q_data->coded_width * + info->bytesperline_mult; - if (!V4L2_TYPE_IS_OUTPUT(q->type)) { - if (!ctx->is_enc) { - state->width = q_data->width; - state->height = q_data->height; - } - return 0; - } - - if (ctx->is_enc) { - state->width = q_data->width; - state->height = q_data->height; - } - state->ref_frame.width = state->ref_frame.height = 0; state->ref_frame.luma = kvmalloc(total_planes_size, GFP_KERNEL); - ctx->comp_max_size = total_planes_size + sizeof(struct fwht_cframe_hdr); - state->compressed_frame = kvmalloc(ctx->comp_max_size, GFP_KERNEL); - if (!state->ref_frame.luma || !state->compressed_frame) { + ctx->comp_max_size = total_planes_size; + new_comp_frame = kvmalloc(ctx->comp_max_size, GFP_KERNEL); + + if (!state->ref_frame.luma || !new_comp_frame) { kvfree(state->ref_frame.luma); - kvfree(state->compressed_frame); + kvfree(new_comp_frame); vicodec_return_bufs(q, VB2_BUF_STATE_QUEUED); return -ENOMEM; } - if (info->id == V4L2_PIX_FMT_FWHT || info->components_num >= 3) { + /* + * if state->compressed_frame was already allocated then + * it contain data of the first frame of the new resolution + */ + if (state->compressed_frame) { + if (ctx->comp_size > ctx->comp_max_size) + ctx->comp_size = ctx->comp_max_size; + + memcpy(new_comp_frame, + state->compressed_frame, ctx->comp_size); + } + + kvfree(state->compressed_frame); + state->compressed_frame = new_comp_frame; + + if (info->components_num >= 3) { state->ref_frame.cb = state->ref_frame.luma + size; state->ref_frame.cr = state->ref_frame.cb + size / chroma_div; } else { @@ -1036,20 +1397,11 @@ static int vicodec_start_streaming(struct vb2_queue *q, state->ref_frame.cr = NULL; } - if (info->id == V4L2_PIX_FMT_FWHT || info->components_num == 4) + if (info->components_num == 4) state->ref_frame.alpha = state->ref_frame.cr + size / chroma_div; else state->ref_frame.alpha = NULL; - - ctx->last_src_buf = NULL; - ctx->last_dst_buf = NULL; - state->gop_cnt = 0; - ctx->cur_buf_offset = 0; - ctx->comp_size = 0; - ctx->comp_magic_cnt = 0; - ctx->comp_has_frame = false; - return 0; } @@ -1059,11 +1411,20 @@ static void vicodec_stop_streaming(struct vb2_queue *q) vicodec_return_bufs(q, VB2_BUF_STATE_ERROR); - if (!V4L2_TYPE_IS_OUTPUT(q->type)) - return; - - kvfree(ctx->state.ref_frame.luma); - kvfree(ctx->state.compressed_frame); + if ((!V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) || + (V4L2_TYPE_IS_OUTPUT(q->type) && ctx->is_enc)) { + kvfree(ctx->state.ref_frame.luma); + ctx->comp_max_size = 0; + ctx->source_changed = false; + } + if (V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) { + ctx->cur_buf_offset = 0; + ctx->comp_size = 0; + ctx->header_size = 0; + ctx->comp_magic_cnt = 0; + ctx->comp_has_frame = 0; + ctx->comp_has_next_frame = 0; + } } static const struct vb2_ops vicodec_qops = { @@ -1204,8 +1565,10 @@ static int vicodec_open(struct file *file) ctx->q_data[V4L2_M2M_SRC].info = ctx->is_enc ? v4l2_fwht_get_pixfmt(0) : &pixfmt_fwht; - ctx->q_data[V4L2_M2M_SRC].width = 1280; - ctx->q_data[V4L2_M2M_SRC].height = 720; + ctx->q_data[V4L2_M2M_SRC].coded_width = 1280; + ctx->q_data[V4L2_M2M_SRC].coded_height = 720; + ctx->q_data[V4L2_M2M_SRC].visible_width = 1280; + ctx->q_data[V4L2_M2M_SRC].visible_height = 720; size = 1280 * 720 * ctx->q_data[V4L2_M2M_SRC].info->sizeimage_mult / ctx->q_data[V4L2_M2M_SRC].info->sizeimage_div; if (ctx->is_enc) @@ -1213,16 +1576,17 @@ static int vicodec_open(struct file *file) else ctx->q_data[V4L2_M2M_SRC].sizeimage = size + sizeof(struct fwht_cframe_hdr); - ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC]; - ctx->q_data[V4L2_M2M_DST].info = - ctx->is_enc ? &pixfmt_fwht : v4l2_fwht_get_pixfmt(0); - size = 1280 * 720 * ctx->q_data[V4L2_M2M_DST].info->sizeimage_mult / - ctx->q_data[V4L2_M2M_DST].info->sizeimage_div; - if (ctx->is_enc) - ctx->q_data[V4L2_M2M_DST].sizeimage = - size + sizeof(struct fwht_cframe_hdr); - else - ctx->q_data[V4L2_M2M_DST].sizeimage = size; + if (ctx->is_enc) { + ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC]; + ctx->q_data[V4L2_M2M_DST].info = &pixfmt_fwht; + ctx->q_data[V4L2_M2M_DST].sizeimage = 1280 * 720 * + ctx->q_data[V4L2_M2M_DST].info->sizeimage_mult / + ctx->q_data[V4L2_M2M_DST].info->sizeimage_div + + sizeof(struct fwht_cframe_hdr); + } else { + ctx->q_data[V4L2_M2M_DST].info = NULL; + } + ctx->state.colorspace = V4L2_COLORSPACE_REC709; if (ctx->is_enc) { @@ -1310,6 +1674,8 @@ static int vicodec_probe(struct platform_device *pdev) #ifdef CONFIG_MEDIA_CONTROLLER dev->mdev.dev = &pdev->dev; strscpy(dev->mdev.model, "vicodec", sizeof(dev->mdev.model)); + strscpy(dev->mdev.bus_info, "platform:vicodec", + sizeof(dev->mdev.bus_info)); media_device_init(&dev->mdev); dev->v4l2_dev.mdev = &dev->mdev; #endif diff --git a/drivers/media/platform/video-mux.c b/drivers/media/platform/video-mux.c index c33900e3c23e..0ba30756e1e4 100644 --- a/drivers/media/platform/video-mux.c +++ b/drivers/media/platform/video-mux.c @@ -263,6 +263,26 @@ static int video_mux_set_format(struct v4l2_subdev *sd, case MEDIA_BUS_FMT_UYYVYY16_0_5X48: case MEDIA_BUS_FMT_JPEG_1X8: case MEDIA_BUS_FMT_AHSV8888_1X32: + case MEDIA_BUS_FMT_SBGGR8_1X8: + case MEDIA_BUS_FMT_SGBRG8_1X8: + case MEDIA_BUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SRGGB8_1X8: + case MEDIA_BUS_FMT_SBGGR10_1X10: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SRGGB10_1X10: + case MEDIA_BUS_FMT_SBGGR12_1X12: + case MEDIA_BUS_FMT_SGBRG12_1X12: + case MEDIA_BUS_FMT_SGRBG12_1X12: + case MEDIA_BUS_FMT_SRGGB12_1X12: + case MEDIA_BUS_FMT_SBGGR14_1X14: + case MEDIA_BUS_FMT_SGBRG14_1X14: + case MEDIA_BUS_FMT_SGRBG14_1X14: + case MEDIA_BUS_FMT_SRGGB14_1X14: + case MEDIA_BUS_FMT_SBGGR16_1X16: + case MEDIA_BUS_FMT_SGBRG16_1X16: + case MEDIA_BUS_FMT_SGRBG16_1X16: + case MEDIA_BUS_FMT_SRGGB16_1X16: break; default: sdformat->format.code = MEDIA_BUS_FMT_Y8_1X8; diff --git a/drivers/media/platform/vim2m.c b/drivers/media/platform/vim2m.c index 89d9c4c21037..34dcaca45d8b 100644 --- a/drivers/media/platform/vim2m.c +++ b/drivers/media/platform/vim2m.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * A virtual v4l2-mem2mem example device. * @@ -34,22 +35,34 @@ MODULE_DESCRIPTION("Virtual device for mem2mem framework testing"); MODULE_AUTHOR("Pawel Osciak, <pawel@osciak.com>"); MODULE_LICENSE("GPL"); -MODULE_VERSION("0.1.1"); +MODULE_VERSION("0.2"); MODULE_ALIAS("mem2mem_testdev"); -static unsigned debug; +static unsigned int debug; module_param(debug, uint, 0644); -MODULE_PARM_DESC(debug, "activates debug info"); +MODULE_PARM_DESC(debug, "debug level"); + +/* Default transaction time in msec */ +static unsigned int default_transtime = 40; /* Max 25 fps */ +module_param(default_transtime, uint, 0644); +MODULE_PARM_DESC(default_transtime, "default transaction time in ms"); #define MIN_W 32 #define MIN_H 32 #define MAX_W 640 #define MAX_H 480 -#define DIM_ALIGN_MASK 7 /* 8-byte alignment for line length */ + +/* Pixel alignment for non-bayer formats */ +#define WIDTH_ALIGN 2 +#define HEIGHT_ALIGN 1 + +/* Pixel alignment for bayer formats */ +#define BAYER_WIDTH_ALIGN 2 +#define BAYER_HEIGHT_ALIGN 2 /* Flags that indicate a format can be used for capture/output */ -#define MEM2MEM_CAPTURE (1 << 0) -#define MEM2MEM_OUTPUT (1 << 1) +#define MEM2MEM_CAPTURE BIT(0) +#define MEM2MEM_OUTPUT BIT(1) #define MEM2MEM_NAME "vim2m" @@ -58,18 +71,12 @@ MODULE_PARM_DESC(debug, "activates debug info"); /* In bytes, per queue */ #define MEM2MEM_VID_MEM_LIMIT (16 * 1024 * 1024) -/* Default transaction time in msec */ -#define MEM2MEM_DEF_TRANSTIME 40 -#define MEM2MEM_COLOR_STEP (0xff >> 4) -#define MEM2MEM_NUM_TILES 8 - /* Flags that indicate processing mode */ -#define MEM2MEM_HFLIP (1 << 0) -#define MEM2MEM_VFLIP (1 << 1) - -#define dprintk(dev, fmt, arg...) \ - v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg) +#define MEM2MEM_HFLIP BIT(0) +#define MEM2MEM_VFLIP BIT(1) +#define dprintk(dev, lvl, fmt, arg...) \ + v4l2_dbg(lvl, debug, &(dev)->v4l2_dev, "%s: " fmt, __func__, ## arg) static void vim2m_dev_release(struct device *dev) {} @@ -83,21 +90,46 @@ struct vim2m_fmt { u32 fourcc; int depth; /* Types the format can be used for */ - u32 types; + u32 types; }; static struct vim2m_fmt formats[] = { { - .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ + .fourcc = V4L2_PIX_FMT_RGB565, /* rrrrrggg gggbbbbb */ .depth = 16, - /* Both capture and output format */ - .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, - }, - { + .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, + }, { + .fourcc = V4L2_PIX_FMT_RGB565X, /* gggbbbbb rrrrrggg */ + .depth = 16, + .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, + }, { + .fourcc = V4L2_PIX_FMT_RGB24, + .depth = 24, + .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, + }, { + .fourcc = V4L2_PIX_FMT_BGR24, + .depth = 24, + .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, + }, { .fourcc = V4L2_PIX_FMT_YUYV, .depth = 16, - /* Output-only format */ - .types = MEM2MEM_OUTPUT, + .types = MEM2MEM_CAPTURE, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR8, + .depth = 8, + .types = MEM2MEM_CAPTURE, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG8, + .depth = 8, + .types = MEM2MEM_CAPTURE, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG8, + .depth = 8, + .types = MEM2MEM_CAPTURE, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB8, + .depth = 8, + .types = MEM2MEM_CAPTURE, }, }; @@ -120,14 +152,14 @@ enum { #define V4L2_CID_TRANS_TIME_MSEC (V4L2_CID_USER_BASE + 0x1000) #define V4L2_CID_TRANS_NUM_BUFS (V4L2_CID_USER_BASE + 0x1001) -static struct vim2m_fmt *find_format(struct v4l2_format *f) +static struct vim2m_fmt *find_format(u32 fourcc) { struct vim2m_fmt *fmt; unsigned int k; for (k = 0; k < NUM_FORMATS; k++) { fmt = &formats[k]; - if (fmt->fourcc == f->fmt.pix.pixelformat) + if (fmt->fourcc == fourcc) break; } @@ -137,6 +169,24 @@ static struct vim2m_fmt *find_format(struct v4l2_format *f) return &formats[k]; } +static void get_alignment(u32 fourcc, + unsigned int *walign, unsigned int *halign) +{ + switch (fourcc) { + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + *walign = BAYER_WIDTH_ALIGN; + *halign = BAYER_HEIGHT_ALIGN; + return; + default: + *walign = WIDTH_ALIGN; + *halign = HEIGHT_ALIGN; + return; + } +} + struct vim2m_dev { struct v4l2_device v4l2_dev; struct video_device vfd; @@ -146,9 +196,6 @@ struct vim2m_dev { atomic_t num_inst; struct mutex dev_mutex; - spinlock_t irqlock; - - struct delayed_work work_run; struct v4l2_m2m_dev *m2m_dev; }; @@ -167,6 +214,10 @@ struct vim2m_ctx { /* Transaction time (i.e. simulated processing time) in milliseconds */ u32 transtime; + struct mutex vb_mutex; + struct delayed_work work_run; + spinlock_t irqlock; + /* Abort requested by m2m */ int aborting; @@ -188,7 +239,7 @@ static inline struct vim2m_ctx *file2ctx(struct file *file) } static struct vim2m_q_data *get_q_data(struct vim2m_ctx *ctx, - enum v4l2_buf_type type) + enum v4l2_buf_type type) { switch (type) { case V4L2_BUF_TYPE_VIDEO_OUTPUT: @@ -196,28 +247,221 @@ static struct vim2m_q_data *get_q_data(struct vim2m_ctx *ctx, case V4L2_BUF_TYPE_VIDEO_CAPTURE: return &ctx->q_data[V4L2_M2M_DST]; default: - BUG(); + return NULL; + } +} + +static const char *type_name(enum v4l2_buf_type type) +{ + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + return "Output"; + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return "Capture"; + default: + return "Invalid"; + } +} + +#define CLIP(__color) \ + (u8)(((__color) > 0xff) ? 0xff : (((__color) < 0) ? 0 : (__color))) + +static void copy_line(struct vim2m_q_data *q_data_out, + u8 *src, u8 *dst, bool reverse) +{ + int x, depth = q_data_out->fmt->depth >> 3; + + if (!reverse) { + memcpy(dst, src, q_data_out->width * depth); + } else { + for (x = 0; x < q_data_out->width >> 1; x++) { + memcpy(dst, src, depth); + memcpy(dst + depth, src - depth, depth); + src -= depth << 1; + dst += depth << 1; + } + return; } - return NULL; } +static void copy_two_pixels(struct vim2m_q_data *q_data_in, + struct vim2m_q_data *q_data_out, + u8 *src[2], u8 **dst, int ypos, bool reverse) +{ + struct vim2m_fmt *out = q_data_out->fmt; + struct vim2m_fmt *in = q_data_in->fmt; + u8 _r[2], _g[2], _b[2], *r, *g, *b; + int i; + + /* Step 1: read two consecutive pixels from src pointer */ + + r = _r; + g = _g; + b = _b; + + switch (in->fourcc) { + case V4L2_PIX_FMT_RGB565: /* rrrrrggg gggbbbbb */ + for (i = 0; i < 2; i++) { + u16 pix = *(u16 *)(src[i]); + + *r++ = (u8)(((pix & 0xf800) >> 11) << 3) | 0x07; + *g++ = (u8)((((pix & 0x07e0) >> 5)) << 2) | 0x03; + *b++ = (u8)((pix & 0x1f) << 3) | 0x07; + } + break; + case V4L2_PIX_FMT_RGB565X: /* gggbbbbb rrrrrggg */ + for (i = 0; i < 2; i++) { + u16 pix = *(u16 *)(src[i]); + + *r++ = (u8)(((0x00f8 & pix) >> 3) << 3) | 0x07; + *g++ = (u8)(((pix & 0x7) << 2) | + ((pix & 0xe000) >> 5)) | 0x03; + *b++ = (u8)(((pix & 0x1f00) >> 8) << 3) | 0x07; + } + break; + default: + case V4L2_PIX_FMT_RGB24: + for (i = 0; i < 2; i++) { + *r++ = src[i][0]; + *g++ = src[i][1]; + *b++ = src[i][2]; + } + break; + case V4L2_PIX_FMT_BGR24: + for (i = 0; i < 2; i++) { + *b++ = src[i][0]; + *g++ = src[i][1]; + *r++ = src[i][2]; + } + break; + } + + /* Step 2: store two consecutive points, reversing them if needed */ + + r = _r; + g = _g; + b = _b; + + switch (out->fourcc) { + case V4L2_PIX_FMT_RGB565: /* rrrrrggg gggbbbbb */ + for (i = 0; i < 2; i++) { + u16 *pix = (u16 *)*dst; + + *pix = ((*r << 8) & 0xf800) | ((*g << 3) & 0x07e0) | + (*b >> 3); + + *dst += 2; + } + return; + case V4L2_PIX_FMT_RGB565X: /* gggbbbbb rrrrrggg */ + for (i = 0; i < 2; i++) { + u16 *pix = (u16 *)*dst; + u8 green = *g++ >> 2; + + *pix = ((green << 8) & 0xe000) | (green & 0x07) | + ((*b++ << 5) & 0x1f00) | ((*r++ & 0xf8)); + + *dst += 2; + } + return; + case V4L2_PIX_FMT_RGB24: + for (i = 0; i < 2; i++) { + *(*dst)++ = *r++; + *(*dst)++ = *g++; + *(*dst)++ = *b++; + } + return; + case V4L2_PIX_FMT_BGR24: + for (i = 0; i < 2; i++) { + *(*dst)++ = *b++; + *(*dst)++ = *g++; + *(*dst)++ = *r++; + } + return; + case V4L2_PIX_FMT_YUYV: + default: + { + u8 y, y1, u, v; + + y = ((8453 * (*r) + 16594 * (*g) + 3223 * (*b) + + 524288) >> 15); + u = ((-4878 * (*r) - 9578 * (*g) + 14456 * (*b) + + 4210688) >> 15); + v = ((14456 * (*r++) - 12105 * (*g++) - 2351 * (*b++) + + 4210688) >> 15); + y1 = ((8453 * (*r) + 16594 * (*g) + 3223 * (*b) + + 524288) >> 15); + + *(*dst)++ = y; + *(*dst)++ = u; + + *(*dst)++ = y1; + *(*dst)++ = v; + return; + } + case V4L2_PIX_FMT_SBGGR8: + if (!(ypos & 1)) { + *(*dst)++ = *b; + *(*dst)++ = *++g; + } else { + *(*dst)++ = *g; + *(*dst)++ = *++r; + } + return; + case V4L2_PIX_FMT_SGBRG8: + if (!(ypos & 1)) { + *(*dst)++ = *g; + *(*dst)++ = *++b; + } else { + *(*dst)++ = *r; + *(*dst)++ = *++g; + } + return; + case V4L2_PIX_FMT_SGRBG8: + if (!(ypos & 1)) { + *(*dst)++ = *g; + *(*dst)++ = *++r; + } else { + *(*dst)++ = *b; + *(*dst)++ = *++g; + } + return; + case V4L2_PIX_FMT_SRGGB8: + if (!(ypos & 1)) { + *(*dst)++ = *r; + *(*dst)++ = *++g; + } else { + *(*dst)++ = *g; + *(*dst)++ = *++b; + } + return; + } +} static int device_process(struct vim2m_ctx *ctx, struct vb2_v4l2_buffer *in_vb, struct vb2_v4l2_buffer *out_vb) { struct vim2m_dev *dev = ctx->dev; - struct vim2m_q_data *q_data; - u8 *p_in, *p_out; - int x, y, t, w; - int tile_w, bytes_left; - int width, height, bytesperline; + struct vim2m_q_data *q_data_in, *q_data_out; + u8 *p_in, *p_line, *p_in_x[2], *p, *p_out; + unsigned int width, height, bytesperline, bytes_per_pixel; + unsigned int x, y, y_in, y_out, x_int, x_fract, x_err, x_offset; + int start, end, step; + + q_data_in = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + if (!q_data_in) + return 0; + bytesperline = (q_data_in->width * q_data_in->fmt->depth) >> 3; + bytes_per_pixel = q_data_in->fmt->depth >> 3; - q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + q_data_out = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (!q_data_out) + return 0; - width = q_data->width; - height = q_data->height; - bytesperline = (q_data->width * q_data->fmt->depth) >> 3; + /* As we're doing scaling, use the output dimensions here */ + height = q_data_out->height; + width = q_data_out->width; p_in = vb2_plane_vaddr(&in_vb->vb2_buf, 0); p_out = vb2_plane_vaddr(&out_vb->vb2_buf, 0); @@ -227,109 +471,86 @@ static int device_process(struct vim2m_ctx *ctx, return -EFAULT; } - if (vb2_plane_size(&in_vb->vb2_buf, 0) > - vb2_plane_size(&out_vb->vb2_buf, 0)) { - v4l2_err(&dev->v4l2_dev, "Output buffer is too small\n"); - return -EINVAL; - } + out_vb->sequence = q_data_out->sequence++; + in_vb->sequence = q_data_in->sequence++; + v4l2_m2m_buf_copy_metadata(in_vb, out_vb, true); - tile_w = (width * (q_data[V4L2_M2M_DST].fmt->depth >> 3)) - / MEM2MEM_NUM_TILES; - bytes_left = bytesperline - tile_w * MEM2MEM_NUM_TILES; - w = 0; - - out_vb->sequence = - get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE)->sequence++; - in_vb->sequence = q_data->sequence++; - out_vb->vb2_buf.timestamp = in_vb->vb2_buf.timestamp; - - if (in_vb->flags & V4L2_BUF_FLAG_TIMECODE) - out_vb->timecode = in_vb->timecode; - out_vb->field = in_vb->field; - out_vb->flags = in_vb->flags & - (V4L2_BUF_FLAG_TIMECODE | - V4L2_BUF_FLAG_KEYFRAME | - V4L2_BUF_FLAG_PFRAME | - V4L2_BUF_FLAG_BFRAME | - V4L2_BUF_FLAG_TSTAMP_SRC_MASK); - - switch (ctx->mode) { - case MEM2MEM_HFLIP | MEM2MEM_VFLIP: - p_out += bytesperline * height - bytes_left; - for (y = 0; y < height; ++y) { - for (t = 0; t < MEM2MEM_NUM_TILES; ++t) { - if (w & 0x1) { - for (x = 0; x < tile_w; ++x) - *--p_out = *p_in++ + - MEM2MEM_COLOR_STEP; - } else { - for (x = 0; x < tile_w; ++x) - *--p_out = *p_in++ - - MEM2MEM_COLOR_STEP; - } - ++w; - } - p_in += bytes_left; - p_out -= bytes_left; - } - break; + if (ctx->mode & MEM2MEM_VFLIP) { + start = height - 1; + end = -1; + step = -1; + } else { + start = 0; + end = height; + step = 1; + } + y_out = 0; + + /* + * When format and resolution are identical, + * we can use a faster copy logic + */ + if (q_data_in->fmt->fourcc == q_data_out->fmt->fourcc && + q_data_in->width == q_data_out->width && + q_data_in->height == q_data_out->height) { + for (y = start; y != end; y += step, y_out++) { + p = p_in + (y * bytesperline); + if (ctx->mode & MEM2MEM_HFLIP) + p += bytesperline - (q_data_in->fmt->depth >> 3); + + copy_line(q_data_out, p, p_out, + ctx->mode & MEM2MEM_HFLIP); - case MEM2MEM_HFLIP: - for (y = 0; y < height; ++y) { - p_out += MEM2MEM_NUM_TILES * tile_w; - for (t = 0; t < MEM2MEM_NUM_TILES; ++t) { - if (w & 0x01) { - for (x = 0; x < tile_w; ++x) - *--p_out = *p_in++ + - MEM2MEM_COLOR_STEP; - } else { - for (x = 0; x < tile_w; ++x) - *--p_out = *p_in++ - - MEM2MEM_COLOR_STEP; - } - ++w; - } - p_in += bytes_left; p_out += bytesperline; } - break; + return 0; + } + + /* Slower algorithm with format conversion, hflip, vflip and scaler */ + + /* To speed scaler up, use Bresenham for X dimension */ + x_int = q_data_in->width / q_data_out->width; + x_fract = q_data_in->width % q_data_out->width; + + for (y = start; y != end; y += step, y_out++) { + y_in = (y * q_data_in->height) / q_data_out->height; + x_offset = 0; + x_err = 0; - case MEM2MEM_VFLIP: - p_out += bytesperline * (height - 1); - for (y = 0; y < height; ++y) { - for (t = 0; t < MEM2MEM_NUM_TILES; ++t) { - if (w & 0x1) { - for (x = 0; x < tile_w; ++x) - *p_out++ = *p_in++ + - MEM2MEM_COLOR_STEP; - } else { - for (x = 0; x < tile_w; ++x) - *p_out++ = *p_in++ - - MEM2MEM_COLOR_STEP; - } - ++w; + p_line = p_in + (y_in * bytesperline); + if (ctx->mode & MEM2MEM_HFLIP) + p_line += bytesperline - (q_data_in->fmt->depth >> 3); + p_in_x[0] = p_line; + + for (x = 0; x < width >> 1; x++) { + x_offset += x_int; + x_err += x_fract; + if (x_err > width) { + x_offset++; + x_err -= width; } - p_in += bytes_left; - p_out += bytes_left - 2 * bytesperline; - } - break; - default: - for (y = 0; y < height; ++y) { - for (t = 0; t < MEM2MEM_NUM_TILES; ++t) { - if (w & 0x1) { - for (x = 0; x < tile_w; ++x) - *p_out++ = *p_in++ + - MEM2MEM_COLOR_STEP; - } else { - for (x = 0; x < tile_w; ++x) - *p_out++ = *p_in++ - - MEM2MEM_COLOR_STEP; - } - ++w; + if (ctx->mode & MEM2MEM_HFLIP) + p_in_x[1] = p_line - x_offset * bytes_per_pixel; + else + p_in_x[1] = p_line + x_offset * bytes_per_pixel; + + copy_two_pixels(q_data_in, q_data_out, + p_in_x, &p_out, y_out, + ctx->mode & MEM2MEM_HFLIP); + + /* Calculate the next p_in_x0 */ + x_offset += x_int; + x_err += x_fract; + if (x_err > width) { + x_offset++; + x_err -= width; } - p_in += bytes_left; - p_out += bytes_left; + + if (ctx->mode & MEM2MEM_HFLIP) + p_in_x[0] = p_line - x_offset * bytes_per_pixel; + else + p_in_x[0] = p_line + x_offset * bytes_per_pixel; } } @@ -349,7 +570,7 @@ static int job_ready(void *priv) if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) < ctx->translen || v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) < ctx->translen) { - dprintk(ctx->dev, "Not enough buffers available\n"); + dprintk(ctx->dev, 1, "Not enough buffers available\n"); return 0; } @@ -373,7 +594,6 @@ static void job_abort(void *priv) static void device_run(void *priv) { struct vim2m_ctx *ctx = priv; - struct vim2m_dev *dev = ctx->dev; struct vb2_v4l2_buffer *src_buf, *dst_buf; src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); @@ -390,37 +610,38 @@ static void device_run(void *priv) &ctx->hdl); /* Run delayed work, which simulates a hardware irq */ - schedule_delayed_work(&dev->work_run, msecs_to_jiffies(ctx->transtime)); + schedule_delayed_work(&ctx->work_run, msecs_to_jiffies(ctx->transtime)); } static void device_work(struct work_struct *w) { - struct vim2m_dev *vim2m_dev = - container_of(w, struct vim2m_dev, work_run.work); struct vim2m_ctx *curr_ctx; + struct vim2m_dev *vim2m_dev; struct vb2_v4l2_buffer *src_vb, *dst_vb; unsigned long flags; - curr_ctx = v4l2_m2m_get_curr_priv(vim2m_dev->m2m_dev); + curr_ctx = container_of(w, struct vim2m_ctx, work_run.work); - if (NULL == curr_ctx) { + if (!curr_ctx) { pr_err("Instance released before the end of transaction\n"); return; } + vim2m_dev = curr_ctx->dev; + src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx); dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx); curr_ctx->num_processed++; - spin_lock_irqsave(&vim2m_dev->irqlock, flags); + spin_lock_irqsave(&curr_ctx->irqlock, flags); v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE); v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE); - spin_unlock_irqrestore(&vim2m_dev->irqlock, flags); + spin_unlock_irqrestore(&curr_ctx->irqlock, flags); if (curr_ctx->num_processed == curr_ctx->translen || curr_ctx->aborting) { - dprintk(curr_ctx->dev, "Finishing transaction\n"); + dprintk(curr_ctx->dev, 2, "Finishing capture buffer fill\n"); curr_ctx->num_processed = 0; v4l2_m2m_job_finish(vim2m_dev->m2m_dev, curr_ctx->fh.m2m_ctx); } else { @@ -437,7 +658,7 @@ static int vidioc_querycap(struct file *file, void *priv, strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1); strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1); snprintf(cap->bus_info, sizeof(cap->bus_info), - "platform:%s", MEM2MEM_NAME); + "platform:%s", MEM2MEM_NAME); return 0; } @@ -453,8 +674,10 @@ static int enum_fmt(struct v4l2_fmtdesc *f, u32 type) /* index-th format of type type found ? */ if (num == f->index) break; - /* Correct type but haven't reached our index yet, - * just increment per-type index */ + /* + * Correct type but haven't reached our index yet, + * just increment per-type index + */ ++num; } } @@ -482,6 +705,27 @@ static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, return enum_fmt(f, MEM2MEM_OUTPUT); } +static int vidioc_enum_framesizes(struct file *file, void *priv, + struct v4l2_frmsizeenum *fsize) +{ + if (fsize->index != 0) + return -EINVAL; + + if (!find_format(fsize->pixel_format)) + return -EINVAL; + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise.min_width = MIN_W; + fsize->stepwise.min_height = MIN_H; + fsize->stepwise.max_width = MAX_W; + fsize->stepwise.max_height = MAX_H; + + get_alignment(fsize->pixel_format, + &fsize->stepwise.step_width, + &fsize->stepwise.step_height); + return 0; +} + static int vidioc_g_fmt(struct vim2m_ctx *ctx, struct v4l2_format *f) { struct vb2_queue *vq; @@ -492,6 +736,8 @@ static int vidioc_g_fmt(struct vim2m_ctx *ctx, struct v4l2_format *f) return -EINVAL; q_data = get_q_data(ctx, f->type); + if (!q_data) + return -EINVAL; f->fmt.pix.width = q_data->width; f->fmt.pix.height = q_data->height; @@ -521,8 +767,11 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, static int vidioc_try_fmt(struct v4l2_format *f, struct vim2m_fmt *fmt) { - /* V4L2 specification suggests the driver corrects the format struct - * if any of the dimensions is unsupported */ + int walign, halign; + /* + * V4L2 specification specifies the driver corrects the + * format struct if any of the dimensions is unsupported + */ if (f->fmt.pix.height < MIN_H) f->fmt.pix.height = MIN_H; else if (f->fmt.pix.height > MAX_H) @@ -533,7 +782,9 @@ static int vidioc_try_fmt(struct v4l2_format *f, struct vim2m_fmt *fmt) else if (f->fmt.pix.width > MAX_W) f->fmt.pix.width = MAX_W; - f->fmt.pix.width &= ~DIM_ALIGN_MASK; + get_alignment(f->fmt.pix.pixelformat, &walign, &halign); + f->fmt.pix.width &= ~(walign - 1); + f->fmt.pix.height &= ~(halign - 1); f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; f->fmt.pix.field = V4L2_FIELD_NONE; @@ -547,10 +798,10 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct vim2m_fmt *fmt; struct vim2m_ctx *ctx = file2ctx(file); - fmt = find_format(f); + fmt = find_format(f->fmt.pix.pixelformat); if (!fmt) { f->fmt.pix.pixelformat = formats[0].fourcc; - fmt = find_format(f); + fmt = find_format(f->fmt.pix.pixelformat); } if (!(fmt->types & MEM2MEM_CAPTURE)) { v4l2_err(&ctx->dev->v4l2_dev, @@ -572,10 +823,10 @@ static int vidioc_try_fmt_vid_out(struct file *file, void *priv, struct vim2m_fmt *fmt; struct vim2m_ctx *ctx = file2ctx(file); - fmt = find_format(f); + fmt = find_format(f->fmt.pix.pixelformat); if (!fmt) { f->fmt.pix.pixelformat = formats[0].fourcc; - fmt = find_format(f); + fmt = find_format(f->fmt.pix.pixelformat); } if (!(fmt->types & MEM2MEM_OUTPUT)) { v4l2_err(&ctx->dev->v4l2_dev, @@ -607,15 +858,20 @@ static int vidioc_s_fmt(struct vim2m_ctx *ctx, struct v4l2_format *f) return -EBUSY; } - q_data->fmt = find_format(f); + q_data->fmt = find_format(f->fmt.pix.pixelformat); q_data->width = f->fmt.pix.width; q_data->height = f->fmt.pix.height; q_data->sizeimage = q_data->width * q_data->height * q_data->fmt->depth >> 3; - dprintk(ctx->dev, - "Setting format for type %d, wxh: %dx%d, fmt: %d\n", - f->type, q_data->width, q_data->height, q_data->fmt->fourcc); + dprintk(ctx->dev, 1, + "Format for type %s: %dx%d (%d bpp), fmt: %c%c%c%c\n", + type_name(f->type), q_data->width, q_data->height, + q_data->fmt->depth, + (q_data->fmt->fourcc & 0xff), + (q_data->fmt->fourcc >> 8) & 0xff, + (q_data->fmt->fourcc >> 16) & 0xff, + (q_data->fmt->fourcc >> 24) & 0xff); return 0; } @@ -674,6 +930,8 @@ static int vim2m_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_TRANS_TIME_MSEC: ctx->transtime = ctrl->val; + if (ctx->transtime < 1) + ctx->transtime = 1; break; case V4L2_CID_TRANS_NUM_BUFS: @@ -692,11 +950,11 @@ static const struct v4l2_ctrl_ops vim2m_ctrl_ops = { .s_ctrl = vim2m_s_ctrl, }; - static const struct v4l2_ioctl_ops vim2m_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_enum_framesizes = vidioc_enum_framesizes, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, @@ -721,20 +979,23 @@ static const struct v4l2_ioctl_ops vim2m_ioctl_ops = { .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; - /* * Queue operations */ static int vim2m_queue_setup(struct vb2_queue *vq, - unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], struct device *alloc_devs[]) + unsigned int *nbuffers, + unsigned int *nplanes, + unsigned int sizes[], + struct device *alloc_devs[]) { struct vim2m_ctx *ctx = vb2_get_drv_priv(vq); struct vim2m_q_data *q_data; unsigned int size, count = *nbuffers; q_data = get_q_data(ctx, vq->type); + if (!q_data) + return -EINVAL; size = q_data->width * q_data->height * q_data->fmt->depth >> 3; @@ -748,33 +1009,42 @@ static int vim2m_queue_setup(struct vb2_queue *vq, *nplanes = 1; sizes[0] = size; - dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size); + dprintk(ctx->dev, 1, "%s: get %d buffer(s) of size %d each.\n", + type_name(vq->type), count, size); return 0; } -static int vim2m_buf_prepare(struct vb2_buffer *vb) +static int vim2m_buf_out_validate(struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct vim2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + + if (vbuf->field == V4L2_FIELD_ANY) + vbuf->field = V4L2_FIELD_NONE; + if (vbuf->field != V4L2_FIELD_NONE) { + dprintk(ctx->dev, 1, "%s field isn't supported\n", __func__); + return -EINVAL; + } + + return 0; +} + +static int vim2m_buf_prepare(struct vb2_buffer *vb) +{ + struct vim2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); struct vim2m_q_data *q_data; - dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type); + dprintk(ctx->dev, 2, "type: %s\n", type_name(vb->vb2_queue->type)); q_data = get_q_data(ctx, vb->vb2_queue->type); - if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { - if (vbuf->field == V4L2_FIELD_ANY) - vbuf->field = V4L2_FIELD_NONE; - if (vbuf->field != V4L2_FIELD_NONE) { - dprintk(ctx->dev, "%s field isn't supported\n", - __func__); - return -EINVAL; - } - } - + if (!q_data) + return -EINVAL; if (vb2_plane_size(vb, 0) < q_data->sizeimage) { - dprintk(ctx->dev, "%s data will not fit into plane (%lu < %lu)\n", - __func__, vb2_plane_size(vb, 0), (long)q_data->sizeimage); + dprintk(ctx->dev, 1, + "%s data will not fit into plane (%lu < %lu)\n", + __func__, vb2_plane_size(vb, 0), + (long)q_data->sizeimage); return -EINVAL; } @@ -791,11 +1061,14 @@ static void vim2m_buf_queue(struct vb2_buffer *vb) v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); } -static int vim2m_start_streaming(struct vb2_queue *q, unsigned count) +static int vim2m_start_streaming(struct vb2_queue *q, unsigned int count) { struct vim2m_ctx *ctx = vb2_get_drv_priv(q); struct vim2m_q_data *q_data = get_q_data(ctx, q->type); + if (!q_data) + return -EINVAL; + q_data->sequence = 0; return 0; } @@ -803,25 +1076,23 @@ static int vim2m_start_streaming(struct vb2_queue *q, unsigned count) static void vim2m_stop_streaming(struct vb2_queue *q) { struct vim2m_ctx *ctx = vb2_get_drv_priv(q); - struct vim2m_dev *dev = ctx->dev; struct vb2_v4l2_buffer *vbuf; unsigned long flags; - if (v4l2_m2m_get_curr_priv(dev->m2m_dev) == ctx) - cancel_delayed_work_sync(&dev->work_run); + cancel_delayed_work_sync(&ctx->work_run); 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 == NULL) + if (!vbuf) return; v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req, &ctx->hdl); - spin_lock_irqsave(&ctx->dev->irqlock, flags); + spin_lock_irqsave(&ctx->irqlock, flags); v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); - spin_unlock_irqrestore(&ctx->dev->irqlock, flags); + spin_unlock_irqrestore(&ctx->irqlock, flags); } } @@ -834,6 +1105,7 @@ static void vim2m_buf_request_complete(struct vb2_buffer *vb) static const struct vb2_ops vim2m_qops = { .queue_setup = vim2m_queue_setup, + .buf_out_validate = vim2m_buf_out_validate, .buf_prepare = vim2m_buf_prepare, .buf_queue = vim2m_buf_queue, .start_streaming = vim2m_start_streaming, @@ -843,7 +1115,8 @@ static const struct vb2_ops vim2m_qops = { .buf_request_complete = vim2m_buf_request_complete, }; -static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) +static int queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) { struct vim2m_ctx *ctx = priv; int ret; @@ -855,7 +1128,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *ds src_vq->ops = &vim2m_qops; src_vq->mem_ops = &vb2_vmalloc_memops; src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - src_vq->lock = &ctx->dev->dev_mutex; + src_vq->lock = &ctx->vb_mutex; src_vq->supports_requests = true; ret = vb2_queue_init(src_vq); @@ -869,17 +1142,16 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *ds dst_vq->ops = &vim2m_qops; dst_vq->mem_ops = &vb2_vmalloc_memops; dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - dst_vq->lock = &ctx->dev->dev_mutex; + dst_vq->lock = &ctx->vb_mutex; return vb2_queue_init(dst_vq); } -static const struct v4l2_ctrl_config vim2m_ctrl_trans_time_msec = { +static struct v4l2_ctrl_config vim2m_ctrl_trans_time_msec = { .ops = &vim2m_ctrl_ops, .id = V4L2_CID_TRANS_TIME_MSEC, .name = "Transaction Time (msec)", .type = V4L2_CTRL_TYPE_INTEGER, - .def = MEM2MEM_DEF_TRANSTIME, .min = 1, .max = 10001, .step = 1, @@ -921,6 +1193,8 @@ static int vim2m_open(struct file *file) v4l2_ctrl_handler_init(hdl, 4); v4l2_ctrl_new_std(hdl, &vim2m_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0); v4l2_ctrl_new_std(hdl, &vim2m_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0); + + vim2m_ctrl_trans_time_msec.def = default_transtime; v4l2_ctrl_new_custom(hdl, &vim2m_ctrl_trans_time_msec, NULL); v4l2_ctrl_new_custom(hdl, &vim2m_ctrl_trans_num_bufs, NULL); if (hdl->error) { @@ -944,6 +1218,10 @@ static int vim2m_open(struct file *file) ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init); + mutex_init(&ctx->vb_mutex); + spin_lock_init(&ctx->irqlock); + INIT_DELAYED_WORK(&ctx->work_run, device_work); + if (IS_ERR(ctx->fh.m2m_ctx)) { rc = PTR_ERR(ctx->fh.m2m_ctx); @@ -956,7 +1234,7 @@ static int vim2m_open(struct file *file) v4l2_fh_add(&ctx->fh); atomic_inc(&dev->num_inst); - dprintk(dev, "Created instance: %p, m2m_ctx: %p\n", + dprintk(dev, 1, "Created instance: %p, m2m_ctx: %p\n", ctx, ctx->fh.m2m_ctx); open_unlock: @@ -969,7 +1247,7 @@ static int vim2m_release(struct file *file) struct vim2m_dev *dev = video_drvdata(file); struct vim2m_ctx *ctx = file2ctx(file); - dprintk(dev, "Releasing instance %p\n", ctx); + dprintk(dev, 1, "Releasing instance %p\n", ctx); v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); @@ -1024,8 +1302,6 @@ static int vim2m_probe(struct platform_device *pdev) if (!dev) return -ENOMEM; - spin_lock_init(&dev->irqlock); - ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); if (ret) return ret; @@ -1037,7 +1313,6 @@ static int vim2m_probe(struct platform_device *pdev) vfd = &dev->vfd; vfd->lock = &dev->dev_mutex; vfd->v4l2_dev = &dev->v4l2_dev; - INIT_DELAYED_WORK(&dev->work_run, device_work); ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); if (ret) { @@ -1047,7 +1322,7 @@ static int vim2m_probe(struct platform_device *pdev) video_set_drvdata(vfd, dev); v4l2_info(&dev->v4l2_dev, - "Device registered as /dev/video%d\n", vfd->num); + "Device registered as /dev/video%d\n", vfd->num); platform_set_drvdata(pdev, dev); @@ -1061,12 +1336,14 @@ static int vim2m_probe(struct platform_device *pdev) #ifdef CONFIG_MEDIA_CONTROLLER dev->mdev.dev = &pdev->dev; strscpy(dev->mdev.model, "vim2m", sizeof(dev->mdev.model)); + strscpy(dev->mdev.bus_info, "platform:vim2m", + sizeof(dev->mdev.bus_info)); media_device_init(&dev->mdev); dev->mdev.ops = &m2m_media_ops; dev->v4l2_dev.mdev = &dev->mdev; - ret = v4l2_m2m_register_media_controller(dev->m2m_dev, - vfd, MEDIA_ENT_F_PROC_VIDEO_SCALER); + ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd, + MEDIA_ENT_F_PROC_VIDEO_SCALER); if (ret) { v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n"); goto unreg_m2m; diff --git a/drivers/media/platform/vimc/Makefile b/drivers/media/platform/vimc/Makefile index 4b2e3de7856e..c4fc8e7d365a 100644 --- a/drivers/media/platform/vimc/Makefile +++ b/drivers/media/platform/vimc/Makefile @@ -5,6 +5,7 @@ vimc_common-objs := vimc-common.o vimc_debayer-objs := vimc-debayer.o vimc_scaler-objs := vimc-scaler.o vimc_sensor-objs := vimc-sensor.o +vimc_streamer-objs := vimc-streamer.o obj-$(CONFIG_VIDEO_VIMC) += vimc.o vimc_capture.o vimc_common.o vimc-debayer.o \ - vimc_scaler.o vimc_sensor.o + vimc_scaler.o vimc_sensor.o vimc_streamer.o diff --git a/drivers/media/platform/vimc/vimc-capture.c b/drivers/media/platform/vimc/vimc-capture.c index 3f7e9ed56633..ea869631a3f6 100644 --- a/drivers/media/platform/vimc/vimc-capture.c +++ b/drivers/media/platform/vimc/vimc-capture.c @@ -24,6 +24,7 @@ #include <media/videobuf2-vmalloc.h> #include "vimc-common.h" +#include "vimc-streamer.h" #define VIMC_CAP_DRV_NAME "vimc-capture" @@ -44,7 +45,7 @@ struct vimc_cap_device { spinlock_t qlock; struct mutex lock; u32 sequence; - struct media_pipeline pipe; + struct vimc_stream stream; }; static const struct v4l2_pix_format fmt_default = { @@ -69,12 +70,10 @@ struct vimc_cap_buffer { static int vimc_cap_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct vimc_cap_device *vcap = video_drvdata(file); - - strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); + strscpy(cap->driver, VIMC_PDEV_NAME, sizeof(cap->driver)); strscpy(cap->card, KBUILD_MODNAME, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), - "platform:%s", vcap->vdev.v4l2_dev->name); + "platform:%s", VIMC_PDEV_NAME); return 0; } @@ -248,14 +247,13 @@ static int vimc_cap_start_streaming(struct vb2_queue *vq, unsigned int count) vcap->sequence = 0; /* Start the media pipeline */ - ret = media_pipeline_start(entity, &vcap->pipe); + ret = media_pipeline_start(entity, &vcap->stream.pipe); if (ret) { vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_QUEUED); return ret; } - /* Enable streaming from the pipe */ - ret = vimc_pipeline_s_stream(&vcap->vdev.entity, 1); + ret = vimc_streamer_s_stream(&vcap->stream, &vcap->ved, 1); if (ret) { media_pipeline_stop(entity); vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_QUEUED); @@ -273,8 +271,7 @@ static void vimc_cap_stop_streaming(struct vb2_queue *vq) { struct vimc_cap_device *vcap = vb2_get_drv_priv(vq); - /* Disable streaming from the pipe */ - vimc_pipeline_s_stream(&vcap->vdev.entity, 0); + vimc_streamer_s_stream(&vcap->stream, &vcap->ved, 0); /* Stop the media pipeline */ media_pipeline_stop(&vcap->vdev.entity); @@ -355,8 +352,8 @@ static void vimc_cap_comp_unbind(struct device *comp, struct device *master, kfree(vcap); } -static void vimc_cap_process_frame(struct vimc_ent_device *ved, - struct media_pad *sink, const void *frame) +static void *vimc_cap_process_frame(struct vimc_ent_device *ved, + const void *frame) { struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, ved); @@ -370,7 +367,7 @@ static void vimc_cap_process_frame(struct vimc_ent_device *ved, typeof(*vimc_buf), list); if (!vimc_buf) { spin_unlock(&vcap->qlock); - return; + return ERR_PTR(-EAGAIN); } /* Remove this entry from the list */ @@ -391,6 +388,7 @@ static void vimc_cap_process_frame(struct vimc_ent_device *ved, vb2_set_plane_payload(&vimc_buf->vb2.vb2_buf, 0, vcap->format.sizeimage); vb2_buffer_done(&vimc_buf->vb2.vb2_buf, VB2_BUF_STATE_DONE); + return NULL; } static int vimc_cap_comp_bind(struct device *comp, struct device *master, @@ -431,7 +429,7 @@ static int vimc_cap_comp_bind(struct device *comp, struct device *master, /* Initialize the vb2 queue */ q = &vcap->queue; q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - q->io_modes = VB2_MMAP | VB2_DMABUF; + q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_USERPTR; q->drv_priv = vcap; q->buf_struct_size = sizeof(struct vimc_cap_buffer); q->ops = &vimc_cap_qops; diff --git a/drivers/media/platform/vimc/vimc-common.c b/drivers/media/platform/vimc/vimc-common.c index 867e24dbd6b5..c1a74bb2df58 100644 --- a/drivers/media/platform/vimc/vimc-common.c +++ b/drivers/media/platform/vimc/vimc-common.c @@ -207,41 +207,6 @@ const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat) } EXPORT_SYMBOL_GPL(vimc_pix_map_by_pixelformat); -int vimc_propagate_frame(struct media_pad *src, const void *frame) -{ - struct media_link *link; - - if (!(src->flags & MEDIA_PAD_FL_SOURCE)) - return -EINVAL; - - /* Send this frame to all sink pads that are direct linked */ - list_for_each_entry(link, &src->entity->links, list) { - if (link->source == src && - (link->flags & MEDIA_LNK_FL_ENABLED)) { - struct vimc_ent_device *ved = NULL; - struct media_entity *entity = link->sink->entity; - - if (is_media_entity_v4l2_subdev(entity)) { - struct v4l2_subdev *sd = - container_of(entity, struct v4l2_subdev, - entity); - ved = v4l2_get_subdevdata(sd); - } else if (is_media_entity_v4l2_video_device(entity)) { - struct video_device *vdev = - container_of(entity, - struct video_device, - entity); - ved = video_get_drvdata(vdev); - } - if (ved && ved->process_frame) - ved->process_frame(ved, link->sink, frame); - } - } - - return 0; -} -EXPORT_SYMBOL_GPL(vimc_propagate_frame); - /* Helper function to allocate and initialize pads */ struct media_pad *vimc_pads_init(u16 num_pads, const unsigned long *pads_flag) { diff --git a/drivers/media/platform/vimc/vimc-common.h b/drivers/media/platform/vimc/vimc-common.h index 2e9981b18166..84539430b5e7 100644 --- a/drivers/media/platform/vimc/vimc-common.h +++ b/drivers/media/platform/vimc/vimc-common.h @@ -22,6 +22,8 @@ #include <media/media-device.h> #include <media/v4l2-device.h> +#define VIMC_PDEV_NAME "vimc" + /* VIMC-specific controls */ #define VIMC_CID_VIMC_BASE (0x00f00000 | 0xf000) #define VIMC_CID_VIMC_CLASS (0x00f00000 | 1) @@ -113,24 +115,13 @@ struct vimc_pix_map { struct vimc_ent_device { struct media_entity *ent; struct media_pad *pads; - void (*process_frame)(struct vimc_ent_device *ved, - struct media_pad *sink, const void *frame); + void * (*process_frame)(struct vimc_ent_device *ved, + const void *frame); void (*vdev_get_format)(struct vimc_ent_device *ved, struct v4l2_pix_format *fmt); }; /** - * vimc_propagate_frame - propagate a frame through the topology - * - * @src: the source pad where the frame is being originated - * @frame: the frame to be propagated - * - * This function will call the process_frame callback from the vimc_ent_device - * struct of the nodes directly connected to the @src pad - */ -int vimc_propagate_frame(struct media_pad *src, const void *frame); - -/** * vimc_pads_init - initialize pads * * @num_pads: number of pads to initialize diff --git a/drivers/media/platform/vimc/vimc-core.c b/drivers/media/platform/vimc/vimc-core.c index ce809d2e3d53..0fbb7914098f 100644 --- a/drivers/media/platform/vimc/vimc-core.c +++ b/drivers/media/platform/vimc/vimc-core.c @@ -24,7 +24,6 @@ #include "vimc-common.h" -#define VIMC_PDEV_NAME "vimc" #define VIMC_MDEV_MODEL_NAME "VIMC MDEV" #define VIMC_ENT_LINK(src, srcpad, sink, sinkpad, link_flags) { \ @@ -221,6 +220,7 @@ static int vimc_comp_bind(struct device *master) err_mdev_unregister: media_device_unregister(&vimc->mdev); + media_device_cleanup(&vimc->mdev); err_comp_unbind_all: component_unbind_all(master, NULL); err_v4l2_unregister: @@ -237,6 +237,7 @@ static void vimc_comp_unbind(struct device *master) dev_dbg(master, "unbind"); media_device_unregister(&vimc->mdev); + media_device_cleanup(&vimc->mdev); component_unbind_all(master, NULL); v4l2_device_unregister(&vimc->v4l2_dev); } @@ -319,6 +320,8 @@ static int vimc_probe(struct platform_device *pdev) /* Initialize media device */ strscpy(vimc->mdev.model, VIMC_MDEV_MODEL_NAME, sizeof(vimc->mdev.model)); + snprintf(vimc->mdev.bus_info, sizeof(vimc->mdev.bus_info), + "platform:%s", VIMC_PDEV_NAME); vimc->mdev.dev = &pdev->dev; media_device_init(&vimc->mdev); diff --git a/drivers/media/platform/vimc/vimc-debayer.c b/drivers/media/platform/vimc/vimc-debayer.c index 77887f66f323..7d77c63b99d2 100644 --- a/drivers/media/platform/vimc/vimc-debayer.c +++ b/drivers/media/platform/vimc/vimc-debayer.c @@ -321,7 +321,6 @@ static void vimc_deb_set_rgb_mbus_fmt_rgb888_1x24(struct vimc_deb_device *vdeb, static int vimc_deb_s_stream(struct v4l2_subdev *sd, int enable) { struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); - int ret; if (enable) { const struct vimc_pix_map *vpix; @@ -351,22 +350,10 @@ static int vimc_deb_s_stream(struct v4l2_subdev *sd, int enable) if (!vdeb->src_frame) return -ENOMEM; - /* Turn the stream on in the subdevices directly connected */ - ret = vimc_pipeline_s_stream(&vdeb->sd.entity, 1); - if (ret) { - vfree(vdeb->src_frame); - vdeb->src_frame = NULL; - return ret; - } } else { if (!vdeb->src_frame) return 0; - /* Disable streaming from the pipe */ - ret = vimc_pipeline_s_stream(&vdeb->sd.entity, 0); - if (ret) - return ret; - vfree(vdeb->src_frame); vdeb->src_frame = NULL; } @@ -480,9 +467,8 @@ static void vimc_deb_calc_rgb_sink(struct vimc_deb_device *vdeb, } } -static void vimc_deb_process_frame(struct vimc_ent_device *ved, - struct media_pad *sink, - const void *sink_frame) +static void *vimc_deb_process_frame(struct vimc_ent_device *ved, + const void *sink_frame) { struct vimc_deb_device *vdeb = container_of(ved, struct vimc_deb_device, ved); @@ -491,7 +477,7 @@ static void vimc_deb_process_frame(struct vimc_ent_device *ved, /* If the stream in this node is not active, just return */ if (!vdeb->src_frame) - return; + return ERR_PTR(-EINVAL); for (i = 0; i < vdeb->sink_fmt.height; i++) for (j = 0; j < vdeb->sink_fmt.width; j++) { @@ -499,12 +485,8 @@ static void vimc_deb_process_frame(struct vimc_ent_device *ved, vdeb->set_rgb_src(vdeb, i, j, rgb); } - /* Propagate the frame through all source pads */ - for (i = 1; i < vdeb->sd.entity.num_pads; i++) { - struct media_pad *pad = &vdeb->sd.entity.pads[i]; + return vdeb->src_frame; - vimc_propagate_frame(pad, vdeb->src_frame); - } } static void vimc_deb_comp_unbind(struct device *comp, struct device *master, diff --git a/drivers/media/platform/vimc/vimc-scaler.c b/drivers/media/platform/vimc/vimc-scaler.c index b0952ee86296..39b2a73dfcc1 100644 --- a/drivers/media/platform/vimc/vimc-scaler.c +++ b/drivers/media/platform/vimc/vimc-scaler.c @@ -217,7 +217,6 @@ static const struct v4l2_subdev_pad_ops vimc_sca_pad_ops = { static int vimc_sca_s_stream(struct v4l2_subdev *sd, int enable) { struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd); - int ret; if (enable) { const struct vimc_pix_map *vpix; @@ -245,22 +244,10 @@ static int vimc_sca_s_stream(struct v4l2_subdev *sd, int enable) if (!vsca->src_frame) return -ENOMEM; - /* Turn the stream on in the subdevices directly connected */ - ret = vimc_pipeline_s_stream(&vsca->sd.entity, 1); - if (ret) { - vfree(vsca->src_frame); - vsca->src_frame = NULL; - return ret; - } } else { if (!vsca->src_frame) return 0; - /* Disable streaming from the pipe */ - ret = vimc_pipeline_s_stream(&vsca->sd.entity, 0); - if (ret) - return ret; - vfree(vsca->src_frame); vsca->src_frame = NULL; } @@ -346,26 +333,19 @@ static void vimc_sca_fill_src_frame(const struct vimc_sca_device *const vsca, vimc_sca_scale_pix(vsca, i, j, sink_frame); } -static void vimc_sca_process_frame(struct vimc_ent_device *ved, - struct media_pad *sink, - const void *sink_frame) +static void *vimc_sca_process_frame(struct vimc_ent_device *ved, + const void *sink_frame) { struct vimc_sca_device *vsca = container_of(ved, struct vimc_sca_device, ved); - unsigned int i; /* If the stream in this node is not active, just return */ if (!vsca->src_frame) - return; + return ERR_PTR(-EINVAL); vimc_sca_fill_src_frame(vsca, sink_frame); - /* Propagate the frame through all source pads */ - for (i = 1; i < vsca->sd.entity.num_pads; i++) { - struct media_pad *pad = &vsca->sd.entity.pads[i]; - - vimc_propagate_frame(pad, vsca->src_frame); - } + return vsca->src_frame; }; static void vimc_sca_comp_unbind(struct device *comp, struct device *master, diff --git a/drivers/media/platform/vimc/vimc-sensor.c b/drivers/media/platform/vimc/vimc-sensor.c index 32ca9c6172b1..59195f262623 100644 --- a/drivers/media/platform/vimc/vimc-sensor.c +++ b/drivers/media/platform/vimc/vimc-sensor.c @@ -16,8 +16,6 @@ */ #include <linux/component.h> -#include <linux/freezer.h> -#include <linux/kthread.h> #include <linux/module.h> #include <linux/mod_devicetable.h> #include <linux/platform_device.h> @@ -201,38 +199,20 @@ static const struct v4l2_subdev_pad_ops vimc_sen_pad_ops = { .set_fmt = vimc_sen_set_fmt, }; -static int vimc_sen_tpg_thread(void *data) +static void *vimc_sen_process_frame(struct vimc_ent_device *ved, + const void *sink_frame) { - struct vimc_sen_device *vsen = data; - unsigned int i; - - set_freezable(); - set_current_state(TASK_UNINTERRUPTIBLE); - - for (;;) { - try_to_freeze(); - if (kthread_should_stop()) - break; + struct vimc_sen_device *vsen = container_of(ved, struct vimc_sen_device, + ved); - tpg_fill_plane_buffer(&vsen->tpg, 0, 0, vsen->frame); - - /* Send the frame to all source pads */ - for (i = 0; i < vsen->sd.entity.num_pads; i++) - vimc_propagate_frame(&vsen->sd.entity.pads[i], - vsen->frame); - - /* 60 frames per second */ - schedule_timeout(HZ/60); - } - - return 0; + tpg_fill_plane_buffer(&vsen->tpg, 0, 0, vsen->frame); + return vsen->frame; } static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) { struct vimc_sen_device *vsen = container_of(sd, struct vimc_sen_device, sd); - int ret; if (enable) { const struct vimc_pix_map *vpix; @@ -258,26 +238,8 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) /* configure the test pattern generator */ vimc_sen_tpg_s_format(vsen); - /* Initialize the image generator thread */ - vsen->kthread_sen = kthread_run(vimc_sen_tpg_thread, vsen, - "%s-sen", vsen->sd.v4l2_dev->name); - if (IS_ERR(vsen->kthread_sen)) { - dev_err(vsen->dev, "%s: kernel_thread() failed\n", - vsen->sd.name); - vfree(vsen->frame); - vsen->frame = NULL; - return PTR_ERR(vsen->kthread_sen); - } } else { - if (!vsen->kthread_sen) - return 0; - - /* Stop image generator */ - ret = kthread_stop(vsen->kthread_sen); - if (ret) - return ret; - vsen->kthread_sen = NULL; vfree(vsen->frame); vsen->frame = NULL; return 0; @@ -413,6 +375,7 @@ static int vimc_sen_comp_bind(struct device *comp, struct device *master, if (ret) goto err_free_hdl; + vsen->ved.process_frame = vimc_sen_process_frame; dev_set_drvdata(comp, &vsen->ved); vsen->dev = comp; diff --git a/drivers/media/platform/vimc/vimc-streamer.c b/drivers/media/platform/vimc/vimc-streamer.c new file mode 100644 index 000000000000..fcc897fb247b --- /dev/null +++ b/drivers/media/platform/vimc/vimc-streamer.c @@ -0,0 +1,188 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * vimc-streamer.c Virtual Media Controller Driver + * + * Copyright (C) 2018 Lucas A. M. Magalhães <lucmaga@gmail.com> + * + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/freezer.h> +#include <linux/kthread.h> + +#include "vimc-streamer.h" + +/** + * vimc_get_source_entity - get the entity connected with the first sink pad + * + * @ent: reference media_entity + * + * Helper function that returns the media entity containing the source pad + * linked with the first sink pad from the given media entity pad list. + */ +static struct media_entity *vimc_get_source_entity(struct media_entity *ent) +{ + struct media_pad *pad; + int i; + + for (i = 0; i < ent->num_pads; i++) { + if (ent->pads[i].flags & MEDIA_PAD_FL_SOURCE) + continue; + pad = media_entity_remote_pad(&ent->pads[i]); + return pad ? pad->entity : NULL; + } + return NULL; +} + +/* + * vimc_streamer_pipeline_terminate - Disable stream in all ved in stream + * + * @stream: the pointer to the stream structure with the pipeline to be + * disabled. + * + * Calls s_stream to disable the stream in each entity of the pipeline + * + */ +static void vimc_streamer_pipeline_terminate(struct vimc_stream *stream) +{ + struct media_entity *entity; + struct v4l2_subdev *sd; + + while (stream->pipe_size) { + stream->pipe_size--; + entity = stream->ved_pipeline[stream->pipe_size]->ent; + entity = vimc_get_source_entity(entity); + stream->ved_pipeline[stream->pipe_size] = NULL; + + if (!is_media_entity_v4l2_subdev(entity)) + continue; + + sd = media_entity_to_v4l2_subdev(entity); + v4l2_subdev_call(sd, video, s_stream, 0); + } +} + +/* + * vimc_streamer_pipeline_init - initializes the stream structure + * + * @stream: the pointer to the stream structure to be initialized + * @ved: the pointer to the vimc entity initializing the stream + * + * Initializes the stream structure. Walks through the entity graph to + * construct the pipeline used later on the streamer thread. + * Calls s_stream to enable stream in all entities of the pipeline. + */ +static int vimc_streamer_pipeline_init(struct vimc_stream *stream, + struct vimc_ent_device *ved) +{ + struct media_entity *entity; + struct video_device *vdev; + struct v4l2_subdev *sd; + int ret = 0; + + stream->pipe_size = 0; + while (stream->pipe_size < VIMC_STREAMER_PIPELINE_MAX_SIZE) { + if (!ved) { + vimc_streamer_pipeline_terminate(stream); + return -EINVAL; + } + stream->ved_pipeline[stream->pipe_size++] = ved; + + entity = vimc_get_source_entity(ved->ent); + /* Check if the end of the pipeline was reached*/ + if (!entity) + return 0; + + if (is_media_entity_v4l2_subdev(entity)) { + sd = media_entity_to_v4l2_subdev(entity); + ret = v4l2_subdev_call(sd, video, s_stream, 1); + if (ret && ret != -ENOIOCTLCMD) { + vimc_streamer_pipeline_terminate(stream); + return ret; + } + ved = v4l2_get_subdevdata(sd); + } else { + vdev = container_of(entity, + struct video_device, + entity); + ved = video_get_drvdata(vdev); + } + } + + vimc_streamer_pipeline_terminate(stream); + return -EINVAL; +} + +static int vimc_streamer_thread(void *data) +{ + struct vimc_stream *stream = data; + int i; + + set_freezable(); + set_current_state(TASK_UNINTERRUPTIBLE); + + for (;;) { + try_to_freeze(); + if (kthread_should_stop()) + break; + + for (i = stream->pipe_size - 1; i >= 0; i--) { + stream->frame = stream->ved_pipeline[i]->process_frame( + stream->ved_pipeline[i], + stream->frame); + if (!stream->frame) + break; + if (IS_ERR(stream->frame)) + break; + } + //wait for 60hz + schedule_timeout(HZ / 60); + } + + return 0; +} + +int vimc_streamer_s_stream(struct vimc_stream *stream, + struct vimc_ent_device *ved, + int enable) +{ + int ret; + + if (!stream || !ved) + return -EINVAL; + + if (enable) { + if (stream->kthread) + return 0; + + ret = vimc_streamer_pipeline_init(stream, ved); + if (ret) + return ret; + + stream->kthread = kthread_run(vimc_streamer_thread, stream, + "vimc-streamer thread"); + + if (IS_ERR(stream->kthread)) + return PTR_ERR(stream->kthread); + + } else { + if (!stream->kthread) + return 0; + + ret = kthread_stop(stream->kthread); + if (ret) + return ret; + + stream->kthread = NULL; + + vimc_streamer_pipeline_terminate(stream); + } + + return 0; +} +EXPORT_SYMBOL_GPL(vimc_streamer_s_stream); + +MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC) Streamer"); +MODULE_AUTHOR("Lucas A. M. Magalhães <lucmaga@gmail.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/vimc/vimc-streamer.h b/drivers/media/platform/vimc/vimc-streamer.h new file mode 100644 index 000000000000..752af2e2d5a2 --- /dev/null +++ b/drivers/media/platform/vimc/vimc-streamer.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * vimc-streamer.h Virtual Media Controller Driver + * + * Copyright (C) 2018 Lucas A. M. Magalhães <lucmaga@gmail.com> + * + */ + +#ifndef _VIMC_STREAMER_H_ +#define _VIMC_STREAMER_H_ + +#include <media/media-device.h> + +#include "vimc-common.h" + +#define VIMC_STREAMER_PIPELINE_MAX_SIZE 16 + +struct vimc_stream { + struct media_pipeline pipe; + struct vimc_ent_device *ved_pipeline[VIMC_STREAMER_PIPELINE_MAX_SIZE]; + unsigned int pipe_size; + u8 *frame; + struct task_struct *kthread; +}; + +/** + * vimc_streamer_s_streamer - start/stop the stream + * + * @stream: the pointer to the stream to start or stop + * @ved: The last entity of the streamer pipeline + * @enable: any non-zero number start the stream, zero stop + * + */ +int vimc_streamer_s_stream(struct vimc_stream *stream, + struct vimc_ent_device *ved, + int enable); + +#endif //_VIMC_STREAMER_H_ diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index c931f007e5b0..342e0e6c103b 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c @@ -371,7 +371,7 @@ static int vidioc_s_parm(struct file *file, void *fh, if (vdev->vfl_dir == VFL_DIR_RX) return vivid_vid_cap_s_parm(file, fh, parm); - return vivid_vid_out_g_parm(file, fh, parm); + return -ENOTTY; } static int vidioc_log_status(struct file *file, void *fh) @@ -1094,7 +1094,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) q = &dev->vb_vid_cap_q; q->type = dev->multiplanar ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : V4L2_BUF_TYPE_VIDEO_CAPTURE; - q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; + q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; + if (!allocator) + q->io_modes |= VB2_USERPTR; q->drv_priv = dev; q->buf_struct_size = sizeof(struct vivid_buffer); q->ops = &vivid_vid_cap_qops; @@ -1115,7 +1117,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) q = &dev->vb_vid_out_q; q->type = dev->multiplanar ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : V4L2_BUF_TYPE_VIDEO_OUTPUT; - q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_WRITE; + q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_WRITE; + if (!allocator) + q->io_modes |= VB2_USERPTR; q->drv_priv = dev; q->buf_struct_size = sizeof(struct vivid_buffer); q->ops = &vivid_vid_out_qops; @@ -1136,7 +1140,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) q = &dev->vb_vbi_cap_q; q->type = dev->has_raw_vbi_cap ? V4L2_BUF_TYPE_VBI_CAPTURE : V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; - q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; + q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; + if (!allocator) + q->io_modes |= VB2_USERPTR; q->drv_priv = dev; q->buf_struct_size = sizeof(struct vivid_buffer); q->ops = &vivid_vbi_cap_qops; @@ -1157,7 +1163,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) q = &dev->vb_vbi_out_q; q->type = dev->has_raw_vbi_out ? V4L2_BUF_TYPE_VBI_OUTPUT : V4L2_BUF_TYPE_SLICED_VBI_OUTPUT; - q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_WRITE; + q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_WRITE; + if (!allocator) + q->io_modes |= VB2_USERPTR; q->drv_priv = dev; q->buf_struct_size = sizeof(struct vivid_buffer); q->ops = &vivid_vbi_out_qops; @@ -1177,7 +1185,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) /* initialize sdr_cap queue */ q = &dev->vb_sdr_cap_q; q->type = V4L2_BUF_TYPE_SDR_CAPTURE; - q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; + q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; + if (!allocator) + q->io_modes |= VB2_USERPTR; q->drv_priv = dev; q->buf_struct_size = sizeof(struct vivid_buffer); q->ops = &vivid_sdr_cap_qops; @@ -1468,9 +1478,6 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) return 0; unreg_dev: -#ifdef CONFIG_MEDIA_CONTROLLER - media_device_unregister(&dev->mdev); -#endif video_unregister_device(&dev->radio_tx_dev); video_unregister_device(&dev->radio_rx_dev); video_unregister_device(&dev->sdr_cap_dev); @@ -1543,6 +1550,7 @@ static int vivid_remove(struct platform_device *pdev) #ifdef CONFIG_MEDIA_CONTROLLER media_device_unregister(&dev->mdev); + media_device_cleanup(&dev->mdev); #endif if (dev->has_vid_cap) { diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index c059fc12668a..52eeda624d7e 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -124,7 +124,8 @@ static int vid_cap_queue_setup(struct vb2_queue *vq, } } else { for (p = 0; p < buffers; p++) - sizes[p] = tpg_g_line_width(&dev->tpg, p) * h + + sizes[p] = (tpg_g_line_width(&dev->tpg, p) * h) / + dev->fmt_cap->vdownsampling[p] + dev->fmt_cap->data_offset[p]; } @@ -161,7 +162,9 @@ static int vid_cap_buf_prepare(struct vb2_buffer *vb) return -EINVAL; } for (p = 0; p < buffers; p++) { - size = tpg_g_line_width(&dev->tpg, p) * dev->fmt_cap_rect.height + + size = (tpg_g_line_width(&dev->tpg, p) * + dev->fmt_cap_rect.height) / + dev->fmt_cap->vdownsampling[p] + dev->fmt_cap->data_offset[p]; if (vb2_plane_size(vb, p) < size) { @@ -545,7 +548,8 @@ int vivid_g_fmt_vid_cap(struct file *file, void *priv, for (p = 0; p < mp->num_planes; p++) { mp->plane_fmt[p].bytesperline = tpg_g_bytesperline(&dev->tpg, p); mp->plane_fmt[p].sizeimage = - tpg_g_line_width(&dev->tpg, p) * mp->height + + (tpg_g_line_width(&dev->tpg, p) * mp->height) / + dev->fmt_cap->vdownsampling[p] + dev->fmt_cap->data_offset[p]; } return 0; diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index 661f4015fba1..74b83bcc6119 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -169,6 +169,36 @@ struct vivid_fmt vivid_formats[] = { .alpha_mask = 0x000000ff, }, { + .fourcc = V4L2_PIX_FMT_AYUV32, + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0x000000ff, + }, + { + .fourcc = V4L2_PIX_FMT_XYUV32, + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_VUYA32, + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0xff000000, + }, + { + .fourcc = V4L2_PIX_FMT_VUYX32, + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, + }, + { .fourcc = V4L2_PIX_FMT_GREY, .vdownsampling = { 1 }, .bit_depth = { 8 }, diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index ea250aee2b2e..e61b91b414f9 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c @@ -28,11 +28,12 @@ static int vid_out_queue_setup(struct vb2_queue *vq, const struct vivid_fmt *vfmt = dev->fmt_out; unsigned planes = vfmt->buffers; unsigned h = dev->fmt_out_rect.height; - unsigned size = dev->bytesperline_out[0] * h; + unsigned int size = dev->bytesperline_out[0] * h + vfmt->data_offset[0]; unsigned p; for (p = vfmt->buffers; p < vfmt->planes; p++) - size += dev->bytesperline_out[p] * h / vfmt->vdownsampling[p]; + size += dev->bytesperline_out[p] * h / vfmt->vdownsampling[p] + + vfmt->data_offset[p]; if (dev->field_out == V4L2_FIELD_ALTERNATE) { /* @@ -62,12 +63,14 @@ static int vid_out_queue_setup(struct vb2_queue *vq, if (sizes[0] < size) return -EINVAL; for (p = 1; p < planes; p++) { - if (sizes[p] < dev->bytesperline_out[p] * h) + if (sizes[p] < dev->bytesperline_out[p] * h + + vfmt->data_offset[p]) return -EINVAL; } } else { for (p = 0; p < planes; p++) - sizes[p] = p ? dev->bytesperline_out[p] * h : size; + sizes[p] = p ? dev->bytesperline_out[p] * h + + vfmt->data_offset[p] : size; } if (vq->num_buffers + *nbuffers < 2) @@ -81,21 +84,38 @@ static int vid_out_queue_setup(struct vb2_queue *vq, return 0; } -static int vid_out_buf_prepare(struct vb2_buffer *vb) +static int vid_out_buf_out_validate(struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - unsigned long size; - unsigned planes; + + dprintk(dev, 1, "%s\n", __func__); + + if (dev->field_out != V4L2_FIELD_ALTERNATE) + vbuf->field = dev->field_out; + else if (vbuf->field != V4L2_FIELD_TOP && + vbuf->field != V4L2_FIELD_BOTTOM) + return -EINVAL; + return 0; +} + +static int vid_out_buf_prepare(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + const struct vivid_fmt *vfmt = dev->fmt_out; + unsigned int planes = vfmt->buffers; + unsigned int h = dev->fmt_out_rect.height; + unsigned int size = dev->bytesperline_out[0] * h; unsigned p; + for (p = vfmt->buffers; p < vfmt->planes; p++) + size += dev->bytesperline_out[p] * h / vfmt->vdownsampling[p]; + dprintk(dev, 1, "%s\n", __func__); if (WARN_ON(NULL == dev->fmt_out)) return -EINVAL; - planes = dev->fmt_out->planes; - if (dev->buf_prepare_error) { /* * Error injection: test what happens if buf_prepare() returns @@ -105,18 +125,13 @@ static int vid_out_buf_prepare(struct vb2_buffer *vb) return -EINVAL; } - if (dev->field_out != V4L2_FIELD_ALTERNATE) - vbuf->field = dev->field_out; - else if (vbuf->field != V4L2_FIELD_TOP && - vbuf->field != V4L2_FIELD_BOTTOM) - return -EINVAL; - for (p = 0; p < planes; p++) { - size = dev->bytesperline_out[p] * dev->fmt_out_rect.height + - vb->planes[p].data_offset; + if (p) + size = dev->bytesperline_out[p] * h; + size += vb->planes[p].data_offset; if (vb2_get_plane_payload(vb, p) < size) { - dprintk(dev, 1, "%s the payload is too small for plane %u (%lu < %lu)\n", + dprintk(dev, 1, "%s the payload is too small for plane %u (%lu < %u)\n", __func__, p, vb2_get_plane_payload(vb, p), size); return -EINVAL; } @@ -188,6 +203,7 @@ static void vid_out_buf_request_complete(struct vb2_buffer *vb) const struct vb2_ops vivid_vid_out_qops = { .queue_setup = vid_out_queue_setup, + .buf_out_validate = vid_out_buf_out_validate, .buf_prepare = vid_out_buf_prepare, .buf_queue = vid_out_buf_queue, .start_streaming = vid_out_start_streaming, @@ -321,7 +337,8 @@ int vivid_g_fmt_vid_out(struct file *file, void *priv, for (p = 0; p < mp->num_planes; p++) { mp->plane_fmt[p].bytesperline = dev->bytesperline_out[p]; mp->plane_fmt[p].sizeimage = - mp->plane_fmt[p].bytesperline * mp->height; + mp->plane_fmt[p].bytesperline * mp->height + + fmt->data_offset[p]; } for (p = fmt->buffers; p < fmt->planes; p++) { unsigned stride = dev->bytesperline_out[p]; @@ -399,7 +416,7 @@ int vivid_try_fmt_vid_out(struct file *file, void *priv, pfmt[p].bytesperline = bytesperline; pfmt[p].sizeimage = (pfmt[p].bytesperline * mp->height) / - fmt->vdownsampling[p]; + fmt->vdownsampling[p] + fmt->data_offset[p]; memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved)); } diff --git a/drivers/media/platform/vsp1/vsp1_brx.c b/drivers/media/platform/vsp1/vsp1_brx.c index 5e50178b057d..58ad248cd7f7 100644 --- a/drivers/media/platform/vsp1/vsp1_brx.c +++ b/drivers/media/platform/vsp1/vsp1_brx.c @@ -296,7 +296,7 @@ static void brx_configure_stream(struct vsp1_entity *entity, /* * The hardware is extremely flexible but we have no userspace API to * expose all the parameters, nor is it clear whether we would have use - * cases for all the supported modes. Let's just harcode the parameters + * cases for all the supported modes. Let's just hardcode the parameters * to sane default values for now. */ @@ -373,7 +373,7 @@ static void brx_configure_stream(struct vsp1_entity *entity, vsp1_brx_write(brx, dlb, VI6_BRU_CTRL(i), ctrl); /* - * Harcode the blending formula to + * Hardcode the blending formula to * * DSTc = DSTc * (1 - SRCa) + SRCc * SRCa * DSTa = DSTa * (1 - SRCa) + SRCa diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c index 8d86f618ec77..84895385d2e5 100644 --- a/drivers/media/platform/vsp1/vsp1_drm.c +++ b/drivers/media/platform/vsp1/vsp1_drm.c @@ -333,19 +333,19 @@ static int vsp1_du_pipeline_setup_brx(struct vsp1_device *vsp1, * on the BRx sink pad 0 and propagated inside the entity, not on the * source pad. */ - format.pad = pipe->brx->source_pad; + format.pad = brx->source_pad; format.format.width = drm_pipe->width; format.format.height = drm_pipe->height; format.format.field = V4L2_FIELD_NONE; - ret = v4l2_subdev_call(&pipe->brx->subdev, pad, set_fmt, NULL, + ret = v4l2_subdev_call(&brx->subdev, pad, set_fmt, NULL, &format); if (ret < 0) return ret; dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on %s pad %u\n", __func__, format.format.width, format.format.height, - format.format.code, BRX_NAME(pipe->brx), pipe->brx->source_pad); + format.format.code, BRX_NAME(brx), brx->source_pad); if (format.format.width != drm_pipe->width || format.format.height != drm_pipe->height) { diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index 771dfe1f7c20..7ceaf3222145 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c @@ -223,7 +223,7 @@ static void vsp1_video_calculate_partition(struct vsp1_pipeline *pipe, * If the modulus is less than half of the partition size, * the penultimate partition is reduced to half, which is added * to the final partition: |1234|1234|1234|12|341| - * to prevents this: |1234|1234|1234|1234|1|. + * to prevent this: |1234|1234|1234|1234|1|. */ if (modulus) { /* diff --git a/drivers/media/platform/xilinx/xilinx-vip.c b/drivers/media/platform/xilinx/xilinx-vip.c index 18f98838111b..08a825c3a3f6 100644 --- a/drivers/media/platform/xilinx/xilinx-vip.c +++ b/drivers/media/platform/xilinx/xilinx-vip.c @@ -166,7 +166,7 @@ EXPORT_SYMBOL_GPL(xvip_set_format_size); * the register, otherwise the bitmask is cleared from the register * when the flag @set is false. * - * Fox eample, this function can be used to set a control with a boolean value + * Fox example, this function can be used to set a control with a boolean value * requested by users. If the caller knows whether to set or clear in the first * place, the caller should call xvip_clr() or xvip_set() directly instead of * using this function. diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c index 269971145f88..0261f4d28f16 100644 --- a/drivers/media/radio/radio-si476x.c +++ b/drivers/media/radio/radio-si476x.c @@ -1550,7 +1550,7 @@ static int si476x_radio_probe(struct platform_device *pdev) rval = si476x_radio_init_debugfs(radio); if (rval < 0) { - dev_err(&pdev->dev, "Could not creat debugfs interface\n"); + dev_err(&pdev->dev, "Could not create debugfs interface\n"); goto exit; } diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index 9751ea1d80be..15eea2b2c90f 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -28,6 +28,7 @@ #include <linux/i2c.h> #include <linux/slab.h> #include <linux/delay.h> +#include <linux/gpio/consumer.h> #include <linux/interrupt.h> #include "radio-si470x.h" @@ -350,7 +351,7 @@ static int si470x_i2c_probe(struct i2c_client *client, unsigned char version_warning = 0; /* private data allocation and initialization */ - radio = kzalloc(sizeof(struct si470x_device), GFP_KERNEL); + radio = devm_kzalloc(&client->dev, sizeof(*radio), GFP_KERNEL); if (!radio) { retval = -ENOMEM; goto err_initial; @@ -370,7 +371,7 @@ static int si470x_i2c_probe(struct i2c_client *client, retval = v4l2_device_register(&client->dev, &radio->v4l2_dev); if (retval < 0) { dev_err(&client->dev, "couldn't register v4l2_device\n"); - goto err_radio; + goto err_initial; } v4l2_ctrl_handler_init(&radio->hdl, 2); @@ -392,18 +393,29 @@ static int si470x_i2c_probe(struct i2c_client *client, radio->videodev.release = video_device_release_empty; video_set_drvdata(&radio->videodev, radio); + radio->gpio_reset = devm_gpiod_get_optional(&client->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(radio->gpio_reset)) { + retval = PTR_ERR(radio->gpio_reset); + dev_err(&client->dev, "Failed to request gpio: %d\n", retval); + goto err_all; + } + + if (radio->gpio_reset) + gpiod_set_value(radio->gpio_reset, 1); + /* power up : need 110ms */ radio->registers[POWERCFG] = POWERCFG_ENABLE; if (si470x_set_register(radio, POWERCFG) < 0) { retval = -EIO; - goto err_ctrl; + goto err_all; } msleep(110); /* get device and chip versions */ if (si470x_get_all_registers(radio) < 0) { retval = -EIO; - goto err_ctrl; + goto err_all; } dev_info(&client->dev, "DeviceID=0x%4.4hx ChipID=0x%4.4hx\n", radio->registers[DEVICEID], radio->registers[SI_CHIPID]); @@ -430,10 +442,10 @@ static int si470x_i2c_probe(struct i2c_client *client, /* rds buffer allocation */ radio->buf_size = rds_buf * 3; - radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); + radio->buffer = devm_kmalloc(&client->dev, radio->buf_size, GFP_KERNEL); if (!radio->buffer) { retval = -EIO; - goto err_ctrl; + goto err_all; } /* rds buffer configuration */ @@ -441,12 +453,13 @@ static int si470x_i2c_probe(struct i2c_client *client, radio->rd_index = 0; init_waitqueue_head(&radio->read_queue); - retval = request_threaded_irq(client->irq, NULL, si470x_i2c_interrupt, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, DRIVER_NAME, - radio); + retval = devm_request_threaded_irq(&client->dev, client->irq, NULL, + si470x_i2c_interrupt, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + DRIVER_NAME, radio); if (retval) { dev_err(&client->dev, "Failed to register interrupt\n"); - goto err_rds; + goto err_all; } /* register video device */ @@ -460,15 +473,9 @@ static int si470x_i2c_probe(struct i2c_client *client, return 0; err_all: - free_irq(client->irq, radio); -err_rds: - kfree(radio->buffer); -err_ctrl: v4l2_ctrl_handler_free(&radio->hdl); err_dev: v4l2_device_unregister(&radio->v4l2_dev); -err_radio: - kfree(radio); err_initial: return retval; } @@ -481,9 +488,10 @@ static int si470x_i2c_remove(struct i2c_client *client) { struct si470x_device *radio = i2c_get_clientdata(client); - free_irq(client->irq, radio); video_unregister_device(&radio->videodev); - kfree(radio); + + if (radio->gpio_reset) + gpiod_set_value(radio->gpio_reset, 0); return 0; } @@ -527,6 +535,13 @@ static int si470x_i2c_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(si470x_i2c_pm, si470x_i2c_suspend, si470x_i2c_resume); #endif +#if IS_ENABLED(CONFIG_OF) +static const struct of_device_id si470x_of_match[] = { + { .compatible = "silabs,si470x" }, + { }, +}; +MODULE_DEVICE_TABLE(of, si470x_of_match); +#endif /* * si470x_i2c_driver - i2c driver interface @@ -534,6 +549,7 @@ static SIMPLE_DEV_PM_OPS(si470x_i2c_pm, si470x_i2c_suspend, si470x_i2c_resume); static struct i2c_driver si470x_i2c_driver = { .driver = { .name = "si470x", + .of_match_table = of_match_ptr(si470x_of_match), #ifdef CONFIG_PM_SLEEP .pm = &si470x_i2c_pm, #endif diff --git a/drivers/media/radio/si470x/radio-si470x.h b/drivers/media/radio/si470x/radio-si470x.h index 35fa0f3bbdd2..6fd6a399cb77 100644 --- a/drivers/media/radio/si470x/radio-si470x.h +++ b/drivers/media/radio/si470x/radio-si470x.h @@ -189,6 +189,7 @@ struct si470x_device { #if IS_ENABLED(CONFIG_I2C_SI470X) struct i2c_client *client; + struct gpio_desc *gpio_reset; #endif }; diff --git a/drivers/media/radio/wl128x/fmdrv.h b/drivers/media/radio/wl128x/fmdrv.h index 1ff2eec4ed52..4c0d13539988 100644 --- a/drivers/media/radio/wl128x/fmdrv.h +++ b/drivers/media/radio/wl128x/fmdrv.h @@ -133,7 +133,7 @@ struct fm_rds { /* * Current RX channel Alternate Frequency cache. * This info is used to switch to other freq (AF) - * when current channel signal strengh is below RSSI threshold. + * when current channel signal strength is below RSSI threshold. */ struct tuned_station_info { u16 picode; @@ -228,7 +228,7 @@ struct fmdev { struct fm_rx rx; /* FM receiver info */ struct fmtx_data tx_data; - /* V4L2 ctrl framwork handler*/ + /* V4L2 ctrl framework handler*/ struct v4l2_ctrl_handler ctrl_handler; /* For core assisted locking */ diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c index 800d69c3f80b..3c8987af3772 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.c +++ b/drivers/media/radio/wl128x/fmdrv_common.c @@ -908,7 +908,7 @@ static void fm_irq_afjump_setfreq(struct fmdev *fmdev) u16 frq_index; u16 payload; - fmdbg("Swtich to %d KHz\n", fmdev->rx.stat_info.af_cache[fmdev->rx.afjump_idx]); + fmdbg("Switch to %d KHz\n", fmdev->rx.stat_info.af_cache[fmdev->rx.afjump_idx]); frq_index = (fmdev->rx.stat_info.af_cache[fmdev->rx.afjump_idx] - fmdev->rx.region.bot_freq) / FM_FREQ_MUL; @@ -1047,7 +1047,7 @@ static void fm_irq_handle_intmsk_cmd_resp(struct fmdev *fmdev) clear_bit(FM_INTTASK_RUNNING, &fmdev->flag); } -/* Returns availability of RDS data in internel buffer */ +/* Returns availability of RDS data in internal buffer */ int fmc_is_rds_data_available(struct fmdev *fmdev, struct file *file, struct poll_table_struct *pts) { diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 8a216068a35a..96ce3e5524e0 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -133,6 +133,19 @@ config IR_IMON_DECODER remote control and you would like to use it with a raw IR receiver, or if you wish to use an encoder to transmit this IR. +config IR_RCMM_DECODER + tristate "Enable IR raw decoder for the RC-MM protocol" + depends on RC_CORE + help + Enable this option when you have IR with RC-MM protocol, and + you need the software decoder. The driver supports 12, + 24 and 32 bits RC-MM variants. You can enable or disable the + different modes using the following RC protocol keywords: + 'rc-mm-12', 'rc-mm-24' and 'rc-mm-32'. + + To compile this driver as a module, choose M here: the module + will be called ir-rcmm-decoder. + endif #RC_DECODERS menuconfig RC_DEVICES @@ -240,7 +253,7 @@ config IR_FINTEK depends on RC_CORE ---help--- Say Y here to enable support for integrated infrared receiver - /transciever made by Fintek. This chip is found on assorted + /transceiver made by Fintek. This chip is found on assorted Jetway motherboards (and of course, possibly others). To compile this driver as a module, choose M here: the @@ -274,7 +287,7 @@ config IR_NUVOTON depends on RC_CORE ---help--- Say Y here to enable support for integrated infrared receiver - /transciever made by Nuvoton (formerly Winbond). This chip is + /transceiver made by Nuvoton (formerly Winbond). This chip is found in the ASRock ION 330HT, as well as assorted Intel DP55-series motherboards (and of course, possibly others). diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index 92c163816849..48d23433b3c0 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_IR_SHARP_DECODER) += ir-sharp-decoder.o obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o obj-$(CONFIG_IR_XMP_DECODER) += ir-xmp-decoder.o obj-$(CONFIG_IR_IMON_DECODER) += ir-imon-decoder.o +obj-$(CONFIG_IR_RCMM_DECODER) += ir-rcmm-decoder.o # stand-alone IR receivers/transmitters obj-$(CONFIG_RC_ATI_REMOTE) += ati_remote.o diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c index 265e91a2a70d..bc2da64858c3 100644 --- a/drivers/media/rc/ati_remote.c +++ b/drivers/media/rc/ati_remote.c @@ -304,7 +304,7 @@ static const struct { {KIND_LITERAL, 0x7c, BTN_RIGHT},/* right btn down */ {KIND_LITERAL, 0x7d, BTN_RIGHT},/* right btn up */ - /* Artificial "doubleclick" events are generated by the hardware. + /* Artificial "double-click" events are generated by the hardware. * They are mapped to the "side" and "extra" mouse buttons here. */ {KIND_FILTERED, 0x7a, BTN_SIDE}, /* left dblclick */ {KIND_FILTERED, 0x7e, BTN_EXTRA},/* right dblclick */ diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c index dd2fd307ef85..293ccee2c05e 100644 --- a/drivers/media/rc/ene_ir.c +++ b/drivers/media/rc/ene_ir.c @@ -184,7 +184,7 @@ static int ene_hw_detect(struct ene_device *dev) return 0; } -/* Read properities of hw sample buffer */ +/* Read properties of hw sample buffer */ static void ene_rx_setup_hw_buffer(struct ene_device *dev) { u16 tmp; diff --git a/drivers/media/rc/ene_ir.h b/drivers/media/rc/ene_ir.h index 494646b2a284..0a45352efe40 100644 --- a/drivers/media/rc/ene_ir.h +++ b/drivers/media/rc/ene_ir.h @@ -118,7 +118,7 @@ #define ENE_CIRDAT_IN 0xFEC7 -/* RLC configuration - sample period (1us resulution) + idle mode */ +/* RLC configuration - sample period (1us resolution) + idle mode */ #define ENE_CIRRLC_CFG 0xFEC8 #define ENE_CIRRLC_CFG_OVERFLOW 0x80 /* interrupt on overflows if set */ #define ENE_DEFAULT_SAMPLE_PERIOD 50 diff --git a/drivers/media/rc/fintek-cir.h b/drivers/media/rc/fintek-cir.h index ac34a774d018..dffe0bbfc6eb 100644 --- a/drivers/media/rc/fintek-cir.h +++ b/drivers/media/rc/fintek-cir.h @@ -176,7 +176,7 @@ struct fintek_dev { #define CIR_CR_IRCS 0x05 /* Before host writes command to IR, host must set to 1. When host finshes write command to IR, host must clear to 0. */ -#define CIR_CR_COMMAND_DATA 0x06 /* Host read or write comand data */ +#define CIR_CR_COMMAND_DATA 0x06 /* Host read or write command data */ #define CIR_CR_CLASS 0x07 /* 0xff = rx-only, 0x66 = rx + 2 tx, 0x33 = rx + 1 tx */ #define CIR_CR_DEV_EN 0x30 /* bit0 = 1 enables CIR */ diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c index d96aed1343e4..5cc302fa4daa 100644 --- a/drivers/media/rc/ir-rc6-decoder.c +++ b/drivers/media/rc/ir-rc6-decoder.c @@ -40,6 +40,7 @@ #define RC6_6A_MCE_TOGGLE_MASK 0x8000 /* for the body bits */ #define RC6_6A_LCC_MASK 0xffff0000 /* RC6-6A-32 long customer code mask */ #define RC6_6A_MCE_CC 0x800f0000 /* MCE customer code */ +#define RC6_6A_ZOTAC_CC 0x80340000 /* Zotac customer code */ #define RC6_6A_KATHREIN_CC 0x80460000 /* Kathrein RCU-676 customer code */ #ifndef CHAR_BIT #define CHAR_BIT 8 /* Normally in <limits.h> */ @@ -246,6 +247,7 @@ again: switch (scancode & RC6_6A_LCC_MASK) { case RC6_6A_MCE_CC: case RC6_6A_KATHREIN_CC: + case RC6_6A_ZOTAC_CC: protocol = RC_PROTO_RC6_MCE; toggle = !!(scancode & RC6_6A_MCE_TOGGLE_MASK); scancode &= ~RC6_6A_MCE_TOGGLE_MASK; diff --git a/drivers/media/rc/ir-rcmm-decoder.c b/drivers/media/rc/ir-rcmm-decoder.c new file mode 100644 index 000000000000..f1096ac1e5c5 --- /dev/null +++ b/drivers/media/rc/ir-rcmm-decoder.c @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: GPL-2.0+ +// ir-rcmm-decoder.c - A decoder for the RCMM IR protocol +// +// Copyright (C) 2018 by Patrick Lerda <patrick9876@free.fr> + +#include "rc-core-priv.h" +#include <linux/module.h> +#include <linux/version.h> + +#define RCMM_UNIT 166667 /* nanosecs */ +#define RCMM_PREFIX_PULSE 416666 /* 166666.666666666*2.5 */ +#define RCMM_PULSE_0 277777 /* 166666.666666666*(1+2/3) */ +#define RCMM_PULSE_1 444444 /* 166666.666666666*(2+2/3) */ +#define RCMM_PULSE_2 611111 /* 166666.666666666*(3+2/3) */ +#define RCMM_PULSE_3 777778 /* 166666.666666666*(4+2/3) */ + +enum rcmm_state { + STATE_INACTIVE, + STATE_LOW, + STATE_BUMP, + STATE_VALUE, + STATE_FINISHED, +}; + +static bool rcmm_mode(const struct rcmm_dec *data) +{ + return !((0x000c0000 & data->bits) == 0x000c0000); +} + +static int rcmm_miscmode(struct rc_dev *dev, struct rcmm_dec *data) +{ + switch (data->count) { + case 24: + if (dev->enabled_protocols & RC_PROTO_BIT_RCMM24) { + rc_keydown(dev, RC_PROTO_RCMM24, data->bits, 0); + data->state = STATE_INACTIVE; + return 0; + } + return -1; + + case 12: + if (dev->enabled_protocols & RC_PROTO_BIT_RCMM12) { + rc_keydown(dev, RC_PROTO_RCMM12, data->bits, 0); + data->state = STATE_INACTIVE; + return 0; + } + return -1; + } + + return -1; +} + +/** + * ir_rcmm_decode() - Decode one RCMM pulse or space + * @dev: the struct rc_dev descriptor of the device + * @ev: the struct ir_raw_event descriptor of the pulse/space + * + * This function returns -EINVAL if the pulse violates the state machine + */ +static int ir_rcmm_decode(struct rc_dev *dev, struct ir_raw_event ev) +{ + struct rcmm_dec *data = &dev->raw->rcmm; + u32 scancode; + u8 toggle; + int value; + + if (!(dev->enabled_protocols & (RC_PROTO_BIT_RCMM32 | + RC_PROTO_BIT_RCMM24 | + RC_PROTO_BIT_RCMM12))) + return 0; + + if (!is_timing_event(ev)) { + if (ev.reset) + data->state = STATE_INACTIVE; + return 0; + } + + switch (data->state) { + case STATE_INACTIVE: + if (!ev.pulse) + break; + + if (!eq_margin(ev.duration, RCMM_PREFIX_PULSE, RCMM_UNIT / 2)) + break; + + data->state = STATE_LOW; + data->count = 0; + data->bits = 0; + return 0; + + case STATE_LOW: + if (ev.pulse) + break; + + if (!eq_margin(ev.duration, RCMM_PULSE_0, RCMM_UNIT / 2)) + break; + + data->state = STATE_BUMP; + return 0; + + case STATE_BUMP: + if (!ev.pulse) + break; + + if (!eq_margin(ev.duration, RCMM_UNIT, RCMM_UNIT / 2)) + break; + + data->state = STATE_VALUE; + return 0; + + case STATE_VALUE: + if (ev.pulse) + break; + + if (eq_margin(ev.duration, RCMM_PULSE_0, RCMM_UNIT / 2)) + value = 0; + else if (eq_margin(ev.duration, RCMM_PULSE_1, RCMM_UNIT / 2)) + value = 1; + else if (eq_margin(ev.duration, RCMM_PULSE_2, RCMM_UNIT / 2)) + value = 2; + else if (eq_margin(ev.duration, RCMM_PULSE_3, RCMM_UNIT / 2)) + value = 3; + else + value = -1; + + if (value == -1) { + if (!rcmm_miscmode(dev, data)) + return 0; + break; + } + + data->bits <<= 2; + data->bits |= value; + + data->count += 2; + + if (data->count < 32) + data->state = STATE_BUMP; + else + data->state = STATE_FINISHED; + + return 0; + + case STATE_FINISHED: + if (!ev.pulse) + break; + + if (!eq_margin(ev.duration, RCMM_UNIT, RCMM_UNIT / 2)) + break; + + if (rcmm_mode(data)) { + toggle = !!(0x8000 & data->bits); + scancode = data->bits & ~0x8000; + } else { + toggle = 0; + scancode = data->bits; + } + + if (dev->enabled_protocols & RC_PROTO_BIT_RCMM32) { + rc_keydown(dev, RC_PROTO_RCMM32, scancode, toggle); + data->state = STATE_INACTIVE; + return 0; + } + + break; + } + + data->state = STATE_INACTIVE; + return -EINVAL; +} + +static const int rcmmspace[] = { + RCMM_PULSE_0, + RCMM_PULSE_1, + RCMM_PULSE_2, + RCMM_PULSE_3, +}; + +static int ir_rcmm_rawencoder(struct ir_raw_event **ev, unsigned int max, + unsigned int n, u32 data) +{ + int i; + int ret; + + ret = ir_raw_gen_pulse_space(ev, &max, RCMM_PREFIX_PULSE, RCMM_PULSE_0); + if (ret) + return ret; + + for (i = n - 2; i >= 0; i -= 2) { + const unsigned int space = rcmmspace[(data >> i) & 3]; + + ret = ir_raw_gen_pulse_space(ev, &max, RCMM_UNIT, space); + if (ret) + return ret; + } + + return ir_raw_gen_pulse_space(ev, &max, RCMM_UNIT, RCMM_PULSE_3 * 2); +} + +static int ir_rcmm_encode(enum rc_proto protocol, u32 scancode, + struct ir_raw_event *events, unsigned int max) +{ + struct ir_raw_event *e = events; + int ret; + + switch (protocol) { + case RC_PROTO_RCMM32: + ret = ir_rcmm_rawencoder(&e, max, 32, scancode); + break; + case RC_PROTO_RCMM24: + ret = ir_rcmm_rawencoder(&e, max, 24, scancode); + break; + case RC_PROTO_RCMM12: + ret = ir_rcmm_rawencoder(&e, max, 12, scancode); + break; + default: + ret = -EINVAL; + } + + if (ret < 0) + return ret; + + return e - events; +} + +static struct ir_raw_handler rcmm_handler = { + .protocols = RC_PROTO_BIT_RCMM32 | + RC_PROTO_BIT_RCMM24 | + RC_PROTO_BIT_RCMM12, + .decode = ir_rcmm_decode, + .encode = ir_rcmm_encode, + .carrier = 36000, + .min_timeout = RCMM_PULSE_3 + RCMM_UNIT, +}; + +static int __init ir_rcmm_decode_init(void) +{ + ir_raw_handler_register(&rcmm_handler); + + pr_info("IR RCMM protocol handler initialized\n"); + return 0; +} + +static void __exit ir_rcmm_decode_exit(void) +{ + ir_raw_handler_unregister(&rcmm_handler); +} + +module_init(ir_rcmm_decode_init); +module_exit(ir_rcmm_decode_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Patrick Lerda"); +MODULE_DESCRIPTION("RCMM IR protocol decoder"); diff --git a/drivers/media/rc/ir-xmp-decoder.c b/drivers/media/rc/ir-xmp-decoder.c index c965f51df1c1..2639b0b6d2f8 100644 --- a/drivers/media/rc/ir-xmp-decoder.c +++ b/drivers/media/rc/ir-xmp-decoder.c @@ -94,7 +94,7 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev) n = data->durations; /* * the 4th nibble should be 15 so base the divider on this - * to transform durations into nibbles. Substract 2000 from + * to transform durations into nibbles. Subtract 2000 from * the divider to compensate for fluctuations in the signal */ divider = (n[3] - XMP_NIBBLE_PREFIX) / 15 - 2000; diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c index cd3c60ba8519..1d48a9e59f93 100644 --- a/drivers/media/rc/ite-cir.c +++ b/drivers/media/rc/ite-cir.c @@ -515,7 +515,7 @@ static int ite_tx_ir(struct rc_dev *rcdev, unsigned *txbuf, unsigned n) /* and set the carrier values for reception */ ite_set_carrier_params(dev); - /* reenable the receiver */ + /* re-enable the receiver */ if (dev->in_use) dev->params.enable_rx(dev); diff --git a/drivers/media/rc/keymaps/rc-behold-columbus.c b/drivers/media/rc/keymaps/rc-behold-columbus.c index e73057945bd1..b68380a76010 100644 --- a/drivers/media/rc/keymaps/rc-behold-columbus.c +++ b/drivers/media/rc/keymaps/rc-behold-columbus.c @@ -14,7 +14,7 @@ * The "ascii-art picture" below (in comments, first row * is the keycode in hex, and subsequent row(s) shows * the button labels (several variants when appropriate) - * helps to descide which keycodes to assign to the buttons. + * helps to decide which keycodes to assign to the buttons. */ static struct rc_map_table behold_columbus[] = { @@ -68,7 +68,7 @@ static struct rc_map_table behold_columbus[] = { { 0x18, KEY_VOLUMEDOWN }, /* 0x0E 0x1E 0x0F 0x1A * - * Stop Pause Previouse Next * + * Stop Pause Previous Next * * */ { 0x0E, KEY_STOP }, diff --git a/drivers/media/rc/keymaps/rc-behold.c b/drivers/media/rc/keymaps/rc-behold.c index e1b2c8e26883..2b7cddb2f36d 100644 --- a/drivers/media/rc/keymaps/rc-behold.c +++ b/drivers/media/rc/keymaps/rc-behold.c @@ -17,7 +17,7 @@ * The "ascii-art picture" below (in comments, first row * is the keycode in hex, and subsequent row(s) shows * the button labels (several variants when appropriate) - * helps to descide which keycodes to assign to the buttons. + * helps to decide which keycodes to assign to the buttons. */ static struct rc_map_table behold[] = { diff --git a/drivers/media/rc/keymaps/rc-manli.c b/drivers/media/rc/keymaps/rc-manli.c index 29c9feaf413b..5e9a49e2dd6a 100644 --- a/drivers/media/rc/keymaps/rc-manli.c +++ b/drivers/media/rc/keymaps/rc-manli.c @@ -14,7 +14,7 @@ The "ascii-art picture" below (in comments, first row is the keycode in hex, and subsequent row(s) shows the button labels (several variants when appropriate) - helps to descide which keycodes to assign to the buttons. + helps to decide which keycodes to assign to the buttons. */ static struct rc_map_table manli[] = { diff --git a/drivers/media/rc/keymaps/rc-powercolor-real-angel.c b/drivers/media/rc/keymaps/rc-powercolor-real-angel.c index 4988e71c524c..cf98cf8dc13c 100644 --- a/drivers/media/rc/keymaps/rc-powercolor-real-angel.c +++ b/drivers/media/rc/keymaps/rc-powercolor-real-angel.c @@ -26,7 +26,7 @@ static struct rc_map_table powercolor_real_angel[] = { { 0x07, KEY_7 }, { 0x08, KEY_8 }, { 0x09, KEY_9 }, - { 0x0a, KEY_DIGITS }, /* single, double, tripple digit */ + { 0x0a, KEY_DIGITS }, /* single, double, triple digit */ { 0x29, KEY_PREVIOUS }, /* previous channel */ { 0x12, KEY_BRIGHTNESSUP }, { 0x13, KEY_BRIGHTNESSDOWN }, diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 8d7d3ef88862..fa4840940486 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -79,7 +79,7 @@ #define MCE_CMD 0x1f #define MCE_PORT_IR 0x4 /* (0x4 << 5) | MCE_CMD = 0x9f */ #define MCE_PORT_SYS 0x7 /* (0x7 << 5) | MCE_CMD = 0xff */ -#define MCE_PORT_SER 0x6 /* 0xc0 thru 0xdf flush & 0x1f bytes */ +#define MCE_PORT_SER 0x6 /* 0xc0 through 0xdf flush & 0x1f bytes */ #define MCE_PORT_MASK 0xe0 /* Mask out command bits */ /* Command port headers */ diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index c2cbe7f6266c..9f21b3e8b377 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -131,6 +131,11 @@ struct ir_raw_event_ctrl { unsigned int bits; bool stick_keyboard; } imon; + struct rcmm_dec { + int state; + unsigned int count; + u32 bits; + } rcmm; }; /* Mutex for locking raw IR processing and handler change */ diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c index e10b4644a442..39dd46bbd0c1 100644 --- a/drivers/media/rc/rc-ir-raw.c +++ b/drivers/media/rc/rc-ir-raw.c @@ -186,7 +186,7 @@ int ir_raw_event_store_with_filter(struct rc_dev *dev, struct ir_raw_event *ev) dev->raw->this_ev = *ev; } - /* Enter idle mode if nessesary */ + /* Enter idle mode if necessary */ if (!ev->pulse && dev->timeout && dev->raw->this_ev.duration >= dev->timeout) ir_raw_event_set_idle(dev, true); diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 66a174979b3c..e8fa28e20192 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -70,6 +70,12 @@ static const struct { [RC_PROTO_CEC] = { .name = "cec", .repeat_period = 0 }, [RC_PROTO_IMON] = { .name = "imon", .scancode_bits = 0x7fffffff, .repeat_period = 114 }, + [RC_PROTO_RCMM12] = { .name = "rc-mm-12", + .scancode_bits = 0x00000fff, .repeat_period = 114 }, + [RC_PROTO_RCMM24] = { .name = "rc-mm-24", + .scancode_bits = 0x00ffffff, .repeat_period = 114 }, + [RC_PROTO_RCMM32] = { .name = "rc-mm-32", + .scancode_bits = 0xffffffff, .repeat_period = 114 }, }; /* Used to keep track of known keymaps */ @@ -274,6 +280,7 @@ static unsigned int ir_update_mapping(struct rc_dev *dev, unsigned int new_keycode) { int old_keycode = rc_map->scan[index].keycode; + int i; /* Did the user wish to remove the mapping? */ if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) { @@ -288,9 +295,20 @@ static unsigned int ir_update_mapping(struct rc_dev *dev, old_keycode == KEY_RESERVED ? "New" : "Replacing", rc_map->scan[index].scancode, new_keycode); rc_map->scan[index].keycode = new_keycode; + __set_bit(new_keycode, dev->input_dev->keybit); } if (old_keycode != KEY_RESERVED) { + /* A previous mapping was updated... */ + __clear_bit(old_keycode, dev->input_dev->keybit); + /* ... but another scancode might use the same keycode */ + for (i = 0; i < rc_map->len; i++) { + if (rc_map->scan[i].keycode == old_keycode) { + __set_bit(old_keycode, dev->input_dev->keybit); + break; + } + } + /* Possibly shrink the keytable, failure is not a problem */ ir_resize_table(dev, rc_map, GFP_ATOMIC); } @@ -1006,6 +1024,9 @@ static const struct { { RC_PROTO_BIT_XMP, "xmp", "ir-xmp-decoder" }, { RC_PROTO_BIT_CEC, "cec", NULL }, { RC_PROTO_BIT_IMON, "imon", "ir-imon-decoder" }, + { RC_PROTO_BIT_RCMM12 | + RC_PROTO_BIT_RCMM24 | + RC_PROTO_BIT_RCMM32, "rc-mm", "ir-rcmm-decoder" }, }; /** @@ -1035,7 +1056,7 @@ struct rc_filter_attribute { * @buf: a pointer to the output buffer * * This routine is a callback routine for input read the IR protocol type(s). - * it is trigged by reading /sys/class/rc/rc?/protocols. + * it is triggered by reading /sys/class/rc/rc?/protocols. * It returns the protocol names of supported protocols. * Enabled protocols are printed in brackets. * @@ -1206,7 +1227,7 @@ void ir_raw_load_modules(u64 *protocols) * @len: length of the input buffer * * This routine is for changing the IR protocol type. - * It is trigged by writing to /sys/class/rc/rc?/[wakeup_]protocols. + * It is triggered by writing to /sys/class/rc/rc?/[wakeup_]protocols. * See parse_protocol_change() for the valid commands. * Returns @len on success or a negative error code. * @@ -1290,7 +1311,7 @@ out: * @buf: a pointer to the output buffer * * This routine is a callback routine to read a scancode filter value or mask. - * It is trigged by reading /sys/class/rc/rc?/[wakeup_]filter[_mask]. + * It is triggered by reading /sys/class/rc/rc?/[wakeup_]filter[_mask]. * It prints the current scancode filter value or mask of the appropriate filter * type in hexadecimal into @buf and returns the size of the buffer. * @@ -1333,7 +1354,7 @@ static ssize_t show_filter(struct device *device, * @len: length of the input buffer * * This routine is for changing a scancode filter value or mask. - * It is trigged by writing to /sys/class/rc/rc?/[wakeup_]filter[_mask]. + * It is triggered by writing to /sys/class/rc/rc?/[wakeup_]filter[_mask]. * Returns -EINVAL if an invalid filter value for the current protocol was * specified or if scancode filtering is not supported by the driver, otherwise * returns @len. @@ -1417,7 +1438,7 @@ unlock: * @buf: a pointer to the output buffer * * This routine is a callback routine for input read the IR protocol type(s). - * it is trigged by reading /sys/class/rc/rc?/wakeup_protocols. + * it is triggered by reading /sys/class/rc/rc?/wakeup_protocols. * It returns the protocol names of supported protocols. * The enabled protocols are printed in brackets. * @@ -1468,7 +1489,7 @@ static ssize_t show_wakeup_protocols(struct device *device, * @len: length of the input buffer * * This routine is for changing the IR protocol type. - * It is trigged by writing to /sys/class/rc/rc?/wakeup_protocols. + * It is triggered by writing to /sys/class/rc/rc?/wakeup_protocols. * Returns @len on success or a negative error code. * * dev->lock is taken to guard against races between @@ -1750,7 +1771,6 @@ static int rc_prepare_rx_device(struct rc_dev *dev) set_bit(EV_REP, dev->input_dev->evbit); set_bit(EV_MSC, dev->input_dev->evbit); set_bit(MSC_SCAN, dev->input_dev->mscbit); - bitmap_fill(dev->input_dev->keybit, KEY_CNT); /* Pointer/mouse events */ set_bit(EV_REL, dev->input_dev->evbit); diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 08c51ffd74a0..b82a5c9db12c 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -140,7 +140,7 @@ MODULE_PARM_DESC(length_fuzz, "Length Fuzz (0-127)"); * When receiving a continuous ir stream (for example when a user is * holding a button down on a remote), this specifies the minimum size * of a space when the redrat3 sends a irdata packet to the host. Specified - * in miliseconds. Default value 18ms. + * in milliseconds. Default value 18ms. * The value can be between 2 and 30 inclusive. */ static int minimum_pause = 18; diff --git a/drivers/media/spi/cxd2880-spi.c b/drivers/media/spi/cxd2880-spi.c index d5c433e20d4a..4077217777f9 100644 --- a/drivers/media/spi/cxd2880-spi.c +++ b/drivers/media/spi/cxd2880-spi.c @@ -522,13 +522,15 @@ cxd2880_spi_probe(struct spi_device *spi) dvb_spi->vcc_supply = devm_regulator_get_optional(&spi->dev, "vcc"); if (IS_ERR(dvb_spi->vcc_supply)) { - if (PTR_ERR(dvb_spi->vcc_supply) == -EPROBE_DEFER) - return -EPROBE_DEFER; + if (PTR_ERR(dvb_spi->vcc_supply) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto fail_adapter; + } dvb_spi->vcc_supply = NULL; } else { ret = regulator_enable(dvb_spi->vcc_supply); if (ret) - return ret; + goto fail_adapter; } dvb_spi->spi = spi; diff --git a/drivers/media/tuners/mxl5005s.c b/drivers/media/tuners/mxl5005s.c index ec584316c812..1c07e2225fb3 100644 --- a/drivers/media/tuners/mxl5005s.c +++ b/drivers/media/tuners/mxl5005s.c @@ -3584,7 +3584,7 @@ static u32 MXL_Ceiling(u32 value, u32 resolution) return value / resolution + (value % resolution > 0 ? 1 : 0); } -/* Retrieve the Initialzation Registers */ +/* Retrieve the Initialization Registers */ static u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 *RegNum, u8 *RegVal, int *count) { diff --git a/drivers/media/tuners/qm1d1b0004.h b/drivers/media/tuners/qm1d1b0004.h index 7734ed109a22..7950ecd56430 100644 --- a/drivers/media/tuners/qm1d1b0004.h +++ b/drivers/media/tuners/qm1d1b0004.h @@ -14,7 +14,7 @@ struct qm1d1b0004_config { struct dvb_frontend *fe; u32 lpf_freq; /* LPF frequency[kHz]. Default: symbol rate */ - bool half_step; /* use PLL frequency step of 500Hz istead of 1000Hz */ + bool half_step; /* use PLL frequency step of 500Hz instead of 1000Hz */ }; /* special values indicating to use the default in qm1d1b0004_config */ diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index ba4be08a8551..aed2f130ec74 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -1664,7 +1664,7 @@ static int r820t_iq_tree(struct r820t_priv *priv, /* * record IMC results by input gain/phase location then adjust - * gain or phase positive 1 step and negtive 1 step, + * gain or phase positive 1 step and negative 1 step, * both record results */ @@ -2066,7 +2066,7 @@ static int r820t_imr_callibrate(struct r820t_priv *priv) } /* - * Disables IMR callibration. That emulates the same behaviour + * Disables IMR calibration. That emulates the same behaviour * as what is done by rtl-sdr userspace library. Useful for testing */ if (no_imr_cal) { diff --git a/drivers/media/tuners/tda18271-common.c b/drivers/media/tuners/tda18271-common.c index 054b3b747dae..d46a2e775e82 100644 --- a/drivers/media/tuners/tda18271-common.c +++ b/drivers/media/tuners/tda18271-common.c @@ -528,14 +528,14 @@ int tda18271_init_regs(struct dvb_frontend *fe) * Standby modes, EP3 [7:5] * * | SM || SM_LT || SM_XT || mode description - * |=====\\=======\\=======\\=================================== + * |=====\\=======\\=======\\==================================== * | 0 || 0 || 0 || normal mode - * |-----||-------||-------||----------------------------------- + * |-----||-------||-------||------------------------------------ * | || || || standby mode w/ slave tuner output - * | 1 || 0 || 0 || & loop thru & xtal oscillator on - * |-----||-------||-------||----------------------------------- + * | 1 || 0 || 0 || & loop through & xtal oscillator on + * |-----||-------||-------||------------------------------------ * | 1 || 1 || 0 || standby mode w/ xtal oscillator on - * |-----||-------||-------||----------------------------------- + * |-----||-------||-------||------------------------------------ * | 1 || 1 || 1 || power off * */ diff --git a/drivers/media/tuners/tda18271-fe.c b/drivers/media/tuners/tda18271-fe.c index 4d69029229e4..cac6b8e62b73 100644 --- a/drivers/media/tuners/tda18271-fe.c +++ b/drivers/media/tuners/tda18271-fe.c @@ -48,7 +48,7 @@ static int tda18271_toggle_output(struct dvb_frontend *fe, int standby) if (tda_fail(ret)) goto fail; - tda_dbg("%s mode: xtal oscillator %s, slave tuner loop thru %s\n", + tda_dbg("%s mode: xtal oscillator %s, slave tuner loop through %s\n", standby ? "standby" : "active", priv->output_opt & TDA18271_OUTPUT_XT_OFF ? "off" : "on", priv->output_opt & TDA18271_OUTPUT_LT_OFF ? "off" : "on"); diff --git a/drivers/media/tuners/tda18271.h b/drivers/media/tuners/tda18271.h index 7e07966c5ace..1a23532586ef 100644 --- a/drivers/media/tuners/tda18271.h +++ b/drivers/media/tuners/tda18271.h @@ -69,10 +69,10 @@ enum tda18271_i2c_gate { }; enum tda18271_output_options { - /* slave tuner output & loop thru & xtal oscillator always on */ + /* slave tuner output & loop through & xtal oscillator always on */ TDA18271_OUTPUT_LT_XT_ON = 0, - /* slave tuner output loop thru off */ + /* slave tuner output loop through off */ TDA18271_OUTPUT_LT_OFF = 1, /* xtal oscillator off */ diff --git a/drivers/media/tuners/xc4000.c b/drivers/media/tuners/xc4000.c index eb6d65dae748..a351390ee744 100644 --- a/drivers/media/tuners/xc4000.c +++ b/drivers/media/tuners/xc4000.c @@ -1471,8 +1471,8 @@ static int xc4000_get_signal(struct dvb_frontend *fe, u16 *strength) if (rc < 0) goto ret; - /* Informations from real testing of DVB-T and radio part, - coeficient for one dB is 0xff. + /* Information from real testing of DVB-T and radio part, + coefficient for one dB is 0xff. */ tuner_dbg("Signal strength: -%ddB (%05d)\n", value >> 8, value); diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index 1fdb1601dc65..3f8c92a70116 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -234,7 +234,7 @@ static void au0828_media_graph_notify(struct media_entity *new, if (!new) { /* * Called during au0828 probe time to connect - * entites that were created prior to registering + * entities that were created prior to registering * the notify handler. Find mixer and decoder. */ media_device_for_each_entity(entity, dev->media_dev) { diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c index d9093a3c57c5..6e43028112d1 100644 --- a/drivers/media/usb/au0828/au0828-dvb.c +++ b/drivers/media/usb/au0828/au0828-dvb.c @@ -566,7 +566,7 @@ void au0828_dvb_unregister(struct au0828_dev *dev) dvb->frontend = NULL; } -/* All the DVB attach calls go here, this function get's modified +/* All the DVB attach calls go here, this function gets modified * for each new card. No other function in this file needs * to change. */ diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h index 004eadef55c7..425c35d16057 100644 --- a/drivers/media/usb/au0828/au0828.h +++ b/drivers/media/usb/au0828/au0828.h @@ -52,7 +52,7 @@ #define AU0828_INTERLACED_DEFAULT 1 -/* Defination for AU0828 USB transfer */ +/* Definition for AU0828 USB transfer */ #define AU0828_MAX_ISO_BUFS 12 /* maybe resize this value in the future */ #define AU0828_ISO_PACKETS_PER_URB 128 diff --git a/drivers/media/usb/cpia2/cpia2.h b/drivers/media/usb/cpia2/cpia2.h index ab238ac8bfc0..d0a464882510 100644 --- a/drivers/media/usb/cpia2/cpia2.h +++ b/drivers/media/usb/cpia2/cpia2.h @@ -350,7 +350,7 @@ struct cpia2_sbuf { }; struct framebuf { - struct timeval timestamp; + u64 ts; unsigned long seq; int num; int length; diff --git a/drivers/media/usb/cpia2/cpia2_usb.c b/drivers/media/usb/cpia2/cpia2_usb.c index a771e0a52610..e5d8dee38fe4 100644 --- a/drivers/media/usb/cpia2/cpia2_usb.c +++ b/drivers/media/usb/cpia2/cpia2_usb.c @@ -324,7 +324,7 @@ static void cpia2_usb_complete(struct urb *urb) continue; } DBG("Start of frame pattern found\n"); - v4l2_get_timestamp(&cam->workbuff->timestamp); + cam->workbuff->ts = ktime_get_ns(); cam->workbuff->seq = cam->frame_count++; cam->workbuff->data[0] = 0xFF; cam->workbuff->data[1] = 0xD8; diff --git a/drivers/media/usb/cpia2/cpia2_v4l.c b/drivers/media/usb/cpia2/cpia2_v4l.c index 748739c2b8b2..95c0bd4a19dc 100644 --- a/drivers/media/usb/cpia2/cpia2_v4l.c +++ b/drivers/media/usb/cpia2/cpia2_v4l.c @@ -833,7 +833,7 @@ static int cpia2_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf) break; case FRAME_READY: buf->bytesused = cam->buffers[buf->index].length; - buf->timestamp = cam->buffers[buf->index].timestamp; + buf->timestamp = ns_to_timeval(cam->buffers[buf->index].ts); buf->sequence = cam->buffers[buf->index].seq; buf->flags = V4L2_BUF_FLAG_DONE; break; @@ -889,12 +889,7 @@ static int find_earliest_filled_buffer(struct camera_data *cam) found = i; } else { /* find which buffer is earlier */ - struct timeval *tv1, *tv2; - tv1 = &cam->buffers[i].timestamp; - tv2 = &cam->buffers[found].timestamp; - if(tv1->tv_sec < tv2->tv_sec || - (tv1->tv_sec == tv2->tv_sec && - tv1->tv_usec < tv2->tv_usec)) + if (cam->buffers[i].ts < cam->buffers[found].ts) found = i; } } @@ -945,7 +940,7 @@ static int cpia2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; buf->field = V4L2_FIELD_NONE; - buf->timestamp = cam->buffers[buf->index].timestamp; + buf->timestamp = ns_to_timeval(cam->buffers[buf->index].ts); buf->sequence = cam->buffers[buf->index].seq; buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer; buf->length = cam->frame_size; diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index 1c48c497bd6a..0f8ae81f4820 100644 --- a/drivers/media/usb/cx231xx/cx231xx-417.c +++ b/drivers/media/usb/cx231xx/cx231xx-417.c @@ -1316,7 +1316,7 @@ static void buffer_copy(struct cx231xx *dev, char *data, int len, struct urb *ur buf->vb.state = VIDEOBUF_DONE; buf->vb.field_count++; - v4l2_get_timestamp(&buf->vb.ts); + buf->vb.ts = ktime_get_ns(); list_del(&buf->vb.queue); wake_up(&buf->vb.done); dma_q->mpeg_buffer_completed = 0; @@ -1347,7 +1347,7 @@ static void buffer_filled(char *data, int len, struct urb *urb, memcpy(vbuf, data, len); buf->vb.state = VIDEOBUF_DONE; buf->vb.field_count++; - v4l2_get_timestamp(&buf->vb.ts); + buf->vb.ts = ktime_get_ns(); list_del(&buf->vb.queue); wake_up(&buf->vb.done); } diff --git a/drivers/media/usb/cx231xx/cx231xx-avcore.c b/drivers/media/usb/cx231xx/cx231xx-avcore.c index fdd3c221fa0d..3374888b3021 100644 --- a/drivers/media/usb/cx231xx/cx231xx-avcore.c +++ b/drivers/media/usb/cx231xx/cx231xx-avcore.c @@ -2987,7 +2987,7 @@ int cx231xx_gpio_i2c_write_ack(struct cx231xx *dev) { int status = 0; - /* set SDA to ouput */ + /* set SDA to output */ dev->gpio_dir |= 1 << dev->board.tuner_sda_gpio; status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val); diff --git a/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h index 8f00b1d38277..bb4f817be0c5 100644 --- a/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h +++ b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h @@ -86,7 +86,7 @@ enum TS_PORT{ #define EAVP_MASK 0x8 enum EAV_PRESENT{ NO_EXTERNAL_AV = 0x0, /* 0: No External A/V inputs - (no need for i2s blcok), + (no need for i2s block), Analog Tuner must be present */ EXTERNAL_AV = 0x8 /* 1: External A/V inputs present (requires i2s blk) */ diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.c b/drivers/media/usb/cx231xx/cx231xx-vbi.c index 10b2eb7338ad..d16b73c04445 100644 --- a/drivers/media/usb/cx231xx/cx231xx-vbi.c +++ b/drivers/media/usb/cx231xx/cx231xx-vbi.c @@ -528,7 +528,7 @@ static inline void vbi_buffer_filled(struct cx231xx *dev, buf->vb.state = VIDEOBUF_DONE; buf->vb.field_count++; - v4l2_get_timestamp(&buf->vb.ts); + buf->vb.ts = ktime_get_ns(); dev->vbi_mode.bulk_ctl.buf = NULL; diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 0d451c4ea3b9..aebbaf9d92a6 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -182,7 +182,7 @@ static inline void buffer_filled(struct cx231xx *dev, cx231xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i); buf->vb.state = VIDEOBUF_DONE; buf->vb.field_count++; - v4l2_get_timestamp(&buf->vb.ts); + buf->vb.ts = ktime_get_ns(); if (dev->USE_ISO) dev->video_mode.isoc_ctl.buf = NULL; diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index fa640bf20111..86b7f57492b1 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -646,7 +646,7 @@ struct cx231xx { /* frame properties */ int width; /* current frame width */ int height; /* current frame height */ - int interlaced; /* 1=interlace fileds, 0=just top fileds */ + int interlaced; /* 1=interlace fields, 0=just top fields */ struct cx231xx_audio adev; diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h index 3fd6cc0d6340..728ef5f3ada2 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb.h +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb.h @@ -146,7 +146,7 @@ struct dvb_usb_rc { }; /** - * usb streaming configration for adapter + * usb streaming configuration for adapter * @type: urb type * @count: count of used urbs * @endpoint: stream usb endpoint number diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c index 602013cf3e69..15944b95970f 100644 --- a/drivers/media/usb/dvb-usb-v2/lmedm04.c +++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c @@ -308,7 +308,7 @@ static void lme2510_int_response(struct urb *lme_urb) switch (ibuf[0]) { case 0xaa: - debug_data_snipet(1, "INT Remote data snipet", ibuf); + debug_data_snipet(1, "INT Remote data snippet", ibuf); if (!adap_to_d(adap)->rc_dev) break; @@ -358,13 +358,13 @@ static void lme2510_int_response(struct urb *lme_urb) lme2510_update_stats(adap); - debug_data_snipet(5, "INT Remote data snipet in", ibuf); + debug_data_snipet(5, "INT Remote data snippet in", ibuf); break; case 0xcc: - debug_data_snipet(1, "INT Control data snipet", ibuf); + debug_data_snipet(1, "INT Control data snippet", ibuf); break; default: - debug_data_snipet(1, "INT Unknown data snipet", ibuf); + debug_data_snipet(1, "INT Unknown data snippet", ibuf); break; } } diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.c b/drivers/media/usb/dvb-usb-v2/mxl111sf.c index 85cdf593a9ad..5e2d53af68c7 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c @@ -140,7 +140,7 @@ int mxl111sf_write_reg_mask(struct mxl111sf_state *state, if (mask != 0xff) { ret = mxl111sf_read_reg(state, addr, &val); #if 1 - /* dont know why this usually errors out on the first try */ + /* don't know why this usually errors out on the first try */ if (mxl_fail(ret)) pr_err("error writing addr: 0x%02x, mask: 0x%02x, data: 0x%02x, retrying...", addr, mask, data); @@ -783,7 +783,7 @@ static int mxl111sf_attach_demod(struct dvb_usb_adapter *adap, u8 fe_id) if (mxl_fail(ret)) goto fail; - /* dont care if this fails */ + /* don't care if this fails */ mxl111sf_init_port_expander(state); adap->fe[fe_id] = dvb_attach(mxl111sf_demod_attach, state, diff --git a/drivers/media/usb/dvb-usb/af9005.c b/drivers/media/usb/dvb-usb/af9005.c index 16e946e01d2c..0638d907c73e 100644 --- a/drivers/media/usb/dvb-usb/af9005.c +++ b/drivers/media/usb/dvb-usb/af9005.c @@ -845,7 +845,7 @@ static int af9005_rc_query(struct dvb_usb_device *d, u32 * event, int *state) /* deb_info("rc_query\n"); */ st->data[0] = 3; /* rest of packet length low */ - st->data[1] = 0; /* rest of packet lentgh high */ + st->data[1] = 0; /* rest of packet length high */ st->data[2] = 0x40; /* read remote */ st->data[3] = 1; /* rest of packet length */ st->data[4] = seq = st->sequence++; /* sequence number */ diff --git a/drivers/media/usb/dvb-usb/cinergyT2-fe.c b/drivers/media/usb/dvb-usb/cinergyT2-fe.c index df71df7ed524..4c9f83ba260d 100644 --- a/drivers/media/usb/dvb-usb/cinergyT2-fe.c +++ b/drivers/media/usb/dvb-usb/cinergyT2-fe.c @@ -33,7 +33,7 @@ * This function is probably reusable and may better get placed in a support * library. * - * We replace errornous fields by default TPS fields (the ones with value 0). + * We replace erroneous fields by default TPS fields (the ones with value 0). */ static uint16_t compute_tps(struct dtv_frontend_properties *op) diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c index a51a45c60233..9ddb2000249e 100644 --- a/drivers/media/usb/dvb-usb/cxusb.c +++ b/drivers/media/usb/dvb-usb/cxusb.c @@ -1016,7 +1016,7 @@ static int cxusb_dualdig4_rev2_tuner_attach(struct dvb_usb_adapter *adap) /* * No need to call dvb7000p_attach here, as it was called * already, as frontend_attach method is called first, and - * tuner_attach is only called on sucess. + * tuner_attach is only called on success. */ tun_i2c = st->dib7000p_ops.get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); diff --git a/drivers/media/usb/dvb-usb/dvb-usb-init.c b/drivers/media/usb/dvb-usb/dvb-usb-init.c index 40ca4eafb137..99951e02a880 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb-init.c +++ b/drivers/media/usb/dvb-usb/dvb-usb-init.c @@ -98,7 +98,7 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs) /* * when reloading the driver w/o replugging the device - * sometimes a timeout occures, this helps + * sometimes a timeout occurs, this helps */ if (d->props.generic_bulk_ctrl_endpoint != 0) { usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); diff --git a/drivers/media/usb/dvb-usb/dvb-usb.h b/drivers/media/usb/dvb-usb/dvb-usb.h index 317ed6a82d19..32829bdd5f22 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb.h +++ b/drivers/media/usb/dvb-usb/dvb-usb.h @@ -336,7 +336,7 @@ struct usb_data_stream { * struct dvb_usb_adapter - a DVB adapter on a USB device * @id: index of this adapter (starting with 0). * - * @feedcount: number of reqested feeds (used for streaming-activation) + * @feedcount: number of requested feeds (used for streaming-activation) * @pid_filtering: is hardware pid_filtering used or not. * * @pll_addr: I2C address of the tuner for programming diff --git a/drivers/media/usb/dvb-usb/pctv452e.c b/drivers/media/usb/dvb-usb/pctv452e.c index 0af74383083d..150081128196 100644 --- a/drivers/media/usb/dvb-usb/pctv452e.c +++ b/drivers/media/usb/dvb-usb/pctv452e.c @@ -528,13 +528,13 @@ static int pctv452e_power_ctrl(struct dvb_usb_device *d, int i) rx = b0 + 5; - /* hmm where shoud this should go? */ + /* hmm where should this should go? */ ret = usb_set_interface(d->udev, 0, ISOC_INTERFACE_ALTERNATIVE); if (ret != 0) info("%s: Warning set interface returned: %d\n", __func__, ret); - /* this is a one-time initialization, dont know where to put */ + /* this is a one-time initialization, don't know where to put */ b0[0] = 0xaa; b0[1] = state->c++; b0[2] = PCTV_CMD_RESET; diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 02c13d71e6c1..a3155ec196cc 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -296,7 +296,7 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len) return ret; } /* - * NOTE: some devices with two i2c busses have the bad habit to return 0 + * NOTE: some devices with two i2c buses have the bad habit to return 0 * bytes if we are on bus B AND there was no write attempt to the * specified slave address before AND no device is present at the * requested slave address. @@ -427,7 +427,7 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, return ret; } /* - * NOTE: some devices with two i2c busses have the bad habit to return 0 + * NOTE: some devices with two i2c buses have the bad habit to return 0 * bytes if we are on bus B AND there was no write attempt to the * specified slave address before AND no device is present at the * requested slave address. diff --git a/drivers/media/usb/em28xx/em28xx-reg.h b/drivers/media/usb/em28xx/em28xx-reg.h index f53afe18e92d..d7c60862874a 100644 --- a/drivers/media/usb/em28xx/em28xx-reg.h +++ b/drivers/media/usb/em28xx/em28xx-reg.h @@ -67,7 +67,7 @@ #define EM28XX_I2C_CLK_WAIT_ENABLE 0x40 #define EM28XX_I2C_EEPROM_ON_BOARD 0x08 #define EM28XX_I2C_EEPROM_KEY_VALID 0x04 -#define EM2874_I2C_SECONDARY_BUS_SELECT 0x04 /* em2874 has two i2c busses */ +#define EM2874_I2C_SECONDARY_BUS_SELECT 0x04 /* em2874 has two i2c buses */ #define EM28XX_I2C_FREQ_1_5_MHZ 0x03 /* bus frequency (bits [1-0]) */ #define EM28XX_I2C_FREQ_25_KHZ 0x02 #define EM28XX_I2C_FREQ_400_KHZ 0x01 diff --git a/drivers/media/usb/gspca/Kconfig b/drivers/media/usb/gspca/Kconfig index d3b6665c342d..088566e88467 100644 --- a/drivers/media/usb/gspca/Kconfig +++ b/drivers/media/usb/gspca/Kconfig @@ -46,7 +46,7 @@ config USB_GSPCA_CPIA1 depends on VIDEO_V4L2 && USB_GSPCA help Say Y here if you want support for USB cameras based on the cpia - CPiA chip. Note that you need atleast version 0.6.4 of libv4l for + CPiA chip. Note that you need at least version 0.6.4 of libv4l for applications to understand the videoformat generated by this driver. To compile this driver as a module, choose M here: the diff --git a/drivers/media/usb/gspca/autogain_functions.c b/drivers/media/usb/gspca/autogain_functions.c index 6dfab2b077f7..f915cc7c0c63 100644 --- a/drivers/media/usb/gspca/autogain_functions.c +++ b/drivers/media/usb/gspca/autogain_functions.c @@ -98,7 +98,7 @@ EXPORT_SYMBOL(gspca_expo_autogain); 80 %) and if that does not help, only then changes exposure. This leads to a much more stable image then using the knee algorithm which at certain points of the knee graph will only try to adjust exposure, - which leads to oscilating as one exposure step is huge. + which leads to oscillating as one exposure step is huge. Returns 0 if no changes were made, 1 if the gain and or exposure settings where changed. */ diff --git a/drivers/media/usb/gspca/benq.c b/drivers/media/usb/gspca/benq.c index 8a8db5eb6d5f..1744591b8ba0 100644 --- a/drivers/media/usb/gspca/benq.c +++ b/drivers/media/usb/gspca/benq.c @@ -205,12 +205,12 @@ static void sd_isoc_irq(struct urb *urb) * - 80 ba/bb 00 00 = start of image followed by 'ff d8' * - 04 ba/bb oo oo = image piece * where 'oo oo' is the image offset - (not cheked) + (not checked) * - (other -> bad frame) * The images are JPEG encoded with full header and * normal ff escape. * The end of image ('ff d9') may occur in any URB. - * (not cheked) + * (not checked) */ data = (u8 *) urb0->transfer_buffer + urb0->iso_frame_desc[i].offset; diff --git a/drivers/media/usb/gspca/cpia1.c b/drivers/media/usb/gspca/cpia1.c index 2b09af8865f4..7c817a4a93c4 100644 --- a/drivers/media/usb/gspca/cpia1.c +++ b/drivers/media/usb/gspca/cpia1.c @@ -547,10 +547,14 @@ static int do_command(struct gspca_dev *gspca_dev, u16 command, } if (sd->params.qx3.button) { /* button pressed - unlock the latch */ - do_command(gspca_dev, CPIA_COMMAND_WriteMCPort, + ret = do_command(gspca_dev, CPIA_COMMAND_WriteMCPort, 3, 0xdf, 0xdf, 0); - do_command(gspca_dev, CPIA_COMMAND_WriteMCPort, + if (ret) + return ret; + ret = do_command(gspca_dev, CPIA_COMMAND_WriteMCPort, 3, 0xff, 0xff, 0); + if (ret) + return ret; } /* test whether microscope is cradled */ @@ -1430,6 +1434,7 @@ static int sd_config(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; + int ret; sd->mainsFreq = FREQ_DEF == V4L2_CID_POWER_LINE_FREQUENCY_60HZ; reset_camera_params(gspca_dev); @@ -1441,7 +1446,10 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->cam_mode = mode; cam->nmodes = ARRAY_SIZE(mode); - goto_low_power(gspca_dev); + ret = goto_low_power(gspca_dev); + if (ret) + gspca_err(gspca_dev, "Cannot go to low power mode: %d\n", + ret); /* Check the firmware version. */ sd->params.version.firmwareVersion = 0; get_version_information(gspca_dev); diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index 3137f5d89d80..ac70b36d67b7 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -912,25 +912,32 @@ static void gspca_set_default_mode(struct gspca_dev *gspca_dev) } static int wxh_to_mode(struct gspca_dev *gspca_dev, - int width, int height) + int width, int height, u32 pixelformat) { int i; for (i = 0; i < gspca_dev->cam.nmodes; i++) { if (width == gspca_dev->cam.cam_mode[i].width - && height == gspca_dev->cam.cam_mode[i].height) + && height == gspca_dev->cam.cam_mode[i].height + && pixelformat == gspca_dev->cam.cam_mode[i].pixelformat) return i; } return -EINVAL; } static int wxh_to_nearest_mode(struct gspca_dev *gspca_dev, - int width, int height) + int width, int height, u32 pixelformat) { int i; for (i = gspca_dev->cam.nmodes; --i > 0; ) { if (width >= gspca_dev->cam.cam_mode[i].width + && height >= gspca_dev->cam.cam_mode[i].height + && pixelformat == gspca_dev->cam.cam_mode[i].pixelformat) + return i; + } + for (i = gspca_dev->cam.nmodes; --i > 0; ) { + if (width >= gspca_dev->cam.cam_mode[i].width && height >= gspca_dev->cam.cam_mode[i].height) break; } @@ -1058,7 +1065,7 @@ static int try_fmt_vid_cap(struct gspca_dev *gspca_dev, fmt->fmt.pix.pixelformat, w, h); /* search the nearest mode for width and height */ - mode = wxh_to_nearest_mode(gspca_dev, w, h); + mode = wxh_to_nearest_mode(gspca_dev, w, h, fmt->fmt.pix.pixelformat); /* OK if right palette */ if (gspca_dev->cam.cam_mode[mode].pixelformat @@ -1152,7 +1159,8 @@ static int vidioc_enum_frameintervals(struct file *filp, void *priv, int mode; __u32 i; - mode = wxh_to_mode(gspca_dev, fival->width, fival->height); + mode = wxh_to_mode(gspca_dev, fival->width, fival->height, + fival->pixel_format); if (mode < 0) return -EINVAL; diff --git a/drivers/media/usb/gspca/m5602/m5602_mt9m111.c b/drivers/media/usb/gspca/m5602/m5602_mt9m111.c index c9947c4a0f63..8fac814f4779 100644 --- a/drivers/media/usb/gspca/m5602/m5602_mt9m111.c +++ b/drivers/media/usb/gspca/m5602/m5602_mt9m111.c @@ -199,7 +199,7 @@ static const struct v4l2_ctrl_config mt9m111_greenbal_cfg = { int mt9m111_probe(struct sd *sd) { u8 data[2] = {0x00, 0x00}; - int i; + int i, rc = 0; struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; if (force_sensor) { @@ -217,16 +217,18 @@ int mt9m111_probe(struct sd *sd) /* Do the preinit */ for (i = 0; i < ARRAY_SIZE(preinit_mt9m111); i++) { if (preinit_mt9m111[i][0] == BRIDGE) { - m5602_write_bridge(sd, + rc |= m5602_write_bridge(sd, preinit_mt9m111[i][1], preinit_mt9m111[i][2]); } else { data[0] = preinit_mt9m111[i][2]; data[1] = preinit_mt9m111[i][3]; - m5602_write_sensor(sd, + rc |= m5602_write_sensor(sd, preinit_mt9m111[i][1], data, 2); } } + if (rc < 0) + return rc; if (m5602_read_sensor(sd, MT9M111_SC_CHIPVER, data, 2)) return -ENODEV; diff --git a/drivers/media/usb/gspca/m5602/m5602_po1030.c b/drivers/media/usb/gspca/m5602/m5602_po1030.c index 37d2891e5f5b..5e43b4782f02 100644 --- a/drivers/media/usb/gspca/m5602/m5602_po1030.c +++ b/drivers/media/usb/gspca/m5602/m5602_po1030.c @@ -158,6 +158,7 @@ static const struct v4l2_ctrl_config po1030_greenbal_cfg = { int po1030_probe(struct sd *sd) { + int rc = 0; u8 dev_id_h = 0, i; struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; @@ -177,11 +178,14 @@ int po1030_probe(struct sd *sd) for (i = 0; i < ARRAY_SIZE(preinit_po1030); i++) { u8 data = preinit_po1030[i][2]; if (preinit_po1030[i][0] == SENSOR) - m5602_write_sensor(sd, + rc |= m5602_write_sensor(sd, preinit_po1030[i][1], &data, 1); else - m5602_write_bridge(sd, preinit_po1030[i][1], data); + rc |= m5602_write_bridge(sd, preinit_po1030[i][1], + data); } + if (rc < 0) + return rc; if (m5602_read_sensor(sd, PO1030_DEVID_H, &dev_id_h, 1)) return -ENODEV; diff --git a/drivers/media/usb/gspca/mr97310a.c b/drivers/media/usb/gspca/mr97310a.c index bea196361215..af454663e295 100644 --- a/drivers/media/usb/gspca/mr97310a.c +++ b/drivers/media/usb/gspca/mr97310a.c @@ -520,7 +520,7 @@ static int start_cif_cam(struct gspca_dev *gspca_dev) switch (gspca_dev->pixfmt.width) { case 160: data[9] |= 0x04; /* reg 8, 2:1 scale down from 320 */ - /* fall thru */ + /* fall through */ case 320: default: data[3] = 0x28; /* reg 2, H size/8 */ @@ -530,7 +530,7 @@ static int start_cif_cam(struct gspca_dev *gspca_dev) break; case 176: data[9] |= 0x04; /* reg 8, 2:1 scale down from 352 */ - /* fall thru */ + /* fall through */ case 352: data[3] = 0x2c; /* reg 2, H size/8 */ data[4] = 0x48; /* reg 3, V size/4 */ @@ -617,10 +617,10 @@ static int start_vga_cam(struct gspca_dev *gspca_dev) switch (gspca_dev->pixfmt.width) { case 160: data[9] |= 0x0c; /* reg 8, 4:1 scale down */ - /* fall thru */ + /* fall through */ case 320: data[9] |= 0x04; /* reg 8, 2:1 scale down */ - /* fall thru */ + /* fall through */ case 640: default: data[3] = 0x50; /* reg 2, H size/8 */ @@ -637,7 +637,7 @@ static int start_vga_cam(struct gspca_dev *gspca_dev) case 176: data[9] |= 0x04; /* reg 8, 2:1 scale down */ - /* fall thru */ + /* fall through */ case 352: data[3] = 0x2c; /* reg 2, H size */ data[4] = 0x48; /* reg 3, V size */ diff --git a/drivers/media/usb/gspca/ov519.c b/drivers/media/usb/gspca/ov519.c index 10fcbe9e8614..f2799e8cb8e7 100644 --- a/drivers/media/usb/gspca/ov519.c +++ b/drivers/media/usb/gspca/ov519.c @@ -1945,7 +1945,7 @@ static const struct ov_i2c_regvals norm_8610[] = { { 0x62, 0x5f }, /* was 0xd7, new from windrv 090403 */ { 0x63, 0xff }, { 0x64, 0x53 }, /* new windrv 090403 says 0x57, - * maybe thats wrong */ + * maybe that's wrong */ { 0x65, 0x00 }, { 0x66, 0x55 }, { 0x67, 0xb0 }, @@ -3658,7 +3658,7 @@ static void ov518_mode_init_regs(struct sd *sd) case SEN_OV7620AE: /* * HdG: 640x480 needs special handling on device - * revision 2, we check for device revison > 0 to + * revision 2, we check for device revision > 0 to * avoid regressions, as we don't know the correct * thing todo for revision 1. * diff --git a/drivers/media/usb/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c index d06dc0755b9a..02c90ad96b76 100644 --- a/drivers/media/usb/gspca/ov534.c +++ b/drivers/media/usb/gspca/ov534.c @@ -103,6 +103,16 @@ static const struct v4l2_pix_format ov772x_mode[] = { .sizeimage = 640 * 480 * 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 0}, + {320, 240, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {640, 480, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, }; static const struct v4l2_pix_format ov767x_mode[] = { {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, @@ -127,6 +137,14 @@ static const struct framerates ov772x_framerates[] = { .rates = vga_rates, .nrates = ARRAY_SIZE(vga_rates), }, + { /* 320x240 SGBRG8 */ + .rates = qvga_rates, + .nrates = ARRAY_SIZE(qvga_rates), + }, + { /* 640x480 SGBRG8 */ + .rates = vga_rates, + .nrates = ARRAY_SIZE(vga_rates), + }, }; struct reg_array { @@ -411,9 +429,7 @@ static const u8 sensor_start_qvga_767x[][2] = { }; static const u8 bridge_init_772x[][2] = { - { 0xc2, 0x0c }, { 0x88, 0xf8 }, - { 0xc3, 0x69 }, { 0x89, 0xff }, { 0x76, 0x03 }, { 0x92, 0x01 }, @@ -439,7 +455,6 @@ static const u8 bridge_init_772x[][2] = { { 0x1f, 0x81 }, { 0x34, 0x05 }, { 0xe3, 0x04 }, - { 0x88, 0x00 }, { 0x89, 0x00 }, { 0x76, 0x00 }, { 0xe7, 0x2e }, @@ -447,26 +462,9 @@ static const u8 bridge_init_772x[][2] = { { 0x25, 0x42 }, { 0x21, 0xf0 }, - { 0x1c, 0x00 }, - { 0x1d, 0x40 }, - { 0x1d, 0x02 }, /* payload size 0x0200 * 4 = 2048 bytes */ - { 0x1d, 0x00 }, /* payload size */ - - { 0x1d, 0x02 }, /* frame size 0x025800 * 4 = 614400 */ - { 0x1d, 0x58 }, /* frame size */ - { 0x1d, 0x00 }, /* frame size */ - { 0x1c, 0x0a }, { 0x1d, 0x08 }, /* turn on UVC header */ { 0x1d, 0x0e }, /* .. */ - - { 0x8d, 0x1c }, - { 0x8e, 0x80 }, - { 0xe5, 0x04 }, - - { 0xc0, 0x50 }, - { 0xc1, 0x3c }, - { 0xc2, 0x0c }, }; static const u8 sensor_init_772x[][2] = { { 0x12, 0x80 }, @@ -545,13 +543,10 @@ static const u8 sensor_init_772x[][2] = { { 0x8c, 0xe8 }, { 0x8d, 0x20 }, - { 0x0c, 0x90 }, - { 0x2b, 0x00 }, { 0x22, 0x7f }, { 0x23, 0x03 }, { 0x11, 0x01 }, - { 0x0c, 0xd0 }, { 0x64, 0xff }, { 0x0d, 0x41 }, @@ -559,9 +554,9 @@ static const u8 sensor_init_772x[][2] = { { 0x0e, 0xcd }, { 0xac, 0xbf }, { 0x8e, 0x00 }, /* De-noise threshold */ - { 0x0c, 0xd0 } }; -static const u8 bridge_start_vga_772x[][2] = { +static const u8 bridge_start_vga_yuyv_772x[][2] = { + {0x88, 0x00}, {0x1c, 0x00}, {0x1d, 0x40}, {0x1d, 0x02}, @@ -569,10 +564,14 @@ static const u8 bridge_start_vga_772x[][2] = { {0x1d, 0x02}, {0x1d, 0x58}, {0x1d, 0x00}, + {0x8d, 0x1c}, + {0x8e, 0x80}, {0xc0, 0x50}, {0xc1, 0x3c}, + {0xc2, 0x0c}, + {0xc3, 0x69}, }; -static const u8 sensor_start_vga_772x[][2] = { +static const u8 sensor_start_vga_yuyv_772x[][2] = { {0x12, 0x00}, {0x17, 0x26}, {0x18, 0xa0}, @@ -581,8 +580,10 @@ static const u8 sensor_start_vga_772x[][2] = { {0x29, 0xa0}, {0x2c, 0xf0}, {0x65, 0x20}, + {0x67, 0x00}, }; -static const u8 bridge_start_qvga_772x[][2] = { +static const u8 bridge_start_qvga_yuyv_772x[][2] = { + {0x88, 0x00}, {0x1c, 0x00}, {0x1d, 0x40}, {0x1d, 0x02}, @@ -590,10 +591,14 @@ static const u8 bridge_start_qvga_772x[][2] = { {0x1d, 0x01}, {0x1d, 0x4b}, {0x1d, 0x00}, + {0x8d, 0x1c}, + {0x8e, 0x80}, {0xc0, 0x28}, {0xc1, 0x1e}, + {0xc2, 0x0c}, + {0xc3, 0x69}, }; -static const u8 sensor_start_qvga_772x[][2] = { +static const u8 sensor_start_qvga_yuyv_772x[][2] = { {0x12, 0x40}, {0x17, 0x3f}, {0x18, 0x50}, @@ -602,6 +607,61 @@ static const u8 sensor_start_qvga_772x[][2] = { {0x29, 0x50}, {0x2c, 0x78}, {0x65, 0x2f}, + {0x67, 0x00}, +}; +static const u8 bridge_start_vga_gbrg_772x[][2] = { + {0x88, 0x08}, + {0x1c, 0x00}, + {0x1d, 0x00}, + {0x1d, 0x02}, + {0x1d, 0x00}, + {0x1d, 0x01}, + {0x1d, 0x2c}, + {0x1d, 0x00}, + {0x8d, 0x00}, + {0x8e, 0x00}, + {0xc0, 0x50}, + {0xc1, 0x3c}, + {0xc2, 0x01}, + {0xc3, 0x01}, +}; +static const u8 sensor_start_vga_gbrg_772x[][2] = { + {0x12, 0x01}, + {0x17, 0x26}, + {0x18, 0xa0}, + {0x19, 0x07}, + {0x1a, 0xf0}, + {0x29, 0xa0}, + {0x2c, 0xf0}, + {0x65, 0x20}, + {0x67, 0x02}, +}; +static const u8 bridge_start_qvga_gbrg_772x[][2] = { + {0x88, 0x08}, + {0x1c, 0x00}, + {0x1d, 0x00}, + {0x1d, 0x02}, + {0x1d, 0x00}, + {0x1d, 0x00}, + {0x1d, 0x4b}, + {0x1d, 0x00}, + {0x8d, 0x00}, + {0x8e, 0x00}, + {0xc0, 0x28}, + {0xc1, 0x1e}, + {0xc2, 0x01}, + {0xc3, 0x01}, +}; +static const u8 sensor_start_qvga_gbrg_772x[][2] = { + {0x12, 0x41}, + {0x17, 0x3f}, + {0x18, 0x50}, + {0x19, 0x03}, + {0x1a, 0x78}, + {0x29, 0x50}, + {0x2c, 0x78}, + {0x65, 0x2f}, + {0x67, 0x02}, }; static void ov534_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val) @@ -679,7 +739,7 @@ static int sccb_check_status(struct gspca_dev *gspca_dev) int i; for (i = 0; i < 5; i++) { - msleep(10); + usleep_range(10000, 20000); data = ov534_reg_read(gspca_dev, OV534_REG_STATUS); switch (data) { @@ -1277,7 +1337,7 @@ static int sd_init(struct gspca_dev *gspca_dev) /* reset sensor */ sccb_reg_write(gspca_dev, 0x12, 0x80); - msleep(10); + usleep_range(10000, 20000); /* probe the sensor */ sccb_reg_read(gspca_dev, 0x0a); @@ -1315,25 +1375,33 @@ static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; int mode; - static const struct reg_array bridge_start[NSENSORS][2] = { + static const struct reg_array bridge_start[NSENSORS][4] = { [SENSOR_OV767x] = {{bridge_start_qvga_767x, ARRAY_SIZE(bridge_start_qvga_767x)}, {bridge_start_vga_767x, ARRAY_SIZE(bridge_start_vga_767x)}}, - [SENSOR_OV772x] = {{bridge_start_qvga_772x, - ARRAY_SIZE(bridge_start_qvga_772x)}, - {bridge_start_vga_772x, - ARRAY_SIZE(bridge_start_vga_772x)}}, + [SENSOR_OV772x] = {{bridge_start_qvga_yuyv_772x, + ARRAY_SIZE(bridge_start_qvga_yuyv_772x)}, + {bridge_start_vga_yuyv_772x, + ARRAY_SIZE(bridge_start_vga_yuyv_772x)}, + {bridge_start_qvga_gbrg_772x, + ARRAY_SIZE(bridge_start_qvga_gbrg_772x)}, + {bridge_start_vga_gbrg_772x, + ARRAY_SIZE(bridge_start_vga_gbrg_772x)} }, }; - static const struct reg_array sensor_start[NSENSORS][2] = { + static const struct reg_array sensor_start[NSENSORS][4] = { [SENSOR_OV767x] = {{sensor_start_qvga_767x, ARRAY_SIZE(sensor_start_qvga_767x)}, {sensor_start_vga_767x, ARRAY_SIZE(sensor_start_vga_767x)}}, - [SENSOR_OV772x] = {{sensor_start_qvga_772x, - ARRAY_SIZE(sensor_start_qvga_772x)}, - {sensor_start_vga_772x, - ARRAY_SIZE(sensor_start_vga_772x)}}, + [SENSOR_OV772x] = {{sensor_start_qvga_yuyv_772x, + ARRAY_SIZE(sensor_start_qvga_yuyv_772x)}, + {sensor_start_vga_yuyv_772x, + ARRAY_SIZE(sensor_start_vga_yuyv_772x)}, + {sensor_start_qvga_gbrg_772x, + ARRAY_SIZE(sensor_start_qvga_gbrg_772x)}, + {sensor_start_vga_gbrg_772x, + ARRAY_SIZE(sensor_start_vga_gbrg_772x)} }, }; /* (from ms-win trace) */ @@ -1439,10 +1507,9 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, /* If this packet is marked as EOF, end the frame */ } else if (data[1] & UVC_STREAM_EOF) { sd->last_pts = 0; - if (gspca_dev->pixfmt.pixelformat == V4L2_PIX_FMT_YUYV + if (gspca_dev->pixfmt.pixelformat != V4L2_PIX_FMT_JPEG && gspca_dev->image_len + len - 12 != - gspca_dev->pixfmt.width * - gspca_dev->pixfmt.height * 2) { + gspca_dev->pixfmt.sizeimage) { gspca_dbg(gspca_dev, D_PACK, "wrong sized frame\n"); goto discard; } diff --git a/drivers/media/usb/gspca/pac_common.h b/drivers/media/usb/gspca/pac_common.h index 31f2a42af4dd..aae97a5534e3 100644 --- a/drivers/media/usb/gspca/pac_common.h +++ b/drivers/media/usb/gspca/pac_common.h @@ -21,7 +21,7 @@ /* We calculate the autogain at the end of the transfer of a frame, at this moment a frame with the old settings is being captured and transmitted. So - if we adjust the gain or exposure we must ignore atleast the next frame for + if we adjust the gain or exposure we must ignore at least the next frame for the new settings to come into effect before doing any other adjustments. */ #define PAC_AUTOGAIN_IGNORE_FRAMES 2 diff --git a/drivers/media/usb/gspca/sn9c20x.c b/drivers/media/usb/gspca/sn9c20x.c index 5984bb12bcff..ab912903f8d7 100644 --- a/drivers/media/usb/gspca/sn9c20x.c +++ b/drivers/media/usb/gspca/sn9c20x.c @@ -1634,7 +1634,7 @@ static int sd_config(struct gspca_dev *gspca_dev, break; case SENSOR_HV7131R: sd->i2c_intf = 0x81; /* i2c 400 Kb/s */ - /* fall thru */ + /* fall through */ default: cam->cam_mode = vga_mode; cam->nmodes = ARRAY_SIZE(vga_mode); diff --git a/drivers/media/usb/gspca/sonixb.c b/drivers/media/usb/gspca/sonixb.c index 5f3f2979540a..583c9f10198c 100644 --- a/drivers/media/usb/gspca/sonixb.c +++ b/drivers/media/usb/gspca/sonixb.c @@ -121,7 +121,7 @@ struct sensor_data { /* We calculate the autogain at the end of the transfer of a frame, at this moment a frame with the old settings is being captured and transmitted. So - if we adjust the gain or exposure we must ignore atleast the next frame for + if we adjust the gain or exposure we must ignore at least the next frame for the new settings to come into effect before doing any other adjustments. */ #define AUTOGAIN_IGNORE_FRAMES 1 @@ -757,7 +757,7 @@ static void setexposure(struct gspca_dev *gspca_dev) /* Don't allow this to get below 10 when using autogain, the steps become very large (relatively) when below 10 causing - the image to oscilate from much too dark, to much too bright + the image to oscillate from much too dark, to much too bright and back again. */ if (gspca_dev->autogain->val && reg10 < 10) reg10 = 10; diff --git a/drivers/media/usb/gspca/sonixj.c b/drivers/media/usb/gspca/sonixj.c index df8d8482b795..a63f155f1515 100644 --- a/drivers/media/usb/gspca/sonixj.c +++ b/drivers/media/usb/gspca/sonixj.c @@ -2677,7 +2677,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, * which is 62 bytes long and is followed by various information * including statuses and luminosity. * - * A marker may be splitted on two packets. + * A marker may be split on two packets. * * The 6th byte of a marker contains the bits: * 0x08: USB full diff --git a/drivers/media/usb/gspca/spca501.c b/drivers/media/usb/gspca/spca501.c index 2cce74b166d8..3d215952af18 100644 --- a/drivers/media/usb/gspca/spca501.c +++ b/drivers/media/usb/gspca/spca501.c @@ -574,7 +574,7 @@ static const __u16 spca501_3com_open_data[][3] = { {0x0, 0x0001, 0x0010}, /* TG Start Clock */ /* {0x2, 0x006a, 0x0001}, * C/S Enable ISOSYNCH Packet Engine */ - {0x2, 0x0068, 0x0001}, /* C/S Diable ISOSYNCH Packet Engine */ + {0x2, 0x0068, 0x0001}, /* C/S Disable ISOSYNCH Packet Engine */ {0x2, 0x0000, 0x0005}, {0x2, 0x0043, 0x0000}, /* C/S Set Timing Mode, Disable TG soft reset */ {0x2, 0x0043, 0x0000}, /* C/S Set Timing Mode, Disable TG soft reset */ diff --git a/drivers/media/usb/gspca/sq905.c b/drivers/media/usb/gspca/sq905.c index ffea9c35b0a0..d5c48216deb7 100644 --- a/drivers/media/usb/gspca/sq905.c +++ b/drivers/media/usb/gspca/sq905.c @@ -18,7 +18,7 @@ * History and Acknowledgments * * The original Linux driver for SQ905 based cameras was written by - * Marcell Lengyel and furter developed by many other contributors + * Marcell Lengyel and further developed by many other contributors * and is available from http://sourceforge.net/projects/sqcam/ * * This driver takes advantage of the reverse engineering work done for diff --git a/drivers/media/usb/gspca/sunplus.c b/drivers/media/usb/gspca/sunplus.c index 437a3367ab97..e1e2a605a46c 100644 --- a/drivers/media/usb/gspca/sunplus.c +++ b/drivers/media/usb/gspca/sunplus.c @@ -555,7 +555,7 @@ static void init_ctl_reg(struct gspca_dev *gspca_dev) case BRIDGE_SPCA504: case BRIDGE_SPCA504C: pollreg = 0; - /* fall thru */ + /* fall through */ default: /* case BRIDGE_SPCA533: */ /* case BRIDGE_SPCA504B: */ @@ -638,7 +638,7 @@ static int sd_init(struct gspca_dev *gspca_dev) reg_w_riv(gspca_dev, 0x00, 0x2000, 0x00); reg_w_riv(gspca_dev, 0x00, 0x2301, 0x13); reg_w_riv(gspca_dev, 0x00, 0x2306, 0x00); - /* fall thru */ + /* fall through */ case BRIDGE_SPCA533: spca504B_PollingDataReady(gspca_dev); spca50x_GetFirmware(gspca_dev); diff --git a/drivers/media/usb/gspca/t613.c b/drivers/media/usb/gspca/t613.c index 445782919446..ed9b925b723e 100644 --- a/drivers/media/usb/gspca/t613.c +++ b/drivers/media/usb/gspca/t613.c @@ -966,7 +966,7 @@ static int sd_init_controls(struct gspca_dev *gspca_dev) V4L2_CID_SATURATION, 0, 0xf, 1, 5); v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_GAMMA, 0, GAMMA_MAX, 1, 10); - /* Activate lowlight, some apps dont bring up the + /* Activate lowlight, some apps don't bring up the backlight_compensation control) */ v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_BACKLIGHT_COMPENSATION, 0, 1, 1, 1); diff --git a/drivers/media/usb/gspca/touptek.c b/drivers/media/usb/gspca/touptek.c index d1b9032d7863..6c056a448231 100644 --- a/drivers/media/usb/gspca/touptek.c +++ b/drivers/media/usb/gspca/touptek.c @@ -185,7 +185,7 @@ static const struct v4l2_pix_format vga_mode[] = { }; /* - * As theres no known frame sync, the only way to keep synced is to try hard + * As there's no known frame sync, the only way to keep synced is to try hard * to never miss any packets */ #if MAX_NURBS < 4 @@ -259,7 +259,7 @@ static void setexposure(struct gspca_dev *gspca_dev, s32 val) return; } gspca_dbg(gspca_dev, D_STREAM, "exposure: 0x%04X ms\n\n", value); - /* Wonder if theres a good reason for sending it twice */ + /* Wonder if there's a good reason for sending it twice */ /* probably not but leave it in because...why not */ reg_w(gspca_dev, value, REG_COARSE_INTEGRATION_TIME_); reg_w(gspca_dev, value, REG_COARSE_INTEGRATION_TIME_); diff --git a/drivers/media/usb/gspca/w996Xcf.c b/drivers/media/usb/gspca/w996Xcf.c index abfab3de1866..36cc5a5ce77a 100644 --- a/drivers/media/usb/gspca/w996Xcf.c +++ b/drivers/media/usb/gspca/w996Xcf.c @@ -431,7 +431,7 @@ static void w9968cf_set_crop_window(struct sd *sd) start_cropy = 35; } - /* Work around to avoid FP arithmetics */ + /* Work around to avoid FP arithmetic */ #define SC(x) ((x) << 10) /* Scaling factors */ diff --git a/drivers/media/usb/gspca/zc3xx-reg.h b/drivers/media/usb/gspca/zc3xx-reg.h index 71fda38e85e0..26f6153b687f 100644 --- a/drivers/media/usb/gspca/zc3xx-reg.h +++ b/drivers/media/usb/gspca/zc3xx-reg.h @@ -26,7 +26,7 @@ /* Test mode */ #define ZC3XX_R00B_TESTMODECONTROL 0x000b -/* Frame retreiving */ +/* Frame retrieving */ #define ZC3XX_R00C_LASTACQTIME 0x000c #define ZC3XX_R00D_MONITORRES 0x000d #define ZC3XX_R00E_TIMESTAMPHIGH 0x000e diff --git a/drivers/media/usb/gspca/zc3xx.c b/drivers/media/usb/gspca/zc3xx.c index cf21991e3d99..ad7194029031 100644 --- a/drivers/media/usb/gspca/zc3xx.c +++ b/drivers/media/usb/gspca/zc3xx.c @@ -3602,7 +3602,7 @@ static const struct usb_action pas106b_InitialScale[] = { /* 176x144 */ {0xaa, 0x14, 0x0081}, /* Other registers */ {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, -/* Frame retreiving */ +/* Frame retrieving */ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* Gains */ {0xa0, 0xa0, ZC3XX_R1A8_DIGITALGAIN}, @@ -3718,7 +3718,7 @@ static const struct usb_action pas106b_Initial[] = { /* 352x288 */ {0xaa, 0x14, 0x0081}, /* Other registers */ {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, -/* Frame retreiving */ +/* Frame retrieving */ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* Gains */ {0xa0, 0xa0, ZC3XX_R1A8_DIGITALGAIN}, @@ -6775,7 +6775,7 @@ static int sd_start(struct gspca_dev *gspca_dev) case SENSOR_HV7131R: case SENSOR_TAS5130C: reg_r(gspca_dev, 0x0008); - /* fall thru */ + /* fall through */ case SENSOR_PO2030: reg_w(gspca_dev, 0x03, 0x0008); break; @@ -6824,7 +6824,7 @@ static int sd_start(struct gspca_dev *gspca_dev) case SENSOR_TAS5130C: reg_w(gspca_dev, 0x09, 0x01ad); /* (from win traces) */ reg_w(gspca_dev, 0x15, 0x01ae); - /* fall thru */ + /* fall through */ case SENSOR_PAS202B: case SENSOR_PO2030: /* reg_w(gspca_dev, 0x40, ZC3XX_R117_GGAIN); in win traces */ diff --git a/drivers/media/usb/hdpvr/hdpvr-i2c.c b/drivers/media/usb/hdpvr/hdpvr-i2c.c index 5a3cb614a211..d76173f1ced1 100644 --- a/drivers/media/usb/hdpvr/hdpvr-i2c.c +++ b/drivers/media/usb/hdpvr/hdpvr-i2c.c @@ -61,10 +61,10 @@ static int hdpvr_i2c_read(struct hdpvr_device *dev, int bus, return -EINVAL; if (wlen) { - memcpy(&dev->i2c_buf, wdata, wlen); + memcpy(dev->i2c_buf, wdata, wlen); ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST, - (bus << 8) | addr, 0, &dev->i2c_buf, + (bus << 8) | addr, 0, dev->i2c_buf, wlen, 1000); if (ret < 0) return ret; @@ -72,10 +72,10 @@ static int hdpvr_i2c_read(struct hdpvr_device *dev, int bus, ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), REQTYPE_I2C_READ, CTRL_READ_REQUEST, - (bus << 8) | addr, 0, &dev->i2c_buf, len, 1000); + (bus << 8) | addr, 0, dev->i2c_buf, len, 1000); if (ret == len) { - memcpy(data, &dev->i2c_buf, len); + memcpy(data, dev->i2c_buf, len); ret = 0; } else if (ret >= 0) ret = -EIO; @@ -91,17 +91,17 @@ static int hdpvr_i2c_write(struct hdpvr_device *dev, int bus, if (len > sizeof(dev->i2c_buf)) return -EINVAL; - memcpy(&dev->i2c_buf, data, len); + memcpy(dev->i2c_buf, data, len); ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST, - (bus << 8) | addr, 0, &dev->i2c_buf, len, 1000); + (bus << 8) | addr, 0, dev->i2c_buf, len, 1000); if (ret < 0) return ret; ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), REQTYPE_I2C_WRITE_STATT, CTRL_READ_REQUEST, - 0, 0, &dev->i2c_buf, 2, 1000); + 0, 0, dev->i2c_buf, 2, 1000); if ((ret == 2) && (dev->i2c_buf[1] == (len - 1))) ret = 0; diff --git a/drivers/media/usb/hdpvr/hdpvr.h b/drivers/media/usb/hdpvr/hdpvr.h index 1d65b4185f57..fa43e1d45ea9 100644 --- a/drivers/media/usb/hdpvr/hdpvr.h +++ b/drivers/media/usb/hdpvr/hdpvr.h @@ -215,7 +215,7 @@ enum { */ /* :0 s 38 01 1700 0003 0001 1 = 00 - * VIDEO STANDARD or FREQUNCY 0 = 60hz, 1 = 50hz + * VIDEO STANDARD or FREQUENCY 0 = 60hz, 1 = 50hz */ /* :0 s 38 01 3100 0003 0004 4 = 03030000 diff --git a/drivers/media/usb/pwc/pwc-dec23.c b/drivers/media/usb/pwc/pwc-dec23.c index 1283b3bd9800..854c36a5dec9 100644 --- a/drivers/media/usb/pwc/pwc-dec23.c +++ b/drivers/media/usb/pwc/pwc-dec23.c @@ -41,7 +41,7 @@ * UNROLL_LOOP_FOR_COPYING_BLOCK * 0: use a loop for a smaller code (but little slower) * 1: when unrolling the loop, gcc produces some faster code (perhaps only - * valid for intel processor class). Activating this option, automaticaly + * valid for intel processor class). Activating this option, automatically * activate USE_LOOKUP_TABLE_TO_CLAMP */ #define UNROLL_LOOP_FOR_COPY 1 @@ -332,7 +332,7 @@ void pwc_dec23_init(struct pwc_device *pdev, const unsigned char *cmd) build_table_color(TimonRomTable[version][1], pdec->table_0004_pass2, pdec->table_8004_pass2); } - /* Informations can be coded on a variable number of bits but never less than 8 */ + /* Information can be coded on a variable number of bits but never less than 8 */ shift = 8 - pdec->nbits; pdec->scalebits = SCALEBITS - shift; pdec->nbitsmask = 0xFF >> shift; diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c index 72704f4d5330..4e94197094ad 100644 --- a/drivers/media/usb/pwc/pwc-if.c +++ b/drivers/media/usb/pwc/pwc-if.c @@ -76,6 +76,9 @@ #include "pwc-dec23.h" #include "pwc-dec1.h" +#define CREATE_TRACE_POINTS +#include <trace/events/pwc.h> + /* Function prototypes and driver templates */ /* hotplug device table support */ @@ -156,6 +159,32 @@ static const struct video_device pwc_template = { /***************************************************************************/ /* Private functions */ +static void *pwc_alloc_urb_buffer(struct device *dev, + size_t size, dma_addr_t *dma_handle) +{ + void *buffer = kmalloc(size, GFP_KERNEL); + + if (!buffer) + return NULL; + + *dma_handle = dma_map_single(dev, buffer, size, DMA_FROM_DEVICE); + if (dma_mapping_error(dev, *dma_handle)) { + kfree(buffer); + return NULL; + } + + return buffer; +} + +static void pwc_free_urb_buffer(struct device *dev, + size_t size, + void *buffer, + dma_addr_t dma_handle) +{ + dma_unmap_single(dev, dma_handle, size, DMA_FROM_DEVICE); + kfree(buffer); +} + static struct pwc_frame_buf *pwc_get_next_fill_buf(struct pwc_device *pdev) { unsigned long flags = 0; @@ -260,6 +289,8 @@ static void pwc_isoc_handler(struct urb *urb) int i, fst, flen; unsigned char *iso_buf = NULL; + trace_pwc_handler_enter(urb, pdev); + if (urb->status == -ENOENT || urb->status == -ECONNRESET || urb->status == -ESHUTDOWN) { PWC_DEBUG_OPEN("URB (%p) unlinked %ssynchronously.\n", @@ -301,6 +332,11 @@ static void pwc_isoc_handler(struct urb *urb) /* Reset ISOC error counter. We did get here, after all. */ pdev->visoc_errors = 0; + dma_sync_single_for_cpu(&urb->dev->dev, + urb->transfer_dma, + urb->transfer_buffer_length, + DMA_FROM_DEVICE); + /* vsync: 0 = don't copy data 1 = sync-hunt 2 = synched @@ -347,7 +383,14 @@ static void pwc_isoc_handler(struct urb *urb) pdev->vlast_packet_size = flen; } + dma_sync_single_for_device(&urb->dev->dev, + urb->transfer_dma, + urb->transfer_buffer_length, + DMA_FROM_DEVICE); + handler_end: + trace_pwc_handler_exit(urb, pdev); + i = usb_submit_urb(urb, GFP_ATOMIC); if (i != 0) PWC_ERROR("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i); @@ -421,16 +464,15 @@ retry: urb->dev = udev; urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint); urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; - urb->transfer_buffer = usb_alloc_coherent(udev, - ISO_BUFFER_SIZE, - GFP_KERNEL, - &urb->transfer_dma); + urb->transfer_buffer_length = ISO_BUFFER_SIZE; + urb->transfer_buffer = pwc_alloc_urb_buffer(&udev->dev, + urb->transfer_buffer_length, + &urb->transfer_dma); if (urb->transfer_buffer == NULL) { PWC_ERROR("Failed to allocate urb buffer %d\n", i); pwc_isoc_cleanup(pdev); return -ENOMEM; } - urb->transfer_buffer_length = ISO_BUFFER_SIZE; urb->complete = pwc_isoc_handler; urb->context = pdev; urb->start_frame = 0; @@ -481,15 +523,16 @@ static void pwc_iso_free(struct pwc_device *pdev) /* Freeing ISOC buffers one by one */ for (i = 0; i < MAX_ISO_BUFS; i++) { - if (pdev->urbs[i]) { + struct urb *urb = pdev->urbs[i]; + + if (urb) { PWC_DEBUG_MEMORY("Freeing URB\n"); - if (pdev->urbs[i]->transfer_buffer) { - usb_free_coherent(pdev->udev, - pdev->urbs[i]->transfer_buffer_length, - pdev->urbs[i]->transfer_buffer, - pdev->urbs[i]->transfer_dma); - } - usb_free_urb(pdev->urbs[i]); + if (urb->transfer_buffer) + pwc_free_urb_buffer(&urb->dev->dev, + urb->transfer_buffer_length, + urb->transfer_buffer, + urb->transfer_dma); + usb_free_urb(urb); pdev->urbs[i] = NULL; } } @@ -610,7 +653,7 @@ static int buffer_prepare(struct vb2_buffer *vb) { struct pwc_device *pdev = vb2_get_drv_priv(vb->vb2_queue); - /* Don't allow queing new buffers after device disconnection */ + /* Don't allow queueing new buffers after device disconnection */ if (!pdev->udev) return -ENODEV; diff --git a/drivers/media/usb/pwc/pwc-misc.c b/drivers/media/usb/pwc/pwc-misc.c index 9be5adffa874..03888fc3804d 100644 --- a/drivers/media/usb/pwc/pwc-misc.c +++ b/drivers/media/usb/pwc/pwc-misc.c @@ -59,7 +59,7 @@ int pwc_get_size(struct pwc_device *pdev, int width, int height) return i; } - /* Never reached there always is atleast one supported mode */ + /* Never reached there always is at least one supported mode */ return 0; } diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c index 2ffded08407b..4fc03ec8a4f1 100644 --- a/drivers/media/usb/siano/smsusb.c +++ b/drivers/media/usb/siano/smsusb.c @@ -75,7 +75,7 @@ static int smsusb_submit_urb(struct smsusb_device_t *dev, struct smsusb_urb_t *surb); /* - * Completing URB's callback handler - bottom half (proccess context) + * Completing URB's callback handler - bottom half (process context) * submits the URB prepared on smsusb_onresponse() */ static void do_submit_urb(struct work_struct *work) diff --git a/drivers/media/usb/stk1160/stk1160-core.c b/drivers/media/usb/stk1160/stk1160-core.c index 468f5ccf4ae6..a44a44ff3bb1 100644 --- a/drivers/media/usb/stk1160/stk1160-core.c +++ b/drivers/media/usb/stk1160/stk1160-core.c @@ -297,7 +297,7 @@ static int stk1160_probe(struct usb_interface *interface, return -ENOMEM; /* - * Scan usb posibilities and populate alt_max_pkt_size array. + * Scan usb possibilities and populate alt_max_pkt_size array. * Also, check if device speed is fast enough. */ rc = stk1160_scan_usb(interface, udev, alt_max_pkt_size); @@ -426,7 +426,7 @@ static void stk1160_disconnect(struct usb_interface *interface) /* * This calls stk1160_release if it's the last reference. - * Otherwise, release is posponed until there are no users left. + * Otherwise, release is postponed until there are no users left. */ v4l2_device_put(&dev->v4l2_dev); } diff --git a/drivers/media/usb/stk1160/stk1160-reg.h b/drivers/media/usb/stk1160/stk1160-reg.h index 7b08a3cc4504..2e400db0ad0e 100644 --- a/drivers/media/usb/stk1160/stk1160-reg.h +++ b/drivers/media/usb/stk1160/stk1160-reg.h @@ -23,7 +23,7 @@ /* GPIO Control */ #define STK1160_GCTRL 0x000 -/* Remote Wakup Control */ +/* Remote Wakeup Control */ #define STK1160_RMCTL 0x00c /* Power-on Strapping Data */ @@ -104,7 +104,7 @@ #define STK1160_SBUSR_RA 0x208 #define STK1160_SBUSR_RD 0x209 -/* Alternate Serial Inteface Control */ +/* Alternate Serial Interface Control */ #define STK1160_ASIC 0x2fc /* PLL Select Options */ diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index b8ec74d98e8d..8f545861471e 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -1006,7 +1006,7 @@ static int stk_setup_format(struct stk_camera *dev) stk_camera_write_reg(dev, 0x001c, 0x46); /* * Registers 0x0115 0x0114 are the size of each line (bytes), - * regs 0x0117 0x0116 are the heigth of the image. + * regs 0x0117 0x0116 are the height of the image. */ stk_camera_write_reg(dev, 0x0115, ((stk_sizes[i].w * depth) >> 8) & 0xff); @@ -1144,7 +1144,7 @@ static int stk_vidioc_dqbuf(struct file *filp, sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED; sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE; sbuf->v4lbuf.sequence = ++dev->sequence; - v4l2_get_timestamp(&sbuf->v4lbuf.timestamp); + sbuf->v4lbuf.timestamp = ns_to_timeval(ktime_get_ns()); *buf = sbuf->v4lbuf; return 0; diff --git a/drivers/media/usb/tm6000/tm6000-alsa.c b/drivers/media/usb/tm6000/tm6000-alsa.c index b965931793b5..d6c79c13b332 100644 --- a/drivers/media/usb/tm6000/tm6000-alsa.c +++ b/drivers/media/usb/tm6000/tm6000-alsa.c @@ -58,7 +58,7 @@ module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable debug messages"); /**************************************************************************** - Module specific funtions + Module specific functions ****************************************************************************/ /* diff --git a/drivers/media/usb/tm6000/tm6000-core.c b/drivers/media/usb/tm6000/tm6000-core.c index d3229aa45fcb..2c723706f8c8 100644 --- a/drivers/media/usb/tm6000/tm6000-core.c +++ b/drivers/media/usb/tm6000/tm6000-core.c @@ -668,7 +668,7 @@ int tm6000_set_audio_rinput(struct tm6000_core *dev) areg_f0 = 0x04; break; default: - printk(KERN_INFO "%s: audio input dosn't support\n", + printk(KERN_INFO "%s: audio input doesn't support\n", dev->name); return 0; break; @@ -690,7 +690,7 @@ int tm6000_set_audio_rinput(struct tm6000_core *dev) areg_eb = 0x04; break; default: - printk(KERN_INFO "%s: audio input dosn't support\n", + printk(KERN_INFO "%s: audio input doesn't support\n", dev->name); return 0; break; diff --git a/drivers/media/usb/tm6000/tm6000-dvb.c b/drivers/media/usb/tm6000/tm6000-dvb.c index 3a4e545c6037..36eea1950e77 100644 --- a/drivers/media/usb/tm6000/tm6000-dvb.c +++ b/drivers/media/usb/tm6000/tm6000-dvb.c @@ -149,7 +149,7 @@ static int tm6000_start_stream(struct tm6000_core *dev) ret, __func__); return ret; } else - printk(KERN_ERR "tm6000: pipe resetted\n"); + printk(KERN_ERR "tm6000: pipe reset\n"); /* mutex_lock(&tm6000_driver.open_close_mutex); */ ret = usb_submit_urb(dvb->bulk_urb, GFP_ATOMIC); diff --git a/drivers/media/usb/tm6000/tm6000-i2c.c b/drivers/media/usb/tm6000/tm6000-i2c.c index 8c0476dfe54f..b37782d6f79c 100644 --- a/drivers/media/usb/tm6000/tm6000-i2c.c +++ b/drivers/media/usb/tm6000/tm6000-i2c.c @@ -155,7 +155,7 @@ static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap, /* * The TM6000 only supports a read transaction * immediately after a 1 or 2 byte write to select - * a register. We cannot fulfil this request. + * a register. We cannot fulfill this request. */ i2c_dprintk(2, " read without preceding write not supported"); rc = -EOPNOTSUPP; diff --git a/drivers/media/usb/tm6000/tm6000-stds.c b/drivers/media/usb/tm6000/tm6000-stds.c index c0c75951246b..858cb4f3a9ca 100644 --- a/drivers/media/usb/tm6000/tm6000-stds.c +++ b/drivers/media/usb/tm6000/tm6000-stds.c @@ -323,7 +323,7 @@ static int tm6000_set_audio_std(struct tm6000_core *dev) { uint8_t areg_02 = 0x04; /* GC1 Fixed gain 0dB */ uint8_t areg_05 = 0x01; /* Auto 4.5 = M Japan, Auto 6.5 = DK */ - uint8_t areg_06 = 0x02; /* Auto de-emphasis, mannual channel mode */ + uint8_t areg_06 = 0x02; /* Auto de-emphasis, manual channel mode */ if (dev->radio) { tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00); diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index ee7b5318b351..072210f5f92f 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c @@ -106,7 +106,7 @@ static inline void buffer_filled(struct tm6000_core *dev, dprintk(dev, V4L2_DEBUG_ISOC, "[%p/%d] wakeup\n", buf, buf->vb.i); buf->vb.state = VIDEOBUF_DONE; buf->vb.field_count++; - v4l2_get_timestamp(&buf->vb.ts); + buf->vb.ts = ktime_get_ns(); list_del(&buf->vb.queue); wake_up(&buf->vb.done); @@ -180,7 +180,7 @@ static int copy_streams(u8 *data, unsigned long len, field = (header >> 11) & 0x1; line = (header >> 12) & 0x1ff; cmd = (header >> 21) & 0x7; - /* Validates haeder fields */ + /* Validates header fields */ if (size > TM6000_URB_MSG_LEN) size = TM6000_URB_MSG_LEN; pktsize = TM6000_URB_MSG_LEN; diff --git a/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c index 6eb84cf007b4..4db7a013e049 100644 --- a/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c @@ -306,7 +306,7 @@ static int ttusb_boot_dsp(struct ttusb *ttusb) b[3] = 28; /* upload dsp code in 32 byte steps (36 didn't work for me ...) */ - /* 32 is max packet size, no messages should be splitted. */ + /* 32 is max packet size, no messages should be split. */ for (i = 0; i < fw->size; i += 28) { memcpy(&b[4], &fw->data[i], 28); diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c index 44ca66cb9b8f..897ef5e1da71 100644 --- a/drivers/media/usb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c @@ -284,7 +284,7 @@ static void ttusb_dec_handle_irq( struct urb *urb) * * this is an fact a bit too simple implementation; * the box also reports a keyrepeat signal - * (with buffer[3] == 0x40) in an intervall of ~100ms. + * (with buffer[3] == 0x40) in an interval of ~100ms. * But to handle this correctly we had to imlemenent some * kind of timer which signals a 'key up' event if no * keyrepeat signal is received for lets say 200ms. diff --git a/drivers/media/usb/usbvision/usbvision-core.c b/drivers/media/usb/usbvision/usbvision-core.c index 31e0e98d6daf..92d166bf8c12 100644 --- a/drivers/media/usb/usbvision/usbvision-core.c +++ b/drivers/media/usb/usbvision/usbvision-core.c @@ -900,7 +900,7 @@ static enum parse_state usbvision_parse_lines_420(struct usb_usbvision *usbvisio if ((frame->curline + 1) >= frame->frmheight) return parse_state_next_frame; - block_split = (pixel_per_line%y_block_size) ? 1 : 0; /* are some blocks splitted into different lines? */ + block_split = (pixel_per_line%y_block_size) ? 1 : 0; /* are some blocks split into different lines? */ y_odd_offset = (pixel_per_line / y_block_size) * (y_block_size + uv_block_size) + block_split * uv_block_size; @@ -1160,7 +1160,7 @@ static void usbvision_parse_data(struct usb_usbvision *usbvision) if (newstate == parse_state_next_frame) { frame->grabstate = frame_state_done; - v4l2_get_timestamp(&(frame->timestamp)); + frame->ts = ktime_get_ns(); frame->sequence = usbvision->frame_num; spin_lock_irqsave(&usbvision->queue_lock, lock_flags); @@ -1865,7 +1865,7 @@ static int usbvision_set_compress_params(struct usb_usbvision *usbvision) value[4] = 0xA2; /* Reg.48 BUF_THR I'm not sure if this does something in not compressed mode. */ value[5] = 0x00; /* Reg.49 DVI_YUV This has nothing to do with compression */ - /* catched values for NT1004 */ + /* caught values for NT1004 */ /* value[0] = 0xFF; Never apply intra mode automatically */ /* value[1] = 0xF1; Use full frame height for virtual strip width; One line per strip */ /* value[2] = 0x01; Force intra mode on all new frames */ @@ -1943,7 +1943,7 @@ int usbvision_set_input(struct usb_usbvision *usbvision) /* SAA7113 uses 8 bit output */ value[0] = USBVISION_8_422_SYNC; } else { - /* I'm sure only about d2-d0 [010] 16 bit 4:2:2 usin sync pulses + /* I'm sure only about d2-d0 [010] 16 bit 4:2:2 using sync pulses * as that is how saa7111 is configured */ value[0] = USBVISION_16_422_SYNC; /* | USBVISION_VSNC_POL | USBVISION_VCLK_POL);*/ @@ -2146,7 +2146,7 @@ int usbvision_power_on(struct usb_usbvision *usbvision) /* * usbvision_begin_streaming() - * Sure you have to put bit 7 to 0, if not incoming frames are droped, but no + * Sure you have to put bit 7 to 0, if not incoming frames are dropped, but no * idea about the rest */ int usbvision_begin_streaming(struct usb_usbvision *usbvision) diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c index dd2ff8ed6c6a..e611052ebf59 100644 --- a/drivers/media/usb/usbvision/usbvision-video.c +++ b/drivers/media/usb/usbvision/usbvision-video.c @@ -706,7 +706,7 @@ static int vidioc_querybuf(struct file *file, vb->length = usbvision->curwidth * usbvision->curheight * usbvision->palette.bytes_per_pixel; - vb->timestamp = usbvision->frame[vb->index].timestamp; + vb->timestamp = ns_to_timeval(usbvision->frame[vb->index].ts); vb->sequence = usbvision->frame[vb->index].sequence; return 0; } @@ -775,7 +775,7 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *vb) V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; vb->index = f->index; vb->sequence = f->sequence; - vb->timestamp = f->timestamp; + vb->timestamp = ns_to_timeval(f->ts); vb->field = V4L2_FIELD_NONE; vb->bytesused = f->scanlength; diff --git a/drivers/media/usb/usbvision/usbvision.h b/drivers/media/usb/usbvision/usbvision.h index 017e7baf5747..668167f8951d 100644 --- a/drivers/media/usb/usbvision/usbvision.h +++ b/drivers/media/usb/usbvision/usbvision.h @@ -135,11 +135,11 @@ #define MIN_FRAME_WIDTH 64 #define MAX_USB_WIDTH 320 /* 384 */ -#define MAX_FRAME_WIDTH 320 /* 384 */ /* streching sometimes causes crashes*/ +#define MAX_FRAME_WIDTH 320 /* 384 */ /* stretching sometimes causes crashes*/ #define MIN_FRAME_HEIGHT 48 #define MAX_USB_HEIGHT 240 /* 288 */ -#define MAX_FRAME_HEIGHT 240 /* 288 */ /* Streching sometimes causes crashes*/ +#define MAX_FRAME_HEIGHT 240 /* 288 */ /* Stretching sometimes causes crashes*/ #define MAX_FRAME_SIZE (MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT * MAX_BYTES_PER_PIXEL) #define USBVISION_CLIPMASK_SIZE (MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT / 8) /* bytesize of clipmask */ @@ -177,7 +177,7 @@ enum { * G = 1.164*(Y-16) - 0.813*(U-128) - 0.391*(V-128) * R = 1.164*(Y-16) + 1.596*(U-128) * - * If you fancy integer arithmetics (as you should), hear this: + * If you fancy integer arithmetic (as you should), hear this: * * 65536*B = 76284*(Y-16) + 132252*(V-128) * 65536*G = 76284*(Y-16) - 53281*(U-128) - 25625*(V-128) @@ -316,7 +316,7 @@ struct usbvision_frame { long bytes_read; /* amount of scanlength that has been read from data */ struct usbvision_v4l2_format_st v4l2_format; /* format the user needs*/ int v4l2_linesize; /* bytes for one videoline*/ - struct timeval timestamp; + u64 ts; int sequence; /* How many video frames we send to user */ }; @@ -438,7 +438,7 @@ struct usb_usbvision { int last_compr_level; /* How strong (100) or weak (0) was compression */ int usb_bandwidth; /* Mbit/s */ - /* Statistics that can be overlayed on the screen */ + /* Statistics that can be overlaid on the screen */ unsigned long isoc_urb_count; /* How many URBs we received so far */ unsigned long urb_length; /* Length of last URB */ unsigned long isoc_data_count; /* How many bytes we received */ diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index d45415cbe6e7..14cff91b7aea 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -1212,7 +1212,7 @@ static void uvc_ctrl_fill_event(struct uvc_video_chain *chain, __uvc_query_v4l2_ctrl(chain, ctrl, mapping, &v4l2_ctrl); - memset(ev->reserved, 0, sizeof(ev->reserved)); + memset(ev, 0, sizeof(*ev)); ev->type = V4L2_EVENT_CTRL; ev->id = v4l2_ctrl.id; ev->u.ctrl.value = value; diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index b62cbd800111..10cfe8e51626 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -1106,11 +1106,19 @@ static int uvc_parse_standard_control(struct uvc_device *dev, return -EINVAL; } - /* Make sure the terminal type MSB is not null, otherwise it - * could be confused with a unit. + /* + * Reject invalid terminal types that would cause issues: + * + * - The high byte must be non-zero, otherwise it would be + * confused with a unit. + * + * - Bit 15 must be 0, as we use it internally as a terminal + * direction flag. + * + * Other unknown types are accepted. */ type = get_unaligned_le16(&buffer[4]); - if ((type & 0xff00) == 0) { + if ((type & 0x7f00) == 0 || (type & 0x8000) != 0) { uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " "interface %d INPUT_TERMINAL %d has invalid " "type 0x%04x, skipping\n", udev->devnum, @@ -2175,7 +2183,7 @@ static int uvc_probe(struct usb_interface *intf, if (udev->serial) strscpy(dev->mdev.serial, udev->serial, sizeof(dev->mdev.serial)); - strscpy(dev->mdev.bus_info, udev->devpath, sizeof(dev->mdev.bus_info)); + usb_make_path(udev, dev->mdev.bus_info, sizeof(dev->mdev.bus_info)); dev->mdev.hw_revision = le16_to_cpu(udev->descriptor.bcdDevice); media_device_init(&dev->mdev); diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 84525ff04745..182dcac49aa3 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -676,6 +676,14 @@ void uvc_video_clock_update(struct uvc_streaming *stream, if (!uvc_hw_timestamps_param) return; + /* + * We will get called from __vb2_queue_cancel() if there are buffers + * done but not dequeued by the user, but the sample array has already + * been released at that time. Just bail out in that case. + */ + if (!clock->samples) + return; + spin_lock_irqsave(&clock->lock, flags); if (clock->count < clock->size) @@ -2000,7 +2008,7 @@ int uvc_video_init(struct uvc_streaming *stream) usb_set_interface(stream->dev->udev, stream->intfnum, 0); /* Set the streaming probe control with default streaming parameters - * retrieved from the device. Webcams that don't suport GET_DEF + * retrieved from the device. Webcams that don't support GET_DEF * requests on the probe control will just keep their current streaming * parameters. */ diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 9b41b14ce076..c7c1baa90dea 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -620,8 +620,10 @@ struct uvc_streaming { (uvc_urb) < &(uvc_streaming)->uvc_urb[UVC_URBS]; \ ++(uvc_urb)) -#define uvc_urb_index(uvc_urb) \ - (unsigned int)((uvc_urb) - (&(uvc_urb)->stream->uvc_urb[0])) +static inline u32 uvc_urb_index(const struct uvc_urb *uvc_urb) +{ + return uvc_urb - &uvc_urb->stream->uvc_urb[0]; +} struct uvc_device_info { u32 quirks; diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c index ab35554cbffa..96fee8d5b865 100644 --- a/drivers/media/usb/zr364xx/zr364xx.c +++ b/drivers/media/usb/zr364xx/zr364xx.c @@ -2,7 +2,7 @@ * Zoran 364xx based USB webcam module version 0.73 * * Allows you to use your USB webcam with V4L2 applications - * This is still in heavy developpement ! + * This is still in heavy development ! * * Copyright (C) 2004 Antoine Jacquet <royale@zerezo.com> * http://royale.zerezo.com/zr364xx/ @@ -521,7 +521,7 @@ static void zr364xx_fillbuff(struct zr364xx_camera *cam, /* tell v4l buffer was filled */ buf->vb.field_count = cam->frame_count * 2; - v4l2_get_timestamp(&buf->vb.ts); + buf->vb.ts = ktime_get_ns(); buf->vb.state = VIDEOBUF_DONE; } @@ -549,7 +549,7 @@ static int zr364xx_got_frame(struct zr364xx_camera *cam, int jpgsize) goto unlock; } list_del(&buf->vb.queue); - v4l2_get_timestamp(&buf->vb.ts); + buf->vb.ts = ktime_get_ns(); DBG("[%p/%d] wakeup\n", buf, buf->vb.i); zr364xx_fillbuff(cam, buf, jpgsize); wake_up(&buf->vb.done); diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index 50763fb42a1b..663730f088cd 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -398,16 +398,6 @@ __v4l2_find_nearest_size(const void *array, size_t array_size, } EXPORT_SYMBOL_GPL(__v4l2_find_nearest_size); -void v4l2_get_timestamp(struct timeval *tv) -{ - struct timespec ts; - - ktime_get_ts(&ts); - tv->tv_sec = ts.tv_sec; - tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC; -} -EXPORT_SYMBOL_GPL(v4l2_get_timestamp); - int v4l2_g_parm_cap(struct video_device *vdev, struct v4l2_subdev *sd, struct v4l2_streamparm *a) { diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 5e3806feb5d7..b79d3bbd8350 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -825,6 +825,9 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER:return "H264 Number of HC Layers"; case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP: return "H264 Set QP Value for HC Layers"; + case V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION: + return "H264 Constrained Intra Pred"; + case V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET: return "H264 Chroma QP Index Offset"; case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: return "MPEG4 I-Frame QP Value"; case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP: return "MPEG4 P-Frame QP Value"; case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP: return "MPEG4 B-Frame QP Value"; @@ -1387,7 +1390,7 @@ static u32 user_flags(const struct v4l2_ctrl *ctrl) static void fill_event(struct v4l2_event *ev, struct v4l2_ctrl *ctrl, u32 changes) { - memset(ev->reserved, 0, sizeof(ev->reserved)); + memset(ev, 0, sizeof(*ev)); ev->type = V4L2_EVENT_CTRL; ev->id = ctrl->id; ev->u.ctrl.changes = changes; @@ -1661,15 +1664,6 @@ static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx, return -EINVAL; } - if (p_mpeg2_slice_params->backward_ref_index >= VIDEO_MAX_FRAME || - p_mpeg2_slice_params->forward_ref_index >= VIDEO_MAX_FRAME) - return -EINVAL; - - if (p_mpeg2_slice_params->pad || - p_mpeg2_slice_params->picture.pad || - p_mpeg2_slice_params->sequence.pad) - return -EINVAL; - return 0; case V4L2_CTRL_TYPE_MPEG2_QUANTIZATION: @@ -4172,9 +4166,9 @@ __poll_t v4l2_ctrl_poll(struct file *file, struct poll_table_struct *wait) { struct v4l2_fh *fh = file->private_data; + poll_wait(file, &fh->wait, wait); if (v4l2_event_pending(fh)) return EPOLLPRI; - poll_wait(file, &fh->wait, wait); return 0; } EXPORT_SYMBOL(v4l2_ctrl_poll); diff --git a/drivers/media/v4l2-core/v4l2-event.c b/drivers/media/v4l2-core/v4l2-event.c index 481e3c65cf97..c46d14c996fc 100644 --- a/drivers/media/v4l2-core/v4l2-event.c +++ b/drivers/media/v4l2-core/v4l2-event.c @@ -52,6 +52,7 @@ static int __v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event) kev->event.pending = fh->navailable; *event = kev->event; + event->timestamp = ns_to_timespec(kev->ts); kev->sev->first = sev_pos(kev->sev, 1); kev->sev->in_use--; @@ -103,8 +104,8 @@ static struct v4l2_subscribed_event *v4l2_event_subscribed( return NULL; } -static void __v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *ev, - const struct timespec *ts) +static void __v4l2_event_queue_fh(struct v4l2_fh *fh, + const struct v4l2_event *ev, u64 ts) { struct v4l2_subscribed_event *sev; struct v4l2_kevent *kev; @@ -144,7 +145,7 @@ static void __v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *e if (copy_payload) kev->event.u = ev->u; kev->event.id = ev->id; - kev->event.timestamp = *ts; + kev->ts = ts; kev->event.sequence = fh->sequence; sev->in_use++; list_add_tail(&kev->list, &fh->available); @@ -158,17 +159,17 @@ void v4l2_event_queue(struct video_device *vdev, const struct v4l2_event *ev) { struct v4l2_fh *fh; unsigned long flags; - struct timespec timestamp; + u64 ts; if (vdev == NULL) return; - ktime_get_ts(×tamp); + ts = ktime_get_ns(); spin_lock_irqsave(&vdev->fh_lock, flags); list_for_each_entry(fh, &vdev->fh_list, list) - __v4l2_event_queue_fh(fh, ev, ×tamp); + __v4l2_event_queue_fh(fh, ev, ts); spin_unlock_irqrestore(&vdev->fh_lock, flags); } @@ -177,12 +178,10 @@ EXPORT_SYMBOL_GPL(v4l2_event_queue); void v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *ev) { unsigned long flags; - struct timespec timestamp; - - ktime_get_ts(×tamp); + u64 ts = ktime_get_ns(); spin_lock_irqsave(&fh->vdev->fh_lock, flags); - __v4l2_event_queue_fh(fh, ev, ×tamp); + __v4l2_event_queue_fh(fh, ev, ts); spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); } EXPORT_SYMBOL_GPL(v4l2_event_queue_fh); diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index 9bfedd7596a1..20571846e636 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -46,7 +46,7 @@ static const struct v4l2_fwnode_bus_conv { enum v4l2_fwnode_bus_type fwnode_bus_type; enum v4l2_mbus_type mbus_type; const char *name; -} busses[] = { +} buses[] = { { V4L2_FWNODE_BUS_TYPE_GUESS, V4L2_MBUS_UNKNOWN, @@ -83,9 +83,9 @@ get_v4l2_fwnode_bus_conv_by_fwnode_bus(enum v4l2_fwnode_bus_type type) { unsigned int i; - for (i = 0; i < ARRAY_SIZE(busses); i++) - if (busses[i].fwnode_bus_type == type) - return &busses[i]; + for (i = 0; i < ARRAY_SIZE(buses); i++) + if (buses[i].fwnode_bus_type == type) + return &buses[i]; return NULL; } @@ -113,9 +113,9 @@ get_v4l2_fwnode_bus_conv_by_mbus(enum v4l2_mbus_type type) { unsigned int i; - for (i = 0; i < ARRAY_SIZE(busses); i++) - if (busses[i].mbus_type == type) - return &busses[i]; + for (i = 0; i < ARRAY_SIZE(buses); i++) + if (buses[i].mbus_type == type) + return &buses[i]; return NULL; } @@ -809,7 +809,7 @@ error: * root node and the value of that property matching with the integer argument * of the reference, at the same index. * - * The child fwnode reched at the end of the iteration is then returned to the + * The child fwnode reached at the end of the iteration is then returned to the * caller. * * The core reason for this is that you cannot refer to just any node in ACPI. diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 90aad465f9ed..f6d663934648 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -88,7 +88,7 @@ const char *v4l2_norm_to_name(v4l2_std_id id) int i; /* HACK: ppc32 architecture doesn't have __ucmpdi2 function to handle - 64 bit comparations. So, on that architecture, with some gcc + 64 bit comparisons. So, on that architecture, with some gcc variants, compilation fails. Currently, the max value is 30bit wide. */ BUG_ON(myid != id); @@ -1017,6 +1017,12 @@ static void v4l_sanitize_format(struct v4l2_format *fmt) { unsigned int offset; + /* Make sure num_planes is not bogus */ + if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE || + fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + fmt->fmt.pix_mp.num_planes = min_t(u32, fmt->fmt.pix_mp.num_planes, + VIDEO_MAX_PLANES); + /* * The v4l2_pix_format structure has been extended with fields that were * not previously required to be set to zero by applications. The priv @@ -1214,6 +1220,10 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_YUV555: descr = "16-bit A/XYUV 1-5-5-5"; break; case V4L2_PIX_FMT_YUV565: descr = "16-bit YUV 5-6-5"; break; case V4L2_PIX_FMT_YUV32: descr = "32-bit A/XYUV 8-8-8-8"; break; + case V4L2_PIX_FMT_AYUV32: descr = "32-bit AYUV 8-8-8-8"; break; + case V4L2_PIX_FMT_XYUV32: descr = "32-bit XYUV 8-8-8-8"; break; + case V4L2_PIX_FMT_VUYA32: descr = "32-bit VUYA 8-8-8-8"; break; + case V4L2_PIX_FMT_VUYX32: descr = "32-bit VUYX 8-8-8-8"; break; case V4L2_PIX_FMT_YUV410: descr = "Planar YUV 4:1:0"; break; case V4L2_PIX_FMT_YUV420: descr = "Planar YUV 4:2:0"; break; case V4L2_PIX_FMT_HI240: descr = "8-bit Dithered RGB (BTTV)"; break; @@ -1553,8 +1563,6 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, if (unlikely(!ops->vidioc_s_fmt_vid_cap_mplane)) break; CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); - if (p->fmt.pix_mp.num_planes > VIDEO_MAX_PLANES) - break; for (i = 0; i < p->fmt.pix_mp.num_planes; i++) CLEAR_AFTER_FIELD(&p->fmt.pix_mp.plane_fmt[i], bytesperline); @@ -1586,8 +1594,6 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, if (unlikely(!ops->vidioc_s_fmt_vid_out_mplane)) break; CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); - if (p->fmt.pix_mp.num_planes > VIDEO_MAX_PLANES) - break; for (i = 0; i < p->fmt.pix_mp.num_planes; i++) CLEAR_AFTER_FIELD(&p->fmt.pix_mp.plane_fmt[i], bytesperline); @@ -1656,8 +1662,6 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, if (unlikely(!ops->vidioc_try_fmt_vid_cap_mplane)) break; CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); - if (p->fmt.pix_mp.num_planes > VIDEO_MAX_PLANES) - break; for (i = 0; i < p->fmt.pix_mp.num_planes; i++) CLEAR_AFTER_FIELD(&p->fmt.pix_mp.plane_fmt[i], bytesperline); @@ -1689,8 +1693,6 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, if (unlikely(!ops->vidioc_try_fmt_vid_out_mplane)) break; CLEAR_AFTER_FIELD(p, fmt.pix_mp.xfer_func); - if (p->fmt.pix_mp.num_planes > VIDEO_MAX_PLANES) - break; for (i = 0; i < p->fmt.pix_mp.num_planes; i++) CLEAR_AFTER_FIELD(&p->fmt.pix_mp.plane_fmt[i], bytesperline); diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index 5bbdec55b7d7..3392833d9541 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -131,7 +131,7 @@ struct vb2_queue *v4l2_m2m_get_vq(struct v4l2_m2m_ctx *m2m_ctx, } EXPORT_SYMBOL(v4l2_m2m_get_vq); -void *v4l2_m2m_next_buf(struct v4l2_m2m_queue_ctx *q_ctx) +struct vb2_v4l2_buffer *v4l2_m2m_next_buf(struct v4l2_m2m_queue_ctx *q_ctx) { struct v4l2_m2m_buffer *b; unsigned long flags; @@ -149,7 +149,7 @@ void *v4l2_m2m_next_buf(struct v4l2_m2m_queue_ctx *q_ctx) } EXPORT_SYMBOL_GPL(v4l2_m2m_next_buf); -void *v4l2_m2m_last_buf(struct v4l2_m2m_queue_ctx *q_ctx) +struct vb2_v4l2_buffer *v4l2_m2m_last_buf(struct v4l2_m2m_queue_ctx *q_ctx) { struct v4l2_m2m_buffer *b; unsigned long flags; @@ -167,7 +167,7 @@ void *v4l2_m2m_last_buf(struct v4l2_m2m_queue_ctx *q_ctx) } EXPORT_SYMBOL_GPL(v4l2_m2m_last_buf); -void *v4l2_m2m_buf_remove(struct v4l2_m2m_queue_ctx *q_ctx) +struct vb2_v4l2_buffer *v4l2_m2m_buf_remove(struct v4l2_m2m_queue_ctx *q_ctx) { struct v4l2_m2m_buffer *b; unsigned long flags; @@ -617,36 +617,35 @@ __poll_t v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, __poll_t rc = 0; unsigned long flags; + src_q = v4l2_m2m_get_src_vq(m2m_ctx); + dst_q = v4l2_m2m_get_dst_vq(m2m_ctx); + + poll_wait(file, &src_q->done_wq, wait); + poll_wait(file, &dst_q->done_wq, wait); + if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) { struct v4l2_fh *fh = file->private_data; + poll_wait(file, &fh->wait, wait); if (v4l2_event_pending(fh)) rc = EPOLLPRI; - else if (req_events & EPOLLPRI) - poll_wait(file, &fh->wait, wait); if (!(req_events & (EPOLLOUT | EPOLLWRNORM | EPOLLIN | EPOLLRDNORM))) return rc; } - src_q = v4l2_m2m_get_src_vq(m2m_ctx); - dst_q = v4l2_m2m_get_dst_vq(m2m_ctx); - /* * There has to be at least one buffer queued on each queued_list, which * means either in driver already or waiting for driver to claim it * and start processing. */ - if ((!src_q->streaming || list_empty(&src_q->queued_list)) - && (!dst_q->streaming || list_empty(&dst_q->queued_list))) { + if ((!src_q->streaming || src_q->error || + list_empty(&src_q->queued_list)) && + (!dst_q->streaming || dst_q->error || + list_empty(&dst_q->queued_list))) { rc |= EPOLLERR; goto end; } - spin_lock_irqsave(&src_q->done_lock, flags); - if (list_empty(&src_q->done_list)) - poll_wait(file, &src_q->done_wq, wait); - spin_unlock_irqrestore(&src_q->done_lock, flags); - spin_lock_irqsave(&dst_q->done_lock, flags); if (list_empty(&dst_q->done_list)) { /* @@ -657,8 +656,6 @@ __poll_t v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, spin_unlock_irqrestore(&dst_q->done_lock, flags); return rc | EPOLLIN | EPOLLRDNORM; } - - poll_wait(file, &dst_q->done_wq, wait); } spin_unlock_irqrestore(&dst_q->done_lock, flags); @@ -975,6 +972,27 @@ void v4l2_m2m_buf_queue(struct v4l2_m2m_ctx *m2m_ctx, } EXPORT_SYMBOL_GPL(v4l2_m2m_buf_queue); +void v4l2_m2m_buf_copy_metadata(const struct vb2_v4l2_buffer *out_vb, + struct vb2_v4l2_buffer *cap_vb, + bool copy_frame_flags) +{ + u32 mask = V4L2_BUF_FLAG_TIMECODE | V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + + if (copy_frame_flags) + mask |= V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_PFRAME | + V4L2_BUF_FLAG_BFRAME; + + cap_vb->vb2_buf.timestamp = out_vb->vb2_buf.timestamp; + + if (out_vb->flags & V4L2_BUF_FLAG_TIMECODE) + cap_vb->timecode = out_vb->timecode; + cap_vb->field = out_vb->field; + cap_vb->flags &= ~mask; + cap_vb->flags |= out_vb->flags & mask; + cap_vb->vb2_buf.copied_timestamp = 1; +} +EXPORT_SYMBOL_GPL(v4l2_m2m_buf_copy_metadata); + void v4l2_m2m_request_queue(struct media_request *req) { struct media_request_object *obj, *obj_safe; diff --git a/drivers/media/v4l2-core/videobuf-core.c b/drivers/media/v4l2-core/videobuf-core.c index 7491b337002c..bf7dfb2a34af 100644 --- a/drivers/media/v4l2-core/videobuf-core.c +++ b/drivers/media/v4l2-core/videobuf-core.c @@ -214,7 +214,7 @@ int videobuf_queue_is_busy(struct videobuf_queue *q) return 1; } if (q->bufs[i]->state == VIDEOBUF_ACTIVE) { - dprintk(1, "busy: buffer #%d avtive\n", i); + dprintk(1, "busy: buffer #%d active\n", i); return 1; } } @@ -367,7 +367,7 @@ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b, } b->field = vb->field; - b->timestamp = vb->ts; + b->timestamp = ns_to_timeval(vb->ts); b->bytesused = vb->size; b->sequence = vb->field_count >> 1; } @@ -581,7 +581,7 @@ int videobuf_qbuf(struct videobuf_queue *q, struct v4l2_buffer *b) || q->type == V4L2_BUF_TYPE_SDR_OUTPUT) { buf->size = b->bytesused; buf->field = b->field; - buf->ts = b->timestamp; + buf->ts = v4l2_timeval_to_ns(&b->timestamp); } break; case V4L2_MEMORY_USERPTR: @@ -1119,13 +1119,14 @@ done: EXPORT_SYMBOL_GPL(videobuf_read_stream); __poll_t videobuf_poll_stream(struct file *file, - struct videobuf_queue *q, - poll_table *wait) + struct videobuf_queue *q, + poll_table *wait) { __poll_t req_events = poll_requested_events(wait); struct videobuf_buffer *buf = NULL; __poll_t rc = 0; + poll_wait(file, &buf->done, wait); videobuf_queue_lock(q); if (q->streaming) { if (!list_empty(&q->stream)) @@ -1149,7 +1150,6 @@ __poll_t videobuf_poll_stream(struct file *file, rc = EPOLLERR; if (0 == rc) { - poll_wait(file, &buf->done, wait); if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) { switch (q->type) { diff --git a/drivers/media/v4l2-core/videobuf-dma-contig.c b/drivers/media/v4l2-core/videobuf-dma-contig.c index f46132504d88..e1bf50df4c70 100644 --- a/drivers/media/v4l2-core/videobuf-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf-dma-contig.c @@ -248,7 +248,7 @@ static int __videobuf_iolock(struct videobuf_queue *q, /* All handling should be done by __videobuf_mmap_mapper() */ if (!mem->vaddr) { - dev_err(q->dev, "memory is not alloced/mmapped.\n"); + dev_err(q->dev, "memory is not allocated/mmapped.\n"); return -EINVAL; } break; diff --git a/drivers/media/v4l2-core/videobuf-vmalloc.c b/drivers/media/v4l2-core/videobuf-vmalloc.c index 45fe781aeeec..cb50f1957828 100644 --- a/drivers/media/v4l2-core/videobuf-vmalloc.c +++ b/drivers/media/v4l2-core/videobuf-vmalloc.c @@ -171,7 +171,7 @@ static int __videobuf_iolock(struct videobuf_queue *q, /* All handling should be done by __videobuf_mmap_mapper() */ if (!mem->vaddr) { - printk(KERN_ERR "memory is not alloced/mmapped.\n"); + printk(KERN_ERR "memory is not allocated/mmapped.\n"); return -EINVAL; } break; @@ -196,26 +196,6 @@ static int __videobuf_iolock(struct videobuf_queue *q, } dprintk(1, "vmalloc is at addr %p (%d pages)\n", mem->vaddr, pages); - -#if 0 - int rc; - /* Kernel userptr is used also by read() method. In this case, - there's no need to remap, since data will be copied to user - */ - if (!vb->baddr) - return 0; - - /* FIXME: to properly support USERPTR, remap should occur. - The code below won't work, since mem->vma = NULL - */ - /* Try to remap memory */ - rc = remap_vmalloc_range(mem->vma, (void *)vb->baddr, 0); - if (rc < 0) { - printk(KERN_ERR "mmap: remap failed with error %d", rc); - return -ENOMEM; - } -#endif - break; case V4L2_MEMORY_OVERLAY: default: |