cregit-Linux how code gets into the kernel

Release 4.7 drivers/media/platform/marvell-ccic/mcam-core.c

/*
 * The Marvell camera core.  This device appears in a number of settings,
 * so it needs platform-specific support outside of the core.
 *
 * Copyright 2011 Jonathan Corbet corbet@lwn.net
 */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/wait.h>
#include <linux/list.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
#include <linux/vmalloc.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-event.h>
#include <media/i2c/ov7670.h>
#include <media/videobuf2-vmalloc.h>
#include <media/videobuf2-dma-contig.h>
#include <media/videobuf2-dma-sg.h>

#include "mcam-core.h"

#ifdef MCAM_MODE_VMALLOC
/*
 * Internal DMA buffer management.  Since the controller cannot do S/G I/O,
 * we must have physically contiguous buffers to bring frames into.
 * These parameters control how many buffers we use, whether we
 * allocate them at load time (better chance of success, but nails down
 * memory) or when somebody tries to use the camera (riskier), and,
 * for load-time allocation, how big they should be.
 *
 * The controller can cycle through three buffers.  We could use
 * more by flipping pointers around, but it probably makes little
 * sense.
 */


static bool alloc_bufs_at_read;
module_param(alloc_bufs_at_read, bool, 0444);
MODULE_PARM_DESC(alloc_bufs_at_read,
		"Non-zero value causes DMA buffers to be allocated when the "
		"video capture device is read, rather than at module load "
		"time.  This saves memory, but decreases the chances of "
		"successfully getting those buffers.  This parameter is "
		"only used in the vmalloc buffer mode");


static int n_dma_bufs = 3;
module_param(n_dma_bufs, uint, 0644);
MODULE_PARM_DESC(n_dma_bufs,
		"The number of DMA buffers to allocate.  Can be either two "
		"(saves memory, makes timing tighter) or three.");


static int dma_buf_size = VGA_WIDTH * VGA_HEIGHT * 2;  
/* Worst case */
module_param(dma_buf_size, uint, 0444);
MODULE_PARM_DESC(dma_buf_size,
		"The size of the allocated DMA buffers.  If actual operating "
		"parameters require larger buffers, an attempt to reallocate "
		"will be made.");
#else /* MCAM_MODE_VMALLOC */

static const bool alloc_bufs_at_read;

static const int n_dma_bufs = 3;  
/* Used by S/G_PARM */
#endif /* MCAM_MODE_VMALLOC */


static bool flip;
module_param(flip, bool, 0444);
MODULE_PARM_DESC(flip,
		"If set, the sensor will be instructed to flip the image "
		"vertically.");


static int buffer_mode = -1;
module_param(buffer_mode, int, 0444);
MODULE_PARM_DESC(buffer_mode,
		"Set the buffer mode to be used; default is to go with what "
		"the platform driver asks for.  Set to 0 for vmalloc, 1 for "
		"DMA contiguous.");

/*
 * Status flags.  Always manipulated with bit operations.
 */

#define CF_BUF0_VALID	 0	
/* Buffers valid - first three */

#define CF_BUF1_VALID	 1

#define CF_BUF2_VALID	 2

#define CF_DMA_ACTIVE	 3	
/* A frame is incoming */

#define CF_CONFIG_NEEDED 4	
/* Must configure hardware */

#define CF_SINGLE_BUFFER 5	
/* Running with a single buffer */

#define CF_SG_RESTART	 6	
/* SG restart needed */

#define CF_FRAME_SOF0	 7	
/* Frame 0 started */

#define CF_FRAME_SOF1	 8

#define CF_FRAME_SOF2	 9


#define sensor_call(cam, o, f, args...) \
	v4l2_subdev_call(cam->sensor, o, f, ##args)


static struct mcam_format_struct {
	
__u8 *desc;
	
__u32 pixelformat;
	
int bpp;   /* Bytes per pixel */
	
bool planar;
	
u32 mbus_code;
} 
mcam_formats[] = {
	{
		.desc		= "YUYV 4:2:2",
		.pixelformat	= V4L2_PIX_FMT_YUYV,
		.mbus_code	= MEDIA_BUS_FMT_YUYV8_2X8,
		.bpp		= 2,
		.planar		= false,
        },
	{
		.desc		= "YVYU 4:2:2",
		.pixelformat	= V4L2_PIX_FMT_YVYU,
		.mbus_code	= MEDIA_BUS_FMT_YUYV8_2X8,
		.bpp		= 2,
		.planar		= false,
        },
	{
		.desc		= "YUV 4:2:0 PLANAR",
		.pixelformat	= V4L2_PIX_FMT_YUV420,
		.mbus_code	= MEDIA_BUS_FMT_YUYV8_2X8,
		.bpp		= 1,
		.planar		= true,
        },
	{
		.desc		= "YVU 4:2:0 PLANAR",
		.pixelformat	= V4L2_PIX_FMT_YVU420,
		.mbus_code	= MEDIA_BUS_FMT_YUYV8_2X8,
		.bpp		= 1,
		.planar		= true,
        },
	{
		.desc		= "XRGB 444",
		.pixelformat	= V4L2_PIX_FMT_XRGB444,
		.mbus_code	= MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE,
		.bpp		= 2,
		.planar		= false,
        },
	{
		.desc		= "RGB 565",
		.pixelformat	= V4L2_PIX_FMT_RGB565,
		.mbus_code	= MEDIA_BUS_FMT_RGB565_2X8_LE,
		.bpp		= 2,
		.planar		= false,
        },
	{
		.desc		= "Raw RGB Bayer",
		.pixelformat	= V4L2_PIX_FMT_SBGGR8,
		.mbus_code	= MEDIA_BUS_FMT_SBGGR8_1X8,
		.bpp		= 1,
		.planar		= false,
        },
};

#define N_MCAM_FMTS ARRAY_SIZE(mcam_formats)


static struct mcam_format_struct *mcam_find_format(u32 pixelformat) { unsigned i; for (i = 0; i < N_MCAM_FMTS; i++) if (mcam_formats[i].pixelformat == pixelformat) return mcam_formats + i; /* Not found? Then return the first format. */ return mcam_formats; }

Contributors

PersonTokensPropCommitsCommitProp
hans verkuilhans verkuil4187.23%150.00%
jonathan corbetjonathan corbet612.77%150.00%
Total47100.00%2100.00%

/* * The default format we use until somebody says otherwise. */ static const struct v4l2_pix_format mcam_def_pix_format = { .width = VGA_WIDTH, .height = VGA_HEIGHT, .pixelformat = V4L2_PIX_FMT_YUYV, .field = V4L2_FIELD_NONE, .bytesperline = VGA_WIDTH*2, .sizeimage = VGA_WIDTH*VGA_HEIGHT*2, .colorspace = V4L2_COLORSPACE_SRGB, }; static const u32 mcam_def_mbus_code = MEDIA_BUS_FMT_YUYV8_2X8; /* * The two-word DMA descriptor format used by the Armada 610 and like. There * Is a three-word format as well (set C1_DESC_3WORD) where the third * word is a pointer to the next descriptor, but we don't use it. Two-word * descriptors have to be contiguous in memory. */ struct mcam_dma_desc { u32 dma_addr; u32 segment_len; }; /* * Our buffer type for working with videobuf2. Note that the vb2 * developers have decreed that struct vb2_v4l2_buffer must be at the * beginning of this structure. */ struct mcam_vb_buffer { struct vb2_v4l2_buffer vb_buf; struct list_head queue; struct mcam_dma_desc *dma_desc; /* Descriptor virtual address */ dma_addr_t dma_desc_pa; /* Descriptor physical address */ int dma_desc_nent; /* Number of mapped descriptors */ };
static inline struct mcam_vb_buffer *vb_to_mvb(struct vb2_v4l2_buffer *vb) { return container_of(vb, struct mcam_vb_buffer, vb_buf); }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet2496.00%150.00%
junghak sungjunghak sung14.00%150.00%
Total25100.00%2100.00%

/* * Hand a completed buffer back to user space. */
static void mcam_buffer_done(struct mcam_camera *cam, int frame, struct vb2_v4l2_buffer *vbuf) { vbuf->vb2_buf.planes[0].bytesused = cam->pix_format.sizeimage; vbuf->sequence = cam->buf_seq[frame]; vbuf->field = V4L2_FIELD_NONE; vbuf->vb2_buf.timestamp = ktime_get_ns(); vb2_set_plane_payload(&vbuf->vb2_buf, 0, cam->pix_format.sizeimage); vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE); }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet6068.18%125.00%
junghak sungjunghak sung1820.45%250.00%
hans verkuilhans verkuil1011.36%125.00%
Total88100.00%4100.00%

