Hi Robert, Thanks for the patch! On 04/02/2016 04:26 PM, Robert Jarzmik wrote: > This patch removes the soc_camera API dependency from pxa_camera. > In the current status : > - all previously captures are working the same on pxa270 > - the s_crop() call was removed, judged not working > (see what happens soc_camera_s_crop() when get_crop() == NULL) > - if the pixel clock is provided by then sensor, ie. not MCLK, the dual > stage change is not handled yet. > => there is no in-tree user of this, so I'll let it that way > > - the MCLK is not yet finished, it's as in the legacy way, > ie. activated at video device opening and closed at video device > closing. > In a subsequence patch pxa_camera_mclk_ops should be used, and > platform data MCLK ignored. It will be the sensor's duty to request > the clock and enable it, which will end in pxa_camera_mclk_ops. > > Signed-off-by: Robert Jarzmik <robert.jarzmik@xxxxxxx> > --- > Since v1: > - function namings were cleaned into pxac_XXX_YYYY() > - function were regrouped in the 3 big categories : > - device probing/removal : pxa_camera_*() > - videobuf2 : pxac_vb2_*() > - v42l file operations : pxac_vidioc_*() > - internal driver functions : pxa_camera_*() : to be found a cute > pattern for RFC v3 > --- > drivers/media/platform/soc_camera/pxa_camera.c | 1086 ++++++++++++++---------- > include/linux/platform_data/media/camera-pxa.h | 2 + > 2 files changed, 620 insertions(+), 468 deletions(-) > > diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c > index b8dd878e98d6..30d266bbab55 100644 > --- a/drivers/media/platform/soc_camera/pxa_camera.c > +++ b/drivers/media/platform/soc_camera/pxa_camera.c When you prepare the final patch series, please put the driver in drivers/media/platform/pxa-camera and not in the soc-camera directory. <snip> > -static int pxa_camera_set_crop(struct soc_camera_device *icd, > - const struct v4l2_crop *a) > +static int pxac_vidioc_enum_fmt_vid_cap(struct file *filp, void *priv, > + struct v4l2_fmtdesc *f) > { > - const struct v4l2_rect *rect = &a->c; > - struct device *dev = icd->parent; > - struct soc_camera_host *ici = to_soc_camera_host(dev); > - struct pxa_camera_dev *pcdev = ici->priv; > - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); > - struct soc_camera_sense sense = { > - .master_clock = pcdev->mclk, > - .pixel_clock_max = pcdev->ciclk / 4, > - }; > - struct v4l2_subdev_format fmt = { > - .which = V4L2_SUBDEV_FORMAT_ACTIVE, > - }; > - struct v4l2_mbus_framefmt *mf = &fmt.format; > - struct pxa_cam *cam = icd->host_priv; > - u32 fourcc = icd->current_fmt->host_fmt->fourcc; > - int ret; > - > - /* If PCLK is used to latch data from the sensor, check sense */ > - if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN) > - icd->sense = &sense; > - > - ret = v4l2_subdev_call(sd, video, s_crop, a); > - > - icd->sense = NULL; > - > - if (ret < 0) { > - dev_warn(dev, "Failed to crop to %ux%u@%u:%u\n", > - rect->width, rect->height, rect->left, rect->top); > - return ret; > - } > - > - ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); > - if (ret < 0) > - return ret; > + struct pxa_camera_dev *pcdev = video_drvdata(filp); > + const struct soc_mbus_pixelfmt *format; > + unsigned int idx; > > - if (pxa_camera_check_frame(mf->width, mf->height)) { > - /* > - * Camera cropping produced a frame beyond our capabilities. > - * FIXME: just extract a subframe, that we can process. > - */ > - v4l_bound_align_image(&mf->width, 48, 2048, 1, > - &mf->height, 32, 2048, 0, > - fourcc == V4L2_PIX_FMT_YUV422P ? 4 : 0); > - ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &fmt); > - if (ret < 0) > - return ret; > - > - if (pxa_camera_check_frame(mf->width, mf->height)) { > - dev_warn(icd->parent, > - "Inconsistent state. Use S_FMT to repair\n"); > - return -EINVAL; > - } > - } > + for (idx = 0; pcdev->user_formats[idx].code; idx++); > + if (f->index >= idx) > + return -EINVAL; > > - if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { > - if (sense.pixel_clock > sense.pixel_clock_max) { > - dev_err(dev, > - "pixel clock %lu set by the camera too high!", > - sense.pixel_clock); > - return -EIO; > - } > - recalculate_fifo_timeout(pcdev, sense.pixel_clock); > - } > + format = pcdev->user_formats[f->index].host_fmt; > > - icd->user_width = mf->width; > - icd->user_height = mf->height; > + if (format->name) > + strlcpy(f->description, format->name, sizeof(f->description)); You can drop this since the core fills in the description. That means the 'name' field of struct soc_mbus_pixelfmt is not needed either. > + f->pixelformat = format->fourcc; > + return 0; > +} <snip> > +static int pxac_vidioc_querycap(struct file *file, void *priv, > + struct v4l2_capability *cap) > +{ > + strlcpy(cap->bus_info, "platform:pxa-camera", sizeof(cap->bus_info)); > + strlcpy(cap->driver, PXA_CAM_DRV_NAME, sizeof(cap->driver)); > + strlcpy(cap->card, pxa_cam_driver_description, sizeof(cap->card)); > + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; > + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; Tiny fix: you can drop the capabilities assignment: the v4l2 core does that for you these days. > + > + return 0; > +} > + > +static int pxac_vidioc_enum_input(struct file *file, void *priv, > + struct v4l2_input *i) > +{ > + if (i->index > 0) > + return -EINVAL; > + > + memset(i, 0, sizeof(*i)); The memset can be dropped, it's cleared for you. > + i->type = V4L2_INPUT_TYPE_CAMERA; > + strlcpy(i->name, "Camera", sizeof(i->name)); > + > + return 0; > +} > + > +static int pxac_vidioc_g_input(struct file *file, void *priv, unsigned int *i) > +{ > + *i = 0; > + > + return 0; > +} > + > +static int pxac_vidioc_s_input(struct file *file, void *priv, unsigned int i) > +{ > + if (i > 0) > + return -EINVAL; > + > + return 0; > +} > + > +static int pxac_fops_camera_open(struct file *filp) > +{ > + struct pxa_camera_dev *pcdev = video_drvdata(filp); > + int ret; > + > + mutex_lock(&pcdev->mlock); > + ret = v4l2_fh_open(filp); > + if (ret < 0) > + goto out; > + > + ret = sensor_call(pcdev, core, s_power, 1); > + if (ret) > + v4l2_fh_release(filp); > +out: > + mutex_unlock(&pcdev->mlock); > + return ret; > +} > + > +static int pxac_fops_camera_release(struct file *filp) > +{ > + struct pxa_camera_dev *pcdev = video_drvdata(filp); > + int ret; > + > + ret = vb2_fop_release(filp); > if (ret < 0) > return ret; > > - pix->width = mf->width; > - pix->height = mf->height; > - pix->field = mf->field; > - pix->colorspace = mf->colorspace; > - icd->current_fmt = xlate; > + mutex_lock(&pcdev->mlock); > + ret = sensor_call(pcdev, core, s_power, 0); > + mutex_unlock(&pcdev->mlock); > > return ret; > } > > -static int pxa_camera_try_fmt(struct soc_camera_device *icd, > - struct v4l2_format *f) > +static const struct v4l2_file_operations pxa_camera_fops = { > + .owner = THIS_MODULE, > + .open = pxac_fops_camera_open, > + .release = pxac_fops_camera_release, > + .read = vb2_fop_read, > + .poll = vb2_fop_poll, > + .mmap = vb2_fop_mmap, > + .unlocked_ioctl = video_ioctl2, > +}; > + > +static const struct v4l2_ioctl_ops pxa_camera_ioctl_ops = { > + .vidioc_querycap = pxac_vidioc_querycap, > + > + .vidioc_enum_input = pxac_vidioc_enum_input, > + .vidioc_g_input = pxac_vidioc_g_input, > + .vidioc_s_input = pxac_vidioc_s_input, > + > + .vidioc_enum_fmt_vid_cap = pxac_vidioc_enum_fmt_vid_cap, > + .vidioc_g_fmt_vid_cap = pxac_vidioc_g_fmt_vid_cap, > + .vidioc_s_fmt_vid_cap = pxac_vidioc_s_fmt_vid_cap, > + .vidioc_try_fmt_vid_cap = pxac_vidioc_try_fmt_vid_cap, > + > + .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, > +}; > + > + > +static void pxac_vb2_cleanup(struct vb2_buffer *vb) > { > - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); > - const struct soc_camera_format_xlate *xlate; > - struct v4l2_pix_format *pix = &f->fmt.pix; > - 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 ret; > + struct pxa_buffer *buf = vb2_to_pxa_buffer(vb); > + struct pxa_camera_dev *pcdev = vb2_get_drv_priv(vb->vb2_queue); > > - xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); > - if (!xlate) { > - dev_warn(icd->parent, "Format %x not found\n", pixfmt); > + dev_dbg(pcdev_to_dev(pcdev), > + "%s(vb=%p)\n", __func__, vb); > + pxa_buffer_cleanup(buf); > +} > + > +static void pxac_vb2_queue(struct vb2_buffer *vb) > +{ > + struct pxa_buffer *buf = vb2_to_pxa_buffer(vb); > + struct pxa_camera_dev *pcdev = vb2_get_drv_priv(vb->vb2_queue); > + > + dev_dbg(pcdev_to_dev(pcdev), > + "%s(vb=%p) nb_channels=%d size=%lu active=%p\n", > + __func__, vb, pcdev->channels, vb2_get_plane_payload(vb, 0), > + pcdev->active); > + > + list_add_tail(&buf->queue, &pcdev->capture); > + > + pxa_dma_add_tail_buf(pcdev, buf); > + > + if (!pcdev->active) > + pxa_camera_start_capture(pcdev); This is normally done from start_streaming. Are you really sure this is the right place? I strongly recommend moving this start_capture call. You may also want to use the struct vb2queue min_buffers_needed field to specify the minimum number of buffers that should be queued up before start_streaming can be called. Whether that's needed depends on your DMA engine. > +} > + > +/* > + * Please check the DMA prepared buffer structure in : > + * Documentation/video4linux/pxa_camera.txt > + * Please check also in pxa_camera_check_link_miss() to understand why DMA chain > + * modification while DMA chain is running will work anyway. > + */ > +static int pxac_vb2_prepare(struct vb2_buffer *vb) > +{ > + struct pxa_camera_dev *pcdev = vb2_get_drv_priv(vb->vb2_queue); > + struct pxa_buffer *buf = vb2_to_pxa_buffer(vb); > + int ret = 0; > + > + switch (pcdev->channels) { > + case 1: > + case 3: > + vb2_set_plane_payload(vb, 0, pcdev->current_pix.sizeimage); > + break; > + default: > return -EINVAL; > } > > + dev_dbg(pcdev_to_dev(pcdev), > + "%s (vb=%p) nb_channels=%d size=%lu\n", > + __func__, vb, pcdev->channels, vb2_get_plane_payload(vb, 0)); > + > + WARN_ON(!pcdev->current_fmt); > + > +#ifdef DEBUG > /* > - * Limit to pxa hardware capabilities. YUV422P planar format requires > - * images size to be a multiple of 16 bytes. If not, zeros will be > - * inserted between Y and U planes, and U and V planes, which violates > - * the YUV422P standard. > + * This can be useful if you want to see if we actually fill > + * the buffer with something > */ > - v4l_bound_align_image(&pix->width, 48, 2048, 1, > - &pix->height, 32, 2048, 0, > - pixfmt == V4L2_PIX_FMT_YUV422P ? 4 : 0); > + for (i = 0; i < vb->num_planes; i++) > + memset((void *)vb2_plane_vaddr(vb, i), > + 0xaa, vb2_get_plane_payload(vb, i)); > +#endif > > - /* limit to sensor capabilities */ > - mf->width = pix->width; > - mf->height = pix->height; > - /* Only progressive video supported so far */ > - mf->field = V4L2_FIELD_NONE; > - mf->colorspace = pix->colorspace; > - mf->code = xlate->code; > + /* > + * I think, in buf_prepare you only have to protect global data, > + * the actual buffer is yours > + */ > + buf->inwork = 0; > + pxa_videobuf_set_actdma(pcdev, buf); > > - ret = v4l2_subdev_call(sd, pad, set_fmt, &pad_cfg, &format); > - if (ret < 0) > - return ret; > + return ret; > +} > + > +static int pxac_vb2_init(struct vb2_buffer *vb) > +{ > + struct pxa_camera_dev *pcdev = vb2_get_drv_priv(vb->vb2_queue); > + struct pxa_buffer *buf = vb2_to_pxa_buffer(vb); > > - pix->width = mf->width; > - pix->height = mf->height; > - pix->colorspace = mf->colorspace; > + dev_dbg(pcdev_to_dev(pcdev), > + "%s(nb_channels=%d)\n", > + __func__, pcdev->channels); > > - switch (mf->field) { > - case V4L2_FIELD_ANY: > - case V4L2_FIELD_NONE: > - pix->field = V4L2_FIELD_NONE; > + return pxa_buffer_init(pcdev, buf); > +} > + > +static int pxac_vb2_queue_setup(struct vb2_queue *vq, > + unsigned int *nbufs, > + unsigned int *num_planes, unsigned int sizes[], > + void *alloc_ctxs[]) > +{ > + struct pxa_camera_dev *pcdev = vb2_get_drv_priv(vq); > + int size = pcdev->current_pix.sizeimage; > + > + dev_dbg(pcdev_to_dev(pcdev), > + "%s(vq=%p nbufs=%d num_planes=%d size=%d)\n", > + __func__, vq, *nbufs, *num_planes, size); > + /* > + * Called from VIDIOC_REQBUFS or in compatibility mode For YUV422P > + * format, even if there are 3 planes Y, U and V, we reply there is only > + * one plane, containing Y, U and V data, one after the other. > + */ > + if (*num_planes) > + return sizes[0] < size ? -EINVAL : 0; > + > + *num_planes = 1; > + switch (pcdev->channels) { > + case 1: > + case 3: > + sizes[0] = size; > break; > default: > - /* TODO: support interlaced at least in pass-through mode */ > - dev_err(icd->parent, "Field type %d unsupported.\n", > - mf->field); > return -EINVAL; > } > > + alloc_ctxs[0] = pcdev->alloc_ctx; > + if (!*nbufs) > + *nbufs = 1; > + > + return 0; > +} > + > +static void pxac_vb2_stop_streaming(struct vb2_queue *vq) > +{ > + vb2_wait_for_all_buffers(vq); > +} > + > +static struct vb2_ops pxac_vb2_ops = { > + .queue_setup = pxac_vb2_queue_setup, > + .buf_init = pxac_vb2_init, > + .buf_prepare = pxac_vb2_prepare, > + .buf_queue = pxac_vb2_queue, > + .buf_cleanup = pxac_vb2_cleanup, > + .stop_streaming = pxac_vb2_stop_streaming, > + .wait_prepare = vb2_ops_wait_prepare, > + .wait_finish = vb2_ops_wait_finish, > +}; > + > +static int pxa_camera_init_videobuf2(struct pxa_camera_dev *pcdev) > +{ > + int ret; > + struct vb2_queue *vq = &pcdev->vb2_vq; > + > + memset(vq, 0, sizeof(*vq)); > + vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; > + vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; > + vq->drv_priv = pcdev; > + vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; > + vq->buf_struct_size = sizeof(struct pxa_buffer); > + > + vq->ops = &pxac_vb2_ops; > + vq->mem_ops = &vb2_dma_sg_memops; > + vq->lock = &pcdev->mlock; > + > + ret = vb2_queue_init(vq); > + dev_dbg(pcdev_to_dev(pcdev), > + "vb2_queue_init(vq=%p): %d\n", vq, ret); > + > return ret; > } > > -static unsigned int pxa_camera_poll(struct file *file, poll_table *pt) > +static struct v4l2_clk_ops pxa_camera_mclk_ops = { > +}; > + > +static const struct video_device pxa_camera_videodev_template = { > + .name = "pxa-camera", > + .minor = -1, > + .fops = &pxa_camera_fops, > + .ioctl_ops = &pxa_camera_ioctl_ops, > + .release = video_device_release_empty, > +}; > + > +static int pxa_camera_sensor_bound(struct v4l2_async_notifier *notifier, > + struct v4l2_subdev *subdev, > + struct v4l2_async_subdev *asd) > { > - struct soc_camera_device *icd = file->private_data; > + int err; > + struct v4l2_device *v4l2_dev = notifier->v4l2_dev; > + struct pxa_camera_dev *pcdev = v4l2_dev_to_pcdev(v4l2_dev); > + struct video_device *vdev = &pcdev->vdev; > + struct v4l2_pix_format *pix = &pcdev->current_pix; > + struct v4l2_subdev_format format = { > + .which = V4L2_SUBDEV_FORMAT_ACTIVE, > + }; > + struct v4l2_mbus_framefmt *mf = &format.format; > > - return vb2_poll(&icd->vb2_vidq, file, pt); > + dev_info(pcdev_to_dev(pcdev), "%s(): trying to bind a device\n", > + __func__); > + mutex_lock(&pcdev->mlock); > + *vdev = pxa_camera_videodev_template; > + vdev->v4l2_dev = v4l2_dev; > + vdev->lock = &pcdev->mlock; > + pcdev->sensor = subdev; > + pcdev->vdev.queue = &pcdev->vb2_vq; > + pcdev->vdev.v4l2_dev = &pcdev->v4l2_dev; > + video_set_drvdata(&pcdev->vdev, pcdev); > + > + v4l2_disable_ioctl(vdev, VIDIOC_G_STD); > + v4l2_disable_ioctl(vdev, VIDIOC_S_STD); > + v4l2_disable_ioctl(vdev, VIDIOC_ENUMSTD); I don't think this is needed since the tvnorms field of struct video_device == 0, signalling that there is no STD support. > + > + err = pxa_camera_build_formats(pcdev); > + if (err) { > + dev_err(pcdev_to_dev(pcdev), "building formats failed: %d\n", > + err); > + goto out; > + } > + > + pcdev->current_fmt = pcdev->user_formats; > + pix->field = V4L2_FIELD_NONE; > + pix->width = DEFAULT_WIDTH; > + pix->height = DEFAULT_HEIGHT; > + pix->bytesperline = > + soc_mbus_bytes_per_line(pix->width, > + pcdev->current_fmt->host_fmt); > + pix->sizeimage = > + soc_mbus_image_size(pcdev->current_fmt->host_fmt, > + pix->bytesperline, pix->height); > + pix->pixelformat = pcdev->current_fmt->host_fmt->fourcc; > + v4l2_fill_mbus_format(mf, pix, pcdev->current_fmt->code); > + err = sensor_call(pcdev, pad, set_fmt, NULL, &format); > + if (err) > + goto out; > + > + v4l2_fill_pix_format(pix, mf); > + pr_info("%s(): colorspace=0x%x pixfmt=0x%x\n", > + __func__, pix->colorspace, pix->pixelformat); > + > + err = pxa_camera_init_videobuf2(pcdev); > + if (err) > + goto out; > + > + err = video_register_device(&pcdev->vdev, VFL_TYPE_GRABBER, -1); > + if (err) { > + v4l2_err(v4l2_dev, "register video device failed: %d\n", err); > + pcdev->sensor = NULL; > + } else { > + dev_info(pcdev_to_dev(pcdev), > + "PXA Camera driver attached to camera %s\n", > + subdev->name); > + subdev->owner = v4l2_dev->dev->driver->owner; > + } > +out: > + mutex_unlock(&pcdev->mlock); > + return err; > } > > -static int pxa_camera_querycap(struct soc_camera_host *ici, > - struct v4l2_capability *cap) > +static void pxa_camera_sensor_unbind(struct v4l2_async_notifier *notifier, > + struct v4l2_subdev *subdev, > + struct v4l2_async_subdev *asd) > { > - /* cap->name is set by the firendly caller:-> */ > - strlcpy(cap->card, pxa_cam_driver_description, sizeof(cap->card)); > - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; > - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; > + struct pxa_camera_dev *pcdev = v4l2_dev_to_pcdev(notifier->v4l2_dev); > > - return 0; > + mutex_lock(&pcdev->mlock); > + dev_info(pcdev_to_dev(pcdev), > + "PXA Camera driver detached from camera %s\n", > + subdev->name); > + > + /* disable capture, disable interrupts */ > + __raw_writel(0x3ff, pcdev->base + CICR0); > + > + /* Stop DMA engine */ > + pxa_dma_stop_channels(pcdev); > + > + pxa_camera_destroy_formats(pcdev); > + video_unregister_device(&pcdev->vdev); > + pcdev->sensor = NULL; > + > + mutex_unlock(&pcdev->mlock); > } > > static int pxa_camera_suspend(struct device *dev) > { > - struct soc_camera_host *ici = to_soc_camera_host(dev); > - struct pxa_camera_dev *pcdev = ici->priv; > + struct pxa_camera_dev *pcdev = dev_get_drvdata(dev); > int i = 0, ret = 0; > > pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR0); > @@ -1498,9 +1623,8 @@ static int pxa_camera_suspend(struct device *dev) > pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR3); > pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR4); > > - if (pcdev->soc_host.icd) { > - struct v4l2_subdev *sd = soc_camera_to_subdev(pcdev->soc_host.icd); > - ret = v4l2_subdev_call(sd, core, s_power, 0); > + if (pcdev->sensor) { > + ret = sensor_call(pcdev, core, s_power, 0); > if (ret == -ENOIOCTLCMD) > ret = 0; > } > @@ -1510,8 +1634,7 @@ static int pxa_camera_suspend(struct device *dev) > > static int pxa_camera_resume(struct device *dev) > { > - struct soc_camera_host *ici = to_soc_camera_host(dev); > - struct pxa_camera_dev *pcdev = ici->priv; > + struct pxa_camera_dev *pcdev = dev_get_drvdata(dev); > int i = 0, ret = 0; > > __raw_writel(pcdev->save_cicr[i++] & ~CICR0_ENB, pcdev->base + CICR0); > @@ -1520,9 +1643,8 @@ static int pxa_camera_resume(struct device *dev) > __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR3); > __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR4); > > - if (pcdev->soc_host.icd) { > - struct v4l2_subdev *sd = soc_camera_to_subdev(pcdev->soc_host.icd); > - ret = v4l2_subdev_call(sd, core, s_power, 1); > + if (pcdev->sensor) { > + ret = sensor_call(pcdev, core, s_power, 1); > if (ret == -ENOIOCTLCMD) > ret = 0; > } > @@ -1534,28 +1656,12 @@ static int pxa_camera_resume(struct device *dev) > return ret; > } > > -static struct soc_camera_host_ops pxa_soc_camera_host_ops = { > - .owner = THIS_MODULE, > - .add = pxa_camera_add_device, > - .remove = pxa_camera_remove_device, > - .clock_start = pxa_camera_clock_start, > - .clock_stop = pxa_camera_clock_stop, > - .set_crop = pxa_camera_set_crop, > - .get_formats = pxa_camera_get_formats, > - .put_formats = pxa_camera_put_formats, > - .set_fmt = pxa_camera_set_fmt, > - .try_fmt = pxa_camera_try_fmt, > - .init_videobuf2 = pxa_camera_init_videobuf2, > - .poll = pxa_camera_poll, > - .querycap = pxa_camera_querycap, > - .set_bus_param = pxa_camera_set_bus_param, > -}; > - > static int pxa_camera_pdata_from_dt(struct device *dev, > - struct pxa_camera_dev *pcdev) > + struct pxa_camera_dev *pcdev, > + struct v4l2_async_subdev *asd) > { > u32 mclk_rate; > - struct device_node *np = dev->of_node; > + struct device_node *remote, *np = dev->of_node; > struct v4l2_of_endpoint ep; > int err = of_property_read_u32(np, "clock-frequency", > &mclk_rate); > @@ -1607,6 +1713,15 @@ static int pxa_camera_pdata_from_dt(struct device *dev, > if (ep.bus.parallel.flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) > pcdev->platform_flags |= PXA_CAMERA_PCLK_EN; > > + asd->match_type = V4L2_ASYNC_MATCH_OF; > + remote = of_graph_get_remote_port(np); > + if (remote) { > + asd->match.of.node = remote; > + of_node_put(remote); > + } else { > + dev_notice(dev, "no remote for %s\n", of_node_full_name(np)); > + } > + > out: > of_node_put(np); > > @@ -1625,6 +1740,7 @@ static int pxa_camera_probe(struct platform_device *pdev) > }; > dma_cap_mask_t mask; > struct pxad_param params; > + char clk_name[V4L2_CLK_NAME_SIZE]; > int irq; > int err = 0, i; > > @@ -1651,10 +1767,14 @@ static int pxa_camera_probe(struct platform_device *pdev) > > pcdev->pdata = pdev->dev.platform_data; > if (&pdev->dev.of_node && !pcdev->pdata) { > - err = pxa_camera_pdata_from_dt(&pdev->dev, pcdev); > + err = pxa_camera_pdata_from_dt(&pdev->dev, pcdev, &pcdev->asd); > } else { > 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; > } > if (err < 0) > return err; > @@ -1686,6 +1806,7 @@ static int pxa_camera_probe(struct platform_device *pdev) > > INIT_LIST_HEAD(&pcdev->capture); > spin_lock_init(&pcdev->lock); > + mutex_init(&pcdev->mlock); > > /* > * Request the regions. > @@ -1748,19 +1869,48 @@ static int pxa_camera_probe(struct platform_device *pdev) > goto exit_free_dma; > } > > - pcdev->soc_host.drv_name = PXA_CAM_DRV_NAME; > - pcdev->soc_host.ops = &pxa_soc_camera_host_ops; > - pcdev->soc_host.priv = pcdev; > - pcdev->soc_host.v4l2_dev.dev = &pdev->dev; > - pcdev->soc_host.nr = pdev->id; > tasklet_init(&pcdev->task_eof, pxa_camera_eof, (unsigned long)pcdev); > > - err = soc_camera_host_register(&pcdev->soc_host); > + pxa_camera_activate(pcdev); > + > + dev_set_drvdata(&pdev->dev, pcdev); > + err = v4l2_device_register(&pdev->dev, &pcdev->v4l2_dev); > if (err) > goto exit_free_dma; > > - return 0; > + pcdev->asds[0] = &pcdev->asd; > + pcdev->notifier.subdevs = pcdev->asds; > + pcdev->notifier.num_subdevs = 1; > + pcdev->notifier.bound = pxa_camera_sensor_bound; > + pcdev->notifier.unbind = pxa_camera_sensor_unbind; > + > + if (!of_have_populated_dt()) > + pcdev->asd.match_type = V4L2_ASYNC_MATCH_I2C; > > + err = pxa_camera_init_videobuf2(pcdev); > + if (err) > + goto exit_free_v4l2dev; > + > + if (pcdev->mclk) { > + v4l2_clk_name_i2c(clk_name, sizeof(clk_name), > + pcdev->asd.match.i2c.adapter_id, > + pcdev->asd.match.i2c.address); > + > + pcdev->mclk_clk = v4l2_clk_register(&pxa_camera_mclk_ops, > + clk_name, NULL); > + if (IS_ERR(pcdev->mclk_clk)) > + return PTR_ERR(pcdev->mclk_clk); > + } > + > + err = v4l2_async_notifier_register(&pcdev->v4l2_dev, &pcdev->notifier); > + if (err) > + goto exit_free_clk; > + > + return 0; > +exit_free_clk: > + v4l2_clk_unregister(pcdev->mclk_clk); > +exit_free_v4l2dev: > + v4l2_device_unregister(&pcdev->v4l2_dev); > exit_free_dma: > dma_release_channel(pcdev->dma_chans[2]); > exit_free_dma_u: > @@ -1772,16 +1922,16 @@ exit_free_dma_y: > > static int pxa_camera_remove(struct platform_device *pdev) > { > - struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); > - struct pxa_camera_dev *pcdev = container_of(soc_host, > - struct pxa_camera_dev, soc_host); > + struct pxa_camera_dev *pcdev = dev_get_drvdata(&pdev->dev); > > + pxa_camera_deactivate(pcdev); > dma_release_channel(pcdev->dma_chans[0]); > dma_release_channel(pcdev->dma_chans[1]); > dma_release_channel(pcdev->dma_chans[2]); > vb2_dma_sg_cleanup_ctx(pcdev->alloc_ctx); > + v4l2_clk_unregister(pcdev->mclk_clk); > > - soc_camera_host_unregister(soc_host); > + v4l2_device_unregister(&pcdev->v4l2_dev); > > dev_info(&pdev->dev, "PXA Camera driver unloaded\n"); > > diff --git a/include/linux/platform_data/media/camera-pxa.h b/include/linux/platform_data/media/camera-pxa.h > index 6709b1cd7c77..ce5d90e1a6e4 100644 > --- a/include/linux/platform_data/media/camera-pxa.h > +++ b/include/linux/platform_data/media/camera-pxa.h > @@ -37,6 +37,8 @@ > struct pxacamera_platform_data { > unsigned long flags; > unsigned long mclk_10khz; > + int sensor_i2c_adapter_id; > + int sensor_i2c_address; > }; > > extern void pxa_set_camera_info(struct pxacamera_platform_data *); > Thanks! Hans -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html