[PATCH 2/2] [ARM] samsung-rotator: Add Samsung S3C/S5P rotator driver

2009-12-23 Thread Pawel Osciak
The rotator device present on Samsung S3C and S5P series SoCs allows image
rotation and flipping. It requires contiguous memory buffers to operate,
as it does not have scatter-gather support. It is also an example of
a memory-to-memory device, and so uses the mem-2-mem device V4L2 framework.

Signed-off-by: Pawel Osciak p.osc...@samsung.com
Signed-off-by: Sylwester Nawrocki s.nawro...@samsung.com
Reviewed-by: Marek Szyprowski m.szyprow...@samsung.com
Reviewed-by: Kyungmin Park kyungmin.p...@samsung.com
---
 drivers/media/video/Kconfig   |   10 +
 drivers/media/video/Makefile  |2 +
 drivers/media/video/samsung-rotator/Makefile  |1 +
 drivers/media/video/samsung-rotator/s3c_rotator.c | 1026 +
 4 files changed, 1039 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/video/samsung-rotator/Makefile
 create mode 100644 drivers/media/video/samsung-rotator/s3c_rotator.c

diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 6fe4b53..b6040bd 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -1100,4 +1100,14 @@ config VIDEO_MEM2MEM_TESTDEV
  This is a virtual test device for the memory-to-memory driver
  framework.
 
+config VIDEO_SAMSUNG_ROTATOR
+   tristate Samsung S3C/S5P embedded image rotator
+   depends on VIDEO_V4L2
+   select VIDEOBUF_DMA_CONTIG
+   select V4L2_MEM2MEM_DEV
+   default n
+   help
+ An image rotator device present on Samsung S3C and S5P series SoCs
+ allows image rotation and flipping.
+
 endif # V4L_MEM2MEM_DRIVERS
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 8667f1c..72196df 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -172,6 +172,8 @@ obj-$(CONFIG_VIDEO_IR_I2C)  += ir-kbd-i2c.o
 
 obj-$(CONFIG_ARCH_DAVINCI) += davinci/
 
+obj-$(CONFIG_VIDEO_SAMSUNG_ROTATOR)+= samsung-rotator/
+
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
 EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
 EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/media/video/samsung-rotator/Makefile 
