mirror of
https://git.yoctoproject.org/meta-ti
synced 2026-07-17 06:48:07 +00:00
9bc77dff5f
Regenerate all beaglebone patches and add one vfs tracer patch for powertop Signed-off-by: Koen Kooi <koen@dominion.thruhere.net> Signed-off-by: Denys Dmytriyenko <denys@ti.com>
1613 lines
44 KiB
Diff
1613 lines
44 KiB
Diff
From e3a4f83627a111ae21ea8c6521ad98201f55eacc Mon Sep 17 00:00:00 2001
|
|
From: Dan Aizenstros <daizenstros@quicklogic.com>
|
|
Date: Fri, 29 Jun 2012 13:57:49 -0400
|
|
Subject: [PATCH 72/79] beaglebone: add support for QuickLogic Camera
|
|
interface on camera cape
|
|
|
|
Signed-off-by: Dan Aizenstros <daizenstros@quicklogic.com>
|
|
---
|
|
arch/arm/mach-omap2/board-am335xevm.c | 205 ++++-
|
|
arch/arm/mach-omap2/devices.c | 2 +-
|
|
arch/arm/plat-omap/include/plat/dma-33xx.h | 1 +
|
|
drivers/media/video/Kconfig | 7 +
|
|
drivers/media/video/Makefile | 2 +
|
|
drivers/media/video/cssp_camera/Makefile | 3 +
|
|
drivers/media/video/cssp_camera/cssp_camera.c | 1119 +++++++++++++++++++++++++
|
|
drivers/media/video/cssp_camera/cssp_camera.h | 148 ++++
|
|
8 files changed, 1478 insertions(+), 9 deletions(-)
|
|
create mode 100644 drivers/media/video/cssp_camera/Makefile
|
|
create mode 100644 drivers/media/video/cssp_camera/cssp_camera.c
|
|
create mode 100644 drivers/media/video/cssp_camera/cssp_camera.h
|
|
|
|
diff --git a/arch/arm/mach-omap2/board-am335xevm.c b/arch/arm/mach-omap2/board-am335xevm.c
|
|
index d2481af..22a740f 100644
|
|
--- a/arch/arm/mach-omap2/board-am335xevm.c
|
|
+++ b/arch/arm/mach-omap2/board-am335xevm.c
|
|
@@ -65,6 +65,10 @@
|
|
#include <plat/mmc.h>
|
|
#include <plat/emif.h>
|
|
#include <plat/nand.h>
|
|
+#include <plat/dma-33xx.h>
|
|
+
|
|
+#include <media/soc_camera.h>
|
|
+#include <media/mt9t112.h>
|
|
|
|
#include "board-flash.h"
|
|
#include "cpuidle33xx.h"
|
|
@@ -803,6 +807,42 @@ static struct pinmux_config i2c1_pin_mux[] = {
|
|
{NULL, 0},
|
|
};
|
|
|
|
+/* Pin mux for GPMC bus */
|
|
+static struct pinmux_config gpmc_pin_mux[] = {
|
|
+ {"gpmc_ad0.gpmc_ad0", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
|
|
+ {"gpmc_ad1.gpmc_ad1", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
|
|
+ {"gpmc_ad2.gpmc_ad2", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
|
|
+ {"gpmc_ad3.gpmc_ad3", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
|
|
+ {"gpmc_ad4.gpmc_ad4", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
|
|
+ {"gpmc_ad5.gpmc_ad5", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
|
|
+ {"gpmc_ad6.gpmc_ad6", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
|
|
+ {"gpmc_ad7.gpmc_ad7", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
|
|
+ {"gpmc_ad8.gpmc_ad8", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
|
|
+ {"gpmc_ad9.gpmc_ad9", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
|
|
+ {"gpmc_ad10.gpmc_ad10", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
|
|
+ {"gpmc_ad11.gpmc_ad11", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
|
|
+ {"gpmc_ad12.gpmc_ad12", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
|
|
+ {"gpmc_ad13.gpmc_ad13", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
|
|
+ {"gpmc_ad14.gpmc_ad14", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
|
|
+ {"gpmc_ad15.gpmc_ad15", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
|
|
+ {"gpmc_wait0.gpmc_wait0", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT_PULLUP},
|
|
+ {"gpmc_wpn.gpmc_wpn", OMAP_MUX_MODE7 | AM33XX_PIN_INPUT_PULLUP},
|
|
+ {"gpmc_csn1.gpmc_csn1", OMAP_MUX_MODE0 | AM33XX_PULL_DISA},
|
|
+ {"gpmc_advn_ale.gpmc_advn_ale", OMAP_MUX_MODE0 | AM33XX_PULL_DISA},
|
|
+ {"gpmc_oen_ren.gpmc_oen_ren", OMAP_MUX_MODE0 | AM33XX_PULL_DISA},
|
|
+ {"gpmc_wen.gpmc_wen", OMAP_MUX_MODE0 | AM33XX_PULL_DISA},
|
|
+ {"gpmc_ben0_cle.gpmc_ben0_cle", OMAP_MUX_MODE0 | AM33XX_PULL_DISA},
|
|
+ {"gpmc_clk.gpmc_clk", OMAP_MUX_MODE0 | AM33XX_PIN_INPUT},
|
|
+ {"ecap0_in_pwm0_out.xdma_event_intr2", OMAP_MUX_MODE6 | AM33XX_PIN_INPUT}, // DMAREQ
|
|
+ {NULL, 0},
|
|
+};
|
|
+
|
|
+static struct pinmux_config camera_cape_pin_mux[] = {
|
|
+ {"spi0_d1.gpio0_4", OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT }, // QL CSSP and Camera Sensor Reset
|
|
+ {"spi0_cs0.gpio0_5", OMAP_MUX_MODE7 | AM33XX_PIN_OUTPUT_PULLUP }, // 1V8 and 2V8 Power Enable
|
|
+ {NULL, 0},
|
|
+};
|
|
+
|
|
static struct pinmux_config i2c2_pin_mux[] = {
|
|
{"uart1_ctsn.i2c2_sda", OMAP_MUX_MODE3 | AM33XX_SLEWCTRL_SLOW |
|
|
AM33XX_PIN_INPUT_PULLUP},
|
|
@@ -1802,6 +1842,156 @@ static void dvileds_init(int evm_id, int profile )
|
|
pr_err("failed to register BeagleBone DVI cape LEDS\n");
|
|
}
|
|
|
|
+static struct resource cssp_camera_resources[] = {
|
|
+ {
|
|
+ .name = "gpmc_phys_mem_slot",
|
|
+ .flags = IORESOURCE_MEM,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct mt9t112_camera_info mt9t111_cam_info = {
|
|
+ /* divider calculated for 32Mhz CAM_MCLK */
|
|
+ .divider = {
|
|
+ .m = 24, .n = 1,
|
|
+ .p1 = 0, .p2 = 7, .p3 = 0, .p4 = 11, .p5 = 15, .p6 = 7, .p7 = 0,
|
|
+ },
|
|
+};
|
|
+
|
|
+static struct soc_camera_link mt9t111_camera_link = {
|
|
+ .priv = &mt9t111_cam_info,
|
|
+ .i2c_adapter_id = 3,
|
|
+};
|
|
+
|
|
+static struct i2c_board_info i2c_camera = {
|
|
+ I2C_BOARD_INFO("mt9t112", 0x3c),
|
|
+ .platform_data = &mt9t111_camera_link,
|
|
+};
|
|
+
|
|
+struct cssp_cam_platform_data {
|
|
+ struct i2c_board_info *cam_i2c_board_info;
|
|
+ const char *cam_clk_name;
|
|
+ int dma_ch;
|
|
+ int cssp_reset_pin;
|
|
+};
|
|
+
|
|
+static struct cssp_cam_platform_data cssp_cam_platform_data = {
|
|
+ .cam_i2c_board_info = &i2c_camera,
|
|
+ .cam_clk_name = "clkout2_ck",
|
|
+ .dma_ch = AM33XX_DMA_XDMA_EVENT_INTR2,
|
|
+ .cssp_reset_pin = GPIO_TO_PIN(0, 4),
|
|
+};
|
|
+
|
|
+static struct platform_device cssp_camera = {
|
|
+ .name = "cssp-camera",
|
|
+ .id = -1,
|
|
+ .dev = {
|
|
+ .platform_data = &cssp_cam_platform_data,
|
|
+ },
|
|
+ .num_resources = sizeof(cssp_camera_resources) / sizeof(cssp_camera_resources[0]),
|
|
+ .resource = cssp_camera_resources,
|
|
+};
|
|
+
|
|
+static struct gpmc_timings cssp_timings = {
|
|
+ /* Minimum clock period for synchronous mode (in picoseconds) */
|
|
+ .sync_clk = 10000,
|
|
+
|
|
+ .cs_on = 0,
|
|
+ .cs_rd_off = 23 * 10, /* Read deassertion time */
|
|
+ .cs_wr_off = 23 * 10, /* Write deassertion time */
|
|
+
|
|
+ /* ADV signal timings corresponding to GPMC_CONFIG3 */
|
|
+ .adv_on = 0, /* Assertion time */
|
|
+ .adv_rd_off = 2 * 10, /* Read deassertion time */
|
|
+ .adv_wr_off = 2 * 10, /* Write deassertion time */
|
|
+
|
|
+ /* WE signals timings corresponding to GPMC_CONFIG4 */
|
|
+ .we_on = 3 * 10, /* WE assertion time */
|
|
+ .we_off = 23 * 10, /* WE deassertion time */
|
|
+
|
|
+ /* OE signals timings corresponding to GPMC_CONFIG4 */
|
|
+ .oe_on = 3 * 10, /* OE assertion time */
|
|
+ .oe_off = 23 * 10, /* OE deassertion time */
|
|
+
|
|
+ /* Access time and cycle time timings corresponding to GPMC_CONFIG5 */
|
|
+ .page_burst_access = 1 * 10, /* Multiple access word delay */
|
|
+ .access = 7 * 10, /* Start-cycle to first data valid delay */
|
|
+ .rd_cycle = 23 * 10, /* Total read cycle time */
|
|
+ .wr_cycle = 23 * 10, /* Total write cycle time */
|
|
+
|
|
+ /* The following are only on OMAP3430 */
|
|
+ .wr_access = 7 * 10, /* WRACCESSTIME */
|
|
+ .wr_data_mux_bus = 3 * 10, /* WRDATAONADMUXBUS */
|
|
+};
|
|
+
|
|
+static int gpmc_cssp_init(void)
|
|
+{
|
|
+ int cs = 1; /* Chip Select on GPMC bus */
|
|
+ int val;
|
|
+ long unsigned int cssp_gpmc_mem_base_phys;
|
|
+
|
|
+ if (gpmc_cs_request(cs, SZ_16M, &cssp_gpmc_mem_base_phys) < 0) {
|
|
+ printk(KERN_ERR "[cssp_cam platform init]: gpmc_cs_request failed\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ cssp_camera_resources[0].start = cssp_gpmc_mem_base_phys;
|
|
+ cssp_camera_resources[0].end = cssp_gpmc_mem_base_phys + 0x1ffff;
|
|
+
|
|
+ if (gpmc_cs_configure(cs, GPMC_CONFIG_DEV_TYPE, GPMC_DEVICETYPE_NOR) < 0) {
|
|
+ printk(KERN_ERR "[cssp_cam platform init]: gpmc_cs_configure failed\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ val = GPMC_CONFIG1_READMULTIPLE_SUPP;
|
|
+ val |= GPMC_CONFIG1_READTYPE_SYNC;
|
|
+ val |= GPMC_CONFIG1_WRITETYPE_SYNC;
|
|
+ val |= GPMC_CONFIG1_CLKACTIVATIONTIME(1);
|
|
+ val |= GPMC_CONFIG1_PAGE_LEN(2);
|
|
+ val |= GPMC_CONFIG1_DEVICESIZE_16;
|
|
+ val |= GPMC_CONFIG1_DEVICETYPE_NOR;
|
|
+ val |= GPMC_CONFIG1_MUXADDDATA;
|
|
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, val);
|
|
+
|
|
+ if (gpmc_cs_set_timings(cs, &cssp_timings) < 0) {
|
|
+ printk(KERN_ERR "Failed gpmc_cs_set_timings for QuickLogic CAMIF device\n");
|
|
+ goto free;
|
|
+ }
|
|
+
|
|
+ val = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG6);
|
|
+ val &= 0xe0f0f030;
|
|
+ val |= 0x07030481;
|
|
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG6, val);
|
|
+
|
|
+ printk(KERN_INFO "gpmc_cssp_init for QuickLogic CAMIF device succeeded\n");
|
|
+
|
|
+ return 0;
|
|
+
|
|
+free:
|
|
+ gpmc_cs_free(cs);
|
|
+
|
|
+ printk(KERN_ERR "Could not initialize QuickLogic CAMIF device\n");
|
|
+
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static void cssp_gpmc_init(void)
|
|
+{
|
|
+ struct gpmc_devices_info gpmc_device[2] = {
|
|
+ { NULL, GPMC_DEVICE_NOR },
|
|
+ };
|
|
+
|
|
+ setup_pin_mux(camera_cape_pin_mux);
|
|
+ setup_pin_mux(gpmc_pin_mux);
|
|
+
|
|
+ omap_init_gpmc(gpmc_device, sizeof(gpmc_device));
|
|
+ gpmc_cssp_init();
|
|
+
|
|
+ platform_device_register(&cssp_camera);
|
|
+
|
|
+ printk(KERN_INFO "[cssp_cam platform init]: cssp_gpmc_init: DONE\n");
|
|
+}
|
|
+
|
|
+
|
|
static void lcd3leds_init(int evm_id, int profile )
|
|
{
|
|
int err;
|
|
@@ -2821,6 +3011,7 @@ static void beaglebone_cape_setup(struct memory_accessor *mem_acc, void *context
|
|
if (!strncmp("BB-BONE-CAM-01", cape_config.partnumber, 14)) {
|
|
pr_info("BeagleBone cape: recognized Camera cape\n");
|
|
beaglebone_w1gpio_free = 0;
|
|
+ cssp_gpmc_init();
|
|
}
|
|
|
|
goto out2;
|
|
@@ -3729,15 +3920,13 @@ static struct pinmux_config clkout2_pin_mux[] = {
|
|
|
|
static void __init clkout2_enable(void)
|
|
{
|
|
- struct clk *ck_32;
|
|
-
|
|
- ck_32 = clk_get(NULL, "clkout2_ck");
|
|
- if (IS_ERR(ck_32)) {
|
|
- pr_err("Cannot clk_get ck_32\n");
|
|
- return;
|
|
- }
|
|
+ void __iomem *base;
|
|
+ unsigned int val;
|
|
|
|
- clk_enable(ck_32);
|
|
+ base = ioremap(0x44E00700, SZ_4K);
|
|
+ val = (5 << 3) | (3 << 0); //32 MHz
|
|
+ writel(val, base);
|
|
+ iounmap(base);
|
|
|
|
setup_pin_mux(clkout2_pin_mux);
|
|
}
|
|
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
|
|
index 41c9b0f..3ef045e 100644
|
|
--- a/arch/arm/mach-omap2/devices.c
|
|
+++ b/arch/arm/mach-omap2/devices.c
|
|
@@ -968,7 +968,7 @@ static struct event_to_channel_map am33xx_xbar_event_mapping[] = {
|
|
{27, -1},
|
|
{28, -1},
|
|
{29, -1},
|
|
- {30, -1},
|
|
+ {30, 20}, /* XDMA_EVENT_INTR2 */
|
|
{31, -1},
|
|
{-1, -1}
|
|
};
|
|
diff --git a/arch/arm/plat-omap/include/plat/dma-33xx.h b/arch/arm/plat-omap/include/plat/dma-33xx.h
|
|
index bebdaa7..ded00aa 100644
|
|
--- a/arch/arm/plat-omap/include/plat/dma-33xx.h
|
|
+++ b/arch/arm/plat-omap/include/plat/dma-33xx.h
|
|
@@ -83,5 +83,6 @@
|
|
#define AM33XX_DMA_PWMSS2_EPW 63
|
|
#define AM33XX_DMA_MMCHS2_W 64 /* xBar */
|
|
#define AM33XX_DMA_MMCHS2_R 65 /* xBar */
|
|
+#define AM33XX_DMA_XDMA_EVENT_INTR2 93 /* xBar */
|
|
|
|
#endif
|
|
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
|
|
index b303a3f..a31723f 100644
|
|
--- a/drivers/media/video/Kconfig
|
|
+++ b/drivers/media/video/Kconfig
|
|
@@ -1002,6 +1002,13 @@ config VIDEO_S5P_MIPI_CSIS
|
|
|
|
source "drivers/media/video/s5p-tv/Kconfig"
|
|
|
|
+config VIDEO_QL_CAMIF
|
|
+ tristate "QuickLogic Camera Interface support (EXPERIMENTAL)"
|
|
+ depends on VIDEO_DEV && SOC_CAMERA && SOC_OMAPAM33XX && EXPERIMENTAL
|
|
+ select VIDEOBUF2_DMA_CONTIG
|
|
+ ---help---
|
|
+ This is a v4l2 driver for the QuickLogic CAMIF controller.
|
|
+
|
|
#
|
|
# USB Multimedia device configuration
|
|
#
|
|
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
|
|
index 117f9c4..af7af692 100644
|
|
--- a/drivers/media/video/Makefile
|
|
+++ b/drivers/media/video/Makefile
|
|
@@ -195,6 +195,8 @@ obj-y += davinci/
|
|
|
|
obj-$(CONFIG_ARCH_OMAP) += omap/
|
|
|
|
+obj-$(CONFIG_VIDEO_QL_CAMIF) += cssp_camera/
|
|
+
|
|
ccflags-y += -Idrivers/media/dvb/dvb-core
|
|
ccflags-y += -Idrivers/media/dvb/frontends
|
|
ccflags-y += -Idrivers/media/common/tuners
|
|
diff --git a/drivers/media/video/cssp_camera/Makefile b/drivers/media/video/cssp_camera/Makefile
|
|
new file mode 100644
|
|
index 0000000..d85a84e
|
|
--- /dev/null
|
|
+++ b/drivers/media/video/cssp_camera/Makefile
|
|
@@ -0,0 +1,3 @@
|
|
+# cssp_camera
|
|
+
|
|
+obj-$(CONFIG_VIDEO_QL_CAMIF) += cssp_camera.o
|
|
diff --git a/drivers/media/video/cssp_camera/cssp_camera.c b/drivers/media/video/cssp_camera/cssp_camera.c
|
|
new file mode 100644
|
|
index 0000000..39aa003
|
|
--- /dev/null
|
|
+++ b/drivers/media/video/cssp_camera/cssp_camera.c
|
|
@@ -0,0 +1,1119 @@
|
|
+/*
|
|
+ * cssp-camera driver
|
|
+ *
|
|
+ * Based on Vivi driver
|
|
+ *
|
|
+ * Copyright (C) 2012 QuickLogic Corp.
|
|
+ *
|
|
+ * Developed for QuickLogic by:
|
|
+ * Damian Eppel <damian.eppel@teleca.com>
|
|
+ * Przemek Szewczyk <przemek.szewczyk@teleca.com>
|
|
+ * Dan Aizenstros <daizenstros@quicklogic.com>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License version 2 as
|
|
+ * published by the Free Software Foundation.
|
|
+ *
|
|
+ */
|
|
+
|
|
+
|
|
+#include <linux/init.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/gpio.h>
|
|
+#include <linux/i2c.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/spinlock.h>
|
|
+#include <linux/dma-mapping.h>
|
|
+#include <linux/interrupt.h>
|
|
+#include <mach/edma.h>
|
|
+#include <linux/clk.h>
|
|
+// V4L2 Interface *********************
|
|
+#include <media/soc_camera.h>
|
|
+#include <media/v4l2-mediabus.h>
|
|
+#include <media/videobuf2-dma-contig.h>
|
|
+#include <media/v4l2-ioctl.h>
|
|
+#include <media/v4l2-event.h>
|
|
+//*************************************
|
|
+#include "cssp_camera.h"
|
|
+
|
|
+
|
|
+/*
|
|
+ * ---------------------------------------------------------------------------
|
|
+ * QuickLoigc Camera Interface registers
|
|
+ * ---------------------------------------------------------------------------
|
|
+ */
|
|
+
|
|
+#define REG_MODE 0x00000
|
|
+#define REG_DATA 0x10000
|
|
+
|
|
+/* MODE bit shifts */
|
|
+#define FMT_2X8_EN BIT(15) /* Enable 2 byte format on CAMIF bus (0 - 10 bit, 1 - 16 bit 2x8) */
|
|
+#define PCLK_POL BIT(14) /* PCLK polarity (0 - rising edge, 1 - falling edge */
|
|
+#define HS_EN BIT(13) /* High speed bus (0 =< 50 MHz, 1 > 50 MHz) */
|
|
+#define ENABLE BIT(12)
|
|
+
|
|
+
|
|
+static struct cssp_cam_fmt formats[] = {
|
|
+ {
|
|
+ .name = "4:2:2, packed, YUYV",
|
|
+ .fourcc = V4L2_PIX_FMT_YUYV,
|
|
+ .depth = 16,
|
|
+ .code = V4L2_MBUS_FMT_YUYV8_2X8,
|
|
+ },
|
|
+ {
|
|
+ .name = "4:2:2, packed, UYVY",
|
|
+ .fourcc = V4L2_PIX_FMT_UYVY,
|
|
+ .depth = 16,
|
|
+ .code = V4L2_MBUS_FMT_UYVY8_2X8,
|
|
+ },
|
|
+ {
|
|
+ .name = "4:2:2, packed, VYUY",
|
|
+ .fourcc = V4L2_PIX_FMT_VYUY,
|
|
+ .depth = 16,
|
|
+ .code = V4L2_MBUS_FMT_VYUY8_2X8,
|
|
+ },
|
|
+ {
|
|
+ .name = "4:2:2, packed, YVYU",
|
|
+ .fourcc = V4L2_PIX_FMT_YVYU,
|
|
+ .depth = 16,
|
|
+ .code = V4L2_MBUS_FMT_YVYU8_2X8,
|
|
+ },
|
|
+ {
|
|
+ .name = "RGB565 (LE)",
|
|
+ .fourcc = V4L2_PIX_FMT_RGB565,
|
|
+ .depth = 16,
|
|
+ .code = V4L2_MBUS_FMT_RGB565_2X8_LE,
|
|
+ },
|
|
+ {
|
|
+ .name = "RGB555 (LE)",
|
|
+ .fourcc = V4L2_PIX_FMT_RGB555,
|
|
+ .depth = 16,
|
|
+ .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
|
|
+ },
|
|
+};
|
|
+
|
|
+
|
|
+/***************************************************************************/
|
|
+
|
|
+
|
|
+static int configure_gpio(int nr, int val, const char *name)
|
|
+{
|
|
+ unsigned long flags = val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
|
|
+ int ret;
|
|
+ if (!gpio_is_valid(nr))
|
|
+ return 0;
|
|
+ ret = gpio_request_one(nr, flags, name);
|
|
+ if (!ret)
|
|
+ gpio_export(nr, 0);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int reset_cssp(struct cssp_cam_dev *cam)
|
|
+{
|
|
+ struct platform_device *pdev = cam->pdev;
|
|
+ int err;
|
|
+
|
|
+ cam->reset_pin = ((struct cssp_cam_platform_data *)pdev->dev.platform_data)->gpio_reset_pin;
|
|
+
|
|
+ err = configure_gpio(cam->reset_pin, 0, "cssp_reset");
|
|
+ if (err) {
|
|
+ printk(KERN_ERR "[%s]: failed to configure cssp reset pin\n", pdev->name);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ mdelay(1);
|
|
+
|
|
+ gpio_direction_output(cam->reset_pin, 1);
|
|
+
|
|
+ return err;
|
|
+}
|
|
+
|
|
+static int trigger_dma_transfer_to_buf(struct cssp_cam_dev *dev, struct vb2_buffer *vb)
|
|
+{
|
|
+ dma_addr_t dma_buf = vb2_dma_contig_plane_dma_addr(vb, 0);
|
|
+
|
|
+ if (!dma_buf) {
|
|
+ /* Is this possible? Release the vb2_buffer with an error here, */
|
|
+ vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
|
|
+ dev->current_vb = NULL;
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ dev->dma_tr_params.dst = dma_buf;
|
|
+
|
|
+ // Enable DMA
|
|
+ edma_write_slot(dev->dma_ch, &dev->dma_tr_params);
|
|
+
|
|
+ // Enable data capture
|
|
+ dev->mode |= ENABLE;
|
|
+ writew(dev->mode, dev->reg_base_virt + REG_MODE);
|
|
+ readw(dev->reg_base_virt + REG_MODE);
|
|
+
|
|
+ dev->current_vb = vb;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void dequeue_buffer_for_dma(struct cssp_cam_dev *dev)
|
|
+{
|
|
+ struct cssp_cam_dmaqueue *dma_q = &dev->vidq;
|
|
+ unsigned long flags = 0;
|
|
+
|
|
+ spin_lock_irqsave(&dev->slock, flags);
|
|
+ if (!list_empty(&dma_q->active)) {
|
|
+ struct cssp_cam_buffer *buf;
|
|
+
|
|
+ buf = list_entry(dma_q->active.next, struct cssp_cam_buffer, list);
|
|
+ list_del(&buf->list);
|
|
+ spin_unlock_irqrestore(&dev->slock, flags);
|
|
+
|
|
+ buf->fmt = dev->fmt;
|
|
+
|
|
+ trigger_dma_transfer_to_buf(dev, &buf->vb);
|
|
+ } else {
|
|
+ spin_unlock_irqrestore(&dev->slock, flags);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void dma_callback(unsigned lch, u16 ch_status, void *data)
|
|
+{
|
|
+ struct cssp_cam_dev *dev = (struct cssp_cam_dev *)data;
|
|
+
|
|
+ // Disable data capture
|
|
+ dev->mode &= ~ENABLE;
|
|
+ writew(dev->mode, dev->reg_base_virt + REG_MODE);
|
|
+ readw(dev->reg_base_virt + REG_MODE);
|
|
+
|
|
+ if (ch_status == DMA_COMPLETE) {
|
|
+ struct vb2_buffer *vb = dev->current_vb;
|
|
+ struct timeval ts;
|
|
+
|
|
+ vb->v4l2_buf.field = dev->field;
|
|
+ dev->field_count++;
|
|
+ vb->v4l2_buf.sequence = dev->field_count >> 1;
|
|
+ do_gettimeofday(&ts);
|
|
+ vb->v4l2_buf.timestamp = ts;
|
|
+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
|
|
+ dev->current_vb = NULL;
|
|
+ dev->frame_cnt++;
|
|
+
|
|
+ /* check if we have new buffer queued */
|
|
+ dequeue_buffer_for_dma(dev);
|
|
+ } else {
|
|
+ printk(KERN_ERR "[cssp_camera]: EDMA error (ch_status = %d)\n", ch_status);
|
|
+ /* we got a missed interrupt so just start a new DMA with the existing buffer */
|
|
+ if (dev->current_vb != NULL)
|
|
+ trigger_dma_transfer_to_buf(dev, dev->current_vb);
|
|
+ }
|
|
+}
|
|
+
|
|
+static int configure_edma(struct cssp_cam_dev *cam)
|
|
+{
|
|
+ struct platform_device *pdev = cam->pdev;
|
|
+ int dma_channel;
|
|
+
|
|
+ dma_channel = ((struct cssp_cam_platform_data *)pdev->dev.platform_data)->dma_ch;
|
|
+
|
|
+ pdev->dev.dma_mask = &cam->dma_mask;
|
|
+
|
|
+ pdev->dev.coherent_dma_mask = (u32)~0;
|
|
+
|
|
+ if (dma_set_mask(&pdev->dev, (u32)~0)) {
|
|
+ printk(KERN_ERR "[%s]: failed setting mask for DMA\n", pdev->name);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ cam->dma_ch = edma_alloc_channel(dma_channel, dma_callback, cam, EVENTQ_1);
|
|
+ if (cam->dma_ch < 0) {
|
|
+ printk(KERN_ERR "[%s]: allocating channel for DMA failed\n", pdev->name);
|
|
+ return -EBUSY;
|
|
+ } else {
|
|
+ printk(KERN_ERR "[%s]: allocating channel for DMA succeeded, chan=%d\n", pdev->name, cam->dma_ch);
|
|
+ }
|
|
+
|
|
+ cam->dma_tr_params.opt = TCINTEN | TCC(cam->dma_ch);
|
|
+ cam->dma_tr_params.src = cam->reg_base_phys + REG_DATA;
|
|
+ cam->dma_tr_params.a_b_cnt = ACNT(BYTES_PER_DMA_EVT) | BCNT((VGA_WIDTH * BYTES_PER_PIXEL) / BYTES_PER_DMA_EVT);
|
|
+ cam->dma_tr_params.src_dst_bidx = SRCBIDX(0) | DSTBIDX(BYTES_PER_DMA_EVT);
|
|
+ cam->dma_tr_params.link_bcntrld = BCNTRLD((VGA_WIDTH * BYTES_PER_PIXEL) / BYTES_PER_DMA_EVT) | LINK(0xffff);
|
|
+ cam->dma_tr_params.src_dst_cidx = SRCCIDX(0) | DSTCIDX(BYTES_PER_DMA_EVT);
|
|
+ cam->dma_tr_params.ccnt = CCNT(VGA_HEIGHT);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int configure_cssp(struct cssp_cam_dev *cam)
|
|
+{
|
|
+ struct platform_device *pdev = cam->pdev;
|
|
+ int ret = 0;
|
|
+ unsigned int val;
|
|
+ struct resource *res;
|
|
+
|
|
+ ret = reset_cssp(cam);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gpmc_phys_mem_slot");
|
|
+ if (res == NULL) {
|
|
+ printk(KERN_ERR "[%s]: failed to get gpmc_phys_mem_slot resource\n", pdev->name);
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Request the region.
|
|
+ */
|
|
+ if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
|
|
+ return -EBUSY;
|
|
+ }
|
|
+
|
|
+ cam->reg_base_phys = res->start;
|
|
+ cam->reg_size = resource_size(res);
|
|
+
|
|
+ cam->reg_base_virt = (unsigned int)ioremap(cam->reg_base_phys, cam->reg_size);
|
|
+ if (cam->reg_base_virt == 0) {
|
|
+ printk(KERN_ERR "[%s]: ioremap of registers region failed\n", pdev->name);
|
|
+ release_mem_region(cam->reg_base_phys, cam->reg_size);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ printk(KERN_INFO "[%s]: reg_base_virt = 0x%x\n", pdev->name, cam->reg_base_virt);
|
|
+
|
|
+ val = readw(cam->reg_base_virt + REG_MODE);
|
|
+ printk(KERN_INFO "[%s]: reading register address=0x0 returns 0x%x\n", pdev->name, val);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int configure_camera_sensor(struct cssp_cam_dev *cam)
|
|
+{
|
|
+ struct i2c_board_info *info = cam->camera_board_info;
|
|
+ struct i2c_client *client;
|
|
+ struct i2c_adapter *adapter;
|
|
+ struct v4l2_subdev *subdev;
|
|
+ struct v4l2_mbus_framefmt f_format = {
|
|
+ .width = VGA_WIDTH,
|
|
+ .height = VGA_HEIGHT,
|
|
+ .code = V4L2_MBUS_FMT_YUYV8_2X8,
|
|
+ .colorspace = V4L2_COLORSPACE_JPEG,
|
|
+ };
|
|
+
|
|
+ /* Enable the clock just for the time of loading the camera driver and disable after that */
|
|
+ /* It is going to be be re-enabled later, when camera will be in use */
|
|
+ clk_enable(cam->camera_clk);
|
|
+ udelay(5); // let the clock stabilize
|
|
+
|
|
+ adapter = i2c_get_adapter(((struct soc_camera_link *)(info->platform_data))->i2c_adapter_id);
|
|
+ if (!adapter) {
|
|
+ printk(KERN_INFO "[%s]: failed to get adapter...\n", __func__);
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
+ client = i2c_new_device(adapter, info);
|
|
+ i2c_put_adapter(adapter);
|
|
+
|
|
+ if (client == NULL) {
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
+ printk(KERN_INFO "[%s]: client's name is: %s\n", __func__, client->name);
|
|
+
|
|
+ subdev = (struct v4l2_subdev *)i2c_get_clientdata(client);
|
|
+ if (subdev == NULL) {
|
|
+ i2c_unregister_device(client);
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
+ cam->subdev = subdev;
|
|
+
|
|
+ v4l2_subdev_call(subdev, video, s_mbus_fmt, &f_format);
|
|
+
|
|
+ clk_disable(cam->camera_clk);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int start_camera_sensor(struct cssp_cam_dev *cam)
|
|
+{
|
|
+ clk_enable(cam->camera_clk);
|
|
+ udelay(5); /* let the clock stabilize */
|
|
+
|
|
+ v4l2_subdev_call(cam->subdev, video, s_stream, 1);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void stop_camera_sensor(struct cssp_cam_dev *cam)
|
|
+{
|
|
+ v4l2_subdev_call(cam->subdev, video, s_stream, 0);
|
|
+
|
|
+ clk_disable(cam->camera_clk);
|
|
+
|
|
+ return;
|
|
+}
|
|
+
|
|
+
|
|
+/************************************************
|
|
+ * Video4Linux2
|
|
+ */
|
|
+
|
|
+static struct cssp_cam_fmt *get_format(struct v4l2_format *f)
|
|
+{
|
|
+ struct cssp_cam_fmt *fmt;
|
|
+ unsigned int k;
|
|
+
|
|
+ for (k = 0; k < ARRAY_SIZE(formats); k++) {
|
|
+ fmt = &formats[k];
|
|
+ if (fmt->fourcc == f->fmt.pix.pixelformat)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (k == ARRAY_SIZE(formats))
|
|
+ return NULL;
|
|
+
|
|
+ return &formats[k];
|
|
+}
|
|
+
|
|
+
|
|
+/* ------------------------------------------------------------------
|
|
+ Videobuf operations
|
|
+ ------------------------------------------------------------------*/
|
|
+
|
|
+static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
|
|
+ unsigned int *nbuffers, unsigned int *nplanes,
|
|
+ unsigned int sizes[], void *alloc_ctxs[])
|
|
+{
|
|
+ struct cssp_cam_dev *dev = vb2_get_drv_priv(vq);
|
|
+ unsigned long size;
|
|
+
|
|
+ size = dev->sizeimage;
|
|
+
|
|
+ if (0 == *nbuffers)
|
|
+ *nbuffers = 32;
|
|
+
|
|
+ while (size * *nbuffers > vid_limit * 1024 * 1024)
|
|
+ (*nbuffers)--;
|
|
+
|
|
+ *nplanes = 1;
|
|
+
|
|
+ sizes[0] = size;
|
|
+
|
|
+ alloc_ctxs[0] = dev->dma_cont_ctx;
|
|
+
|
|
+ dprintk(dev, 1, "%s, count=%d, size=%ld\n", __func__, *nbuffers, size);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int buffer_init(struct vb2_buffer *vb)
|
|
+{
|
|
+ struct cssp_cam_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
|
|
+
|
|
+ BUG_ON(NULL == dev->fmt);
|
|
+
|
|
+ /*
|
|
+ * This callback is called once per buffer, after its allocation.
|
|
+ *
|
|
+ * Vivi does not allow changing format during streaming, but it is
|
|
+ * possible to do so when streaming is paused (i.e. in streamoff state).
|
|
+ * Buffers however are not freed when going into streamoff and so
|
|
+ * buffer size verification has to be done in buffer_prepare, on each
|
|
+ * qbuf.
|
|
+ * It would be best to move verification code here to buf_init and
|
|
+ * s_fmt though.
|
|
+ */
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int buffer_prepare(struct vb2_buffer *vb)
|
|
+{
|
|
+ struct cssp_cam_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
|
|
+ struct cssp_cam_buffer *buf = container_of(vb, struct cssp_cam_buffer, vb);
|
|
+ unsigned long size;
|
|
+
|
|
+ dprintk(dev, 1, "%s, field=%d\n", __func__, vb->v4l2_buf.field);
|
|
+
|
|
+ BUG_ON(NULL == dev->fmt);
|
|
+
|
|
+ /*
|
|
+ * Theses properties only change when queue is idle, see s_fmt.
|
|
+ * The below checks should not be performed here, on each
|
|
+ * buffer_prepare (i.e. on each qbuf). Most of the code in this function
|
|
+ * should thus be moved to buffer_init and s_fmt.
|
|
+ */
|
|
+ if (dev->width < 48 || dev->width > MAX_WIDTH ||
|
|
+ dev->height < 32 || dev->height > MAX_HEIGHT)
|
|
+ return -EINVAL;
|
|
+
|
|
+ size = dev->sizeimage;
|
|
+ if (vb2_plane_size(vb, 0) < size) {
|
|
+ dprintk(dev, 1, "%s data will not fit into plane (%lu < %lu)\n",
|
|
+ __func__, vb2_plane_size(vb, 0), size);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ vb2_set_plane_payload(&buf->vb, 0, size);
|
|
+
|
|
+ buf->fmt = dev->fmt;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int buffer_finish(struct vb2_buffer *vb)
|
|
+{
|
|
+ struct cssp_cam_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
|
|
+ dprintk(dev, 1, "%s\n", __func__);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void buffer_cleanup(struct vb2_buffer *vb)
|
|
+{
|
|
+ struct cssp_cam_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
|
|
+ dprintk(dev, 1, "%s\n", __func__);
|
|
+}
|
|
+
|
|
+static void buffer_queue(struct vb2_buffer *vb)
|
|
+{
|
|
+ struct cssp_cam_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
|
|
+ struct cssp_cam_buffer *buf = container_of(vb, struct cssp_cam_buffer, vb);
|
|
+ struct cssp_cam_dmaqueue *vidq = &dev->vidq;
|
|
+ unsigned long flags = 0;
|
|
+
|
|
+ dprintk(dev, 1, "%s\n", __func__);
|
|
+
|
|
+ if (dev->streaming_started && !dev->current_vb) {
|
|
+ trigger_dma_transfer_to_buf(dev, &buf->vb);
|
|
+ } else {
|
|
+ spin_lock_irqsave(&dev->slock, flags);
|
|
+ list_add_tail(&buf->list, &vidq->active);
|
|
+ spin_unlock_irqrestore(&dev->slock, flags);
|
|
+ }
|
|
+}
|
|
+
|
|
+static int start_streaming(struct vb2_queue *vq, unsigned int count)
|
|
+{
|
|
+ struct cssp_cam_dev *dev = vb2_get_drv_priv(vq);
|
|
+ int ret;
|
|
+
|
|
+ dprintk(dev, 1, "%s\n", __func__);
|
|
+
|
|
+ ret = start_camera_sensor(dev);
|
|
+ if (ret != 0)
|
|
+ return ret;
|
|
+
|
|
+ // Enable DMA
|
|
+ edma_start(dev->dma_ch);
|
|
+
|
|
+ dev->streaming_started = 1;
|
|
+
|
|
+ /* check if we have new buffer queued */
|
|
+ dequeue_buffer_for_dma(dev);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* abort streaming and wait for last buffer */
|
|
+static int stop_streaming(struct vb2_queue *vq)
|
|
+{
|
|
+ struct cssp_cam_dev *dev = vb2_get_drv_priv(vq);
|
|
+ struct cssp_cam_dmaqueue *dma_q = &dev->vidq;
|
|
+
|
|
+ dprintk(dev, 1, "%s\n", __func__);
|
|
+
|
|
+ // Disable DMA
|
|
+ edma_stop(dev->dma_ch);
|
|
+
|
|
+ // Disable data capture
|
|
+ dev->mode &= ~ENABLE;
|
|
+ writew(dev->mode, dev->reg_base_virt + REG_MODE);
|
|
+ readw(dev->reg_base_virt + REG_MODE);
|
|
+
|
|
+ stop_camera_sensor(dev);
|
|
+
|
|
+ dev->streaming_started = 0;
|
|
+
|
|
+ /* Release all active buffers */
|
|
+ while (!list_empty(&dma_q->active)) {
|
|
+ struct cssp_cam_buffer *buf;
|
|
+
|
|
+ buf = list_entry(dma_q->active.next, struct cssp_cam_buffer, list);
|
|
+ list_del(&buf->list);
|
|
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
|
|
+ dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index);
|
|
+ }
|
|
+
|
|
+ dev->current_vb = NULL;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void cssp_cam_lock(struct vb2_queue *vq)
|
|
+{
|
|
+ struct cssp_cam_dev *dev = vb2_get_drv_priv(vq);
|
|
+ mutex_lock(&dev->mutex);
|
|
+}
|
|
+
|
|
+static void cssp_cam_unlock(struct vb2_queue *vq)
|
|
+{
|
|
+ struct cssp_cam_dev *dev = vb2_get_drv_priv(vq);
|
|
+ mutex_unlock(&dev->mutex);
|
|
+}
|
|
+
|
|
+static struct vb2_ops cssp_cam_video_qops = {
|
|
+ .queue_setup = queue_setup,
|
|
+ .buf_init = buffer_init,
|
|
+ .buf_prepare = buffer_prepare,
|
|
+ .buf_finish = buffer_finish,
|
|
+ .buf_cleanup = buffer_cleanup,
|
|
+ .buf_queue = buffer_queue,
|
|
+ .start_streaming = start_streaming,
|
|
+ .stop_streaming = stop_streaming,
|
|
+ .wait_prepare = cssp_cam_unlock,
|
|
+ .wait_finish = cssp_cam_lock,
|
|
+};
|
|
+
|
|
+
|
|
+/* ------------------------------------------------------------------
|
|
+ IOCTL vidioc handling
|
|
+ ------------------------------------------------------------------*/
|
|
+
|
|
+static int vidioc_querycap(struct file *file, void *priv,
|
|
+ struct v4l2_capability *cap)
|
|
+{
|
|
+ struct cssp_cam_dev *dev = video_drvdata(file);
|
|
+
|
|
+ strcpy(cap->driver, "cssp_camera");
|
|
+ strcpy(cap->card, "cssp_camera");
|
|
+ strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
|
|
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
|
|
+ V4L2_CAP_READWRITE;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
|
|
+ struct v4l2_fmtdesc *f)
|
|
+{
|
|
+ struct cssp_cam_fmt *fmt;
|
|
+
|
|
+ if (f->index >= ARRAY_SIZE(formats))
|
|
+ return -EINVAL;
|
|
+
|
|
+ fmt = &formats[f->index];
|
|
+
|
|
+ strlcpy(f->description, fmt->name, sizeof(f->description));
|
|
+ f->pixelformat = fmt->fourcc;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
|
|
+ struct v4l2_format *f)
|
|
+{
|
|
+ struct cssp_cam_dev *dev = video_drvdata(file);
|
|
+
|
|
+ f->fmt.pix.width = dev->width;
|
|
+ f->fmt.pix.height = dev->height;
|
|
+ f->fmt.pix.field = dev->field;
|
|
+ f->fmt.pix.pixelformat = dev->fmt->fourcc;
|
|
+ f->fmt.pix.bytesperline = dev->bytesperline;
|
|
+ f->fmt.pix.sizeimage = dev->sizeimage;
|
|
+ f->fmt.pix.colorspace = dev->colorspace;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
|
|
+ struct v4l2_format *f)
|
|
+{
|
|
+ struct cssp_cam_dev *dev = video_drvdata(file);
|
|
+ struct cssp_cam_fmt *fmt;
|
|
+ struct v4l2_mbus_framefmt mbus_fmt;
|
|
+ struct v4l2_pix_format *pix = &f->fmt.pix;
|
|
+
|
|
+ fmt = get_format(f);
|
|
+ if (!fmt) {
|
|
+ dprintk(dev, 1, "Fourcc format (0x%08x) invalid.\n",
|
|
+ f->fmt.pix.pixelformat);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ v4l2_fill_mbus_format(&mbus_fmt, pix, fmt->code);
|
|
+ v4l2_subdev_call(dev->subdev, video, try_mbus_fmt, &mbus_fmt);
|
|
+ v4l2_fill_pix_format(pix, &mbus_fmt);
|
|
+ pix->bytesperline = (pix->width * fmt->depth) >> 3;
|
|
+ pix->sizeimage = pix->height * pix->bytesperline;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
|
|
+ struct v4l2_format *f)
|
|
+{
|
|
+ struct cssp_cam_dev *dev = video_drvdata(file);
|
|
+ struct vb2_queue *q = &dev->vb_vidq;
|
|
+ struct v4l2_pix_format *pix = &f->fmt.pix;
|
|
+ struct v4l2_mbus_framefmt mbus_fmt;
|
|
+
|
|
+ int ret = vidioc_try_fmt_vid_cap(file, priv, f);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ if (vb2_is_streaming(q)) {
|
|
+ dprintk(dev, 1, "%s device busy\n", __func__);
|
|
+ return -EBUSY;
|
|
+ }
|
|
+
|
|
+ dev->fmt = get_format(f);
|
|
+ dev->width = f->fmt.pix.width;
|
|
+ dev->height = f->fmt.pix.height;
|
|
+ dev->field = f->fmt.pix.field;
|
|
+ dev->colorspace = f->fmt.pix.colorspace;
|
|
+ dev->bytesperline = f->fmt.pix.bytesperline;
|
|
+ dev->sizeimage = f->fmt.pix.sizeimage;
|
|
+
|
|
+ /* Set the sensor into the new format */
|
|
+ v4l2_fill_mbus_format(&mbus_fmt, pix, dev->fmt->code);
|
|
+ v4l2_subdev_call(dev->subdev, video, s_mbus_fmt, &mbus_fmt);
|
|
+
|
|
+ /* Set the EDMA for the new resolution */
|
|
+ dev->dma_tr_params.a_b_cnt = ACNT(BYTES_PER_DMA_EVT) | BCNT(dev->bytesperline / BYTES_PER_DMA_EVT);
|
|
+ dev->dma_tr_params.link_bcntrld = BCNTRLD(dev->bytesperline / BYTES_PER_DMA_EVT) | LINK(0xffff);
|
|
+ dev->dma_tr_params.ccnt = CCNT(dev->height);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int vidioc_reqbufs(struct file *file, void *priv,
|
|
+ struct v4l2_requestbuffers *p)
|
|
+{
|
|
+ struct cssp_cam_dev *dev = video_drvdata(file);
|
|
+ return vb2_reqbufs(&dev->vb_vidq, p);
|
|
+}
|
|
+
|
|
+static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
|
|
+{
|
|
+ struct cssp_cam_dev *dev = video_drvdata(file);
|
|
+ return vb2_querybuf(&dev->vb_vidq, p);
|
|
+}
|
|
+
|
|
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
|
|
+{
|
|
+ struct cssp_cam_dev *dev = video_drvdata(file);
|
|
+ return vb2_qbuf(&dev->vb_vidq, p);
|
|
+}
|
|
+
|
|
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
|
|
+{
|
|
+ struct cssp_cam_dev *dev = video_drvdata(file);
|
|
+ return vb2_dqbuf(&dev->vb_vidq, p, file->f_flags & O_NONBLOCK);
|
|
+}
|
|
+
|
|
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
|
|
+{
|
|
+ struct cssp_cam_dev *dev = video_drvdata(file);
|
|
+ return vb2_streamon(&dev->vb_vidq, i);
|
|
+}
|
|
+
|
|
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
|
|
+{
|
|
+ struct cssp_cam_dev *dev = video_drvdata(file);
|
|
+ return vb2_streamoff(&dev->vb_vidq, i);
|
|
+}
|
|
+
|
|
+static int vidioc_log_status(struct file *file, void *priv)
|
|
+{
|
|
+ struct cssp_cam_dev *dev = video_drvdata(file);
|
|
+
|
|
+ v4l2_ctrl_handler_log_status(&dev->ctrl_handler, dev->v4l2_dev.name);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* only one input in this sample driver */
|
|
+static int vidioc_enum_input(struct file *file, void *priv,
|
|
+ struct v4l2_input *inp)
|
|
+{
|
|
+ return -EINVAL;
|
|
+
|
|
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
|
|
+ inp->std = V4L2_STD_525_60;
|
|
+ sprintf(inp->name, "Camera %u", inp->index);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
|
|
+{
|
|
+ struct cssp_cam_dev *dev = video_drvdata(file);
|
|
+
|
|
+ *i = dev->input;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
|
|
+{
|
|
+ struct cssp_cam_dev *dev = video_drvdata(file);
|
|
+
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (i == dev->input)
|
|
+ return 0;
|
|
+
|
|
+ dev->input = i;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int vidioc_subscribe_event(struct v4l2_fh *fh,
|
|
+ struct v4l2_event_subscription *sub)
|
|
+{
|
|
+ switch (sub->type) {
|
|
+ case V4L2_EVENT_CTRL:
|
|
+ return v4l2_event_subscribe(fh, sub, 0);
|
|
+ default:
|
|
+ return -EINVAL;
|
|
+ }
|
|
+}
|
|
+
|
|
+static const struct v4l2_ioctl_ops cssp_cam_ioctl_ops = {
|
|
+ .vidioc_querycap = vidioc_querycap,
|
|
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
|
|
+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
|
|
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
|
|
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
|
|
+ .vidioc_reqbufs = vidioc_reqbufs,
|
|
+ .vidioc_querybuf = vidioc_querybuf,
|
|
+ .vidioc_qbuf = vidioc_qbuf,
|
|
+ .vidioc_dqbuf = vidioc_dqbuf,
|
|
+ .vidioc_s_std = vidioc_s_std,
|
|
+ .vidioc_enum_input = vidioc_enum_input,
|
|
+ .vidioc_g_input = vidioc_g_input,
|
|
+ .vidioc_s_input = vidioc_s_input,
|
|
+ .vidioc_streamon = vidioc_streamon,
|
|
+ .vidioc_streamoff = vidioc_streamoff,
|
|
+ .vidioc_log_status = vidioc_log_status,
|
|
+ .vidioc_subscribe_event = vidioc_subscribe_event,
|
|
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
|
|
+};
|
|
+
|
|
+
|
|
+/* ------------------------------------------------------------------
|
|
+ File operations
|
|
+ ------------------------------------------------------------------*/
|
|
+
|
|
+static unsigned int video_poll(struct file *file, struct poll_table_struct *wait)
|
|
+{
|
|
+ struct cssp_cam_dev *dev = video_drvdata(file);
|
|
+ struct v4l2_fh *fh = file->private_data;
|
|
+ struct vb2_queue *q = &dev->vb_vidq;
|
|
+ unsigned int res;
|
|
+
|
|
+ dprintk(dev, 1, "%s\n", __func__);
|
|
+ res = vb2_poll(q, file, wait);
|
|
+ if (v4l2_event_pending(fh))
|
|
+ res |= POLLPRI;
|
|
+ else
|
|
+ poll_wait(file, &fh->wait, wait);
|
|
+ return res;
|
|
+}
|
|
+
|
|
+static int video_mmap(struct file *file, struct vm_area_struct *vma)
|
|
+{
|
|
+ struct cssp_cam_dev *dev = video_drvdata(file);
|
|
+ int ret;
|
|
+
|
|
+ dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
|
|
+
|
|
+ ret = vb2_mmap(&dev->vb_vidq, vma);
|
|
+ dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n",
|
|
+ (unsigned long)vma->vm_start,
|
|
+ (unsigned long)vma->vm_end - (unsigned long)vma->vm_start,
|
|
+ ret);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static ssize_t video_read(struct file *file, char __user *buf, size_t size, loff_t *offset)
|
|
+{
|
|
+ struct cssp_cam_dev *cam_dev = video_drvdata(file);
|
|
+
|
|
+ dprintk(cam_dev, 1, "read called\n");
|
|
+ return vb2_read(&cam_dev->vb_vidq, buf, size, offset, file->f_flags & O_NONBLOCK);
|
|
+}
|
|
+
|
|
+static int video_close(struct file *file)
|
|
+{
|
|
+ struct video_device *vdev = video_devdata(file);
|
|
+ struct cssp_cam_dev *cam_dev = video_drvdata(file);
|
|
+
|
|
+ dprintk(cam_dev, 1, "close called (dev=%s), file %p\n",
|
|
+ video_device_node_name(vdev), file);
|
|
+
|
|
+ if (v4l2_fh_is_singular_file(file))
|
|
+ vb2_queue_release(&cam_dev->vb_vidq);
|
|
+ return v4l2_fh_release(file);
|
|
+}
|
|
+
|
|
+static const struct v4l2_file_operations cssp_cam_fops = {
|
|
+ .owner = THIS_MODULE,
|
|
+ .open = v4l2_fh_open,
|
|
+ .release = video_close,
|
|
+ .read = video_read,
|
|
+ .poll = video_poll,
|
|
+ .unlocked_ioctl = video_ioctl2,
|
|
+ .mmap = video_mmap,
|
|
+};
|
|
+
|
|
+
|
|
+/* ------------------------------------------------------------------
|
|
+ Driver initialization
|
|
+ ------------------------------------------------------------------*/
|
|
+
|
|
+static struct video_device cssp_cam_template = {
|
|
+ .name = "cssp_camera",
|
|
+ .fops = &cssp_cam_fops,
|
|
+ .ioctl_ops = &cssp_cam_ioctl_ops,
|
|
+ .minor = -1,
|
|
+ .release = video_device_release,
|
|
+ .tvnorms = V4L2_STD_525_60,
|
|
+ .current_norm = V4L2_STD_NTSC_M,
|
|
+};
|
|
+
|
|
+static int __init video_probe(struct cssp_cam_dev *cam_dev)
|
|
+{
|
|
+ struct video_device *vfd;
|
|
+ struct v4l2_ctrl_handler *hdl;
|
|
+ struct vb2_queue *q;
|
|
+ int ret = 0;
|
|
+
|
|
+ snprintf(cam_dev->v4l2_dev.name, sizeof(cam_dev->v4l2_dev.name),
|
|
+ "%s-%03d", "cssp_camera", 0);
|
|
+ ret = v4l2_device_register(NULL, &cam_dev->v4l2_dev);
|
|
+ if (ret)
|
|
+ goto free_dev;
|
|
+
|
|
+ cam_dev->fmt = &formats[0];
|
|
+ cam_dev->width = VGA_WIDTH;
|
|
+ cam_dev->height = VGA_HEIGHT;
|
|
+ cam_dev->sizeimage = VGA_WIDTH * VGA_HEIGHT * BYTES_PER_PIXEL;
|
|
+ hdl = &cam_dev->ctrl_handler;
|
|
+ v4l2_ctrl_handler_init(hdl, 0);
|
|
+
|
|
+ if (hdl->error) {
|
|
+ ret = hdl->error;
|
|
+ goto unreg_dev;
|
|
+ }
|
|
+ cam_dev->v4l2_dev.ctrl_handler = hdl;
|
|
+
|
|
+ /* initialize locks */
|
|
+ spin_lock_init(&cam_dev->slock);
|
|
+
|
|
+ /* initialize queue */
|
|
+ q = &cam_dev->vb_vidq;
|
|
+ memset(q, 0, sizeof(cam_dev->vb_vidq));
|
|
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
+ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
|
|
+ q->drv_priv = cam_dev;
|
|
+ q->buf_struct_size = sizeof(struct cssp_cam_buffer);
|
|
+ q->ops = &cssp_cam_video_qops;
|
|
+ q->mem_ops = &vb2_dma_contig_memops;
|
|
+
|
|
+ vb2_queue_init(q);
|
|
+
|
|
+ mutex_init(&cam_dev->mutex);
|
|
+
|
|
+ /* init video dma queues */
|
|
+ INIT_LIST_HEAD(&cam_dev->vidq.active);
|
|
+
|
|
+ ret = -ENOMEM;
|
|
+ vfd = video_device_alloc();
|
|
+ if (!vfd)
|
|
+ goto unreg_dev;
|
|
+
|
|
+ *vfd = cssp_cam_template;
|
|
+ vfd->debug = debug;
|
|
+ vfd->v4l2_dev = &cam_dev->v4l2_dev;
|
|
+ set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
|
|
+
|
|
+ /*
|
|
+ * Provide a mutex to v4l2 core. It will be used to protect
|
|
+ * all fops and v4l2 ioctls.
|
|
+ */
|
|
+ vfd->lock = &cam_dev->mutex;
|
|
+
|
|
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
|
|
+ if (ret < 0)
|
|
+ goto rel_vdev;
|
|
+
|
|
+ video_set_drvdata(vfd, cam_dev);
|
|
+
|
|
+ if (video_nr != -1)
|
|
+ video_nr++;
|
|
+
|
|
+ cam_dev->vdev = vfd;
|
|
+ v4l2_info(&cam_dev->v4l2_dev, "V4L2 device registered as %s\n",
|
|
+ video_device_node_name(vfd));
|
|
+
|
|
+ return 0;
|
|
+
|
|
+rel_vdev:
|
|
+ video_device_release(vfd);
|
|
+unreg_dev:
|
|
+ v4l2_ctrl_handler_free(hdl);
|
|
+ v4l2_device_unregister(&cam_dev->v4l2_dev);
|
|
+free_dev:
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int video_remove(struct cssp_cam_dev *cam_dev)
|
|
+{
|
|
+ if (cam_dev->dma_cont_ctx != NULL)
|
|
+ vb2_dma_contig_cleanup_ctx(cam_dev->dma_cont_ctx);
|
|
+
|
|
+ v4l2_info(&cam_dev->v4l2_dev, "unregistering %s\n",
|
|
+ video_device_node_name(cam_dev->vdev));
|
|
+ video_unregister_device(cam_dev->vdev);
|
|
+ v4l2_device_unregister(&cam_dev->v4l2_dev);
|
|
+ v4l2_ctrl_handler_free(&cam_dev->ctrl_handler);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int __init cssp_cam_probe(struct platform_device *pdev)
|
|
+{
|
|
+ struct cssp_cam_dev *cam_dev;
|
|
+ int ret = 0;
|
|
+ struct cssp_cam_platform_data *cssp_cam_platform_data;
|
|
+
|
|
+ cssp_cam_platform_data = (struct cssp_cam_platform_data *) pdev->dev.platform_data;
|
|
+ if (cssp_cam_platform_data == NULL) {
|
|
+ printk(KERN_ERR "[%s]: missing platform data\n", pdev->name);
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
+ if (cssp_cam_platform_data->cam_i2c_board_info == NULL) {
|
|
+ printk(KERN_ERR "[%s]: missing camera i2c board info\n", pdev->name);
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
+ cam_dev = kzalloc(sizeof(*cam_dev), GFP_KERNEL);
|
|
+ if (!cam_dev)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ cam_dev->pdev = pdev;
|
|
+ platform_set_drvdata(pdev, cam_dev);
|
|
+
|
|
+ cam_dev->camera_board_info = cssp_cam_platform_data->cam_i2c_board_info;
|
|
+
|
|
+ cam_dev->camera_clk = clk_get(&pdev->dev, cssp_cam_platform_data->cam_clk_name);
|
|
+ if (IS_ERR(cam_dev->camera_clk)) {
|
|
+ ret = PTR_ERR(cam_dev->camera_clk);
|
|
+ printk(KERN_ERR "[%s]: cannot clk_get %s\n", pdev->name, cssp_cam_platform_data->cam_clk_name);
|
|
+ goto fail0;
|
|
+ }
|
|
+
|
|
+ ret = configure_cssp(cam_dev);
|
|
+ if (ret)
|
|
+ goto fail1;
|
|
+
|
|
+ ret = configure_edma(cam_dev);
|
|
+ if (ret)
|
|
+ goto fail2;
|
|
+
|
|
+ cam_dev->mode = FMT_2X8_EN | PCLK_POL | HS_EN;
|
|
+
|
|
+ ret = configure_camera_sensor(cam_dev);
|
|
+ if (ret) {
|
|
+ printk(KERN_ERR "[%s]: camera sensor configuration failed\n", pdev->name);
|
|
+ goto fail3;
|
|
+ }
|
|
+
|
|
+ cam_dev->dma_cont_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
|
|
+ if (IS_ERR(cam_dev->dma_cont_ctx)) {
|
|
+ ret = PTR_ERR(cam_dev->dma_cont_ctx);
|
|
+ goto fail3;
|
|
+ }
|
|
+
|
|
+ ret = video_probe(cam_dev);
|
|
+ if (ret)
|
|
+ goto fail4;
|
|
+
|
|
+ return ret;
|
|
+
|
|
+fail4:
|
|
+ vb2_dma_contig_cleanup_ctx(cam_dev->dma_cont_ctx);
|
|
+
|
|
+fail3:
|
|
+ edma_free_channel(cam_dev->dma_ch);
|
|
+
|
|
+fail2:
|
|
+ gpio_free(cam_dev->reset_pin);
|
|
+ iounmap((void *)cam_dev->reg_base_virt);
|
|
+ release_mem_region(cam_dev->reg_base_phys, cam_dev->reg_size);
|
|
+
|
|
+fail1:
|
|
+ clk_put(cam_dev->camera_clk);
|
|
+
|
|
+fail0:
|
|
+ kfree(cam_dev);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int cssp_cam_remove(struct platform_device *pdev)
|
|
+{
|
|
+ struct cssp_cam_dev *cam = platform_get_drvdata(pdev);
|
|
+
|
|
+ iounmap((void *)cam->reg_base_virt);
|
|
+
|
|
+ release_mem_region(cam->reg_base_phys, cam->reg_size);
|
|
+
|
|
+ gpio_free(cam->reset_pin);
|
|
+
|
|
+ edma_free_channel(cam->dma_ch);
|
|
+
|
|
+ video_remove(cam);
|
|
+
|
|
+ clk_put(cam->camera_clk);
|
|
+
|
|
+ kfree(cam);
|
|
+
|
|
+ printk(KERN_INFO "[%s]: removed\n", pdev->name);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+static struct platform_driver cssp_cam_driver = {
|
|
+ .probe = cssp_cam_probe,
|
|
+ .remove = __devexit_p(cssp_cam_remove),
|
|
+ .driver = {
|
|
+ .name = "cssp-camera",
|
|
+ .owner = THIS_MODULE,
|
|
+ },
|
|
+};
|
|
+
|
|
+
|
|
+static int __init cssp_cam_init(void)
|
|
+{
|
|
+ return platform_driver_register(&cssp_cam_driver);
|
|
+}
|
|
+
|
|
+static void __exit cssp_cam_exit(void)
|
|
+{
|
|
+ platform_driver_unregister(&cssp_cam_driver);
|
|
+}
|
|
+
|
|
+
|
|
+module_init(cssp_cam_init);
|
|
+module_exit(cssp_cam_exit);
|
|
+
|
|
+/*
|
|
+ * Macros sets license, author and description
|
|
+ */
|
|
+MODULE_LICENSE("GPLv2");
|
|
+MODULE_AUTHOR("Dan Aizenstros, Damian Eppel, Przemek Szewczyk");
|
|
+MODULE_DESCRIPTION("QuickLogic Camera Interface driver");
|
|
+
|
|
diff --git a/drivers/media/video/cssp_camera/cssp_camera.h b/drivers/media/video/cssp_camera/cssp_camera.h
|
|
new file mode 100644
|
|
index 0000000..d018ca1
|
|
--- /dev/null
|
|
+++ b/drivers/media/video/cssp_camera/cssp_camera.h
|
|
@@ -0,0 +1,148 @@
|
|
+/*
|
|
+ * cssp-camera driver
|
|
+ *
|
|
+ * Based on Vivi driver
|
|
+ *
|
|
+ * Copyright (C) 2012 QuickLogic Corp.
|
|
+ *
|
|
+ * Developed for QuickLogic by:
|
|
+ * Damian Eppel <damian.eppel@teleca.com>
|
|
+ * Przemek Szewczyk <przemek.szewczyk@teleca.com>
|
|
+ * Dan Aizenstros <daizenstros@quicklogic.com>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License version 2 as
|
|
+ * published by the Free Software Foundation.
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef CSSP_CAMERA_H
|
|
+#define CSSP_CAMERA_H
|
|
+
|
|
+
|
|
+static unsigned video_nr = -1;
|
|
+module_param(video_nr, uint, 0644);
|
|
+MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect");
|
|
+
|
|
+static unsigned debug;
|
|
+module_param(debug, uint, 0644);
|
|
+MODULE_PARM_DESC(debug, "activates debug info");
|
|
+
|
|
+static unsigned int vid_limit = 1;
|
|
+module_param(vid_limit, uint, 0644);
|
|
+MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
|
|
+
|
|
+#define dprintk(dev, level, fmt, arg...) \
|
|
+ v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg)
|
|
+
|
|
+#define VGA_WIDTH 640
|
|
+#define VGA_HEIGHT 480
|
|
+
|
|
+#define MAX_WIDTH 2048
|
|
+#define MAX_HEIGHT 1536
|
|
+
|
|
+#define VGA_RES (VGA_WIDTH * VGA_HEIGHT)
|
|
+#define BYTES_PER_PIXEL 2
|
|
+#define BYTES_PER_DMA_EVT 32
|
|
+
|
|
+/* PaRAM.opt: */
|
|
+#define TCC(v) (((v) & 0x3f) << 12)
|
|
+/* PaRAM.a_b_cnt: */
|
|
+#define ACNT(v) ((v) & 0xffff)
|
|
+#define BCNT(v) (((v) & 0xffff) << 16)
|
|
+/* PaRAM.src_dst_bidx: */
|
|
+#define SRCBIDX(v) ((v) & 0xffff)
|
|
+#define DSTBIDX(v) (((v) & 0xffff) << 16)
|
|
+/* PaRAM.link_bcntrld: */
|
|
+#define LINK(v) ((v) & 0xffff)
|
|
+#define BCNTRLD(v) (((v) & 0xffff) << 16)
|
|
+/* PaRAM.src_dst_cidx: */
|
|
+#define SRCCIDX(v) ((v) & 0xffff)
|
|
+#define DSTCIDX(v) (((v) & 0xffff) << 16)
|
|
+/* PaRAM.ccnt: */
|
|
+#define CCNT(v) ((v) & 0xffff)
|
|
+
|
|
+
|
|
+struct cssp_cam_platform_data {
|
|
+ struct i2c_board_info *cam_i2c_board_info;
|
|
+ const char *cam_clk_name;
|
|
+ int dma_ch;
|
|
+ int gpio_reset_pin;
|
|
+};
|
|
+
|
|
+
|
|
+/* ------------------------------------------------------------------
|
|
+ video Basic structures
|
|
+ ------------------------------------------------------------------*/
|
|
+
|
|
+struct cssp_cam_fmt {
|
|
+ char *name;
|
|
+ u32 fourcc; /* v4l2 format id */
|
|
+ int depth;
|
|
+ enum v4l2_mbus_pixelcode code;
|
|
+};
|
|
+
|
|
+/* buffer for one video frame */
|
|
+struct cssp_cam_buffer {
|
|
+ /* common v4l buffer stuff -- must be first */
|
|
+ struct vb2_buffer vb;
|
|
+ struct list_head list;
|
|
+ struct cssp_cam_fmt *fmt;
|
|
+};
|
|
+
|
|
+struct cssp_cam_dmaqueue {
|
|
+ struct list_head active;
|
|
+};
|
|
+
|
|
+struct cssp_cam_dev {
|
|
+ struct v4l2_device v4l2_dev;
|
|
+ struct v4l2_ctrl_handler ctrl_handler;
|
|
+ struct v4l2_subdev *subdev;
|
|
+
|
|
+ spinlock_t slock;
|
|
+ struct mutex mutex;
|
|
+
|
|
+ /* various device info */
|
|
+ struct video_device *vdev;
|
|
+ struct platform_device *pdev;
|
|
+
|
|
+ struct cssp_cam_dmaqueue vidq;
|
|
+ void *dma_cont_ctx;
|
|
+ int streaming_started;
|
|
+ struct vb2_buffer *current_vb;
|
|
+
|
|
+ /* Input Number */
|
|
+ int input;
|
|
+
|
|
+ /* video capture */
|
|
+ struct cssp_cam_fmt *fmt;
|
|
+ u32 width;
|
|
+ u32 height;
|
|
+ u32 bytesperline;
|
|
+ u32 sizeimage;
|
|
+ enum v4l2_colorspace colorspace;
|
|
+ struct vb2_queue vb_vidq;
|
|
+ enum v4l2_field field;
|
|
+ unsigned int field_count;
|
|
+
|
|
+
|
|
+ /* Camera Sensor */
|
|
+ struct i2c_board_info *camera_board_info;
|
|
+ struct clk *camera_clk;
|
|
+
|
|
+ unsigned int reg_base_virt;
|
|
+ unsigned int reg_base_phys;
|
|
+ resource_size_t reg_size;
|
|
+ u16 mode;
|
|
+
|
|
+ struct edmacc_param dma_tr_params;
|
|
+ int dma_ch;
|
|
+ u64 dma_mask;
|
|
+
|
|
+ int frame_cnt;
|
|
+
|
|
+ int reset_pin;
|
|
+};
|
|
+
|
|
+
|
|
+#endif /* CSSP_CAMERA_H */
|
|
--
|
|
1.7.10
|
|
|