#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/videodev2.h>
+#include <linux/clk.h>
#include <media/v4l2-common.h>
#include <media/v4l2-dev.h>
unsigned int irq;
void __iomem *base;
+ struct clk *clk;
unsigned long video_limit;
/* lock used to protect videobuf */
ceu_write(pcdev, CETCR, 0x0317f313 ^ 0x10);
if (pcdev->active) {
+ pcdev->active->state = VIDEOBUF_ACTIVE;
ceu_write(pcdev, CDAYR, videobuf_to_dma_contig(pcdev->active));
ceu_write(pcdev, CAPSR, 0x1); /* start capture */
}
dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__,
vb, vb->baddr, vb->bsize);
- vb->state = VIDEOBUF_ACTIVE;
+ vb->state = VIDEOBUF_QUEUED;
spin_lock_irqsave(&pcdev->lock, flags);
list_add_tail(&vb->queue, &pcdev->capture);
if (ret)
goto err;
+ clk_enable(pcdev->clk);
+
ceu_write(pcdev, CAPSR, 1 << 16); /* reset */
while (ceu_read(pcdev, CSTSR) & 1)
msleep(1);
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
+ unsigned long flags;
BUG_ON(icd != pcdev->icd);
/* disable capture, disable interrupts */
ceu_write(pcdev, CEIER, 0);
ceu_write(pcdev, CAPSR, 1 << 16); /* reset */
+
+ /* make sure active buffer is canceled */
+ spin_lock_irqsave(&pcdev->lock, flags);
+ if (pcdev->active) {
+ list_del(&pcdev->active->queue);
+ pcdev->active->state = VIDEOBUF_ERROR;
+ wake_up_all(&pcdev->active->done);
+ pcdev->active = NULL;
+ }
+ spin_unlock_irqrestore(&pcdev->lock, flags);
+
+ clk_disable(pcdev->clk);
+
icd->ops->release(icd);
dev_info(&icd->dev,
static int sh_mobile_ceu_set_fmt_cap(struct soc_camera_device *icd,
__u32 pixfmt, struct v4l2_rect *rect)
{
- return icd->ops->set_fmt_cap(icd, pixfmt, rect);
+ const struct soc_camera_data_format *cam_fmt;
+ int ret;
+
+ /*
+ * TODO: find a suitable supported by the SoC output format, check
+ * whether the sensor supports one of acceptable input formats.
+ */
+ if (pixfmt) {
+ cam_fmt = soc_camera_format_by_fourcc(icd, pixfmt);
+ if (!cam_fmt)
+ return -EINVAL;
+ }
+
+ ret = icd->ops->set_fmt_cap(icd, pixfmt, rect);
+ if (pixfmt && !ret)
+ icd->current_fmt = cam_fmt;
+
+ return ret;
}
static int sh_mobile_ceu_try_fmt_cap(struct soc_camera_device *icd,
struct v4l2_format *f)
{
+ const struct soc_camera_data_format *cam_fmt;
+ int ret = sh_mobile_ceu_try_bus_param(icd, f->fmt.pix.pixelformat);
+
+ if (ret < 0)
+ return ret;
+
+ /*
+ * TODO: find a suitable supported by the SoC output format, check
+ * whether the sensor supports one of acceptable input formats.
+ */
+ cam_fmt = soc_camera_format_by_fourcc(icd, f->fmt.pix.pixelformat);
+ if (!cam_fmt)
+ return -EINVAL;
+
/* FIXME: calculate using depth and bus width */
if (f->fmt.pix.height < 4)
f->fmt.pix.width &= ~0x01;
f->fmt.pix.height &= ~0x03;
+ f->fmt.pix.bytesperline = f->fmt.pix.width *
+ DIV_ROUND_UP(cam_fmt->depth, 8);
+ f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+
/* limit to sensor capabilities */
return icd->ops->try_fmt_cap(icd, f);
}
.reqbufs = sh_mobile_ceu_reqbufs,
.poll = sh_mobile_ceu_poll,
.querycap = sh_mobile_ceu_querycap,
- .try_bus_param = sh_mobile_ceu_try_bus_param,
.set_bus_param = sh_mobile_ceu_set_bus_param,
.init_videobuf = sh_mobile_ceu_init_videobuf,
};
struct sh_mobile_ceu_dev *pcdev;
struct resource *res;
void __iomem *base;
+ char clk_name[8];
unsigned int irq;
int err = 0;
/* request irq */
err = request_irq(pcdev->irq, sh_mobile_ceu_irq, IRQF_DISABLED,
- pdev->dev.bus_id, pcdev);
+ dev_name(&pdev->dev), pcdev);
if (err) {
dev_err(&pdev->dev, "Unable to register CEU interrupt.\n");
goto exit_release_mem;
}
+ snprintf(clk_name, sizeof(clk_name), "ceu%d", pdev->id);
+ pcdev->clk = clk_get(&pdev->dev, clk_name);
+ if (IS_ERR(pcdev->clk)) {
+ dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
+ err = PTR_ERR(pcdev->clk);
+ goto exit_free_irq;
+ }
+
pcdev->ici.priv = pcdev;
pcdev->ici.dev.parent = &pdev->dev;
pcdev->ici.nr = pdev->id;
- pcdev->ici.drv_name = pdev->dev.bus_id,
- pcdev->ici.ops = &sh_mobile_ceu_host_ops,
+ pcdev->ici.drv_name = dev_name(&pdev->dev);
+ pcdev->ici.ops = &sh_mobile_ceu_host_ops;
err = soc_camera_host_register(&pcdev->ici);
if (err)
- goto exit_free_irq;
+ goto exit_free_clk;
return 0;
+exit_free_clk:
+ clk_put(pcdev->clk);
exit_free_irq:
free_irq(pcdev->irq, pcdev);
exit_release_mem:
struct sh_mobile_ceu_dev *pcdev = platform_get_drvdata(pdev);
soc_camera_host_unregister(&pcdev->ici);
+ clk_put(pcdev->clk);
free_irq(pcdev->irq, pcdev);
if (platform_get_resource(pdev, IORESOURCE_MEM, 1))
dma_release_declared_memory(&pdev->dev);