// SPDX-License-Identifier: GPL-2.0 /* * 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 * Copyright 2018 Lubomir Rintel <lkundrak@v3.sk>
*/ #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/clk-provider.h> #include <linux/videodev2.h> #include <linux/pm_runtime.h> #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-event.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.
*/
staticbool 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");
staticint 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.");
staticint 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 */ staticconstbool alloc_bufs_at_read; staticconstint n_dma_bufs = 3; /* Used by S/G_PARM */ #endif/* MCAM_MODE_VMALLOC */
staticbool flip;
module_param(flip, bool, 0444);
MODULE_PARM_DESC(flip, "If set, the sensor will be instructed to flip the image vertically.");
staticint 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)
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;
}
/* * The default format we use until somebody says otherwise.
*/ staticconststruct 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,
};
/* * 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 */
};
staticvoid 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);
}
/* ------------------------------------------------------------------- */ /* * Make the controller start grabbing images. Everything must * be set up before doing this.
*/ staticvoid 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);
}
staticvoid 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;
}
case 2: if (n_dma_bufs > 2)
cam_warn(cam, "Will limp along with only 2 buffers\n"); break;
} return 0;
}
staticvoid 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;
}
/* * Set up DMA buffers when operating in vmalloc mode
*/ staticvoid 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 */
}
/* * Copy data out to user space in the vmalloc case
*/ staticvoid mcam_frame_work(struct work_struct *t)
{ struct mcam_camera *cam = from_work(cam, t, s_bh_work); int i; unsignedlong 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);
}
/* * Make sure our allocated buffers are up to the task.
*/ staticint 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;
}
staticvoid mcam_vmalloc_done(struct mcam_camera *cam, int frame)
{
queue_work(system_bh_wq, &cam->s_bh_work);
}
#else/* MCAM_MODE_VMALLOC */
staticinlineint mcam_alloc_dma_bufs(struct mcam_camera *cam, int loadtime)
{ return 0;
}
/* * 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.
*/ staticvoid 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);
}
/* * Set up the next buffer for S/G I/O; caller should be sure that * the controller is stopped and a buffer is available.
*/ staticvoid mcam_sg_next_buffer(struct mcam_camera *cam)
{ struct mcam_vb_buffer *buf; struct sg_table *sg_table;
buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer, queue);
list_del_init(&buf->queue);
sg_table = vb2_dma_sg_plane_desc(&buf->vb_buf.vb2_buf, 0); /* * 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,
sg_table->nents * 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;
}
/* * Initial B_DMA_sg setup
*/ staticvoid 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;
}
/* * 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).
*/ staticvoid 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);
}
/* * 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 getting things going again.
*/ staticvoid mcam_sg_restart(struct mcam_camera *cam)
{
mcam_ctlr_dma_sg(cam);
mcam_ctlr_start(cam);
clear_bit(CF_SG_RESTART, &cam->flags);
}
staticvoid 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);
}
/* * Stop the controller, and don't return until we're really sure that no * further DMA is going on.
*/ staticvoid mcam_ctlr_stop_dma(struct mcam_camera *cam)
{ unsignedlong 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);
}
/* * Power up and down.
*/ staticint mcam_ctlr_power_up(struct mcam_camera *cam)
{ unsignedlong flags; int ret;
spin_lock_irqsave(&cam->dev_lock, flags); if (cam->plat_power_up) {
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); return 0;
}
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); if (cam->plat_power_down)
cam->plat_power_down(cam);
spin_unlock_irqrestore(&cam->dev_lock, flags);
}
/* * We have found the sensor on the i2c. Let's try to have a * conversation.
*/ staticint 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; return ret;
}
/* * Configure the sensor to match the parameters we have. Caller should * hold s_mutex
*/ staticint mcam_cam_set_flip(struct mcam_camera *cam)
{ struct v4l2_control ctrl;
staticint 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;
}
/* * Get everything ready, and start grabbing frames.
*/ staticint mcam_read_setup(struct mcam_camera *cam)
{ int ret; unsignedlong 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;
}
/* * These need to be called with the mutex held from vb2
*/ staticint mcam_vb_start_streaming(struct vb2_queue *vq, unsignedint count)
{ struct mcam_camera *cam = vb2_get_drv_priv(vq); unsignedint 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;
}
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); /* * VB2 reclaims the buffers, so we need to forget * about them.
*/
mcam_vb_requeue_bufs(vq, VB2_BUF_STATE_ERROR);
}
/* * 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;
}
/* * 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.
*/ staticint 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;
}
/* * We only have one input - the sensor - so minimize the nonsense here.
*/ staticint mcam_vidioc_enum_input(struct file *filp, void *priv, struct v4l2_input *input)
{ if (input->index != 0) return -EINVAL;
staticint mcam_vidioc_s_input(struct file *filp, void *priv, unsignedint i)
{ if (i != 0) return -EINVAL; return 0;
}
/* * G/S_PARM. Most of this is done by the sensor, but we are * the level which controls the number of read buffers.
*/ staticint mcam_vidioc_g_parm(struct file *filp, void *priv, struct v4l2_streamparm *a)
{ struct mcam_camera *cam = video_drvdata(filp); int ret;
/* * This template device holds all of those v4l2 methods; we * clone it for specific real devices.
*/ staticconststruct video_device mcam_v4l_template = {
.name = "mcam",
.fops = &mcam_v4l_fops,
.ioctl_ops = &mcam_v4l_ioctl_ops,
.release = video_device_release_empty,
.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING,
};
/* ---------------------------------------------------------------------- */ /* * Interrupt handler stuff
*/ staticvoid 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);
}
/* * The interrupt handler; this needs to be called from the * platform irq handler with the lock held.
*/ int mccic_irq(struct mcam_camera *cam, unsignedint irqs)
{ unsignedint 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;
}
EXPORT_SYMBOL_GPL(mccic_irq);
/* ---------------------------------------------------------------------- */ /* * Registration and such.
*/
cam->mclk = devm_clk_register(cam->dev, &cam->mclk_hw); if (IS_ERR(cam->mclk)) {
ret = PTR_ERR(cam->mclk);
dev_err(cam->dev, "can't register clock\n"); goto out;
}
/* * 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.");
}
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");
sensor_call(cam, core, s_power, 0);
} if (cam->buffer_mode == B_vmalloc)
mcam_free_dma_bufs(cam);
v4l2_ctrl_handler_free(&cam->ctrl_handler);
v4l2_async_nf_unregister(&cam->notifier);
v4l2_async_nf_cleanup(&cam->notifier);
}
EXPORT_SYMBOL_GPL(mccic_shutdown);
/* * Power management
*/ 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;
int mccic_resume(struct mcam_camera *cam)
{ int ret = 0;
mutex_lock(&cam->s_mutex); if (!list_empty(&cam->vdev.fh_list)) {
ret = sensor_call(cam, core, s_power, 1); if (ret) {
mutex_unlock(&cam->s_mutex); return ret;
}
__mcam_cam_reset(cam);
} else {
sensor_call(cam, core, s_power, 0);
}
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;
}
EXPORT_SYMBOL_GPL(mccic_resume);
MODULE_DESCRIPTION("Marvell camera core driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Jonathan Corbet ");
Messung V0.5
¤ Dauer der Verarbeitung: 0.25 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.