/* * Debugging and related. */ #define cam_err(cam, fmt, arg...) \ dev_err((cam)->dev, fmt, ##arg); #define cam_warn(cam, fmt, arg...) \ dev_warn((cam)->dev, fmt, ##arg); #define cam_dbg(cam, fmt, arg...) \ dev_dbg((cam)->dev, fmt, ##arg); /* * Flag manipulation helpers */
static void mcam_reset_buffers(struct mcam_camera *cam) { int i; cam->next_buf = -1; for (i = 0; i < cam->nbufs; i++) { clear_bit(i, &cam->flags); clear_bit(CF_FRAME_SOF0 + i, &cam->flags); } }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet4676.67%375.00%
libin yanglibin yang1423.33%125.00%
Total60100.00%4100.00%


static inline int mcam_needs_config(struct mcam_camera *cam) { return test_bit(CF_CONFIG_NEEDED, &cam->flags); }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet23100.00%3100.00%
Total23100.00%3100.00%


static void mcam_set_config_needed(struct mcam_camera *cam, int needed) { if (needed) set_bit(CF_CONFIG_NEEDED, &cam->flags); else clear_bit(CF_CONFIG_NEEDED, &cam->flags); }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet39100.00%2100.00%
Total39100.00%2100.00%

/* ------------------------------------------------------------------- */ /* * Make the controller start grabbing images. Everything must * be set up before doing this. */
static void mcam_ctlr_start(struct mcam_camera *cam) { /* set_bit performs a read, so no other barrier should be needed here */ mcam_reg_set_bit(cam, REG_CTRL0, C0_ENABLE); }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet21100.00%2100.00%
Total21100.00%2100.00%


static void mcam_ctlr_stop(struct mcam_camera *cam) { mcam_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE); }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet20100.00%2100.00%
Total20100.00%2100.00%


static void mcam_enable_mipi(struct mcam_camera *mcam) { /* Using MIPI mode and enable MIPI */ cam_dbg(mcam, "camera: DPHY3=0x%x, DPHY5=0x%x, DPHY6=0x%x\n", mcam->dphy[0], mcam->dphy[1], mcam->dphy[2]); mcam_reg_write(mcam, REG_CSI2_DPHY3, mcam->dphy[0]); mcam_reg_write(mcam, REG_CSI2_DPHY5, mcam->dphy[1]); mcam_reg_write(mcam, REG_CSI2_DPHY6, mcam->dphy[2]); if (!mcam->mipi_enabled) { if (mcam->lane > 4 || mcam->lane <= 0) { cam_warn(mcam, "lane number error\n"); mcam->lane = 1; /* set the default value */ } /* * 0x41 actives 1 lane * 0x43 actives 2 lanes * 0x45 actives 3 lanes (never happen) * 0x47 actives 4 lanes */ mcam_reg_write(mcam, REG_CSI2_CTRL0, CSI2_C0_MIPI_EN | CSI2_C0_ACT_LANE(mcam->lane)); mcam_reg_write(mcam, REG_CLKCTRL, (mcam->mclk_src << 29) | mcam->mclk_div); mcam->mipi_enabled = true; } }

Contributors

PersonTokensPropCommitsCommitProp
libin yanglibin yang163100.00%1100.00%
Total163100.00%1100.00%


static void mcam_disable_mipi(struct mcam_camera *mcam) { /* Using Parallel mode or disable MIPI */ mcam_reg_write(mcam, REG_CSI2_CTRL0, 0x0); mcam_reg_write(mcam, REG_CSI2_DPHY3, 0x0); mcam_reg_write(mcam, REG_CSI2_DPHY5, 0x0); mcam_reg_write(mcam, REG_CSI2_DPHY6, 0x0); mcam->mipi_enabled = false; }

Contributors

PersonTokensPropCommitsCommitProp
libin yanglibin yang54100.00%1100.00%
Total54100.00%1100.00%


static bool mcam_fmt_is_planar(__u32 pfmt) { struct mcam_format_struct *f; f = mcam_find_format(pfmt); return f->planar; }

Contributors

PersonTokensPropCommitsCommitProp
hans verkuilhans verkuil26100.00%1100.00%
Total26100.00%1100.00%


static void mcam_write_yuv_bases(struct mcam_camera *cam, unsigned frame, dma_addr_t base) { struct v4l2_pix_format *fmt = &cam->pix_format; u32 pixel_count = fmt->width * fmt->height; dma_addr_t y, u = 0, v = 0; y = base; switch (fmt->pixelformat) { case V4L2_PIX_FMT_YUV420: u = y + pixel_count; v = u + pixel_count / 4; break; case V4L2_PIX_FMT_YVU420: v = y + pixel_count; u = v + pixel_count / 4; break; default: break; } mcam_reg_write(cam, REG_Y0BAR + frame * 4, y); if (mcam_fmt_is_planar(fmt->pixelformat)) { mcam_reg_write(cam, REG_U0BAR + frame * 4, u); mcam_reg_write(cam, REG_V0BAR + frame * 4, v); } }

Contributors

PersonTokensPropCommitsCommitProp
hans verkuilhans verkuil149100.00%1100.00%
Total149100.00%1100.00%