b/drivers/media/video/samsung-rotator/Makefile
new file mode 100644
index 000..9ce9ee9
--- /dev/null
+++ b/drivers/media/video/samsung-rotator/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_VIDEO_SAMSUNG_ROTATOR) += s3c_rotator.o
diff --git a/drivers/media/video/samsung-rotator/s3c_rotator.c 
b/drivers/media/video/samsung-rotator/s3c_rotator.c
new file mode 100644
index 000..83f9059
--- /dev/null
+++ b/drivers/media/video/samsung-rotator/s3c_rotator.c
@@ -0,0 +1,1026 @@
+/*
+ * Samsung S3C/S5P image rotator driver.
+ *
+ * Copyright (c) 2009 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, p.osc...@samsung.com
+ * Sylwester Nawrocki, s.nawro...@samsung.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version
+ */
+#include linux/module.h
+#include linux/interrupt.h
+#include asm/io.h
+#include linux/platform_device.h
+#include linux/version.h
+
+#include media/v4l2-device.h
+#include media/v4l2-ioctl.h
+
+#include media/v4l2-mem2mem.h
+#include media/videobuf-dma-contig.h
+
+#include plat/regs-rotator.h
+
+#define S3C_ROTATOR_NAME   s3c-rotator
+#define S3C_ROTATOR_MEM_LIMIT  (16 * 1024 * 1024)
+#define S3C_ROTATOR_MAX_WIDTH  2048
+#define S3C_ROTATOR_MAX_HEIGHT 2048
+
+/*#define S3C_ROTATOR_DEBUG_REGWRITE*/
+#ifdef S3C_ROTATOR_DEBUG_REGWRITE
+#undef writel
+#define writel(v, r) do { \
+   printk(KERN_DEBUG %s: %08x = %p\n, __func__, (unsigned int)v, r); \
+   __raw_writel(v, r); } while(0)
+#endif /* S3C_ROTATOR_DEBUG_REGWRITE */
+
+#define V4L2_CID_PRIVATE_ROTATE (V4L2_CID_PRIVATE_BASE + 0)
+
+struct s3c_rotator_fmt {
+   char*name;
+   u32 fourcc;
+   u32 depth;
+};
+
+/* Input/output formats (no conversion) */
+static struct s3c_rotator_fmt formats[] = {
+   {
+   .name   = 4:2:2, packed, YUYV,
+   .fourcc = V4L2_PIX_FMT_YUYV,
+   .depth  = 16,
+   },
+   {
+   .name   = 4:2:0, planar YUV,
+   .fourcc = V4L2_PIX_FMT_YUV420,
+   .depth  = 12,
+   },
+   {
+   .name   = BGR565X,
+   .fourcc = V4L2_PIX_FMT_RGB565X,
+   .depth  = 16,
+   },
+   {
+   .name   = BGRA,
+   .fourcc = V4L2_PIX_FMT_BGR32,
+   .depth  = 32,
+   },
+};
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+
+/*
+ * The device can only do one operation at a time,
+ * i.e. simultaneous rotation + flip is not possible
+ */
+static struct v4l2_queryctrl s3c_rotator_ctrls[] = {
+   {
+   .id = V4L2_CID_HFLIP,
+   .type   = 

Re: [PATCH 2/2] [ARM] samsung-rotator: Add Samsung S3C/S5P rotator driver

2009-12-23 Thread Alexey Klimov
Hello,

On Wed, Dec 23, 2009 at 1:08 PM, Pawel Osciak p.osc...@samsung.com wrote:
 The rotator device present on Samsung S3C and S5P series SoCs allows image
 rotation and flipping. It requires contiguous memory buffers to operate,
 as it does not have scatter-gather support. It is also an example of
 a memory-to-memory device, and so uses the mem-2-mem device V4L2 framework.

[...]

 +
 +static const struct v4l2_file_operations s3c_rotator_fops = {
 +       .owner          = THIS_MODULE,
 +       .open           = s3c_rotator_open,
 +       .release        = s3c_rotator_release,
 +       .poll           = s3c_rotator_poll,
 +       .ioctl          = video_ioctl2,
 +       .mmap           = s3c_rotator_mmap,
 +};
 +
 +static struct video_device m2mtest_videodev = {
 +       .name           = S3C_ROTATOR_NAME,
 +       .fops           = s3c_rotator_fops,
 +       .ioctl_ops      = s3c_rotator_ioctl_ops,
 +       .minor          = -1,
 +       .release        = video_device_release,
 +};
 +
 +static struct v4l2_m2m_ops m2m_ops = {
 +       .device_run     = device_run,
 +       .job_abort      = job_abort,
 +};
 +
 +static int s3c_rotator_probe(struct platform_device *pdev)
 +{
 +       struct s3c_rotator_dev *dev;
 +       struct video_device *vfd;
 +       struct resource *res;
 +       int ret = -ENOENT;

Here ^^^ (see below please for comments)

 +
 +       dev = kzalloc(sizeof *dev, GFP_KERNEL);
 +       if (!dev)
 +               return -ENOMEM;
 +
 +       spin_lock_init(dev-irqlock);
 +       ret = -ENOENT;

It's probably bad pedantic part of me speaking but looks like you set
ret equals to -ENOENT two times. Most likely you don't need
assignment second time.


 +       dev-irq = platform_get_irq(pdev, 0);
 +       if (dev-irq = 0) {
 +               dev_err(pdev-dev, Failed to acquire irq\n);
 +               goto free_dev;
 +       }
 +
 +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 +       if (!res) {
 +               dev_err(pdev-dev,
 +                       Failed to acquire memory region resource\n);
 +               goto free_irq;
 +       }
 +
 +       dev-regs_res = request_mem_region(res-start, resource_size(res),
 +                                          dev_name(pdev-dev));
 +       if (!dev-regs_res) {
 +               dev_err(pdev-dev, Failed to reserve memory region\n);
 +               goto free_irq;
 +       }
 +
 +       dev-regs_base = ioremap(res-start, resource_size(res));
 +       if (!dev-regs_base) {
 +               dev_err(pdev-dev, Ioremap failed\n);
 +               ret = -ENXIO;
 +               goto rel_res;
 +       }
 +
 +       ret = request_irq(dev-irq, s3c_rotator_isr, 0,
 +                         S3C_ROTATOR_NAME, dev);
 +       if (ret) {
 +               dev_err(pdev-dev, Requesting irq failed\n);
 +               goto regs_unmap;
 +       }
 +
 +       ret = v4l2_device_register(pdev-dev, dev-v4l2_dev);
 +       if (ret)
 +               goto regs_unmap;
 +
 +       atomic_set(dev-num_inst, 0);
 +
 +       vfd = video_device_alloc();
 +       if (!vfd) {
 +               v4l2_err(dev-v4l2_dev, Failed to allocate video device\n);
 +               goto unreg_dev;
 +       }
 +
 +       *vfd = m2mtest_videodev;
 +
 +       ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
 +       if (ret) {
 +               v4l2_err(dev-v4l2_dev, Failed to register video device\n);
 +               goto rel_vdev;
 +       }
 +
 +       video_set_drvdata(vfd, dev);
 +       snprintf(vfd-name, sizeof(vfd-name), %s, m2mtest_videodev.name);
 +       dev-vfd = vfd;
 +       v4l2_info(dev-v4l2_dev,
 +                       Device registered as /dev/video%d\n, vfd-num);
 +
 +       platform_set_drvdata(pdev, dev);
 +
 +       dev-m2m_dev = v4l2_m2m_init(m2m_ops);
 +       if (IS_ERR(dev-m2m_dev)) {
 +               v4l2_err(dev-v4l2_dev, Failed to init mem2mem device\n);
 +               ret = PTR_ERR(dev-m2m_dev);
 +               goto err_m2m;
 +       }
 +
 +       return 0;
 +
 +err_m2m:
 +       video_unregister_device(dev-vfd);
 +rel_vdev:
 +       video_device_release(vfd);
 +unreg_dev:
 +       v4l2_device_unregister(dev-v4l2_dev);
 +regs_unmap:
 +       iounmap(dev-regs_base);
 +rel_res:
 +       release_resource(dev-regs_res);
 +       kfree(dev-regs_res);
 +free_irq:
 +       free_irq(dev-irq, dev);
 +free_dev:
 +       kfree(dev);
 +
 +       return ret;
 +}
 +
 +static int s3c_rotator_remove(struct platform_device *pdev)
 +{
 +       struct s3c_rotator_dev *dev =
 +               (struct s3c_rotator_dev *)platform_get_drvdata(pdev);
 +
 +       v4l2_info(dev-v4l2_dev, Removing %s\n, S3C_ROTATOR_NAME);
 +
 +       v4l2_m2m_release(dev-m2m_dev);
 +       video_unregister_device(dev-vfd);
 +       v4l2_device_unregister(dev-v4l2_dev);
 +       iounmap(dev-regs_base);
 +       release_resource(dev-regs_res);
 +       kfree(dev-regs_res);
 +       free_irq(dev-irq, dev);
 +       kfree(dev);
 +
 +       return 0;
 +}
 +
 +static int