/* ------------------------------------------------------------------- */ #ifdef MCAM_MODE_VMALLOC /* * Code specific to the vmalloc buffer mode. */ /* * Allocate in-kernel DMA buffers for vmalloc mode. */
static int mcam_alloc_dma_bufs(struct mcam_camera *cam, int loadtime) { int i; mcam_set_config_needed(cam, 1); if (loadtime) cam->dma_buf_size = dma_buf_size; else cam->dma_buf_size = cam->pix_format.sizeimage; if (n_dma_bufs > 3) n_dma_bufs = 3; cam->nbufs = 0; for (i = 0; i < n_dma_bufs; i++) { cam->dma_bufs[i] = dma_alloc_coherent(cam->dev, cam->dma_buf_size, cam->dma_handles + i, GFP_KERNEL); if (cam->dma_bufs[i] == NULL) { cam_warn(cam, "Failed to allocate DMA buffer\n"); break; } (cam->nbufs)++; } switch (cam->nbufs) { case 1: dma_free_coherent(cam->dev, cam->dma_buf_size, cam->dma_bufs[0], cam->dma_handles[0]); cam->nbufs = 0; case 0: cam_err(cam, "Insufficient DMA buffers, cannot operate\n"); return -ENOMEM; case 2: if (n_dma_bufs > 2) cam_warn(cam, "Will limp along with only 2 buffers\n"); break; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet206100.00%3100.00%
Total206100.00%3100.00%


static void mcam_free_dma_bufs(struct mcam_camera *cam) { int i; for (i = 0; i < cam->nbufs; i++) { dma_free_coherent(cam->dev, cam->dma_buf_size, cam->dma_bufs[i], cam->dma_handles[i]); cam->dma_bufs[i] = NULL; } cam->nbufs = 0; }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet71100.00%3100.00%
Total71100.00%3100.00%

/* * Set up DMA buffers when operating in vmalloc mode */
static void mcam_ctlr_dma_vmalloc(struct mcam_camera *cam) { /* * Store the first two YUV buffers. Then either * set the third if it exists, or tell the controller * to just use two. */ mcam_write_yuv_bases(cam, 0, cam->dma_handles[0]); mcam_write_yuv_bases(cam, 1, cam->dma_handles[1]); if (cam->nbufs > 2) { mcam_write_yuv_bases(cam, 2, cam->dma_handles[2]); mcam_reg_clear_bit(cam, REG_CTRL1, C1_TWOBUFS); } else mcam_reg_set_bit(cam, REG_CTRL1, C1_TWOBUFS); if (cam->chip_id == MCAM_CAFE) mcam_reg_write(cam, REG_UBAR, 0); /* 32 bits only */ }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet9392.08%360.00%
hans verkuilhans verkuil87.92%240.00%
Total101100.00%5100.00%

/* * Copy data out to user space in the vmalloc case */
static void mcam_frame_tasklet(unsigned long data) { struct mcam_camera *cam = (struct mcam_camera *) data; int i; unsigned long flags; struct mcam_vb_buffer *buf; spin_lock_irqsave(&cam->dev_lock, flags); for (i = 0; i < cam->nbufs; i++) { int bufno = cam->next_buf; if (cam->state != S_STREAMING || bufno < 0) break; /* I/O got stopped */ if (++(cam->next_buf) >= cam->nbufs) cam->next_buf = 0; if (!test_bit(bufno, &cam->flags)) continue; if (list_empty(&cam->buffers)) { cam->frame_state.singles++; break; /* Leave it valid, hope for better later */ } cam->frame_state.delivered++; clear_bit(bufno, &cam->flags); buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer, queue); list_del_init(&buf->queue); /* * Drop the lock during the big copy. This *should* be safe... */ spin_unlock_irqrestore(&cam->dev_lock, flags); memcpy(vb2_plane_vaddr(&buf->vb_buf.vb2_buf, 0), cam->dma_bufs[bufno], cam->pix_format.sizeimage); mcam_buffer_done(cam, bufno, &buf->vb_buf); spin_lock_irqsave(&cam->dev_lock, flags); } spin_unlock_irqrestore(&cam->dev_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet23795.95%466.67%
libin yanglibin yang83.24%116.67%
junghak sungjunghak sung20.81%116.67%
Total247100.00%6100.00%

/* * Make sure our allocated buffers are up to the task. */
static int mcam_check_dma_buffers(struct mcam_camera *cam) { if (cam->nbufs > 0 && cam->dma_buf_size < cam->pix_format.sizeimage) mcam_free_dma_bufs(cam); if (cam->nbufs == 0) return mcam_alloc_dma_bufs(cam, 0); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet53100.00%1100.00%
Total53100.00%1100.00%


static void mcam_vmalloc_done(struct mcam_camera *cam, int frame) { tasklet_schedule(&cam->s_tasklet); }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet22100.00%1100.00%
Total22100.00%1100.00%

#else /* MCAM_MODE_VMALLOC */
static inline int mcam_alloc_dma_bufs(struct mcam_camera *cam, int loadtime) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet18100.00%1100.00%
Total18100.00%1100.00%


static inline void mcam_free_dma_bufs(struct mcam_camera *cam) { return; }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet13100.00%1100.00%
Total13100.00%1100.00%


static inline int mcam_check_dma_buffers(struct mcam_camera *cam) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet15100.00%1100.00%
Total15100.00%1100.00%

#endif /* MCAM_MODE_VMALLOC */ #ifdef MCAM_MODE_DMA_CONTIG /* ---------------------------------------------------------------------- */ /* * DMA-contiguous code. */ /* * Set up a contiguous buffer for the given frame. Here also is where * the underrun strategy is set: if there is no buffer available, reuse * the buffer from the other BAR and set the CF_SINGLE_BUFFER flag to * keep the interrupt handler from giving that buffer back to user * space. In this way, we always have a buffer to DMA to and don't * have to try to play games stopping and restarting the controller. */
static void mcam_set_contig_buffer(struct mcam_camera *cam, int frame) { struct mcam_vb_buffer *buf; dma_addr_t dma_handle; struct vb2_v4l2_buffer *vb; /* * If there are no available buffers, go into single mode */ if (list_empty(&cam->buffers)) { buf = cam->vb_bufs[frame ^ 0x1]; set_bit(CF_SINGLE_BUFFER, &cam->flags); cam->frame_state.singles++; } else { /* * OK, we have a buffer we can use. */ buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer, queue); list_del_init(&buf->queue); clear_bit(CF_SINGLE_BUFFER, &cam->flags); } cam->vb_bufs[frame] = buf; vb = &buf->vb_buf; dma_handle = vb2_dma_contig_plane_dma_addr(&vb->vb2_buf, 0); mcam_write_yuv_bases(cam, frame, dma_handle); }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet8660.56%444.44%
libin yanglibin yang5035.21%333.33%
junghak sungjunghak sung42.82%111.11%
hans verkuilhans verkuil21.41%111.11%
Total142100.00%9100.00%

/* * Initial B_DMA_contig setup. */
static void mcam_ctlr_dma_contig(struct mcam_camera *cam) { mcam_reg_set_bit(cam, REG_CTRL1, C1_TWOBUFS); cam->nbufs = 2; mcam_set_contig_buffer(cam, 0); mcam_set_contig_buffer(cam, 1); }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet40100.00%4100.00%
Total40100.00%4100.00%

/* * Frame completion handling. */
static void mcam_dma_contig_done(struct mcam_camera *cam, int frame) { struct mcam_vb_buffer *buf = cam->vb_bufs[frame]; if (!test_bit(CF_SINGLE_BUFFER, &cam->flags)) { cam->frame_state.delivered++; cam->vb_bufs[frame] = NULL; mcam_buffer_done(cam, frame, &buf->vb_buf); } mcam_set_contig_buffer(cam, frame); }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet6382.89%250.00%
hans verkuilhans verkuil911.84%125.00%
libin yanglibin yang45.26%125.00%
Total76100.00%4100.00%

#endif /* MCAM_MODE_DMA_CONTIG */ #ifdef MCAM_MODE_DMA_SG /* ---------------------------------------------------------------------- */ /* * Scatter/gather-specific code. */ /* * Set up the next buffer for S/G I/O; caller should be sure that * the controller is stopped and a buffer is available. */
static void mcam_sg_next_buffer(struct mcam_camera *cam) { struct mcam_vb_buffer *buf; buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer, queue); list_del_init(&buf->queue); /* * Very Bad Not Good Things happen if you don't clear * C1_DESC_ENA before making any descriptor changes. */ mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_ENA); mcam_reg_write(cam, REG_DMA_DESC_Y, buf->dma_desc_pa); mcam_reg_write(cam, REG_DESC_LEN_Y, buf->dma_desc_nent*sizeof(struct mcam_dma_desc)); mcam_reg_write(cam, REG_DESC_LEN_U, 0); mcam_reg_write(cam, REG_DESC_LEN_V, 0); mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA); cam->vb_bufs[0] = buf; }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet113100.00%6100.00%
Total113100.00%6100.00%

/* * Initial B_DMA_sg setup */
static void mcam_ctlr_dma_sg(struct mcam_camera *cam) { /* * The list-empty condition can hit us at resume time * if the buffer list was empty when the system was suspended. */ if (list_empty(&cam->buffers)) { set_bit(CF_SG_RESTART, &cam->flags); return; } mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_3WORD); mcam_sg_next_buffer(cam); cam->nbufs = 3; }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet55100.00%5100.00%
Total55100.00%5100.00%

/* * Frame completion with S/G is trickier. We can't muck with * a descriptor chain on the fly, since the controller buffers it * internally. So we have to actually stop and restart; Marvell * says this is the way to do it. * * Of course, stopping is easier said than done; experience shows * that the controller can start a frame *after* C0_ENABLE has been * cleared. So when running in S/G mode, the controller is "stopped" * on receipt of the start-of-frame interrupt. That means we can * safely change the DMA descriptor array here and restart things * (assuming there's another buffer waiting to go). */
static void mcam_dma_sg_done(struct mcam_camera *cam, int frame) { struct mcam_vb_buffer *buf = cam->vb_bufs[0]; /* * If we're no longer supposed to be streaming, don't do anything. */ if (cam->state != S_STREAMING) return; /* * If we have another buffer available, put it in and * restart the engine. */ if (!list_empty(&cam->buffers)) { mcam_sg_next_buffer(cam); mcam_ctlr_start(cam); /* * Otherwise set CF_SG_RESTART and the controller will * be restarted once another buffer shows up. */ } else { set_bit(CF_SG_RESTART, &cam->flags); cam->frame_state.singles++; cam->vb_bufs[0] = NULL; } /* * Now we can give the completed frame back to user space. */ cam->frame_state.delivered++; mcam_buffer_done(cam, frame, &buf->vb_buf); }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet10191.82%571.43%
libin yanglibin yang87.27%114.29%
hans verkuilhans verkuil10.91%114.29%
Total110100.00%7100.00%

/* * Scatter/gather mode requires stopping the controller between * frames so we can put in a new DMA descriptor array. If no new * buffer exists at frame completion, the controller is left stopped; * this function is charged with gettig things going again. */
static void mcam_sg_restart(struct mcam_camera *cam) { mcam_ctlr_dma_sg(cam); mcam_ctlr_start(cam); clear_bit(CF_SG_RESTART, &cam->flags); }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet31100.00%3100.00%
Total31100.00%3100.00%

#else /* MCAM_MODE_DMA_SG */
static inline void mcam_sg_restart(struct mcam_camera *cam) { return; }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet13100.00%1100.00%
Total13100.00%1100.00%

#endif /* MCAM_MODE_DMA_SG */ /* ---------------------------------------------------------------------- */ /* * Buffer-mode-independent controller code. */ /* * Image format setup */
static void mcam_ctlr_image(struct mcam_camera *cam) { struct v4l2_pix_format *fmt = &cam->pix_format; u32 widthy = 0, widthuv = 0, imgsz_h, imgsz_w; cam_dbg(cam, "camera: bytesperline = %d; height = %d\n", fmt->bytesperline, fmt->sizeimage / fmt->bytesperline); imgsz_h = (fmt->height << IMGSZ_V_SHIFT) & IMGSZ_V_MASK; imgsz_w = (fmt->width * 2) & IMGSZ_H_MASK; switch (fmt->pixelformat) { case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_YVYU: widthy = fmt->width * 2; widthuv = 0; break; case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: widthy = fmt->width; widthuv = fmt->width / 2; break; default: widthy = fmt->bytesperline; widthuv = 0; break; } mcam_reg_write_mask(cam, REG_IMGPITCH, widthuv << 16 | widthy, IMGP_YP_MASK | IMGP_UVP_MASK); mcam_reg_write(cam, REG_IMGSIZE, imgsz_h | imgsz_w); mcam_reg_write(cam, REG_IMGOFFSET, 0x0); /* * Tell the controller about the image format we are using. */ switch (fmt->pixelformat) { case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: mcam_reg_write_mask(cam, REG_CTRL0, C0_DF_YUV | C0_YUV_420PL | C0_YUVE_VYUY, C0_DF_MASK); break; case V4L2_PIX_FMT_YUYV: mcam_reg_write_mask(cam, REG_CTRL0, C0_DF_YUV | C0_YUV_PACKED | C0_YUVE_NOSWAP, C0_DF_MASK); break; case V4L2_PIX_FMT_YVYU: mcam_reg_write_mask(cam, REG_CTRL0, C0_DF_YUV | C0_YUV_PACKED | C0_YUVE_SWAP24, C0_DF_MASK); break; case V4L2_PIX_FMT_XRGB444: mcam_reg_write_mask(cam, REG_CTRL0, C0_DF_RGB | C0_RGBF_444 | C0_RGB4_XBGR, C0_DF_MASK); break; case V4L2_PIX_FMT_RGB565: mcam_reg_write_mask(cam, REG_CTRL0, C0_DF_RGB | C0_RGBF_565 | C0_RGB5_BGGR, C0_DF_MASK); break; case V4L2_PIX_FMT_SBGGR8: mcam_reg_write_mask(cam, REG_CTRL0, C0_DF_RGB | C0_RGB5_GRBG, C0_DF_MASK); break; default: cam_err(cam, "camera: unknown format: %#x\n", fmt->pixelformat); break; } /* * Make sure it knows we want to use hsync/vsync. */ mcam_reg_write_mask(cam, REG_CTRL0, C0_SIF_HVSYNC, C0_SIFM_MASK); /* * This field controls the generation of EOF(DVP only) */ if (cam->bus_type != V4L2_MBUS_CSI2) mcam_reg_set_bit(cam, REG_CTRL0, C0_EOF_VSYNC | C0_VEDGE_CTRL); }

Contributors

PersonTokensPropCommitsCommitProp
libin yanglibin yang18453.64%218.18%
jonathan corbetjonathan corbet13138.19%327.27%
hans verkuilhans verkuil288.16%654.55%
Total343100.00%11100.00%

/* * Configure the controller for operation; caller holds the * device mutex. */
static int mcam_ctlr_configure(struct mcam_camera *cam) { unsigned long flags; spin_lock_irqsave(&cam->dev_lock, flags); clear_bit(CF_SG_RESTART, &cam->flags); cam->dma_setup(cam); mcam_ctlr_image(cam); mcam_set_config_needed(cam, 0); spin_unlock_irqrestore(&cam->dev_lock, flags); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet67100.00%5100.00%
Total67100.00%5100.00%


static void mcam_ctlr_irq_enable(struct mcam_camera *cam) { /* * Clear any pending interrupts, since we do not * expect to have I/O active prior to enabling. */ mcam_reg_write(cam, REG_IRQSTAT, FRAMEIRQS); mcam_reg_set_bit(cam, REG_IRQMASK, FRAMEIRQS); }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet30100.00%2100.00%
Total30100.00%2100.00%


static void mcam_ctlr_irq_disable(struct mcam_camera *cam) { mcam_reg_clear_bit(cam, REG_IRQMASK, FRAMEIRQS); }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet20100.00%1100.00%
Total20100.00%1100.00%


static void mcam_ctlr_init(struct mcam_camera *cam) { unsigned long flags; spin_lock_irqsave(&cam->dev_lock, flags); /* * Make sure it's not powered down. */ mcam_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN); /* * Turn off the enable bit. It sure should be off anyway, * but it's good to be sure. */ mcam_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE); /* * Clock the sensor appropriately. Controller clock should * be 48MHz, sensor "typical" value is half that. */ mcam_reg_write_mask(cam, REG_CLKCTRL, 2, CLK_DIV_MASK); spin_unlock_irqrestore(&cam->dev_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet67100.00%1100.00%
Total67100.00%1100.00%

/* * Stop the controller, and don't return until we're really sure that no * further DMA is going on. */
static void mcam_ctlr_stop_dma(struct mcam_camera *cam) { unsigned long flags; /* * Theory: stop the camera controller (whether it is operating * or not). Delay briefly just in case we race with the SOF * interrupt, then wait until no DMA is active. */ spin_lock_irqsave(&cam->dev_lock, flags); clear_bit(CF_SG_RESTART, &cam->flags); mcam_ctlr_stop(cam); cam->state = S_IDLE; spin_unlock_irqrestore(&cam->dev_lock, flags); /* * This is a brutally long sleep, but experience shows that * it can take the controller a while to get the message that * it needs to stop grabbing frames. In particular, we can * sometimes (on mmp) get a frame at the end WITHOUT the * start-of-frame indication. */ msleep(150); if (test_bit(CF_DMA_ACTIVE, &cam->flags)) cam_err(cam, "Timeout waiting for DMA to end\n"); /* This would be bad news - what now? */ spin_lock_irqsave(&cam->dev_lock, flags); mcam_ctlr_irq_disable(cam); spin_unlock_irqrestore(&cam->dev_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet108100.00%2100.00%
Total108100.00%2100.00%

/* * Power up and down. */
static int mcam_ctlr_power_up(struct mcam_camera *cam) { unsigned long flags; int ret; spin_lock_irqsave(&cam->dev_lock, flags); ret = cam->plat_power_up(cam); if (ret) { spin_unlock_irqrestore(&cam->dev_lock, flags); return ret; } mcam_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN); spin_unlock_irqrestore(&cam->dev_lock, flags); msleep(5); /* Just to be sure */ return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet5666.67%150.00%
libin yanglibin yang2833.33%150.00%
Total84100.00%2100.00%


static void mcam_ctlr_power_down(struct mcam_camera *cam) { unsigned long flags; spin_lock_irqsave(&cam->dev_lock, flags); /* * School of hard knocks department: be sure we do any register * twiddling on the controller *before* calling the platform * power down routine. */ mcam_reg_set_bit(cam, REG_CTRL1, C1_PWRDWN); cam->plat_power_down(cam); spin_unlock_irqrestore(&cam->dev_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet52100.00%1100.00%
Total52100.00%1100.00%

/* -------------------------------------------------------------------- */ /* * Communications with the sensor. */
static int __mcam_cam_reset(struct mcam_camera *cam) { return sensor_call(cam, core, reset, 0); }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet23100.00%1100.00%
Total23100.00%1100.00%

/* * We have found the sensor on the i2c. Let's try to have a * conversation. */
static int mcam_cam_init(struct mcam_camera *cam) { int ret; if (cam->state != S_NOTREADY) cam_warn(cam, "Cam init with device in funky state %d", cam->state); ret = __mcam_cam_reset(cam); /* Get/set parameters? */ cam->state = S_IDLE; mcam_ctlr_power_down(cam); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet55100.00%2100.00%
Total55100.00%2100.00%

/* * Configure the sensor to match the parameters we have. Caller should * hold s_mutex */
static int mcam_cam_set_flip(struct mcam_camera *cam) { struct v4l2_control ctrl; memset(&ctrl, 0, sizeof(ctrl)); ctrl.id = V4L2_CID_VFLIP; ctrl.value = flip; return sensor_call(cam, core, s_ctrl, &ctrl); }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet53100.00%3100.00%
Total53100.00%3100.00%


static int mcam_cam_configure(struct mcam_camera *cam) { struct v4l2_subdev_format format = { .which = V4L2_SUBDEV_FORMAT_ACTIVE, }; int ret; v4l2_fill_mbus_format(&format.format, &cam->pix_format, cam->mbus_code); ret = sensor_call(cam, core, init, 0); if (ret == 0) ret = sensor_call(cam, pad, set_fmt, NULL, &format); /* * OV7670 does weird things if flip is set *before* format... */ ret += mcam_cam_set_flip(cam); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet7180.68%266.67%
hans verkuilhans verkuil1719.32%133.33%
Total88100.00%3100.00%

/* * Get everything ready, and start grabbing frames. */
static int mcam_read_setup(struct mcam_camera *cam) { int ret; unsigned long flags; /* * Configuration. If we still don't have DMA buffers, * make one last, desperate attempt. */ if (cam->buffer_mode == B_vmalloc && cam->nbufs == 0 && mcam_alloc_dma_bufs(cam, 0)) return -ENOMEM; if (mcam_needs_config(cam)) { mcam_cam_configure(cam); ret = mcam_ctlr_configure(cam); if (ret) return ret; } /* * Turn it loose. */ spin_lock_irqsave(&cam->dev_lock, flags); clear_bit(CF_DMA_ACTIVE, &cam->flags); mcam_reset_buffers(cam); /* * Update CSI2_DPHY value */ if (cam->calc_dphy) cam->calc_dphy(cam); cam_dbg(cam, "camera: DPHY sets: dphy3=0x%x, dphy5=0x%x, dphy6=0x%x\n", cam->dphy[0], cam->dphy[1], cam->dphy[2]); if (cam->bus_type == V4L2_MBUS_CSI2) mcam_enable_mipi(cam); else mcam_disable_mipi(cam); mcam_ctlr_irq_enable(cam); cam->state = S_STREAMING; if (!test_bit(CF_SG_RESTART, &cam->flags)) mcam_ctlr_start(cam); spin_unlock_irqrestore(&cam->dev_lock, flags); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet14069.65%583.33%
libin yanglibin yang6130.35%116.67%
Total201100.00%6100.00%

/* ----------------------------------------------------------------------- */ /* * Videobuf2 interface code. */
static int mcam_vb_queue_setup(struct vb2_queue *vq, unsigned int *nbufs, unsigned int *num_planes, unsigned int sizes[], void *alloc_ctxs[]) { struct mcam_camera *cam = vb2_get_drv_priv(vq); int minbufs = (cam->buffer_mode == B_DMA_contig) ? 3 : 2; unsigned size = cam->pix_format.sizeimage; if (*nbufs < minbufs) *nbufs = minbufs; if (cam->buffer_mode == B_DMA_contig) alloc_ctxs[0] = cam->vb_alloc_ctx; else if (cam->buffer_mode == B_DMA_sg) alloc_ctxs[0] = cam->vb_alloc_ctx_sg; if (*num_planes) return sizes[0] < size ? -EINVAL : 0; sizes[0] = size; *num_planes = 1; /* Someday we have to support planar formats... */ return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet9263.01%457.14%
hans verkuilhans verkuil5336.30%228.57%
marek szyprowskimarek szyprowski10.68%114.29%
Total146100.00%7100.00%


static void mcam_vb_buf_queue(struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct mcam_vb_buffer *mvb = vb_to_mvb(vbuf); struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue); unsigned long flags; int start; spin_lock_irqsave(&cam->dev_lock, flags); start = (cam->state == S_BUFWAIT) && !list_empty(&cam->buffers); list_add(&mvb->queue, &cam->buffers); if (cam->state == S_STREAMING && test_bit(CF_SG_RESTART, &cam->flags)) mcam_sg_restart(cam); spin_unlock_irqrestore(&cam->dev_lock, flags); if (start) mcam_read_setup(cam); }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet12391.79%583.33%
junghak sungjunghak sung118.21%116.67%
Total134100.00%6100.00%


static void mcam_vb_requeue_bufs(struct vb2_queue *vq, enum vb2_buffer_state state) { struct mcam_camera *cam = vb2_get_drv_priv(vq); struct mcam_vb_buffer *buf, *node; unsigned long flags; unsigned i; spin_lock_irqsave(&cam->dev_lock, flags); list_for_each_entry_safe(buf, node, &cam->buffers, queue) { vb2_buffer_done(&buf->vb_buf.vb2_buf, state); list_del(&buf->queue); } for (i = 0; i < MAX_DMA_BUFS; i++) { buf = cam->vb_bufs[i]; if (buf) { vb2_buffer_done(&buf->vb_buf.vb2_buf, state); cam->vb_bufs[i] = NULL; } } spin_unlock_irqrestore(&cam->dev_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
hans verkuilhans verkuil13997.20%150.00%
junghak sungjunghak sung42.80%150.00%
Total143100.00%2100.00%

/* * These need to be called with the mutex held from vb2 */
static int mcam_vb_start_streaming(struct vb2_queue *vq, unsigned int count) { struct mcam_camera *cam = vb2_get_drv_priv(vq); unsigned int frame; int ret; if (cam->state != S_IDLE) { mcam_vb_requeue_bufs(vq, VB2_BUF_STATE_QUEUED); return -EINVAL; } cam->frame_state.frames = 0; cam->frame_state.singles = 0; cam->frame_state.delivered = 0; cam->sequence = 0; /* * Videobuf2 sneakily hoards all the buffers and won't * give them to us until *after* streaming starts. But * we can't actually start streaming until we have a * destination. So go into a wait state and hope they * give us buffers soon. */ if (cam->buffer_mode != B_vmalloc && list_empty(&cam->buffers)) { cam->state = S_BUFWAIT; return 0; } /* * Ensure clear the left over frame flags * before every really start streaming */ for (frame = 0; frame < cam->nbufs; frame++) clear_bit(CF_FRAME_SOF0 + frame, &cam->flags); ret = mcam_read_setup(cam); if (ret) mcam_vb_requeue_bufs(vq, VB2_BUF_STATE_QUEUED); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet7245.00%233.33%
hans verkuilhans verkuil4729.38%233.33%
libin yanglibin yang3220.00%116.67%
marek szyprowskimarek szyprowski95.62%116.67%
Total160100.00%6100.00%


static void mcam_vb_stop_streaming(struct vb2_queue *vq) { struct mcam_camera *cam = vb2_get_drv_priv(vq); cam_dbg(cam, "stop_streaming: %d frames, %d singles, %d delivered\n", cam->frame_state.frames, cam->frame_state.singles, cam->frame_state.delivered); if (cam->state == S_BUFWAIT) { /* They never gave us buffers */ cam->state = S_IDLE; return; } if (cam->state != S_STREAMING) return; mcam_ctlr_stop_dma(cam); /* * Reset the CCIC PHY after stopping streaming, * otherwise, the CCIC may be unstable. */ if (cam->ctlr_reset) cam->ctlr_reset(cam); /* * VB2 reclaims the buffers, so we need to forget * about them. */ mcam_vb_requeue_bufs(vq, VB2_BUF_STATE_ERROR); }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet5555.00%233.33%
hans verkuilhans verkuil3131.00%350.00%
libin yanglibin yang1414.00%116.67%
Total100100.00%6100.00%

static const struct vb2_ops mcam_vb2_ops = { .queue_setup = mcam_vb_queue_setup, .buf_queue = mcam_vb_buf_queue, .start_streaming = mcam_vb_start_streaming, .stop_streaming = mcam_vb_stop_streaming, .wait_prepare = vb2_ops_wait_prepare, .wait_finish = vb2_ops_wait_finish, }; #ifdef MCAM_MODE_DMA_SG /* * Scatter/gather mode uses all of the above functions plus a * few extras to deal with DMA mapping. */
static int mcam_vb_sg_buf_init(struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct mcam_vb_buffer *mvb = vb_to_mvb(vbuf); struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue); int ndesc = cam->pix_format.sizeimage/PAGE_SIZE + 1; mvb->dma_desc = dma_alloc_coherent(cam->dev, ndesc * sizeof(struct mcam_dma_desc), &mvb->dma_desc_pa, GFP_KERNEL); if (mvb->dma_desc == NULL) { cam_err(cam, "Unable to get DMA descriptor array\n"); return -ENOMEM; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet9589.62%266.67%
junghak sungjunghak sung1110.38%133.33%
Total106100.00%3100.00%


static int mcam_vb_sg_buf_prepare(struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct mcam_vb_buffer *mvb = vb_to_mvb(vbuf); struct sg_table *sg_table = vb2_dma_sg_plane_desc(vb, 0); struct mcam_dma_desc *desc = mvb->dma_desc; struct scatterlist *sg; int i; for_each_sg(sg_table->sgl, sg, sg_table->nents, i) { desc->dma_addr = sg_dma_address(sg); desc->segment_len = sg_dma_len(sg); desc++; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet8184.38%350.00%
junghak sungjunghak sung1111.46%116.67%
ricardo ribaldaricardo ribalda33.12%116.67%
hans verkuilhans verkuil11.04%116.67%
Total96100.00%6100.00%


static void mcam_vb_sg_buf_cleanup(struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue); struct mcam_vb_buffer *mvb = vb_to_mvb(vbuf); int ndesc = cam->pix_format.sizeimage/PAGE_SIZE + 1; dma_free_coherent(cam->dev, ndesc * sizeof(struct mcam_dma_desc), mvb->dma_desc, mvb->dma_desc_pa); }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet6886.08%480.00%
junghak sungjunghak sung1113.92%120.00%
Total79100.00%5100.00%

static const struct vb2_ops mcam_vb2_sg_ops = { .queue_setup = mcam_vb_queue_setup, .buf_init = mcam_vb_sg_buf_init, .buf_prepare = mcam_vb_sg_buf_prepare, .buf_queue = mcam_vb_buf_queue, .buf_cleanup = mcam_vb_sg_buf_cleanup, .start_streaming = mcam_vb_start_streaming, .stop_streaming = mcam_vb_stop_streaming, .wait_prepare = vb2_ops_wait_prepare, .wait_finish = vb2_ops_wait_finish, }; #endif /* MCAM_MODE_DMA_SG */
static int mcam_setup_vb2(struct mcam_camera *cam) { struct vb2_queue *vq = &cam->vb_queue; memset(vq, 0, sizeof(*vq)); vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; vq->drv_priv = cam; vq->lock = &cam->s_mutex; vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; vq->buf_struct_size = sizeof(struct mcam_vb_buffer); INIT_LIST_HEAD(&cam->buffers); switch (cam->buffer_mode) { case B_DMA_contig: #ifdef MCAM_MODE_DMA_CONTIG vq->ops = &mcam_vb2_ops; vq->mem_ops = &vb2_dma_contig_memops; cam->dma_setup = mcam_ctlr_dma_contig; cam->frame_complete = mcam_dma_contig_done; cam->vb_alloc_ctx = vb2_dma_contig_init_ctx(cam->dev); if (IS_ERR(cam->vb_alloc_ctx)) return PTR_ERR(cam->vb_alloc_ctx); #endif break; case B_DMA_sg: #ifdef MCAM_MODE_DMA_SG vq->ops = &mcam_vb2_sg_ops; vq->mem_ops = &vb2_dma_sg_memops; cam->dma_setup = mcam_ctlr_dma_sg; cam->frame_complete = mcam_dma_sg_done; cam->vb_alloc_ctx_sg = vb2_dma_sg_init_ctx(cam->dev); if (IS_ERR(cam->vb_alloc_ctx_sg)) return PTR_ERR(cam->vb_alloc_ctx_sg); #endif break; case B_vmalloc: #ifdef MCAM_MODE_VMALLOC tasklet_init(&cam->s_tasklet, mcam_frame_tasklet, (unsigned long) cam); vq->ops = &mcam_vb2_ops; vq->mem_ops = &vb2_vmalloc_memops; cam->dma_setup = mcam_ctlr_dma_vmalloc; cam->frame_complete = mcam_vmalloc_done; #endif break; } return vb2_queue_init(vq); }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet18967.02%660.00%
hans verkuilhans verkuil8429.79%330.00%
prabhakar ladprabhakar lad93.19%110.00%
Total282100.00%10100.00%


static void mcam_cleanup_vb2(struct mcam_camera *cam) { #ifdef MCAM_MODE_DMA_CONTIG if (cam->buffer_mode == B_DMA_contig) vb2_dma_contig_cleanup_ctx(cam->vb_alloc_ctx); #endif #ifdef MCAM_MODE_DMA_SG if (cam->buffer_mode == B_DMA_sg) vb2_dma_sg_cleanup_ctx(cam->vb_alloc_ctx_sg); #endif }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet3160.78%480.00%
hans verkuilhans verkuil2039.22%120.00%
Total51100.00%5100.00%

/* ---------------------------------------------------------------------- */ /* * The long list of V4L2 ioctl() operations. */
static int mcam_vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { struct mcam_camera *cam = video_drvdata(file); strcpy(cap->driver, "marvell_ccic"); strcpy(cap->card, "marvell_ccic"); strlcpy(cap->bus_info, cam->bus_info, sizeof(cap->bus_info)); cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
hans verkuilhans verkuil5359.55%250.00%
jonathan corbetjonathan corbet3640.45%250.00%
Total89100.00%4100.00%


static int mcam_vidioc_enum_fmt_vid_cap(struct file *filp, void *priv, struct v4l2_fmtdesc *fmt) { if (fmt->index >= N_MCAM_FMTS) return -EINVAL; strlcpy(fmt->description, mcam_formats[fmt->index].desc, sizeof(fmt->description)); fmt->pixelformat = mcam_formats[fmt->index].pixelformat; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
hans verkuilhans verkuil4664.79%133.33%
jonathan corbetjonathan corbet2535.21%266.67%
Total71100.00%3100.00%


static int mcam_vidioc_try_fmt_vid_cap(struct file *filp, void *priv, struct v4l2_format *fmt) { struct mcam_camera *cam = video_drvdata(filp); struct mcam_format_struct *f; struct v4l2_pix_format *pix = &fmt->fmt.pix; struct v4l2_subdev_pad_config pad_cfg; struct v4l2_subdev_format format = { .which = V4L2_SUBDEV_FORMAT_TRY, }; int ret; f = mcam_find_format(pix->pixelformat); pix->pixelformat = f->pixelformat; v4l2_fill_mbus_format(&format.format, pix, f->mbus_code); ret = sensor_call(cam, pad, set_fmt, &pad_cfg, &format); v4l2_fill_pix_format(pix, &format.format); pix->bytesperline = pix->width * f->bpp; switch (f->pixelformat) { case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: pix->sizeimage = pix->height * pix->bytesperline * 3 / 2; break; default: pix->sizeimage = pix->height * pix->bytesperline; break; } pix->colorspace = V4L2_COLORSPACE_SRGB; return ret; }

Contributors

PersonTokensPropCommitsCommitProp
hans verkuilhans verkuil15280.42%466.67%
jonathan corbetjonathan corbet3719.58%233.33%
Total189100.00%6100.00%


static int mcam_vidioc_s_fmt_vid_cap(struct file *filp, void *priv, struct v4l2_format *fmt) { struct mcam_camera *cam = video_drvdata(filp); struct mcam_format_struct *f; int ret; /* * Can't do anything if the device is not idle * Also can't if there are streaming buffers in place. */ if (cam->state != S_IDLE || vb2_is_busy(&cam->vb_queue)) return -EBUSY; f = mcam_find_format(fmt->fmt.pix.pixelformat); /* * See if the formatting works in principle. */ ret = mcam_vidioc_try_fmt_vid_cap(filp, priv, fmt); if (ret) return ret; /* * Now we start to change things for real, so let's do it * under lock. */ cam->pix_format = fmt->fmt.pix; cam->mbus_code = f->mbus_code; /* * Make sure we have appropriate DMA buffers. */ if (cam->buffer_mode == B_vmalloc) { ret = mcam_check_dma_buffers(cam); if (ret) goto out; } mcam_set_config_needed(cam, 1); out: return ret; }

Contributors

PersonTokensPropCommitsCommitProp
hans verkuilhans verkuil10269.39%342.86%
jonathan corbetjonathan corbet4530.61%457.14%
Total147100.00%7100.00%

/* * Return our stored notion of how the camera is/should be configured. * The V4l2 spec wants us to be smarter, and actually get this from * the camera (and not mess with it at open time). Someday. */
static int mcam_vidioc_g_fmt_vid_cap(struct file *filp, void *priv, struct v4l2_format *f) { struct mcam_camera *cam = video_drvdata(filp); f->fmt.pix = cam->pix_format; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet2967.44%360.00%
hans verkuilhans verkuil1432.56%240.00%
Total43100.00%5100.00%

/* * We only have one input - the sensor - so minimize the nonsense here. */
static int mcam_vidioc_enum_input(struct file *filp, void *priv, struct v4l2_input *input) { if (input->index != 0) return -EINVAL; input->type = V4L2_INPUT_TYPE_CAMERA; strcpy(input->name, "Camera"); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet2652.00%375.00%
hans verkuilhans verkuil2448.00%125.00%
Total50100.00%4100.00%


static int mcam_vidioc_g_input(struct file *filp, void *priv, unsigned int *i) { *i = 0; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet2071.43%150.00%
hans verkuilhans verkuil828.57%150.00%
Total28100.00%2100.00%


static int mcam_vidioc_s_input(struct file *filp, void *priv, unsigned int i) { if (i != 0) return -EINVAL; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet1753.12%133.33%
hans verkuilhans verkuil1546.88%266.67%
Total32100.00%3100.00%

/* * G/S_PARM. Most of this is done by the sensor, but we are * the level which controls the number of read buffers. */
static int mcam_vidioc_g_parm(struct file *filp, void *priv, struct v4l2_streamparm *parms) { struct mcam_camera *cam = video_drvdata(filp); int ret; ret = sensor_call(cam, video, g_parm, parms); parms->parm.capture.readbuffers = n_dma_bufs; return ret; }

Contributors

PersonTokensPropCommitsCommitProp
hans verkuilhans verkuil3457.63%360.00%
jonathan corbetjonathan corbet2542.37%240.00%
Total59100.00%5100.00%


static int mcam_vidioc_s_parm(struct file *filp, void *priv, struct v4l2_streamparm *parms) { struct mcam_camera *cam = video_drvdata(filp); int ret; ret = sensor_call(cam, video, s_parm, parms); parms->parm.capture.readbuffers = n_dma_bufs; return ret; }

Contributors

PersonTokensPropCommitsCommitProp
hans verkuilhans verkuil4881.36%480.00%
jonathan corbetjonathan corbet1118.64%120.00%
Total59100.00%5100.00%


static int mcam_vidioc_enum_framesizes(struct file *filp, void *priv, struct v4l2_frmsizeenum *sizes) { struct mcam_camera *cam = video_drvdata(filp); struct mcam_format_struct *f; struct v4l2_subdev_frame_size_enum fse = { .index = sizes->index, .which = V4L2_SUBDEV_FORMAT_ACTIVE, }; int ret; f = mcam_find_format(sizes->pixel_format); if (f->pixelformat != sizes->pixel_format) return -EINVAL; fse.code = f->mbus_code; ret = sensor_call(cam, pad, enum_frame_size, NULL, &fse); if (ret) return ret; if (fse.min_width == fse.max_width && fse.min_height == fse.max_height) { sizes->type = V4L2_FRMSIZE_TYPE_DISCRETE; sizes->discrete.width = fse.min_width; sizes->discrete.height = fse.min_height; return 0; } sizes->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; sizes->stepwise.min_width = fse.min_width; sizes->stepwise.max_width = fse.max_width; sizes->stepwise.min_height = fse.min_height; sizes->stepwise.max_height = fse.max_height; sizes->stepwise.step_width = 1; sizes->stepwise.step_height = 1; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
hans verkuilhans verkuil16272.32%342.86%
jonathan corbetjonathan corbet6227.68%457.14%
Total224100.00%7100.00%


static int mcam_vidioc_enum_frameintervals(struct file *filp, void *priv, struct v4l2_frmivalenum *interval) { struct mcam_camera *cam = video_drvdata(filp); struct mcam_format_struct *f; struct v4l2_subdev_frame_interval_enum fie = { .index = interval->index, .width = interval->width, .height = interval->height, .which = V4L2_SUBDEV_FORMAT_ACTIVE, }; int ret; f = mcam_find_format(interval->pixel_format); if (f->pixelformat != interval->pixel_format) return -EINVAL; fie.code = f->mbus_code; ret = sensor_call(cam, pad, enum_frame_interval, NULL, &fie); if (ret) return ret; interval->type = V4L2_FRMIVAL_TYPE_DISCRETE; interval->discrete = fie.interval; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
hans verkuilhans verkuil9063.83%250.00%
jonathan corbetjonathan corbet5136.17%250.00%
Total141100.00%4100.00%

#ifdef CONFIG_VIDEO_ADV_DEBUG
static int mcam_vidioc_g_register(struct file *file, void *priv, struct v4l2_dbg_register *reg) { struct mcam_camera *cam = video_drvdata(file); if (reg->reg > cam->regs_size - 4) return -EINVAL; reg->val = mcam_reg_read(cam, reg->reg); reg->size = 4; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet3652.94%250.00%
hans verkuilhans verkuil3247.06%250.00%
Total68100.00%4100.00%


static int mcam_vidioc_s_register(struct file *file, void *priv, const struct v4l2_dbg_register *reg) { struct mcam_camera *cam = video_drvdata(file); if (reg->reg > cam->regs_size - 4) return -EINVAL; mcam_reg_write(cam, reg->reg, reg->val); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet3352.38%250.00%
hans verkuilhans verkuil3047.62%250.00%
Total63100.00%4100.00%

#endif static const struct v4l2_ioctl_ops mcam_v4l_ioctl_ops = { .vidioc_querycap = mcam_vidioc_querycap, .vidioc_enum_fmt_vid_cap = mcam_vidioc_enum_fmt_vid_cap, .vidioc_try_fmt_vid_cap = mcam_vidioc_try_fmt_vid_cap, .vidioc_s_fmt_vid_cap = mcam_vidioc_s_fmt_vid_cap, .vidioc_g_fmt_vid_cap = mcam_vidioc_g_fmt_vid_cap, .vidioc_enum_input = mcam_vidioc_enum_input, .vidioc_g_input = mcam_vidioc_g_input, .vidioc_s_input = mcam_vidioc_s_input, .vidioc_reqbufs = vb2_ioctl_reqbufs, .vidioc_create_bufs = vb2_ioctl_create_bufs, .vidioc_querybuf = vb2_ioctl_querybuf, .vidioc_qbuf = vb2_ioctl_qbuf, .vidioc_dqbuf = vb2_ioctl_dqbuf, .vidioc_expbuf = vb2_ioctl_expbuf, .vidioc_streamon = vb2_ioctl_streamon, .vidioc_streamoff = vb2_ioctl_streamoff, .vidioc_g_parm = mcam_vidioc_g_parm, .vidioc_s_parm = mcam_vidioc_s_parm, .vidioc_enum_framesizes = mcam_vidioc_enum_framesizes, .vidioc_enum_frameintervals = mcam_vidioc_enum_frameintervals, .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = mcam_vidioc_g_register, .vidioc_s_register = mcam_vidioc_s_register, #endif }; /* ---------------------------------------------------------------------- */ /* * Our various file operations. */
static int mcam_v4l_open(struct file *filp) { struct mcam_camera *cam = video_drvdata(filp); int ret; mutex_lock(&cam->s_mutex); ret = v4l2_fh_open(filp); if (ret) goto out; if (v4l2_fh_is_singular_file(filp)) { ret = mcam_ctlr_power_up(cam); if (ret) goto out; __mcam_cam_reset(cam); mcam_set_config_needed(cam, 1); } out: mutex_unlock(&cam->s_mutex); if (ret) v4l2_fh_release(filp); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet5755.34%466.67%
hans verkuilhans verkuil4644.66%233.33%
Total103100.00%6100.00%


static int mcam_v4l_release(struct file *filp) { struct mcam_camera *cam = video_drvdata(filp); bool last_open; mutex_lock(&cam->s_mutex); last_open = v4l2_fh_is_singular_file(filp); _vb2_fop_release(filp, NULL); if (last_open) { mcam_disable_mipi(cam); mcam_ctlr_power_down(cam); if (cam->buffer_mode == B_vmalloc && alloc_bufs_at_read) mcam_free_dma_bufs(cam); } mutex_unlock(&cam->s_mutex); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
hans verkuilhans verkuil4652.27%250.00%
jonathan corbetjonathan corbet4247.73%250.00%
Total88100.00%4100.00%

static const struct v4l2_file_operations mcam_v4l_fops = { .owner = THIS_MODULE, .open = mcam_v4l_open, .release = mcam_v4l_release, .read = vb2_fop_read, .poll = vb2_fop_poll, .mmap = vb2_fop_mmap, .unlocked_ioctl = video_ioctl2, }; /* * This template device holds all of those v4l2 methods; we * clone it for specific real devices. */ static struct video_device mcam_v4l_template = { .name = "mcam", .fops = &mcam_v4l_fops, .ioctl_ops = &mcam_v4l_ioctl_ops, .release = video_device_release_empty, }; /* ---------------------------------------------------------------------- */ /* * Interrupt handler stuff */
static void mcam_frame_complete(struct mcam_camera *cam, int frame) { /* * Basic frame housekeeping. */ set_bit(frame, &cam->flags); clear_bit(CF_DMA_ACTIVE, &cam->flags); cam->next_buf = frame; cam->buf_seq[frame] = cam->sequence++; cam->frame_state.frames++; /* * "This should never happen" */ if (cam->state != S_STREAMING) return; /* * Process the frame and set up the next one. */ cam->frame_complete(cam, frame); }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet7593.75%571.43%
libin yanglibin yang45.00%114.29%
hans verkuilhans verkuil11.25%114.29%
Total80100.00%7100.00%

/* * The interrupt handler; this needs to be called from the * platform irq handler with the lock held. */
int mccic_irq(struct mcam_camera *cam, unsigned int irqs) { unsigned int frame, handled = 0; mcam_reg_write(cam, REG_IRQSTAT, FRAMEIRQS); /* Clear'em all */ /* * Handle any frame completions. There really should * not be more than one of these, or we have fallen * far behind. * * When running in S/G mode, the frame number lacks any * real meaning - there's only one descriptor array - but * the controller still picks a different one to signal * each time. */ for (frame = 0; frame < cam->nbufs; frame++) if (irqs & (IRQ_EOF0 << frame) && test_bit(CF_FRAME_SOF0 + frame, &cam->flags)) { mcam_frame_complete(cam, frame); handled = 1; clear_bit(CF_FRAME_SOF0 + frame, &cam->flags); if (cam->buffer_mode == B_DMA_sg) break; } /* * If a frame starts, note that we have DMA active. This * code assumes that we won't get multiple frame interrupts * at once; may want to rethink that. */ for (frame = 0; frame < cam->nbufs; frame++) { if (irqs & (IRQ_SOF0 << frame)) { set_bit(CF_FRAME_SOF0 + frame, &cam->flags); handled = IRQ_HANDLED; } } if (handled == IRQ_HANDLED) { set_bit(CF_DMA_ACTIVE, &cam->flags); if (cam->buffer_mode == B_DMA_sg) mcam_ctlr_stop(cam); } return handled; }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet11964.67%480.00%
libin yanglibin yang6535.33%120.00%
Total184100.00%5100.00%

/* ---------------------------------------------------------------------- */ /* * Registration and such. */ static struct ov7670_config sensor_cfg = { /* * Exclude QCIF mode, because it only captures a tiny portion * of the sensor FOV */ .min_width = 320, .min_height = 240, };
int mccic_register(struct mcam_camera *cam) { struct i2c_board_info ov7670_info = { .type = "ov7670", .addr = 0x42 >> 1, .platform_data = &sensor_cfg, }; int ret; /* * Validate the requested buffer mode. */ if (buffer_mode >= 0) cam->buffer_mode = buffer_mode; if (cam->buffer_mode == B_DMA_sg && cam->chip_id == MCAM_CAFE) { printk(KERN_ERR "marvell-cam: Cafe can't do S/G I/O, " "attempting vmalloc mode instead\n"); cam->buffer_mode = B_vmalloc; } if (!mcam_buffer_mode_supported(cam->buffer_mode)) { printk(KERN_ERR "marvell-cam: buffer mode %d unsupported\n", cam->buffer_mode); return -EINVAL; } /* * Register with V4L */ ret = v4l2_device_register(cam->dev, &cam->v4l2_dev); if (ret) return ret; mutex_init(&cam->s_mutex); cam->state = S_NOTREADY; mcam_set_config_needed(cam, 1); cam->pix_format = mcam_def_pix_format; cam->mbus_code = mcam_def_mbus_code; mcam_ctlr_init(cam); /* * Get the v4l2 setup done. */ ret = v4l2_ctrl_handler_init(&cam->ctrl_handler, 10); if (ret) goto out_unregister; cam->v4l2_dev.ctrl_handler = &cam->ctrl_handler; /* * Try to find the sensor. */ sensor_cfg.clock_speed = cam->clock_speed; sensor_cfg.use_smbus = cam->use_smbus; cam->sensor_addr = ov7670_info.addr; cam->sensor = v4l2_i2c_new_subdev_board(&cam->v4l2_dev, cam->i2c_adapter, &ov7670_info, NULL); if (cam->sensor == NULL) { ret = -ENODEV; goto out_unregister; } ret = mcam_cam_init(cam); if (ret) goto out_unregister; ret = mcam_setup_vb2(cam); if (ret) goto out_unregister; mutex_lock(&cam->s_mutex); cam->vdev = mcam_v4l_template; cam->vdev.v4l2_dev = &cam->v4l2_dev; cam->vdev.lock = &cam->s_mutex; cam->vdev.queue = &cam->vb_queue; video_set_drvdata(&cam->vdev, cam); ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1); if (ret) { mutex_unlock(&cam->s_mutex); goto out_unregister; } /* * If so requested, try to get our DMA buffers now. */ if (cam->buffer_mode == B_vmalloc && !alloc_bufs_at_read) { if (mcam_alloc_dma_bufs(cam, 1)) cam_warn(cam, "Unable to alloc DMA buffers at load" " will try again later."); } mutex_unlock(&cam->s_mutex); return 0; out_unregister: v4l2_ctrl_handler_free(&cam->ctrl_handler); v4l2_device_unregister(&cam->v4l2_dev); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet21949.77%735.00%
hans verkuilhans verkuil20346.14%945.00%
javier martinjavier martin102.27%15.00%
daniel drakedaniel drake61.36%210.00%
andres salomonandres salomon20.45%15.00%
Total440100.00%20100.00%


void mccic_shutdown(struct mcam_camera *cam) { /* * If we have no users (and we really, really should have no * users) the device will already be powered down. Trying to * take it down again will wedge the machine, which is frowned * upon. */ if (!list_empty(&cam->vdev.fh_list)) { cam_warn(cam, "Removing a device with users!\n"); mcam_ctlr_power_down(cam); } mcam_cleanup_vb2(cam); if (cam->buffer_mode == B_vmalloc) mcam_free_dma_bufs(cam); video_unregister_device(&cam->vdev); v4l2_ctrl_handler_free(&cam->ctrl_handler); v4l2_device_unregister(&cam->v4l2_dev); }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet5366.25%562.50%
hans verkuilhans verkuil1923.75%225.00%
javier martinjavier martin810.00%112.50%
Total80100.00%8100.00%

/* * Power management */ #ifdef CONFIG_PM
void mccic_suspend(struct mcam_camera *cam) { mutex_lock(&cam->s_mutex); if (!list_empty(&cam->vdev.fh_list)) { enum mcam_state cstate = cam->state; mcam_ctlr_stop_dma(cam); mcam_ctlr_power_down(cam); cam->state = cstate; } mutex_unlock(&cam->s_mutex); }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet5787.69%480.00%
hans verkuilhans verkuil812.31%120.00%
Total65100.00%5100.00%


int mccic_resume(struct mcam_camera *cam) { int ret = 0; mutex_lock(&cam->s_mutex); if (!list_empty(&cam->vdev.fh_list)) { ret = mcam_ctlr_power_up(cam); if (ret) { mutex_unlock(&cam->s_mutex); return ret; } __mcam_cam_reset(cam); } else { mcam_ctlr_power_down(cam); } mutex_unlock(&cam->s_mutex); set_bit(CF_CONFIG_NEEDED, &cam->flags); if (cam->state == S_STREAMING) { /* * If there was a buffer in the DMA engine at suspend * time, put it back on the queue or we'll forget about it. */ if (cam->buffer_mode == B_DMA_sg && cam->vb_bufs[0]) list_add(&cam->vb_bufs[0]->queue, &cam->buffers); ret = mcam_read_setup(cam); } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet8658.50%342.86%
chris ballchris ball2718.37%114.29%
libin yanglibin yang1912.93%114.29%
hans verkuilhans verkuil85.44%114.29%
daniel drakedaniel drake74.76%114.29%
Total147100.00%7100.00%

#endif /* CONFIG_PM */

Overall Contributors

PersonTokensPropCommitsCommitProp
jonathan corbetjonathan corbet491061.16%2228.57%
hans verkuilhans verkuil208726.00%3140.26%
libin yanglibin yang82210.24%67.79%
junghak sungjunghak sung750.93%22.60%
daniel drakedaniel drake320.40%45.19%
chris ballchris ball270.34%11.30%
javier martinjavier martin210.26%11.30%
prabhakar ladprabhakar lad130.16%11.30%
marek szyprowskimarek szyprowski100.12%22.60%
boris brezillonboris brezillon100.12%11.30%
andres salomonandres salomon80.10%11.30%
tejun heotejun heo30.04%11.30%
andrew mortonandrew morton30.04%11.30%
ricardo ribaldaricardo ribalda30.04%11.30%
rusty russellrusty russell30.04%11.30%
mauro carvalho chehabmauro carvalho chehab10.01%11.30%
Total8028100.00%77100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}